Marketplace inversée (Next.js 16 App Router + Supabase Cloud) : auth, schéma + RLS, publication de besoins avec upload d'images, feed avec filtres, offres, acceptation via RPC, messagerie temps réel, dashboards, et Dockerfile pour déploiement Coolify.
56 lines
2.0 KiB
TypeScript
56 lines
2.0 KiB
TypeScript
import Link from "next/link";
|
|
import { verifySession } from "@/lib/dal";
|
|
import { createClient } from "@/lib/supabase/server";
|
|
import { Card, CardContent } from "@/components/ui/card";
|
|
|
|
export default async function MessagesPage() {
|
|
const user = await verifySession();
|
|
const supabase = await createClient();
|
|
|
|
const { data: conversations } = await supabase
|
|
.from("conversations")
|
|
.select(
|
|
"id, created_at, author_id, merchant_id, needs(title), author:profiles!conversations_author_id_fkey(full_name), merchant:profiles!conversations_merchant_id_fkey(full_name)"
|
|
)
|
|
.order("created_at", { ascending: false });
|
|
|
|
return (
|
|
<div className="mx-auto max-w-2xl px-4 py-8 sm:px-6 sm:py-10">
|
|
<h1 className="text-2xl font-semibold">Messages</h1>
|
|
|
|
{!conversations || conversations.length === 0 ? (
|
|
<p className="mt-6 text-muted-foreground">
|
|
Aucune conversation pour le moment. Elles apparaissent ici une fois
|
|
qu'une offre est acceptée.
|
|
</p>
|
|
) : (
|
|
<div className="mt-6 flex flex-col gap-3">
|
|
{conversations.map((conv) => {
|
|
const isAuthor = conv.author_id === user.id;
|
|
const other = isAuthor ? conv.merchant : conv.author;
|
|
const otherName = Array.isArray(other)
|
|
? other[0]?.full_name
|
|
: other?.full_name;
|
|
const need = Array.isArray(conv.needs) ? conv.needs[0] : conv.needs;
|
|
|
|
return (
|
|
<Link key={conv.id} href={`/messages/${conv.id}`}>
|
|
<Card className="transition-shadow hover:shadow-md">
|
|
<CardContent className="min-w-0 py-4">
|
|
<p className="truncate font-medium">
|
|
{otherName ?? "Utilisateur"}
|
|
</p>
|
|
<p className="truncate text-sm text-muted-foreground">
|
|
{need?.title}
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|