infoalloggi-monorepo/apps/infoalloggi/src/components/servizio/conferma.tsx

252 lines
7 KiB
TypeScript
Raw Normal View History

import { CircleCheck, Handshake } from "lucide-react";
2025-10-24 16:10:59 +02:00
import Link from "next/link";
import { useState } from "react";
import toast from "react-hot-toast";
2025-08-04 17:45:44 +02:00
import { AllegatoIframe } from "~/components/allegato-iframe";
2025-08-28 18:27:07 +02:00
import { LoadingPage } from "~/components/loading";
import { useTranslation } from "~/providers/I18nProvider";
import { useServizio, useServizioAnnuncio } from "~/providers/ServizioProvider";
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
import type { UsersStorageUserStorageId } from "~/schemas/public/UsersStorage";
2025-08-28 18:27:07 +02:00
import { api } from "~/utils/api";
import { DocumentiUploadSection } from "../area-riservata/documenti_personali";
import {
Credenza,
CredenzaBody,
CredenzaClose,
CredenzaContent,
CredenzaDescription,
CredenzaFooter,
CredenzaHeader,
CredenzaTitle,
CredenzaTrigger,
} from "../custom_ui/credenza";
import LoadingButton from "../custom_ui/loading-button";
import { Button } from "../ui/button";
2025-08-04 17:45:44 +02:00
2025-10-24 16:10:59 +02:00
export const FileSection = ({ storageId }: { storageId: string }) => {
const { data: fileInfos, isLoading } = api.storage.getFileInfos.useQuery({
2025-08-28 18:27:07 +02:00
storageId,
});
const { t } = useTranslation();
if (isLoading) return <LoadingPage />;
if (!fileInfos) return <p>{t.file_section.error}</p>;
return (
<>
<AllegatoIframe
2025-10-24 16:10:59 +02:00
allegato={fileInfos}
2025-08-28 18:27:07 +02:00
className="h-full max-h-[70vh] min-h-[60vh]"
/>
2025-08-04 17:45:44 +02:00
2025-10-24 16:10:59 +02:00
<Link
2025-08-29 16:18:32 +02:00
className="underline underline-offset-1 after:content-['_↗']"
2025-10-24 16:10:59 +02:00
href={`/storage-api/get/${fileInfos.id}?mode=download`}
2025-08-28 18:27:07 +02:00
>
{t.file_section.download}
2025-10-24 16:10:59 +02:00
</Link>
2025-08-28 18:27:07 +02:00
</>
);
2025-08-04 17:45:44 +02:00
};
export const ConfermaAnnuncioModal = () => {
const { servizio } = useServizio();
const { t } = useTranslation();
const [open, setOpen] = useState(false);
//TODO need to show messaggio in alert dialog after invio conferma about adeguamento saldo e permanenza based on doc presented
const needsDocuments =
!servizio.skipDocMotivazione &&
!servizio.doc_motivazione &&
servizio.tipologia === TipologiaPosizioneEnum.Transitorio;
return (
<Credenza onOpenChange={setOpen} open={open}>
<CredenzaTrigger asChild>
<Button aria-label="Conferma immobile" className="w-fit">
<Handshake className="size-6" /> {t.richieste.cta}
</Button>
</CredenzaTrigger>
<CredenzaContent className="max-h-[90vh]">
<CredenzaHeader>
<CredenzaTitle> {t.richieste.conf_title}</CredenzaTitle>
<CredenzaDescription className="sr-only">
{t.richieste.conf_desc}
</CredenzaDescription>
</CredenzaHeader>
{needsDocuments ? (
<DocCheckpoint />
) : (
<InvioConferma setOpen={setOpen} />
)}
</CredenzaContent>
</Credenza>
);
};
const InvioConferma = ({ setOpen }: { setOpen: (value: boolean) => void }) => {
const { userId, servizioId } = useServizio();
const { annuncioId } = useServizioAnnuncio();
const { t } = useTranslation();
const utils = api.useUtils();
const { mutate, isPending } = api.servizio.userSendConfermaIntent.useMutation(
{
onError: (err) => {
toast.error(err.message, { id: "updateRichiestaToast" });
},
onMutate: () => {
toast.loading("Conferma in corso", { id: "updateRichiestaToast" });
},
onSuccess: async () => {
toast.success("Richiesta confermata con successo", {
id: "updateRichiestaToast",
});
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
setOpen(false);
},
},
);
return (
<>
<CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
<p>{t.richieste.conferma_txt}</p>
</CredenzaBody>
<CredenzaFooter>
<LoadingButton
aria-label="Conferma immobile"
loading={isPending}
onClick={() => {
mutate({
annuncioId,
servizioId,
});
}}
variant="success"
>
{t.conferma}
</LoadingButton>
<CredenzaClose asChild>
<Button aria-label="Chiudi modal credenza">{t.chiudi}</Button>
</CredenzaClose>
</CredenzaFooter>
</>
);
};
const DocCheckpoint = () => {
const { t } = useTranslation();
const { userId, servizio, isAdmin } = useServizio();
const utils = api.useUtils();
const { mutate, isPending } = api.servizio.updateServizio.useMutation({
onSuccess: async () => {
await utils.servizio.getAllServizioAnnunci.invalidate({
userId,
});
await utils.storage.retrieveUserFileData.invalidate({ userId });
await utils.servizio.getServizio.invalidate({
servizioId: servizio.servizio_id,
});
},
onError: (err) => {
toast.error(`Errore aggiornamento servizio: ${err.message}`);
},
});
const handleUpload = (id: UsersStorageUserStorageId) => {
mutate({
servizioId: servizio.servizio_id,
data: { doc_motivazione_ref: id },
});
};
return (
<>
<CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
<div className="space-y-5">
<p>
Devi ancora caricare un tuo documento legato alla permanenza e
motivazione di transitorietà
</p>
<DocumentiUploadSection
caricatoNote
document={servizio.doc_motivazione}
isAdmin={isAdmin}
isPending={isPending}
onUpload={handleUpload}
title="Documento:"
userId={userId}
/>
<br />
<br />
<p className="text-muted-foreground text-sm">
I tuoi dati saranno conservati solamente per la durata del servizio,
in conformità con la nostra{" "}
<Link className="underline" href="/privacy-policy" target="_blank">
Informativa sulla Privacy
</Link>
</p>
</div>
</CredenzaBody>
<CredenzaFooter>
<CredenzaClose asChild>
<Button aria-label="Chiudi" disabled={isPending} variant="outline">
{t.chiudi}
</Button>
</CredenzaClose>
</CredenzaFooter>
</>
);
};
export const ConfermaInLavorazioneModal = () => {
const { t } = useTranslation();
const { data } = useServizioAnnuncio();
return (
<Credenza>
<CredenzaTrigger asChild>
<Button aria-label="Conferma in lavorazione" className="w-fit">
<CircleCheck className="size-7" />
Conferma in lavorazione
</Button>
</CredenzaTrigger>
<CredenzaContent className="max-h-[90vh]">
<CredenzaHeader>
<CredenzaTitle>In attesa di conferma</CredenzaTitle>
<CredenzaDescription className="sr-only">
Consegna status modal
</CredenzaDescription>
</CredenzaHeader>
<CredenzaBody className="prose max-h-[80vh] overflow-auto pb-5">
<p>
Richiesta di conferma inviata il:{" "}
{data.user_confirmed_at &&
new Date(data.user_confirmed_at).toLocaleString("it", {
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
month: "2-digit",
year: "numeric",
})}
</p>
<p>
La conferma è ancora in lavorazione. Stiamo verificando con i
proprietari le condizioni e dettagli della conferma per riferirteli.
Attendi una comunicazione.
</p>
</CredenzaBody>
<CredenzaFooter>
<CredenzaClose asChild>
<Button aria-label="Chiudi modal credenza" variant="outline">
{t.chiudi}
</Button>
</CredenzaClose>
</CredenzaFooter>
</CredenzaContent>
</Credenza>
);
};