ente_nazionale_frontend/app/dashboard/[id]/page.tsx
2026-08-17 11:34:06 +03:00

206 lines
6.9 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { ArrowLeft, Loader2, Plus, Trash2 } from "lucide-react";
import { AppHeader } from "@/components/layout/app-header";
import { PageHeader } from "@/components/layout/page-header";
import { AssociateFormDialog } from "@/components/associations/associate-form-dialog";
import { AssociateTable } from "@/components/associations/associate-table";
import { AssociationInfoCard } from "@/components/associations/association-info-card";
import { EditAssociationDialog } from "@/components/associations/edit-association-dialog";
import { UserAccountsCard } from "@/components/associations/user-accounts-card";
import { UserFormDialog } from "@/components/associations/user-form-dialog";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { ConfirmDialog } from "@/components/ui/confirm-dialog";
import { deleteAssociation, getAssociation, updateAssociation } from "@/lib/api";
import type { Associate, Association, User } from "@/lib/models";
export default function AssociationDetailPage() {
const router = useRouter();
const params = useParams();
const id = params.id as string;
const [association, setAssociation] = useState<Association | null>(null);
const [loading, setLoading] = useState(true);
const [associateDialogOpen, setAssociateDialogOpen] = useState(false);
const [editingAssociateIndex, setEditingAssociateIndex] = useState<number | undefined>(undefined);
const [userDialogOpen, setUserDialogOpen] = useState(false);
const [editingUserIndex, setEditingUserIndex] = useState<number | undefined>(undefined);
useEffect(() => {
getAssociation(id)
.then(setAssociation)
.catch((error) => {
console.error("Failed to load association:", error);
router.push("/dashboard");
})
.finally(() => setLoading(false));
}, [id, router]);
const persist = async (updated: Association) => {
const saved = await updateAssociation(id, updated);
setAssociation(saved);
};
const openAddAssociate = () => {
setEditingAssociateIndex(undefined);
setAssociateDialogOpen(true);
};
const openEditAssociate = (index: number) => {
setEditingAssociateIndex(index);
setAssociateDialogOpen(true);
};
const handleAssociateSubmit = async (associate: Associate) => {
if (!association) return;
const associates = [...(association.associates ?? [])];
if (editingAssociateIndex !== undefined) {
associates[editingAssociateIndex] = associate;
} else {
associates.push(associate);
}
await persist({ ...association, associates });
};
const handleAssociateDelete = async (index: number) => {
if (!association) return;
const associates = (association.associates ?? []).filter((_, i) => i !== index);
await persist({ ...association, associates });
};
const openAddUser = () => {
setEditingUserIndex(undefined);
setUserDialogOpen(true);
};
const openEditUser = (index: number) => {
setEditingUserIndex(index);
setUserDialogOpen(true);
};
const handleUserSubmit = async (user: User) => {
if (!association) return;
const users = [...(association.users ?? [])];
if (editingUserIndex !== undefined) {
const existing = users[editingUserIndex];
users[editingUserIndex] = { ...user, password: user.password || existing.password };
} else {
users.push(user);
}
await persist({ ...association, users });
};
const handleUserDelete = async (index: number) => {
if (!association) return;
const users = (association.users ?? []).filter((_, i) => i !== index);
await persist({ ...association, users });
};
const handleDeleteAssociation = async () => {
await deleteAssociation(id);
router.push("/dashboard");
};
if (loading) {
return (
<div className="flex min-h-screen items-center justify-center text-muted-foreground">
<Loader2 className="size-5 animate-spin" />
</div>
);
}
if (!association) {
return null;
}
return (
<div className="min-h-screen bg-muted/30">
<AppHeader />
<main className="mx-auto max-w-5xl space-y-6 p-6">
<div>
<Button
variant="ghost"
size="sm"
className="-ml-2 mb-2"
onClick={() => router.push("/dashboard")}
>
<ArrowLeft className="size-4" />
Torna alle associazioni
</Button>
<PageHeader
title={association.name}
description={`${association.associates?.length ?? 0} soci registrati`}
actions={
<>
<EditAssociationDialog association={association} onSaved={setAssociation} />
<ConfirmDialog
trigger={
<Button variant="outline" className="text-destructive hover:text-destructive">
<Trash2 className="size-4" />
Elimina
</Button>
}
title="Eliminare questa associazione?"
description={`"${association.name}" e tutti i suoi soci verranno eliminati definitivamente. L'operazione non è reversibile.`}
confirmLabel="Elimina definitivamente"
onConfirm={handleDeleteAssociation}
/>
</>
}
/>
</div>
<AssociationInfoCard association={association} />
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Soci ({association.associates?.length ?? 0})</CardTitle>
<Button size="sm" onClick={openAddAssociate}>
<Plus className="size-4" />
Aggiungi socio
</Button>
</CardHeader>
<CardContent>
<AssociateTable
associates={association.associates ?? []}
onEdit={openEditAssociate}
onDelete={handleAssociateDelete}
/>
</CardContent>
</Card>
<UserAccountsCard
users={association.users ?? []}
onEdit={openEditUser}
onDelete={handleUserDelete}
actions={
<Button size="sm" onClick={openAddUser}>
<Plus className="size-4" />
Aggiungi account
</Button>
}
/>
</main>
<AssociateFormDialog
open={associateDialogOpen}
onOpenChange={setAssociateDialogOpen}
initialValue={editingAssociateIndex !== undefined ? association.associates?.[editingAssociateIndex] : undefined}
onSubmit={handleAssociateSubmit}
/>
<UserFormDialog
open={userDialogOpen}
onOpenChange={setUserDialogOpen}
initialValue={editingUserIndex !== undefined ? association.users?.[editingUserIndex] : undefined}
onSubmit={handleUserSubmit}
/>
</div>
);
}