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

404 lines
11 KiB
TypeScript
Raw Normal View History

2025-08-28 18:27:07 +02:00
import {
CircleCheck,
FileBadge,
FileText,
Handshake,
PackageCheck,
Pointer,
} from "lucide-react";
2025-08-04 17:45:44 +02:00
import Link from "next/link";
2025-08-28 18:27:07 +02:00
import { useRouter } from "next/router";
import { useState } from "react";
2025-08-04 17:45:44 +02:00
import toast from "react-hot-toast";
import {
2025-08-28 18:27:07 +02:00
Credenza,
CredenzaBody,
CredenzaClose,
CredenzaContent,
CredenzaDescription,
CredenzaFooter,
CredenzaHeader,
CredenzaTitle,
CredenzaTrigger,
2025-08-04 17:45:44 +02:00
} from "~/components/custom_ui/credenza";
import LoadingButton from "~/components/custom_ui/loading-button";
2025-08-28 18:27:07 +02:00
import { Button, type ButtonConfigs } from "~/components/ui/button";
2025-08-04 17:45:44 +02:00
import {
2025-08-28 18:27:07 +02:00
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
2025-08-04 17:45:44 +02:00
} from "~/components/ui/tooltip";
2025-08-28 18:27:07 +02:00
import { cn } from "~/lib/utils";
import { useTranslation } from "~/providers/I18nProvider";
import { useServizio, useServizioAnnuncio } from "~/providers/ServizioProvider";
2025-08-04 17:45:44 +02:00
import type { AnnunciId } from "~/schemas/public/Annunci";
2025-08-28 18:27:07 +02:00
import { api } from "~/utils/api";
import { ContattiProprietarioModal } from "./modale_contatti";
2025-08-04 17:45:44 +02:00
export const Interactions = () => {
2025-08-28 18:27:07 +02:00
const { servizio, servizioId } = useServizio();
const { data, annuncioId } = useServizioAnnuncio();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
return (
<div className="flex flex-col gap-3">
<ContattiProprietarioModal />
<div className="flex flex-wrap gap-3">
{data.open_contatti_at !== null && data.user_confirmed_at == null && (
<AnnuncioConfirm />
)}
{data.user_confirmed_at && !data.hasConfermaAdmin && (
<ConfermaLavorazioneModal />
)}
{data.doc_conferma_added &&
data.accettato_conferma_at == null &&
data.hasConfermaAdmin &&
(data.doc_conferma_ref ? (
<Link
aria-label="Conferma immobile"
href={`/servizio/conferma-immobile/${servizioId}/${annuncioId}`}
>
<Button
className="flex w-fit items-center gap-2"
2025-08-29 16:18:32 +02:00
variant="success"
2025-08-28 18:27:07 +02:00
>
<Pointer className="size-6" />
Confermato - Procedi ora
</Button>
</Link>
) : (
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Button
className="flex w-fit cursor-not-allowed items-center gap-2 opacity-50"
2025-08-29 16:18:32 +02:00
variant="success"
2025-08-28 18:27:07 +02:00
>
<Pointer className="size-6" />
Confermato - Procedi ora
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Il documento non è più disponibile</p>
<p>
Se hai bisogno di una copia, contattaci via email o chat.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
))}
{data.accettato_conferma_at != null && (
<Link
aria-label="Conferma immobile"
href={`/servizio/riapri-conferma/${servizioId}/${annuncioId}`}
>
2025-08-29 16:18:32 +02:00
<Button className="flex w-fit items-center gap-2" variant="success">
2025-08-28 18:27:07 +02:00
<Pointer className="size-6" />
Rivedi la conferma
</Button>
</Link>
)}
</div>
{!servizio.isOkSaldo && data.accettato_conferma_at != null && (
<div className="flex flex-col gap-1">
<h3 className="font-semibold">
Questo annuncio è stato confermato, procedi al saldo:
</h3>
<SaldoButton annuncioId={annuncioId} />
</div>
)}
2025-08-28 18:27:07 +02:00
{servizio.isOkSaldo &&
data.accettato_conferma_at != null &&
data.doc_contratto_added == null && (
<div className="flex flex-col gap-1">
<h3 className="font-semibold text-green-500">
Ci siamo quasi! Stiamo preparando il contratto per te.
</h3>
<h3 className="font-semibold">
Una volta pronto, riceverai una notifica via email.
</h3>
</div>
)}
{servizio.isOkSaldo &&
data.accettato_conferma_at != null &&
data.doc_contratto_added && (
<div className="flex flex-col gap-2">
<h3 className="font-semibold">
{servizio.isOkConsulenza
? "Il contratto è pronto, puoi visualizzarlo:"
: "Il contratto è pronto, puoi visualizzarlo e procedere al saldo:"}
</h3>
<div className="flex flex-wrap gap-2">
{data.doc_contratto_ref ? (
<Link
aria-label="Visualizza contratto"
href={`/servizio/contratto/${servizioId}/${annuncioId}`}
target="_blank"
>
<Button className="flex w-fit items-center gap-2">
<FileText className="size-6" />
Visualizza il contratto
</Button>
</Link>
) : (
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Button className="flex w-fit cursor-not-allowed items-center gap-2 opacity-50">
<FileText className="size-6" />
Visualizza il contratto
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Il documento non è più disponibile</p>
<p>
Se hai bisogno di una copia, contattaci via email o
chat.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
{!servizio.isOkConsulenza && data.contratto_tipo && (
<SaldoConsulenzaButton />
)}
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
{data.doc_registrazione_added &&
(data.doc_registrazione_ref ? (
<Link
aria-label="Visualizza registrazione"
href={`/servizio/contratto-registrazione/${servizioId}/${annuncioId}`}
target="_blank"
>
<Button className="flex w-fit items-center gap-2">
<FileBadge className="size-6" />
Visualizza la registrazione
</Button>
</Link>
) : (
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Button className="flex w-fit cursor-not-allowed items-center gap-2 opacity-50">
<FileBadge className="size-6" />
Visualizza la registrazione
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Il documento non è più disponibile</p>
<p>
Se hai bisogno di una copia, contattaci via email o
chat.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
))}
</div>
</div>
)}
</div>
);
2025-08-04 17:45:44 +02:00
};
export const SaldoButton = ({
2025-08-28 18:27:07 +02:00
annuncioId,
variant = "info",
className,
2025-08-04 17:45:44 +02:00
}: {
2025-08-28 18:27:07 +02:00
annuncioId: AnnunciId;
variant?: ButtonConfigs["variant"];
className?: string;
2025-08-04 17:45:44 +02:00
}) => {
2025-08-28 18:27:07 +02:00
const { servizioId } = useServizio();
const router = useRouter();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const { mutate } = api.servizio.setupSaldoServizio.useMutation({
onMutate: () => {
toast.loading("Caricamento ...", { id: "preparazioneSaldo" });
},
onSuccess: async (data) => {
toast.success("Pagamento saldo preparato", {
id: "preparazioneSaldo",
});
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
await router.push(`/servizio/pagamento/${data}`);
},
});
return (
<Button
aria-label="Procedi al saldo"
className={cn("flex w-fit items-center gap-2", className)}
onClick={() => {
mutate({
annuncioId,
2025-08-29 16:18:32 +02:00
servizioId,
2025-08-28 18:27:07 +02:00
});
}}
2025-08-29 16:18:32 +02:00
variant={variant}
2025-08-28 18:27:07 +02:00
>
<PackageCheck className="size-6" />
Procedi al saldo
</Button>
);
2025-08-04 17:45:44 +02:00
};
const SaldoConsulenzaButton = ({
2025-08-28 18:27:07 +02:00
variant = "info",
className,
2025-08-04 17:45:44 +02:00
}: {
2025-08-28 18:27:07 +02:00
variant?: ButtonConfigs["variant"];
className?: string;
2025-08-04 17:45:44 +02:00
}) => {
2025-08-28 18:27:07 +02:00
const { annuncioId } = useServizioAnnuncio();
const { servizioId } = useServizio();
const router = useRouter();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const { mutate } = api.servizio.setupSaldoConsulenzaServizio.useMutation({
onMutate: () => {
toast.loading("Caricamento ...", { id: "preparazioneSaldo" });
},
onSuccess: async (data) => {
toast.success("Pagamento saldo preparato", {
id: "preparazioneSaldo",
});
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
await router.push(`/servizio/pagamento/${data}`);
},
});
return (
<Button
aria-label="Procedi al saldo consulenza"
className={cn("flex w-fit items-center gap-2", className)}
onClick={() => {
mutate({
annuncioId,
2025-08-29 16:18:32 +02:00
servizioId,
2025-08-28 18:27:07 +02:00
});
}}
2025-08-29 16:18:32 +02:00
variant={variant}
2025-08-28 18:27:07 +02:00
>
<PackageCheck className="size-6" />
Procedi al saldo della consulenza
</Button>
);
2025-08-04 17:45:44 +02:00
};
const AnnuncioConfirm = () => {
2025-08-28 18:27:07 +02:00
const { userId, servizioId } = useServizio();
const { annuncioId } = useServizioAnnuncio();
const { t } = useTranslation();
const [open, setOpen] = useState(false);
const utils = api.useUtils();
const { mutate, isPending } = api.servizio.userConfirmImmobile.useMutation({
onError: (err) => {
toast.error(err.message, { id: "updateRichiestaToast" });
},
2025-08-29 16:18:32 +02:00
onMutate: () => {
toast.loading("Conferma in corso", { id: "updateRichiestaToast" });
},
2025-08-28 18:27:07 +02:00
onSuccess: async () => {
toast.success("Richiesta confermata con successo", {
id: "updateRichiestaToast",
});
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
setOpen(false);
},
});
return (
2025-08-29 16:18:32 +02:00
<Credenza onOpenChange={setOpen} open={open}>
2025-08-28 18:27:07 +02:00
<CredenzaTrigger asChild>
<Button
aria-label="Conferma immobile"
2025-08-29 16:18:32 +02:00
className="flex w-fit items-center gap-2"
2025-08-28 18:27:07 +02:00
>
<Handshake className="size-6" /> Conferma immobile
</Button>
</CredenzaTrigger>
<CredenzaContent className="max-h-[90vh]">
<CredenzaHeader>
<CredenzaTitle> {t.richieste.conf_title}</CredenzaTitle>
<CredenzaDescription className="sr-only">
{t.richieste.conf_desc}
</CredenzaDescription>
</CredenzaHeader>
<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,
});
}}
2025-08-29 16:18:32 +02:00
variant="success"
2025-08-28 18:27:07 +02:00
>
{t.conferma}
</LoadingButton>
<CredenzaClose asChild>
<Button aria-label="Chiudi modal credenza">Chiudi</Button>
</CredenzaClose>
</CredenzaFooter>
</CredenzaContent>
</Credenza>
);
2025-08-04 17:45:44 +02:00
};
const ConfermaLavorazioneModal = () => {
2025-08-28 18:27:07 +02:00
const { t } = useTranslation();
const { data } = useServizioAnnuncio();
return (
<Credenza>
<CredenzaTrigger asChild>
<Button
aria-label="Conferma in lavorazione"
2025-08-29 16:18:32 +02:00
className="flex w-fit items-center gap-2"
2025-08-28 18:27:07 +02:00
>
<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",
2025-08-29 16:18:32 +02:00
month: "2-digit",
year: "numeric",
2025-08-28 18:27:07 +02:00
})}
</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>
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
<CredenzaFooter>
<CredenzaClose asChild>
2025-08-29 16:18:32 +02:00
<Button aria-label="Chiudi modal credenza" variant="outline">
2025-08-28 18:27:07 +02:00
{t.chiudi}
</Button>
</CredenzaClose>
</CredenzaFooter>
</CredenzaContent>
</Credenza>
);
2025-08-04 17:45:44 +02:00
};