infoalloggi-monorepo/apps/infoalloggi/src/components/tables/payments-table.tsx

258 lines
6.7 KiB
TypeScript
Raw Normal View History

2025-08-28 18:27:07 +02:00
import type { ColumnDef } from "@tanstack/react-table";
import { EllipsisVertical, Trash2, Wrench } from "lucide-react";
2025-08-04 17:45:44 +02:00
import { DataTable } from "~/components/custom_ui/data-table";
2025-08-28 18:27:07 +02:00
import { DataTableColumnHeader } from "~/components/custom_ui/dataTable-header";
2025-08-04 17:45:44 +02:00
import type {
2025-08-28 18:27:07 +02:00
PinnedFiltro,
SearchFiltro,
2025-08-04 17:45:44 +02:00
} from "~/components/custom_ui/dataTable-toolbar";
2025-08-28 18:27:07 +02:00
import { Button } from "~/components/ui/button";
2025-08-04 17:45:44 +02:00
import {
2025-08-28 18:27:07 +02:00
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuPortal,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
2025-08-04 17:45:44 +02:00
} from "~/components/ui/dropdown-menu";
2025-08-28 18:27:07 +02:00
import { formatCurrency } from "~/lib/utils";
import PaymentStatusEnum from "~/schemas/public/PaymentStatusEnum";
2025-08-04 17:45:44 +02:00
import type { OrdiniWPagamenti } from "~/server/controllers/ordini.controller";
import { api } from "~/utils/api";
type PaymentsTableProps = {
2025-08-28 18:27:07 +02:00
data: OrdiniWPagamenti["pagamenti"];
isAdmin: boolean;
isUserView?: boolean;
2025-08-04 17:45:44 +02:00
};
const StatusMapping = (status: PaymentStatusEnum | null) => {
2025-08-28 18:27:07 +02:00
switch (status) {
case PaymentStatusEnum.success:
return "Successo";
case PaymentStatusEnum.processing:
return "In lavorazione";
case PaymentStatusEnum.failed:
return "Errore";
default:
return "Non completato";
}
2025-08-04 17:45:44 +02:00
};
const EnumFromString = (value: string) => {
2025-08-28 18:27:07 +02:00
switch (value) {
case "Successo":
return PaymentStatusEnum.success;
case "In lavorazione":
return PaymentStatusEnum.processing;
case "Errore":
return PaymentStatusEnum.failed;
default:
return null;
}
2025-08-04 17:45:44 +02:00
};
export const PaymentsTable = ({
2025-08-28 18:27:07 +02:00
data,
isAdmin,
isUserView = false,
2025-08-04 17:45:44 +02:00
}: PaymentsTableProps) => {
2025-08-28 18:27:07 +02:00
const tabledata = data.map((row) => {
return {
2025-08-29 16:18:32 +02:00
actions: "Azioni",
2025-08-28 18:27:07 +02:00
amount: row.amount_cent,
2025-08-29 16:18:32 +02:00
id: row.id,
2025-08-28 18:27:07 +02:00
paid_at: row.paid_at,
raw_status: row.paymentstatus,
2025-08-29 16:18:32 +02:00
status: StatusMapping(row.paymentstatus),
2025-08-28 18:27:07 +02:00
};
});
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const columns_titles = {
2025-08-29 16:18:32 +02:00
actions: "Azioni",
2025-08-28 18:27:07 +02:00
amount: "Importo",
paid_at: "Pagato il",
2025-08-29 16:18:32 +02:00
status: "Stato",
username: "Utente",
2025-08-28 18:27:07 +02:00
};
const status_options = [
{ label: "Inutilizzato", value: "Inutilizzato" },
{ label: "Successo", value: "Successo" },
{ label: "In lavorazione", value: "In lavorazione" },
{ label: "Errore", value: "Errore" },
];
const utils = api.useUtils();
const { mutate: update } = api.servizio.updatePagamento.useMutation({
onSuccess: async () => {
await utils.servizio.getAllPagamenti.invalidate();
await utils.servizio.getOrdini.invalidate();
await utils.servizio.getOrdineById.invalidate({
ordineId: data[0]?.ordine_id,
});
if ((!isAdmin || isUserView) && data[0]) {
await utils.servizio.getUserPagamenti.invalidate({
userId: data[0].userid,
});
}
},
});
const { mutate: remove } = api.servizio.removePagamento.useMutation({
onSuccess: async () => {
await utils.servizio.getAllPagamenti.invalidate();
await utils.servizio.getOrdini.invalidate();
await utils.servizio.getOrdineById.invalidate({
ordineId: data[0]?.ordine_id,
});
if ((!isAdmin || isUserView) && data[0]) {
await utils.servizio.getUserPagamenti.invalidate({
userId: data[0].userid,
});
}
},
});
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
type Column = (typeof tabledata)[number];
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const columns: ColumnDef<Column>[] = [
{
accessorKey: "paid_at",
cell: ({ row }) => {
const date = row.getValue("paid_at");
return new Date(date as Date).toLocaleDateString();
},
enableHiding: false,
header: ({ column }) => (
2025-08-29 16:18:32 +02:00
<DataTableColumnHeader column={column} title={columns_titles.paid_at} />
2025-08-28 18:27:07 +02:00
),
2025-08-29 16:18:32 +02:00
sortingFn: "datetime",
},
{
2025-08-28 18:27:07 +02:00
accessorKey: "status",
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
filterFn: (row, id, value) => {
return value.includes(row.getValue(id));
},
header: ({ column }) => (
2025-08-29 16:18:32 +02:00
<DataTableColumnHeader column={column} title={columns_titles.status} />
2025-08-28 18:27:07 +02:00
),
2025-08-29 16:18:32 +02:00
},
{
2025-08-28 18:27:07 +02:00
accessorKey: "amount",
cell: ({ row }) => {
return <span>{formatCurrency(row.original.amount / 100)}</span>;
},
2025-08-29 16:18:32 +02:00
header: ({ column }) => (
<DataTableColumnHeader column={column} title={columns_titles.amount} />
),
2025-08-28 18:27:07 +02:00
},
{
cell: ({ row }) => {
const data = row.original;
if (!isAdmin) return null;
2025-08-28 18:27:07 +02:00
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
2025-08-29 16:18:32 +02:00
<Button className="size-8 p-0" variant="ghost">
2025-08-28 18:27:07 +02:00
<span className="sr-only">Open menu</span>
<EllipsisVertical />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Azioni</DropdownMenuLabel>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<Wrench />
<span>Aggiorna status</span>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuRadioGroup
onValueChange={(v) => {
update({
data: { paymentstatus: EnumFromString(v) },
2025-08-29 16:18:32 +02:00
pagamentoId: data.id,
2025-08-28 18:27:07 +02:00
});
}}
2025-08-29 16:18:32 +02:00
value={StatusMapping(data.raw_status)}
2025-08-28 18:27:07 +02:00
>
<DropdownMenuRadioItem value="Inutilizzato">
Inutilizzato
</DropdownMenuRadioItem>
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
<DropdownMenuRadioItem value="Successo">
Successo
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="In lavorazione">
In lavorazione
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="Errore">
Errore
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem
aria-label="Elimina Pagamento"
className="flex items-center gap-3 hover:cursor-pointer"
onClick={() =>
confirm("Sei sicuro di voler eliminare il servizio?") &&
remove({ pagamentoId: data.id })
}
>
<Trash2 className="size-6" />
Elimina Pagamento
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
},
2025-08-29 16:18:32 +02:00
enableHiding: false,
id: "actions",
2025-08-28 18:27:07 +02:00
},
];
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const searchFiltro: SearchFiltro | undefined =
isAdmin && !isUserView
? {
columnName: "username",
placeholder: "Cerca utente...",
}
: undefined;
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const pinnedFiltri: PinnedFiltro[] = [
{
columnName: "status",
options: status_options,
2025-08-29 16:18:32 +02:00
title: "Status",
2025-08-28 18:27:07 +02:00
},
];
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
return (
<div className="w-full py-6">
<DataTable
columns={columns}
columns_titles={columns_titles}
2025-08-29 16:18:32 +02:00
data={tabledata}
2025-08-28 18:27:07 +02:00
defaultColumnVisibility={{
2025-08-29 16:18:32 +02:00
actions: true,
2025-08-28 18:27:07 +02:00
amount: true,
2025-08-29 16:18:32 +02:00
packid: true,
2025-08-28 18:27:07 +02:00
paid_at: true,
2025-08-29 16:18:32 +02:00
status: true,
username: isAdmin && !isUserView,
2025-08-28 18:27:07 +02:00
}}
2025-08-29 16:18:32 +02:00
defaultSort={[{ desc: true, id: "paid_at" }]}
pinnedFiltri={pinnedFiltri}
searchColumn={searchFiltro}
2025-08-28 18:27:07 +02:00
/>
</div>
);
2025-08-04 17:45:44 +02:00
};