feat(02-03): build /admin/clients/[id] workspace with tabbed layout and all tab components
- Create /admin/clients/[id]/page.tsx — Server Component using Radix Tabs (Fasi & Task, Pagamenti, Documenti, Commenti) - Create PhasesTab: phases list with add-phase form, task lists with add-task form, status selects for phases and tasks - Create PaymentsTab: accepted_total editor (splits to 50% on each payment), payment status selects with paid_at on saldato - Create DocumentsTab: add document (label + URL) form, document list with delete action - Create CommentsTab: chronological comment display (admin vs cliente style), admin reply form with entity selector - All mutations via inline Server Action closures bound to action= props; revalidatePath ensures fresh data
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import { getClientFullDetail } from "@/lib/admin-queries";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { PhasesTab } from "@/components/admin/tabs/PhasesTab";
|
||||
import { PaymentsTab } from "@/components/admin/tabs/PaymentsTab";
|
||||
import { DocumentsTab } from "@/components/admin/tabs/DocumentsTab";
|
||||
import { CommentsTab } from "@/components/admin/tabs/CommentsTab";
|
||||
import Link from "next/link";
|
||||
|
||||
export const revalidate = 0;
|
||||
|
||||
export default async function ClientDetailPage({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ id: string }>;
|
||||
}) {
|
||||
const { id } = await params;
|
||||
const detail = await getClientFullDetail(id);
|
||||
if (!detail) notFound();
|
||||
|
||||
const { client, phases, payments, documents, notes, comments } = detail;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-4">
|
||||
<Link href="/admin" className="text-sm text-gray-500 hover:text-gray-700">
|
||||
← Clienti
|
||||
</Link>
|
||||
</div>
|
||||
<div className="mb-6 flex items-start justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-gray-900">{client.name}</h1>
|
||||
<p className="text-sm text-gray-500">{client.brand_name}</p>
|
||||
</div>
|
||||
<a
|
||||
href={`/c/${client.token}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-xs text-blue-600 hover:underline font-mono bg-blue-50 px-2 py-1 rounded"
|
||||
>
|
||||
Link cliente →
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<Tabs defaultValue="phases" className="w-full">
|
||||
<TabsList className="mb-6">
|
||||
<TabsTrigger value="phases">Fasi & Task</TabsTrigger>
|
||||
<TabsTrigger value="payments">Pagamenti</TabsTrigger>
|
||||
<TabsTrigger value="documents">Documenti</TabsTrigger>
|
||||
<TabsTrigger value="comments">Commenti</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="phases">
|
||||
<PhasesTab phases={phases} clientId={client.id} />
|
||||
</TabsContent>
|
||||
<TabsContent value="payments">
|
||||
<PaymentsTab
|
||||
payments={payments}
|
||||
acceptedTotal={client.accepted_total ?? "0"}
|
||||
clientId={client.id}
|
||||
/>
|
||||
</TabsContent>
|
||||
<TabsContent value="documents">
|
||||
<DocumentsTab documents={documents} clientId={client.id} />
|
||||
</TabsContent>
|
||||
<TabsContent value="comments">
|
||||
<CommentsTab comments={comments} phases={phases} clientId={client.id} />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user