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;
|
2026-02-20 11:36:47 +01:00
|
|
|
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
|
|
|
};
|