- Association list search now also matches nasFolderNumber. - Dropped the "Indirizzo" column from the list table (still editable in the edit dialog, just not shown in the table). - Removed the manual "Codice ratifica" field from the edit dialog - it's derived automatically now, so a manual override field was redundant and a source of stale/wrong values; the underlying field is untouched by this (existing values are preserved via the spread), just no longer directly editable here. - Saving a NAS folder number that's already used by another association now warns (with the other association's name) before proceeding, since a collision silently produces two associations with the same ratification code. Verified live: table has no Indirizzo column, searching "2" surfaces "#2 ENCAP ODV", the ratification code field is gone from the edit dialog, and setting folder 4 (already used by ENCAP - COMITATO REGIONALE VENETO) triggers the duplicate warning. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017hQcuUQFue2bFvrYw2UQhK
80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useMemo, useState } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { Loader2 } from "lucide-react";
|
|
import { AppHeader } from "@/components/layout/app-header";
|
|
import { PageHeader } from "@/components/layout/page-header";
|
|
import { AssociationSearch } from "@/components/associations/association-search";
|
|
import { AssociationTable } from "@/components/associations/association-table";
|
|
import { CreateAssociationDialog } from "@/components/associations/create-association-dialog";
|
|
import { getAssociations } from "@/lib/api";
|
|
import type { Association } from "@/lib/models";
|
|
|
|
export default function DashboardPage() {
|
|
const router = useRouter();
|
|
const [associations, setAssociations] = useState<Association[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [mounted, setMounted] = useState(false);
|
|
const [query, setQuery] = useState("");
|
|
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!mounted) return;
|
|
getAssociations()
|
|
.then(setAssociations)
|
|
.catch((error: Error) => {
|
|
if (error.message === "Unauthorized") {
|
|
router.push("/login");
|
|
} else {
|
|
console.error(error);
|
|
}
|
|
})
|
|
.finally(() => setLoading(false));
|
|
}, [mounted, router]);
|
|
|
|
const filtered = useMemo(() => {
|
|
const query_ = query.trim().toLowerCase();
|
|
if (!query_) return associations;
|
|
return associations.filter((association) =>
|
|
[
|
|
association.name,
|
|
association.address,
|
|
association.vatNumber,
|
|
association.runtsId,
|
|
association.nasFolderNumber?.toString(),
|
|
].some((value) => value?.toLowerCase().includes(query_))
|
|
);
|
|
}, [associations, query]);
|
|
|
|
if (!mounted || loading) {
|
|
return (
|
|
<div className="flex min-h-screen items-center justify-center text-muted-foreground">
|
|
<Loader2 className="size-5 animate-spin" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-muted/30">
|
|
<AppHeader />
|
|
<main className="mx-auto max-w-7xl space-y-6 p-6">
|
|
<PageHeader
|
|
title="Associazioni"
|
|
description={`${associations.length} associazioni registrate`}
|
|
actions={
|
|
<CreateAssociationDialog
|
|
onCreated={(association) => router.push(`/dashboard/${association.id}`)}
|
|
/>
|
|
}
|
|
/>
|
|
<AssociationSearch value={query} onChange={setQuery} />
|
|
<AssociationTable associations={filtered} />
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|