feat: enhance RichiesteTable with status handling and display logic

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Marco Pedone 2026-05-05 16:30:58 +02:00
parent b7e1e964c3
commit 655d69c94b
2 changed files with 179 additions and 178 deletions

View file

@ -13,6 +13,7 @@ import {
UserActions, UserActions,
} from "~/components/servizio/annuncio_actions"; } from "~/components/servizio/annuncio_actions";
import { IncrociDialog } from "~/components/servizio/incroci"; import { IncrociDialog } from "~/components/servizio/incroci";
import type { StatusKey } from "~/components/tables/richieste-table";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import { Textarea } from "~/components/ui/textarea"; import { Textarea } from "~/components/ui/textarea";
import { useMediaQuery } from "~/hooks/use-media-query"; import { useMediaQuery } from "~/hooks/use-media-query";
@ -143,7 +144,7 @@ export const AnnuncioCardRichieste = ({
tableRef, tableRef,
data, data,
}: { }: {
tableRef: RefObject<Table<RichiesteData> | null>; tableRef: RefObject<Table<RichiesteData & { status: StatusKey }> | null>;
data: ServizioAnnuncioData; data: ServizioAnnuncioData;
}) => { }) => {
const { onMutate, onSettled } = MutationPageRestore(tableRef); const { onMutate, onSettled } = MutationPageRestore(tableRef);

View file

@ -9,11 +9,14 @@ import {
import { it } from "date-fns/locale"; import { it } from "date-fns/locale";
import { import {
BadgeEuro,
CircleCheck, CircleCheck,
CircleCheckBig, CircleCheckBig,
ClipboardPen,
ClockFading, ClockFading,
ExternalLink, ExternalLink,
Logs, Logs,
ReceiptEuro,
SearchX, SearchX,
UserCog, UserCog,
} from "lucide-react"; } from "lucide-react";
@ -69,8 +72,108 @@ type RichiesteTableProps = {
data: RichiesteData[]; data: RichiesteData[];
}; };
const StatusMapping = {
attesa_attivazione: "Attesa di attivazione",
interrotto: "Interrotto",
onboarding: "Onboarding",
scaduto: "Scaduto",
consulenza_da_pagare: "Consulenza da pagare",
consulenza_da_inserire: "Consulenza da inserire",
attesa_saldo: "Attesa pagamento saldo",
attesa_caparra: "Attesa versamento caparra",
attesa_conferma: "Attesa accettazione conferma",
attivo: "Attivo",
attesa_pagamento_acconto: "Attesa pagamento acconto",
confermato: "Confermato",
};
export type StatusKey = keyof typeof StatusMapping;
function statusParser(data: RichiesteData): keyof typeof StatusMapping {
if (data.isInterrotto) {
return "interrotto";
}
if (!data.onboardOk) {
return "onboarding";
}
if (!data.isOkAcconto || !data.decorrenza) {
const acconti = data.ordini_servizio.filter(
(o) => o.type === orderTypeEnum.enum.Acconto,
);
const activeAcconto = acconti.find((a) => a.isActive);
//hasActiveAcconto
if (activeAcconto) {
return "attesa_attivazione";
}
return "attesa_pagamento_acconto";
}
if (
isBefore(
add(data.decorrenza, {
days: DEFAULT_SERVIZIO_DURATION_DAYS,
}),
new Date(),
) &&
!data.isOkSaldo
) {
return "scaduto";
}
const contrattoInserito = data.annunci_servizio.filter(
(a) => a.doc_contratto_added,
);
if (contrattoInserito.length > 0) {
if (data.isOkSaldo) {
if (data.isOkConsulenza) {
return "confermato";
}
if (
//hasConsulanzaDaPagare
data.ordini_servizio.some(
(o) => o.type === orderTypeEnum.enum.Consulenza && !o.isActive,
)
) {
return "consulenza_da_pagare";
}
return "consulenza_da_inserire";
}
}
const annuncioCaparraVersata = data.annunci_servizio.filter(
(a) => a.status_conferma === statusConfermaEnum.enum["Caparra versata"],
);
if (annuncioCaparraVersata.length > 0) {
if (data.isOkSaldo) {
return "confermato";
}
return "attesa_saldo";
}
const annuncioConfermato = data.annunci_servizio.filter(
(a) => a.status_conferma === statusConfermaEnum.enum["Conferma accettata"],
);
if (annuncioConfermato.length > 0) {
return "attesa_caparra";
}
const annuncioAttesaConferma = data.annunci_servizio.filter(
(a) => a.status_conferma === statusConfermaEnum.enum["Inviato conferma"],
);
if (annuncioAttesaConferma.length > 0) {
return "attesa_conferma";
}
return "attivo";
}
export const RichiesteTable = ({ data }: RichiesteTableProps) => { export const RichiesteTable = ({ data }: RichiesteTableProps) => {
const tabledata = data; const tabledata = data.map((d) => ({
...d,
status: statusParser(d),
}));
const columns_titles = { const columns_titles = {
id: "ID Ordine", id: "ID Ordine",
username: "Utente", username: "Utente",
@ -83,12 +186,10 @@ export const RichiesteTable = ({ data }: RichiesteTableProps) => {
interruzione_expires_at: "Scad. interr.", interruzione_expires_at: "Scad. interr.",
actions: "Azioni", actions: "Azioni",
}; };
const statusOptions = [ const statusOptions = Object.entries(StatusMapping).map(([key, label]) => ({
{ label: "Attesa di attivazione", value: "attesa_attivazione" }, label,
{ label: "Acconto pagato", value: "acconto_pagato" }, value: key,
{ label: "Saldo pagato", value: "saldo_pagato" }, }));
{ label: "Conferma in corso", value: "conferma" },
];
const type_options = [ const type_options = [
{ label: "Transitorio", value: tipologiaPosizioneEnum.enum.Transitorio }, { label: "Transitorio", value: tipologiaPosizioneEnum.enum.Transitorio },
@ -307,185 +408,83 @@ export const RichiesteTable = ({ data }: RichiesteTableProps) => {
accessorKey: "status", accessorKey: "status",
cell: ({ row }) => { cell: ({ row }) => {
let badgeClass = ""; let badgeClass = "";
let contents: React.ReactNode; let icon: React.ReactNode;
const statusText =
StatusMapping[row.original.status as StatusKey] ||
row.original.status;
const resolveStatus = () => { switch (row.original.status) {
if (row.original.isInterrotto) { case "interrotto":
badgeClass = badgeClass =
"border-destructive bg-destructive/10 text-destructive"; "border-destructive bg-destructive/10 text-destructive";
contents = ( icon = <SearchX className="stroke-red-500 dark:stroke-red-400" />;
<> break;
<SearchX className="stroke-red-500 dark:stroke-red-400" /> case "onboarding":
Interrotto
</>
);
return;
}
if (!row.original.onboardOk) {
badgeClass = "border-pink-500 bg-pink-500/10 text-pink-600"; badgeClass = "border-pink-500 bg-pink-500/10 text-pink-600";
contents = ( icon = (
<> <ClipboardPen className="stroke-pink-500 dark:stroke-pink-400" />
<ClockFading className="stroke-pink-500 dark:stroke-pink-400" />
Onboarding
</>
); );
return; break;
} case "attesa_attivazione":
if (!row.original.isOkAcconto || !row.original.decorrenza) {
const acconti = row.original.ordini_servizio.filter(
(o) => o.type === orderTypeEnum.enum.Acconto,
);
const activeAcconto = acconti.find((a) => a.isActive);
//hasActiveAcconto
if (activeAcconto) {
badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600"; badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600";
contents = ( icon = (
<>
<ClockFading className="stroke-yellow-500 dark:stroke-yellow-400" /> <ClockFading className="stroke-yellow-500 dark:stroke-yellow-400" />
Attesa attivazione
</>
); );
} else { break;
badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600"; case "attesa_pagamento_acconto":
contents = ( badgeClass = "border-orange-500 bg-orange-500/10 text-orange-600";
<> icon = (
<ClockFading className="stroke-yellow-500 dark:stroke-yellow-400" /> <BadgeEuro className="stroke-orange-500 dark:stroke-orange-400" />
Attesa pag. acconto
</>
); );
} break;
return; case "scaduto":
}
if (
isBefore(
add(row.original.decorrenza, {
days: DEFAULT_SERVIZIO_DURATION_DAYS,
}),
new Date(),
) &&
!row.original.isOkSaldo
) {
badgeClass = "border-red-500 bg-red-500/10 text-red-500"; badgeClass = "border-red-500 bg-red-500/10 text-red-500";
contents = ( icon = <SearchX className="stroke-red-500 dark:stroke-red-400" />;
<> break;
<SearchX className="stroke-red-500 dark:stroke-red-400" /> case "confermato":
Scaduto
</>
);
return;
}
const contrattoInserito = row.original.annunci_servizio.filter(
(a) => a.doc_contratto_added,
);
if (contrattoInserito.length > 0) {
if (row.original.isOkSaldo) {
if (row.original.isOkConsulenza) {
badgeClass = "border-blue-500 bg-blue-500/10 text-blue-500"; badgeClass = "border-blue-500 bg-blue-500/10 text-blue-500";
contents = ( icon = (
<>
<CircleCheckBig className="stroke-blue-500 dark:stroke-blue-400" /> <CircleCheckBig className="stroke-blue-500 dark:stroke-blue-400" />
Confermato
</>
); );
return; break;
} case "consulenza_da_pagare":
if ( badgeClass = "border-orange-500 bg-orange-500/10 text-orange-600";
//hasConsulanzaDaPagare icon = (
row.original.ordini_servizio.some( <BadgeEuro className="stroke-orange-500 dark:stroke-orange-400" />
(o) =>
o.type === orderTypeEnum.enum.Consulenza && !o.isActive,
)
) {
badgeClass =
"border-yellow-500 bg-yellow-500/10 text-yellow-600";
contents = (
<>
<ClockFading className="stroke-yellow-500 dark:stroke-yellow-400" />
Consulenza da pagare
</>
); );
return; break;
} case "consulenza_da_inserire":
badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600"; badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600";
contents = ( icon = (
<>
<ClockFading className="stroke-yellow-500 dark:stroke-yellow-400" /> <ClockFading className="stroke-yellow-500 dark:stroke-yellow-400" />
Consulenza da inserire
</>
); );
return; break;
} case "attesa_saldo":
} badgeClass = "border-orange-500 bg-orange-500/10 text-orange-600";
icon = (
const annuncioCaparraVersata = row.original.annunci_servizio.filter( <BadgeEuro className="stroke-orange-500 dark:stroke-orange-400" />
(a) =>
a.status_conferma === statusConfermaEnum.enum["Caparra versata"],
); );
if (annuncioCaparraVersata.length > 0) { break;
if (row.original.isOkSaldo) { case "attesa_caparra":
badgeClass = "border-blue-500 bg-blue-500/10 text-blue-500";
contents = (
<>
<CircleCheckBig className="stroke-blue-500 dark:stroke-blue-400" />
Confermato
</>
);
} else {
badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600"; badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600";
contents = ( icon = (
<> <ReceiptEuro className="stroke-yellow-500 dark:stroke-yellow-400" />
<ClockFading className="stroke-yellow-500 dark:stroke-yellow-400" />
Attesa saldo
</>
); );
} break;
case "attesa_conferma":
return;
}
const annuncioConfermato = row.original.annunci_servizio.filter(
(a) =>
a.status_conferma ===
statusConfermaEnum.enum["Conferma accettata"],
);
if (annuncioConfermato.length > 0) {
badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600"; badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600";
contents = ( icon = (
<>
<ClockFading className="stroke-yellow-500 dark:stroke-yellow-400" /> <ClockFading className="stroke-yellow-500 dark:stroke-yellow-400" />
Attesa di caparra
</>
); );
break;
return; case "attivo":
}
const annuncioAttesaConferma = row.original.annunci_servizio.filter(
(a) =>
a.status_conferma === statusConfermaEnum.enum["Inviato conferma"],
);
if (annuncioAttesaConferma.length > 0) {
badgeClass = "border-blue-500 bg-blue-500/10 text-blue-500";
contents = (
<>
<CircleCheckBig className="stroke-blue-500 dark:stroke-blue-400" />
Attesa accett. conferma
</>
);
return;
}
badgeClass = "border-green-500 bg-green-500/10 text-green-500"; badgeClass = "border-green-500 bg-green-500/10 text-green-500";
contents = ( icon = (
<>
<CircleCheck className="stroke-green-500 dark:stroke-green-400" /> <CircleCheck className="stroke-green-500 dark:stroke-green-400" />
Attivo
</>
); );
}; break;
resolveStatus(); }
return ( return (
<Badge <Badge
className={cn( className={cn(
@ -494,7 +493,8 @@ export const RichiesteTable = ({ data }: RichiesteTableProps) => {
)} )}
variant="outline" variant="outline"
> >
{contents} {icon}
{statusText}
</Badge> </Badge>
); );
}, },