import type { ColumnDef, Table } from "@tanstack/react-table"; import { add, format, formatDuration, intervalToDuration, isBefore, } from "date-fns"; import { it } from "date-fns/locale"; import { CircleCheck, CircleCheckBig, ClockFading, ExternalLink, Logs, SearchX, UserCog, } from "lucide-react"; import Link from "next/link"; import { useRef } from "react"; import toast from "react-hot-toast"; import { NotePopover } from "~/components/notePopover"; import { AnnuncioCardRichieste } from "~/components/servizio/annuncio_card"; import { OrdersModal } from "~/components/servizio/servizio_actions"; import { WhatsAppIcon2 } from "~/components/svgs"; import { Badge } from "~/components/ui/badge"; import { Button } from "~/components/ui/button"; import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuLabel, ContextMenuTrigger, } from "~/components/ui/context-menu"; import { DataTable } from "~/components/ui/data-table"; import { DataTableColumnHeader } from "~/components/ui/dataTable-header"; import type { PinnedFiltro, SearchFiltro, } from "~/components/ui/dataTable-toolbar"; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, } from "~/components/ui/sheet"; import { Tooltip, TooltipContent, TooltipTrigger, } from "~/components/ui/tooltip"; import { UserAvatar } from "~/components/user_avatar"; import { MutationPageRestore } from "~/lib/tableUtils"; import { cn } from "~/lib/utils"; import OrderTypeEnum from "~/schemas/public/OrderTypeEnum"; import StatusConfermaEnum from "~/schemas/public/StatusConfermaEnum"; import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum"; import type { RichiesteData } from "~/server/controllers/servizio.controller"; import { api } from "~/utils/api"; import { DEFAULT_SERVIZIO_DURATION_DAYS } from "~/utils/config"; type RichiesteTableProps = { data: RichiesteData[]; }; export const RichiesteTable = ({ data }: RichiesteTableProps) => { const tabledata = data; const columns_titles = { id: "ID Ordine", username: "Utente", note: "Note", decorrenza: "Decorrenza", status: "Status", tipologia: "Tipo", annunci: "Annunci", ordini: "Ordini", interruzione_expires_at: "Scad. interr.", actions: "Azioni", }; const statusOptions = [ { label: "Attesa di attivazione", value: "attesa_attivazione" }, { label: "Acconto pagato", value: "acconto_pagato" }, { label: "Saldo pagato", value: "saldo_pagato" }, { label: "Conferma in corso", value: "conferma" }, ]; const type_options = [ { label: "Transitorio", value: TipologiaPosizioneEnum.Transitorio }, { label: "Stabile", value: TipologiaPosizioneEnum.Stabile }, ]; type Column = (typeof tabledata)[number]; const tableRef = useRef | null>(null); const utils = api.useUtils(); const { onMutate, onSettled } = MutationPageRestore(tableRef); const { mutate, isPending } = api.users.editUser.useMutation({ onMutate, onSettled, onSuccess: async () => { toast.success("Note aggiornate con successo"); await utils.users.invalidate(); await utils.servizio.invalidate(); }, onError: (error) => { toast.error(error.message); }, }); const searchFiltro: SearchFiltro = { columnName: "username", placeholder: "Cerca...", }; const columns: ColumnDef[] = [ { accessorKey: "id", cell: () => null, enableHiding: false, header: () => null, }, { accessorKey: "username", cell: ({ row }) => { const data = row.original; return ( {data.username} {data.username} Profilo WhatsApp ); }, enableHiding: false, header: ({ column }) => ( ), }, { accessorKey: "note", cell: ({ row }) => { const note = row.original.note; return ( ); }, header: ({ column }) => ( ), enableSorting: false, }, { accessorKey: "decorrenza", cell: ({ row }) => { let decorrenzaColor = ""; let decorrenzaTooltip = ""; if (!row.original.isOkAcconto || !row.original.decorrenza) { decorrenzaColor = "text-muted-foreground"; decorrenzaTooltip = "Attesa di attivazione"; } else if (row.original.isInterrotto) { decorrenzaColor = "text-destructive"; decorrenzaTooltip = "Servizio interrotto"; } else if (row.original.isOkAcconto && !row.original.isOkSaldo) { decorrenzaColor = "text-warning"; decorrenzaTooltip = "Attesa di saldo"; } return ( {row.original.decorrenza ? format(row.original.decorrenza, "dd/MM") : "---"}

{decorrenzaTooltip}

); }, enableHiding: false, header: ({ column }) => ( ), sortingFn: "datetime", }, { accessorKey: "tipologia", cell: ({ row }) => { const { tipologia } = row.original; return ( {tipologia.toString()} ); }, filterFn: (row, id, value) => { return value.includes(row.getValue(id)); }, header: ({ column }) => ( ), }, { accessorKey: "status", cell: ({ row }) => { let badgeClass = ""; let contents: React.ReactNode; const resolveStatus = () => { if (row.original.isInterrotto) { badgeClass = "border-destructive bg-destructive/10 text-destructive"; contents = ( <> Interrotto ); return; } if (!row.original.onboardOk) { badgeClass = "border-pink-500 bg-pink-500/10 text-pink-600"; contents = ( <> Onboarding ); return; } if (!row.original.isOkAcconto || !row.original.decorrenza) { const acconti = row.original.ordini_servizio.filter( (o) => o.type === OrderTypeEnum.Acconto, ); const activeAcconto = acconti.find((a) => a.isActive); if (activeAcconto) { badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600"; contents = ( <> Attesa attivazione ); } else { badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600"; contents = ( <> Attesa pag. acconto ); } return; } 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"; contents = ( <> 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"; contents = ( <> Confermato ); return; } if ( row.original.ordini_servizio.some( (o) => o.type === OrderTypeEnum.Consulenza && !o.isActive, ) ) { badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600"; contents = ( <> Consulenza da pagare ); return; } badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600"; contents = ( <> Consulenza da inserire ); return; } } const annuncioCaparraVersata = row.original.annunci_servizio.filter( (a) => a.status_conferma === StatusConfermaEnum["Caparra versata"], ); if (annuncioCaparraVersata.length > 0) { if (row.original.isOkSaldo) { badgeClass = "border-blue-500 bg-blue-500/10 text-blue-500"; contents = ( <> Confermato ); } else { badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600"; contents = ( <> Attesa saldo ); } return; } const annuncioConfermato = row.original.annunci_servizio.filter( (a) => a.status_conferma === StatusConfermaEnum["Conferma accettata"], ); if (annuncioConfermato.length > 0) { badgeClass = "border-yellow-500 bg-yellow-500/10 text-yellow-600"; contents = ( <> Attesa di caparra ); return; } const annuncioAttesaConferma = row.original.annunci_servizio.filter( (a) => a.status_conferma === StatusConfermaEnum["Inviato conferma"], ); if (annuncioAttesaConferma.length > 0) { badgeClass = "border-blue-500 bg-blue-500/10 text-blue-500"; contents = ( <> Attesa accett. conferma ); return; } badgeClass = "border-green-500 bg-green-500/10 text-green-500"; contents = ( <> Attivo ); }; resolveStatus(); return ( svg]:size-4", badgeClass, )} variant="outline" > {contents} ); }, filterFn: (row, id, value) => { return value.includes(row.getValue(id)); }, header: ({ column }) => ( ), }, { accessorKey: "interruzione_expires_at", cell: ({ row }) => { if (row.original.isInterrotto) return "---"; if (!row.original.decorrenza) return "---"; const expiresAt = add(row.original.decorrenza, { days: row.original.interruzioneDays, }); const timeLeft = intervalToDuration({ start: new Date(), end: expiresAt, }); const daysLeft = timeLeft.days || 0; let badgeColor = ""; if (daysLeft > 5) { badgeColor = "border-green-500 bg-green-500/10 text-green-500"; } else if (daysLeft > 0) { badgeColor = "border-yellow-500 bg-yellow-500/10 text-yellow-500"; } else { badgeColor = "border-red-500 bg-red-500/10 text-red-500"; } return ( {format(expiresAt, "dd/MM")} {daysLeft > 0 ? (

{formatDuration(timeLeft, { locale: it, format: ["days"] })}{" "} rimanenti

) : (

Interruzione scaduta

)}
); }, enableSorting: false, header: ({ column }) => ( ), }, { accessorKey: "annunci_servizio", cell: ({ row }) => { const annunci = row.original.annunci_servizio; return ( Annunci Inseriti Desc
{annunci.map((a) => ( ))}
); }, header: ({ column }) => ( ), enableSorting: false, }, { accessorKey: "ordini", cell: ({ row }) => { const paidOrders = row.original.ordini_servizio.filter( (o) => o.isActive, ).length; const unpaidOrders = row.original.ordini_servizio.length - paidOrders; return (
{unpaidOrders > 0 && ( {unpaidOrders} )} {paidOrders > 0 && ( {paidOrders} )}
); }, header: ({ column }) => ( ), enableSorting: false, }, { cell: ({ row }) => { return ( ); }, enableHiding: false, id: "actions", }, ]; const pinnedFiltri: PinnedFiltro[] = [ { columnName: "status", options: statusOptions, title: "Stato Ordine", }, { columnName: "tipologia", options: type_options, title: "Tipo Ordine", }, ]; return (
(tableRef.current = t)} pinnedFiltri={pinnedFiltri} searchColumn={searchFiltro} />
); };