2025-08-28 18:27:07 +02:00
|
|
|
import type { ColumnDef } from "@tanstack/react-table";
|
2026-03-08 01:02:57 +01:00
|
|
|
import { Circle, CircleCheck, ExternalLink } from "lucide-react";
|
2025-08-28 18:27:07 +02:00
|
|
|
import Link from "next/link";
|
|
|
|
|
import { useState } from "react";
|
2026-03-08 01:02:57 +01:00
|
|
|
import {
|
|
|
|
|
AdminWrapperOrdiniModal,
|
|
|
|
|
UserOrdiniModal,
|
|
|
|
|
} from "~/components/area-riservata/ordini";
|
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";
|
|
|
|
|
import { Button } from "~/components/ui/button";
|
2026-03-08 01:02:57 +01:00
|
|
|
import { formatCurrency } from "~/lib/utils";
|
2025-08-04 17:45:44 +02:00
|
|
|
import OrderTypeEnum from "~/schemas/public/OrderTypeEnum";
|
|
|
|
|
import type { OrdiniOrdineId } from "~/schemas/public/Ordini";
|
2025-08-28 18:27:07 +02:00
|
|
|
import PaymentStatusEnum from "~/schemas/public/PaymentStatusEnum";
|
|
|
|
|
import type { UsersId } from "~/schemas/public/Users";
|
2026-03-08 01:02:57 +01:00
|
|
|
import type { Ordini_w_Utente } from "~/server/controllers/ordini.controller";
|
2025-08-04 17:45:44 +02:00
|
|
|
|
|
|
|
|
type PaymentsTableProps = {
|
2026-03-08 01:02:57 +01:00
|
|
|
data: Ordini_w_Utente[];
|
2025-08-28 18:27:07 +02:00
|
|
|
isAdmin: boolean;
|
|
|
|
|
userId?: UsersId;
|
2026-03-08 01:02:57 +01:00
|
|
|
filter: OrdiniOrdineId | null;
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
2026-03-08 01:02:57 +01:00
|
|
|
const StatusMapping = (status: PaymentStatusEnum | null) => {
|
|
|
|
|
switch (status) {
|
|
|
|
|
case PaymentStatusEnum.success:
|
|
|
|
|
return "Successo";
|
|
|
|
|
case PaymentStatusEnum.processing:
|
|
|
|
|
return "In lavorazione";
|
|
|
|
|
case PaymentStatusEnum.failed:
|
|
|
|
|
return "Errore";
|
|
|
|
|
default:
|
|
|
|
|
return "Non completato";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const OrdiniTable = ({
|
|
|
|
|
data,
|
|
|
|
|
isAdmin,
|
|
|
|
|
userId,
|
|
|
|
|
filter,
|
|
|
|
|
}: 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",
|
|
|
|
|
created_at: row.created_at,
|
2025-08-28 18:27:07 +02:00
|
|
|
id: row.ordine_id,
|
2026-03-08 01:02:57 +01:00
|
|
|
status: row.isActive,
|
|
|
|
|
payment_status: row.paymentstatus,
|
|
|
|
|
importo: row.amount_cent,
|
2025-08-29 16:18:32 +02:00
|
|
|
packid: row.packid,
|
|
|
|
|
tipo: row.type,
|
|
|
|
|
userId: row.userid,
|
|
|
|
|
username: row.username,
|
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 = {
|
2026-03-08 01:02:57 +01:00
|
|
|
id: "ID Ordine",
|
2025-08-29 16:18:32 +02:00
|
|
|
actions: "Azioni",
|
2025-08-28 18:27:07 +02:00
|
|
|
created_at: "Creato il",
|
2026-03-08 01:02:57 +01:00
|
|
|
importo: "Importo",
|
|
|
|
|
status: "Status",
|
|
|
|
|
payment_status: "Pagamento",
|
2025-08-29 16:18:32 +02:00
|
|
|
packid: "ID Pacchetto",
|
|
|
|
|
tipo: "Tipo",
|
|
|
|
|
username: "Utente",
|
2025-08-28 18:27:07 +02:00
|
|
|
};
|
2026-03-08 01:02:57 +01:00
|
|
|
const statusOptions = [
|
|
|
|
|
{ label: "Attivo", value: "true" },
|
|
|
|
|
{ label: "Non attivo", value: "false" },
|
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 type_options = [
|
2025-08-29 16:18:32 +02:00
|
|
|
{ label: "Acconto", value: OrderTypeEnum.Acconto },
|
|
|
|
|
{ label: "Saldo", value: OrderTypeEnum.Saldo },
|
|
|
|
|
{ label: "Consulenza", value: OrderTypeEnum.Consulenza },
|
|
|
|
|
{ label: "Altro", value: OrderTypeEnum.Altro },
|
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 [selectedOrdine, setSelectedOrdine] = useState<OrdiniOrdineId | null>(
|
|
|
|
|
null,
|
|
|
|
|
);
|
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>[] = [
|
2026-03-08 01:02:57 +01:00
|
|
|
{
|
|
|
|
|
accessorKey: "id",
|
|
|
|
|
cell: () => null,
|
|
|
|
|
enableHiding: false,
|
|
|
|
|
header: () => null,
|
|
|
|
|
},
|
|
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
{
|
|
|
|
|
accessorKey: "username",
|
|
|
|
|
cell: ({ row }) => {
|
|
|
|
|
if (isAdmin) {
|
|
|
|
|
return (
|
|
|
|
|
<Link
|
|
|
|
|
aria-label="Visualizza Utente"
|
|
|
|
|
href={`/area-riservata/admin/user-view/ricerca/${row.original.userId}`}
|
|
|
|
|
>
|
|
|
|
|
<Button size="sm">{row.original.username}</Button>
|
|
|
|
|
</Link>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return <span>{row.original.username}</span>;
|
|
|
|
|
},
|
2025-08-29 16:18:32 +02:00
|
|
|
enableHiding: false,
|
2025-08-28 18:27:07 +02:00
|
|
|
header: ({ column }) => (
|
|
|
|
|
<DataTableColumnHeader
|
|
|
|
|
column={column}
|
2025-08-29 16:18:32 +02:00
|
|
|
title={columns_titles.username}
|
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: "created_at",
|
|
|
|
|
cell: ({ row }) => {
|
|
|
|
|
const date = row.getValue("created_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.created_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: "tipo",
|
|
|
|
|
cell: ({ row }) => {
|
|
|
|
|
return row.original.tipo.toString();
|
|
|
|
|
},
|
|
|
|
|
filterFn: (row, id, value) => {
|
|
|
|
|
return value.includes(row.getValue(id));
|
|
|
|
|
},
|
2025-08-29 16:18:32 +02:00
|
|
|
header: ({ column }) => (
|
|
|
|
|
<DataTableColumnHeader column={column} title={columns_titles.tipo} />
|
|
|
|
|
),
|
2025-08-28 18:27:07 +02:00
|
|
|
},
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
{
|
2025-08-29 16:18:32 +02:00
|
|
|
accessorKey: "packid",
|
2025-08-28 18:27:07 +02:00
|
|
|
header: ({ column }) => (
|
|
|
|
|
<DataTableColumnHeader column={column} title={columns_titles.packid} />
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-03-08 01:02:57 +01:00
|
|
|
accessorKey: "importo",
|
2025-08-28 18:27:07 +02:00
|
|
|
cell: ({ row }) => {
|
2026-03-08 01:02:57 +01:00
|
|
|
return <span>{formatCurrency(row.original.importo / 100)}</span>;
|
|
|
|
|
},
|
|
|
|
|
header: ({ column }) => (
|
|
|
|
|
<DataTableColumnHeader column={column} title={columns_titles.importo} />
|
|
|
|
|
),
|
|
|
|
|
enableHiding: false,
|
|
|
|
|
sortingFn: (a, b, id) => {
|
|
|
|
|
const aValue = a.getValue(id) as number;
|
|
|
|
|
const bValue = b.getValue(id) as number;
|
|
|
|
|
return aValue - bValue;
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
accessorKey: "status",
|
|
|
|
|
cell: ({ row }) => {
|
|
|
|
|
if (!row.original.status) {
|
2025-08-28 18:27:07 +02:00
|
|
|
return (
|
2026-03-08 01:02:57 +01:00
|
|
|
<span className="inline-flex items-center gap-1">
|
|
|
|
|
<Circle className="size-5" />
|
|
|
|
|
Non attivo
|
2025-08-28 18:27:07 +02:00
|
|
|
</span>
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-09-01 16:48:03 +02:00
|
|
|
return (
|
2026-03-08 01:02:57 +01:00
|
|
|
<span className="inline-flex items-center gap-1 text-green-500">
|
2025-09-01 16:48:03 +02:00
|
|
|
<CircleCheck className="size-5" />
|
2026-03-08 01:02:57 +01:00
|
|
|
Attivo
|
2025-09-01 16:48:03 +02:00
|
|
|
</span>
|
|
|
|
|
);
|
2025-08-28 18:27:07 +02:00
|
|
|
},
|
2025-08-29 16:18:32 +02:00
|
|
|
|
|
|
|
|
filterFn: (row, id, value) => {
|
|
|
|
|
return value.includes(row.getValue(id));
|
|
|
|
|
},
|
|
|
|
|
header: ({ column }) => (
|
2026-03-08 01:02:57 +01:00
|
|
|
<DataTableColumnHeader column={column} title={columns_titles.status} />
|
2025-08-29 16:18:32 +02:00
|
|
|
),
|
2025-08-28 18:27:07 +02:00
|
|
|
},
|
2026-03-08 01:02:57 +01:00
|
|
|
{
|
|
|
|
|
accessorKey: "payment_status",
|
|
|
|
|
cell: ({ row }) => {
|
|
|
|
|
return <span>{StatusMapping(row.original.payment_status)}</span>;
|
|
|
|
|
},
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2026-03-08 01:02:57 +01:00
|
|
|
filterFn: (row, id, value) => {
|
|
|
|
|
return value.includes(row.getValue(id));
|
|
|
|
|
},
|
|
|
|
|
header: ({ column }) => (
|
|
|
|
|
<DataTableColumnHeader
|
|
|
|
|
column={column}
|
|
|
|
|
title={columns_titles.payment_status}
|
|
|
|
|
/>
|
|
|
|
|
),
|
|
|
|
|
},
|
2025-08-28 18:27:07 +02:00
|
|
|
{
|
|
|
|
|
cell: ({ row }) => {
|
|
|
|
|
return (
|
|
|
|
|
<Button
|
|
|
|
|
aria-label="Apri Dettagli Ordine"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setSelectedOrdine(row.original.id);
|
|
|
|
|
}}
|
2025-08-29 16:18:32 +02:00
|
|
|
size="sm"
|
|
|
|
|
variant="outline"
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
2026-03-08 01:02:57 +01:00
|
|
|
<ExternalLink className="size-5" />
|
2025-08-28 18:27:07 +02:00
|
|
|
</Button>
|
|
|
|
|
);
|
|
|
|
|
},
|
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
|
|
|
|
2026-03-08 01:02:57 +01:00
|
|
|
const searchFiltro: SearchFiltro = {
|
|
|
|
|
columnName: "id",
|
|
|
|
|
placeholder: "Cerca ordine...",
|
|
|
|
|
};
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const pinnedFiltri: PinnedFiltro[] = [
|
|
|
|
|
{
|
2026-03-08 01:02:57 +01:00
|
|
|
columnName: "status",
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2026-03-08 01:02:57 +01:00
|
|
|
options: statusOptions,
|
|
|
|
|
title: "Stato Ordine",
|
2025-08-28 18:27:07 +02:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
columnName: "tipo",
|
|
|
|
|
options: type_options,
|
2025-08-29 16:18:32 +02:00
|
|
|
title: "Tipo Ordine",
|
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 (
|
2025-12-29 16:09:51 +01:00
|
|
|
<div className="mx-auto w-full">
|
2025-08-28 18:27:07 +02:00
|
|
|
<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,
|
|
|
|
|
tipo: true,
|
|
|
|
|
username: isAdmin && !userId,
|
2025-08-28 18:27:07 +02:00
|
|
|
}}
|
2026-03-08 01:02:57 +01:00
|
|
|
defaultFilterState={
|
|
|
|
|
filter ? [{ id: "id", value: filter.toString() }] : []
|
|
|
|
|
}
|
2025-08-29 16:18:32 +02:00
|
|
|
defaultSort={[{ desc: true, id: "created_at" }]}
|
|
|
|
|
pinnedFiltri={pinnedFiltri}
|
|
|
|
|
searchColumn={searchFiltro}
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
2026-03-08 01:02:57 +01:00
|
|
|
{isAdmin ? (
|
|
|
|
|
<AdminWrapperOrdiniModal
|
2025-08-29 16:18:32 +02:00
|
|
|
ordineId={selectedOrdine}
|
2026-03-08 01:02:57 +01:00
|
|
|
setSelected={setSelectedOrdine}
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
2026-03-08 01:02:57 +01:00
|
|
|
) : (
|
|
|
|
|
selectedOrdine && (
|
|
|
|
|
<UserOrdiniModal
|
|
|
|
|
ordineId={selectedOrdine}
|
|
|
|
|
setSelected={setSelectedOrdine}
|
|
|
|
|
/>
|
|
|
|
|
)
|
2025-08-28 18:27:07 +02:00
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|