import { Confirm } from "~/components/confirm"; import { Button, buttonVariants } from "~/components/ui/button"; import { Check, ChevronsUpDown, CircleCheck, ClipboardPaste, ExternalLink, FolderKanban, Pen, Plus, Trash2, Wrench, } from "lucide-react"; import type { Storageindex, StorageindexId, } from "~/schemas/public/Storageindex"; import { Label } from "~/components/ui/label"; import { UploadModal } from "~/components/upload_modal"; import { ExtIcon } from "~/components/area-riservata/allegati"; import { Popover, PopoverContent, PopoverTrigger, } from "~/components/ui/popover"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "~/components/ui/command"; import { api } from "~/utils/api"; import toast from "react-hot-toast"; import { Credenza, CredenzaBody, CredenzaClose, CredenzaContent, CredenzaDescription, CredenzaFooter, CredenzaHeader, CredenzaTitle, CredenzaTrigger, } from "~/components/custom_ui/credenza"; import { LoadingPage } from "~/components/loading"; import Link from "next/link"; import { cn, formatCurrency } from "~/lib/utils"; import { useRef, useState } from "react"; import { z } from "zod/v4"; import { Separator } from "~/components/ui/separator"; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from "~/components/ui/card"; import type { ServizioAnnunciUpdate } from "~/schemas/public/ServizioAnnunci"; import { Switch } from "~/components/ui/switch"; import { useServizio, useServizioAnnuncio } from "~/providers/ServizioProvider"; import { AnimatedButton, type AnimatedButtonRef, } from "~/components/custom_ui/animated-button"; import type { AnnunciId } from "~/schemas/public/Annunci"; import { useTranslation } from "~/providers/I18nProvider"; import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum"; export const AnnuncioActions = () => { const { servizioId, userId, isAdmin } = useServizio(); const { data, annuncioId } = useServizioAnnuncio(); const utils = api.useUtils(); const { mutate } = api.servizio.removeAnnuncioServizio.useMutation({ onSuccess: async () => { await utils.servizio.getAllServizioAnnunci.invalidate({ userId }); await utils.servizio.getCompatibileAnnunci.invalidate({ servizioId, }); toast.success("Annuncio rimosso"); }, onError: (error) => { console.error(error); toast.error("Errore durante la rimozione dell'annuncio"); }, }); if ((!isAdmin && data.open_contatti_at == null) || isAdmin) { return (
{isAdmin && data.user_confirmed_at != null && } {isAdmin && data.accettato_conferma_at != null && ( <> {data.gestionale_id && ( )} )} {isAdmin && ( <> { mutate({ servizioId, annuncioId, }); }} > )}
); } return null; }; const ContrattoImportSchema = z.object({ gestionale_id: z.number().nullable(), contratto_decorrenza: z.string().nullable(), contratto_scadenza: z.string().nullable(), contratto_tipo: z .enum([ "Transitorio", "Agevolato", "4 + 4", "30 Giorni", "Transi.Age", "Foresteria", "Commerciale", ]) .nullable(), }); interface ContrattoImportObj extends Omit< z.infer, "contratto_decorrenza" | "contratto_scadenza" > { contratto_decorrenza: Date | null; contratto_scadenza: Date | null; } const parseContrattoImport = (ingest: string) => { let parsedJson: unknown; try { parsedJson = JSON.parse(ingest); } catch { toast.error( 'Stringa non valida, clicca "copia stringa" nel gestionale e poi questo pulsante', ); return undefined; } const parsed = ContrattoImportSchema.safeParse(parsedJson); if (parsed.success) { return { ...parsed.data, contratto_decorrenza: parsed.data.contratto_decorrenza ? new Date(parsed.data.contratto_decorrenza) : null, contratto_scadenza: parsed.data.contratto_scadenza ? new Date(parsed.data.contratto_scadenza) : null, }; } else { console.error("Invalid format:", parsed.error); return undefined; } }; const ContrattoImport = ({ handleUpdate, }: { handleUpdate: (upd: ServizioAnnunciUpdate) => void; }) => { const { data } = useServizioAnnuncio(); const [contratto, setContratto] = useState({ gestionale_id: data.gestionale_id, contratto_decorrenza: data.contratto_decorrenza ? new Date(data.contratto_decorrenza) : null, contratto_scadenza: data.contratto_scadenza ? new Date(data.contratto_scadenza) : null, contratto_tipo: data.contratto_tipo as ContrattoImportObj["contratto_tipo"], }); const handleSave = () => { handleUpdate({ ...contratto, }); }; return ( Dati Contratto desc
{contratto ? (

ID Gestionale: {contratto.gestionale_id}{" "}

Decorrenza: {contratto.contratto_decorrenza && new Date(contratto.contratto_decorrenza).toLocaleDateString( "it-IT", )}{" "}

Scadenza: {contratto.contratto_scadenza && new Date(contratto.contratto_scadenza).toLocaleDateString( "it-IT", )}{" "}

Tipo di contratto: {contratto.contratto_tipo}{" "}

) : (

Inserisci la stringa dal gestionale e elabora

)}
); }; const AdminContratto = () => { const { userId, servizioId } = useServizio(); const { data, annuncioId } = useServizioAnnuncio(); const [open, setOpen] = useState(false); const utils = api.useUtils(); const { mutate: updateServizio } = api.servizio.updateServizioAnnunci.useMutation({ onSuccess: async () => { await utils.servizio.getAllServizioAnnunci.invalidate({ userId }); await utils.servizio.getServizio.invalidate({ servizioId, }); toast.success("Dati salvati con successo"); }, onError: (error) => { toast.error(error.message); }, }); const handleUpdate = (upd: ServizioAnnunciUpdate) => { updateServizio({ servizioId, annuncioId, data: { ...upd, }, }); }; return ( Sezione Contratto Contratto modal
); }; const ContrattoSection = ({ handleUpdate, }: { handleUpdate: (upd: ServizioAnnunciUpdate) => void; }) => { const { userId } = useServizio(); const { data } = useServizioAnnuncio(); const [selectedDoc, setSelectedDoc] = useState( data.doc_contratto_ref, ); const utils = api.useUtils(); const { data: files, isLoading } = api.storage.getAll.useQuery(); const { mutate: setUserStorage } = api.storage.addUserStorage.useMutation({ onSuccess: async () => { await utils.storage.getUserStorage.invalidate({ userId, }); await utils.storage.getAll.invalidate(); }, }); const handleSave = () => { handleUpdate({ doc_contratto_ref: selectedDoc, doc_contratto_added: selectedDoc != null, }); if (selectedDoc) { setUserStorage({ userId, fileId: selectedDoc, }); } }; if (isLoading) return ; if (files == undefined) { return

Errore nel caricamento dei documenti

; } return ( Documento del Contratto contratto di locazione {selectedDoc && (
)} { setSelectedDoc(f.id); }} current={selectedDoc} />
); }; const RicevutaSection = ({ handleUpdate, }: { handleUpdate: (upd: ServizioAnnunciUpdate) => void; }) => { const { userId } = useServizio(); const { data } = useServizioAnnuncio(); const [selectedDoc, setSelectedDoc] = useState( data.doc_registrazione_ref, ); const utils = api.useUtils(); const { data: files, isLoading } = api.storage.getAll.useQuery(); const { mutate: setUserStorage } = api.storage.addUserStorage.useMutation({ onSuccess: async () => { await utils.storage.getUserStorage.invalidate({ userId, }); await utils.storage.getAll.invalidate(); }, }); const handleSave = () => { handleUpdate({ doc_registrazione_ref: selectedDoc, doc_registrazione_added: selectedDoc != null, }); if (selectedDoc) { setUserStorage({ userId, fileId: selectedDoc, }); } }; if (isLoading) return ; if (files == undefined) { return

Errore nel caricamento dei documenti

; } return ( Ricevuta di Registrazione desc {selectedDoc && (
)} { setSelectedDoc(f.id); }} current={selectedDoc} />
); }; const AdminLavoraConferma = () => { const { userId, servizioId } = useServizio(); const { data, annuncioId } = useServizioAnnuncio(); const [open, setOpen] = useState(false); const utils = api.useUtils(); const { mutate: updateServizio } = api.servizio.updateServizioAnnunci.useMutation({ onSuccess: async () => { await utils.servizio.getAllServizioAnnunci.invalidate({ userId }); await utils.servizio.getServizio.invalidate({ servizioId, }); toast.success("Dati salvati con successo"); }, onError: (error) => { toast.error(error.message); }, }); const handleUpdate = (upd: ServizioAnnunciUpdate) => { updateServizio({ servizioId, annuncioId, data: { ...upd, }, }); }; return ( Lavorazione conferma Consegna status modal
); }; const DocSection = ({ handleUpdate, }: { handleUpdate: (upd: ServizioAnnunciUpdate) => void; }) => { const { userId } = useServizio(); const { data } = useServizioAnnuncio(); const utils = api.useUtils(); const { data: files, isLoading } = api.storage.getAll.useQuery(); const { mutate: setUserStorage } = api.storage.addUserStorage.useMutation({ onSuccess: async () => { await utils.storage.getUserStorage.invalidate({ userId, }); await utils.storage.getAll.invalidate(); }, }); if (isLoading) return ; if (files == undefined) { return

Errore nel caricamento dei documenti

; } return ( Documento di Conferma documento che l'utente vedra alla conferma {data.doc_conferma_ref && (
)}
{ handleUpdate({ doc_conferma_ref: f.id, doc_conferma_added: true, }); setUserStorage({ userId, fileId: f.id, }); }} current={data.doc_conferma_ref} />
); }; const DocInfo = ({ storageId, children, }: { storageId: StorageindexId; children: React.ReactNode; }) => { const { data: file_info } = api.storage.getStorageFromId.useQuery({ storageId, }); if (!file_info) return null; return (
{file_info.ext && } {file_info.filename}
{children}
); }; const DocCombo = ({ files, onSelect, current, }: { files: Storageindex[]; onSelect: (file: Storageindex) => void; current: StorageindexId | null; }) => { const [open, setOpen] = useState(false); return ( Nessun file. {files.map((file) => ( { if (currentValue !== current) { onSelect(files.find((f) => f.id === currentValue)!); } setOpen(false); }} > {file.ext && } {file.filename} {current === file.id && ( )} ))} ); }; const CaparraSchema = z.object({ caparra_causale: z.string().nullable(), caparra_iban: z.string().nullable(), caparra_importo: z.string().nullable(), caparra_intestazione: z.string().nullable(), }); type CaparraObj = z.infer; const parseCaparra = (ingest: string) => { let parsedJson: unknown; try { parsedJson = JSON.parse(ingest); } catch { toast.error( 'Stringa non valida, clicca "copia stringa" nel gestionale e poi questo pulsante', ); return undefined; } const parsed = CaparraSchema.safeParse(parsedJson); if (parsed.success) { return parsed.data; } else { console.error("Invalid caparra format:", parsed.error); return undefined; } }; const Caparra = ({ handleUpdate, }: { handleUpdate: (upd: ServizioAnnunciUpdate) => void; }) => { const { data } = useServizioAnnuncio(); const [caparra, setCaparra] = useState({ caparra_causale: data.caparra_causale, caparra_iban: data.caparra_iban, caparra_importo: data.caparra_importo, caparra_intestazione: data.caparra_intestazione, }); const handleSave = () => { handleUpdate({ ...caparra, }); }; return ( Dati Pagamento Caparra dati per il pagamento della caparra, da mostrare all'utente
{caparra ? (

Intestazione: {caparra.caparra_intestazione}{" "}

IBAN: {caparra.caparra_iban}{" "}

Importo: {caparra.caparra_importo}{" "}

Causale: {caparra.caparra_causale}{" "}

) : (

Inserisci la stringa dal gestionale e elabora

)}
); }; const SendConferma = ({ handleUpdate, }: { handleUpdate: (upd: ServizioAnnunciUpdate) => void; }) => { const { servizio } = useServizio(); const { data } = useServizioAnnuncio(); const { t } = useTranslation(); const [check, setCheck] = useState(data.hasConfermaAdmin); return ( Lavorazione Conferma controlla i parametri di ricerca prima!

Tipologia servizio: {servizio.tipologia}

{(() => { if (servizio.tipologia === TipologiaPosizioneEnum.Transitorio) { return ( <>

Permanenza (da preferenze):{" "} {servizio.permanenza ? t.preferenze.permanenza[servizio.permanenza] : "non inserita"}

Permanenza (da descrizione): " {(() => { const match = data.desc_it?.match(/Permanenza:.*$/m); return match ? match[0] : ""; })()} "

); } else { return ( <>

Budget (da preferenze): {formatCurrency(servizio.budget)}

Canone Mensile (da descrizione):{" "} {formatCurrency(data.prezzo / 100)}

); } })()}
{ setCheck(c); }} />
); }; export const AddButton = ({ annuncioId }: { annuncioId: AnnunciId }) => { const { servizioId, userId } = useServizio(); const utils = api.useUtils(); const { mutate } = api.servizio.addServizioAnnunci.useMutation({ onSuccess: async () => { await utils.servizio.getAllServizioAnnunci.invalidate({ userId }); await utils.servizio.getAnnunciAvailableToAdd.invalidate({ servizioId, }); await utils.servizio.AnnuncioServizioTipologiaMatch.invalidate({ userId, }); await utils.servizio.getCompatibileAnnunci.invalidate({ servizioId, }); toast.success("Annuncio aggiunto alla ricerca"); }, onError: (error) => { console.error(error); toast.error("Errore durante l'aggiunta dell'annuncio"); }, }); const buttonRef = useRef(null); return ( { buttonRef.current?.sparkle(); //wait for the animation to finish await new Promise((resolve) => setTimeout(resolve, 1000)); mutate({ servizioId, annunci: [annuncioId] }); }} variant="info" className="group flex w-full gap-2" > Aggiungi agli annunci da contattare ); };