2025-11-06 17:03:42 +01:00
|
|
|
import { CircleCheck, Handshake } from "lucide-react";
|
2025-10-24 16:10:59 +02:00
|
|
|
import Link from "next/link";
|
2025-11-06 17:03:42 +01:00
|
|
|
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";
|
2025-08-13 17:29:26 +02:00
|
|
|
import { useTranslation } from "~/providers/I18nProvider";
|
2025-11-06 17:03:42 +01:00
|
|
|
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";
|
2025-11-06 17:03:42 +01:00
|
|
|
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";
|
|
|
|
|
import { type UploadCallback, UploadModal } from "../upload_modal";
|
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
|
|
|
};
|
2025-11-06 17:03:42 +01:00
|
|
|
|
|
|
|
|
export const ConfermaAnnuncioModal = () => {
|
|
|
|
|
const { servizio } = useServizio();
|
|
|
|
|
|
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
const [open, setOpen] = useState(false);
|
|
|
|
|
|
|
|
|
|
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">
|
2025-11-10 11:52:36 +01:00
|
|
|
<Handshake className="size-6" /> {t.richieste.cta}
|
2025-11-06 17:03:42 +01:00
|
|
|
</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>
|
2025-11-10 11:52:36 +01:00
|
|
|
<Button aria-label="Chiudi modal credenza">{t.chiudi}</Button>
|
2025-11-06 17:03:42 +01:00
|
|
|
</CredenzaClose>
|
|
|
|
|
</CredenzaFooter>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const DocComponent = ({
|
|
|
|
|
docInfo,
|
|
|
|
|
cb,
|
|
|
|
|
}: {
|
|
|
|
|
docInfo: {
|
|
|
|
|
storageId: string;
|
|
|
|
|
ref: UsersStorageUserStorageId | null;
|
|
|
|
|
} | null;
|
|
|
|
|
cb: UploadCallback;
|
|
|
|
|
}) => {
|
|
|
|
|
const { isAdmin, userId } = useServizio();
|
|
|
|
|
|
|
|
|
|
if (docInfo?.storageId) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex items-center gap-2 text-green-500">
|
|
|
|
|
<CircleCheck className="size-5" />
|
|
|
|
|
<span>Documento caricato</span>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<UploadModal
|
|
|
|
|
cb_onUpload={cb}
|
|
|
|
|
isAdmin={isAdmin}
|
|
|
|
|
maxFiles={1}
|
|
|
|
|
userId={userId}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const DocCheckpoint = () => {
|
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
const { userId, servizio } = 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>
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-col gap-2">
|
|
|
|
|
<span>Documento:</span>
|
|
|
|
|
<DocComponent
|
|
|
|
|
cb={({ userStorageIds }) =>
|
|
|
|
|
userStorageIds.length > 0 &&
|
|
|
|
|
userStorageIds[0] &&
|
|
|
|
|
handleUpload(userStorageIds[0])
|
|
|
|
|
}
|
|
|
|
|
docInfo={servizio.doc_motivazione}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<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>
|
|
|
|
|
);
|
|
|
|
|
};
|