Add attestato generation UI
"Genera Attestato" button on the association detail page downloads the certificate PDF from the new backend endpoint; the edit dialog gained a ratification-code field (used on the certificate). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017hQcuUQFue2bFvrYw2UQhK
This commit is contained in:
parent
cb0c8dc140
commit
9274377a3d
@ -2,7 +2,7 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { ArrowLeft, Loader2, Plus, Trash2 } from "lucide-react";
|
||||
import { ArrowLeft, FileDown, 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";
|
||||
@ -14,7 +14,7 @@ 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 { deleteAssociation, downloadAttestato, getAssociation, updateAssociation } from "@/lib/api";
|
||||
import type { Associate, Association, User } from "@/lib/models";
|
||||
|
||||
export default function AssociationDetailPage() {
|
||||
@ -31,6 +31,8 @@ export default function AssociationDetailPage() {
|
||||
const [userDialogOpen, setUserDialogOpen] = useState(false);
|
||||
const [editingUserIndex, setEditingUserIndex] = useState<number | undefined>(undefined);
|
||||
|
||||
const [generatingAttestato, setGeneratingAttestato] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
getAssociation(id)
|
||||
.then(setAssociation)
|
||||
@ -106,6 +108,18 @@ export default function AssociationDetailPage() {
|
||||
router.push("/dashboard");
|
||||
};
|
||||
|
||||
const handleDownloadAttestato = async () => {
|
||||
if (!association) return;
|
||||
setGeneratingAttestato(true);
|
||||
try {
|
||||
await downloadAttestato(id, association.name);
|
||||
} catch (error) {
|
||||
console.error("Failed to generate attestato:", error);
|
||||
} finally {
|
||||
setGeneratingAttestato(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center text-muted-foreground">
|
||||
@ -137,6 +151,14 @@ export default function AssociationDetailPage() {
|
||||
description={`${association.associates?.length ?? 0} soci registrati`}
|
||||
actions={
|
||||
<>
|
||||
<Button variant="outline" onClick={handleDownloadAttestato} disabled={generatingAttestato}>
|
||||
{generatingAttestato ? (
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
) : (
|
||||
<FileDown className="size-4" />
|
||||
)}
|
||||
Genera Attestato
|
||||
</Button>
|
||||
<EditAssociationDialog association={association} onSaved={setAssociation} />
|
||||
<ConfirmDialog
|
||||
trigger={
|
||||
|
||||
@ -30,6 +30,7 @@ export function EditAssociationDialog({
|
||||
const [address, setAddress] = useState(association.address);
|
||||
const [vatNumber, setVatNumber] = useState(association.vatNumber ?? "");
|
||||
const [runtsId, setRuntsId] = useState(association.runtsId ?? "");
|
||||
const [ratificationCode, setRatificationCode] = useState(association.ratificationCode ?? "");
|
||||
const [isShown, setIsShown] = useState(association.isShown ?? true);
|
||||
|
||||
useEffect(() => {
|
||||
@ -38,6 +39,7 @@ export function EditAssociationDialog({
|
||||
setAddress(association.address);
|
||||
setVatNumber(association.vatNumber ?? "");
|
||||
setRuntsId(association.runtsId ?? "");
|
||||
setRatificationCode(association.ratificationCode ?? "");
|
||||
setIsShown(association.isShown ?? true);
|
||||
}
|
||||
}, [open, association]);
|
||||
@ -52,6 +54,7 @@ export function EditAssociationDialog({
|
||||
address,
|
||||
vatNumber,
|
||||
runtsId,
|
||||
ratificationCode,
|
||||
isShown,
|
||||
});
|
||||
onSaved(updated);
|
||||
@ -98,6 +101,16 @@ export function EditAssociationDialog({
|
||||
<Input id="e-runtsId" value={runtsId} onChange={(e) => setRuntsId(e.target.value)} />
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="e-ratificationCode">Codice ratifica (es. LO183)</Label>
|
||||
<Input
|
||||
id="e-ratificationCode"
|
||||
value={ratificationCode}
|
||||
onChange={(e) => setRatificationCode(e.target.value)}
|
||||
placeholder="Usato nell'attestato di adesione"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between rounded-lg border p-3 sm:col-span-2">
|
||||
<div>
|
||||
<Label htmlFor="e-isShown">Associazione attiva</Label>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user