feat: integrate DocumentiUploadSection for document handling in various components
This commit is contained in:
parent
4408295f56
commit
d116ebd3d5
3 changed files with 207 additions and 235 deletions
|
|
@ -1,13 +1,15 @@
|
|||
import { ExternalLink, Trash2 } from "lucide-react";
|
||||
import { CircleCheck, ExternalLink, Trash2 } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import toast from "react-hot-toast";
|
||||
import { useSession } from "~/providers/SessionProvider";
|
||||
import type { UsersId } from "~/schemas/public/Users";
|
||||
import type { UsersStorageUserStorageId } from "~/schemas/public/UsersStorage";
|
||||
import type { UserWithAnagrafica } from "~/server/services/user.service";
|
||||
import { api } from "~/utils/api";
|
||||
import { Confirm } from "../confirm";
|
||||
import { ImageFlbk } from "../ImageWithFallback";
|
||||
import { LoadingPage } from "../loading";
|
||||
import { LoadingSpinner } from "../spinner";
|
||||
import { Button } from "../ui/button";
|
||||
import {
|
||||
Card,
|
||||
|
|
@ -63,125 +65,35 @@ export const DocumentiPersonali = ({
|
|||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<h4 className="mb-2 font-medium">
|
||||
Documento d'identità - Fronte
|
||||
</h4>
|
||||
|
||||
{userData.doc_personale_fronte?.storageId ? (
|
||||
<div className="flex items-center gap-4">
|
||||
<ImageFlbk
|
||||
alt="documento personale fronte"
|
||||
className="size-24 rounded-md object-cover"
|
||||
height={50}
|
||||
src={`/storage-api/get/${userData.doc_personale_fronte.storageId}`}
|
||||
width={50}
|
||||
/>
|
||||
|
||||
<div className="flex flex-col justify-center gap-2">
|
||||
<Link
|
||||
href={`/area-riservata/allegato-view/${userData.doc_personale_fronte.storageId}`}
|
||||
target="_blank"
|
||||
>
|
||||
<Button size="sm">
|
||||
<span>Visualizza</span>
|
||||
<ExternalLink />
|
||||
</Button>
|
||||
</Link>
|
||||
<Confirm
|
||||
description="Sei sicuro di voler eliminare il documento?"
|
||||
onConfirm={() => {
|
||||
<DocumentiUploadSection
|
||||
document={userData.doc_personale_fronte}
|
||||
isAdmin={user.isAdmin}
|
||||
isPending={isPending}
|
||||
onRemove={() =>
|
||||
mutate({
|
||||
userId: userData.id,
|
||||
data: { doc_personale_fronte_ref: null },
|
||||
});
|
||||
}}
|
||||
title="Elimina Documento"
|
||||
>
|
||||
<Button
|
||||
aria-label="Elimina Doc"
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
>
|
||||
<span>Elimina Documento</span>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</Confirm>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<UploadModal
|
||||
cb_onUpload={({ userStorageIds }) =>
|
||||
userStorageIds.length > 0 &&
|
||||
userStorageIds[0] &&
|
||||
handleUpload("doc_personale_fronte_ref", userStorageIds[0])
|
||||
})
|
||||
}
|
||||
isAdmin={user.isAdmin}
|
||||
maxFiles={1}
|
||||
onUpload={(id) => handleUpload("doc_personale_fronte_ref", id)}
|
||||
title="Documento d'identità - Fronte"
|
||||
userId={userData.id}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<h4 className="mb-2 font-medium">Documento d'identità - Retro</h4>
|
||||
{userData.doc_personale_retro?.storageId ? (
|
||||
<div className="flex items-center gap-4">
|
||||
<ImageFlbk
|
||||
alt="documento personale retro"
|
||||
className="size-24 rounded-md object-cover"
|
||||
height={50}
|
||||
src={`/storage-api/get/${userData.doc_personale_retro.storageId}`}
|
||||
width={50}
|
||||
/>
|
||||
|
||||
<div className="flex flex-col justify-center gap-2">
|
||||
<Link
|
||||
href={`/area-riservata/allegato-view/${userData.doc_personale_retro.storageId}`}
|
||||
target="_blank"
|
||||
>
|
||||
<Button size="sm">
|
||||
<span>Visualizza</span>
|
||||
<ExternalLink />
|
||||
</Button>
|
||||
</Link>
|
||||
<Confirm
|
||||
description="Sei sicuro di voler eliminare il documento?"
|
||||
onConfirm={() => {
|
||||
<DocumentiUploadSection
|
||||
document={userData.doc_personale_retro}
|
||||
isAdmin={user.isAdmin}
|
||||
isPending={isPending}
|
||||
onRemove={() =>
|
||||
mutate({
|
||||
userId: userData.id,
|
||||
data: { doc_personale_retro_ref: null },
|
||||
});
|
||||
}}
|
||||
title="Elimina Documento"
|
||||
>
|
||||
<Button
|
||||
aria-label="Elimina Doc"
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
>
|
||||
<span>Elimina Documento</span>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</Confirm>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<UploadModal
|
||||
cb_onUpload={({ userStorageIds }) =>
|
||||
userStorageIds.length > 0 &&
|
||||
userStorageIds[0] &&
|
||||
handleUpload("doc_personale_retro_ref", userStorageIds[0])
|
||||
})
|
||||
}
|
||||
isAdmin={user.isAdmin}
|
||||
maxFiles={1}
|
||||
onUpload={(id) => handleUpload("doc_personale_retro_ref", id)}
|
||||
title="Documento d'identità - Retro"
|
||||
userId={userData.id}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
|
|
@ -196,3 +108,96 @@ export const DocumentiPersonali = ({
|
|||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export const DocumentiUploadSection = ({
|
||||
title,
|
||||
document,
|
||||
onUpload,
|
||||
onRemove,
|
||||
isAdmin,
|
||||
userId,
|
||||
isPending,
|
||||
caricatoNote,
|
||||
}: {
|
||||
title: string;
|
||||
document: {
|
||||
storageId: string;
|
||||
ref: UsersStorageUserStorageId | null;
|
||||
} | null;
|
||||
onUpload: (id: UsersStorageUserStorageId) => void;
|
||||
onRemove?: () => void;
|
||||
isAdmin: boolean;
|
||||
userId: UsersId;
|
||||
isPending: boolean;
|
||||
caricatoNote?: boolean;
|
||||
}) => {
|
||||
if (document?.storageId) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<h4 className="font-medium">{title}</h4>
|
||||
{caricatoNote && (
|
||||
<div className="flex items-center gap-2 text-green-500">
|
||||
<CircleCheck className="size-5" />
|
||||
<span>Documento caricato</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-4">
|
||||
{isPending ? (
|
||||
<LoadingSpinner className="size-24 stroke-neutral-300" />
|
||||
) : (
|
||||
<ImageFlbk
|
||||
alt={title}
|
||||
className="size-24 rounded-md border object-cover"
|
||||
height={96}
|
||||
src={`/storage-api/get/${document.storageId}`}
|
||||
width={96}
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-col justify-center gap-2">
|
||||
<Link
|
||||
href={`/area-riservata/allegato-view/${document.storageId}`}
|
||||
target="_blank"
|
||||
>
|
||||
<Button size="sm" variant="outline">
|
||||
<span>Visualizza</span>
|
||||
<ExternalLink className="size-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
{onRemove && (
|
||||
<Confirm
|
||||
description="Sei sicuro di voler eliminare il documento?"
|
||||
onConfirm={onRemove}
|
||||
title="Elimina Documento"
|
||||
>
|
||||
<Button
|
||||
aria-label="Elimina documento"
|
||||
disabled={isPending}
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
>
|
||||
<span>Rimuovi</span>
|
||||
<Trash2 className="size-4" />
|
||||
</Button>
|
||||
</Confirm>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<h4 className="font-medium">{title}</h4>
|
||||
<UploadModal
|
||||
cb_onUpload={({ userStorageIds }) => {
|
||||
const id = userStorageIds[0];
|
||||
if (id) onUpload(id);
|
||||
}}
|
||||
isAdmin={isAdmin}
|
||||
maxFiles={1}
|
||||
userId={userId}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { useServizio, useServizioAnnuncio } from "~/providers/ServizioProvider";
|
|||
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
|
||||
import type { UsersStorageUserStorageId } from "~/schemas/public/UsersStorage";
|
||||
import { api } from "~/utils/api";
|
||||
import { DocumentiUploadSection } from "../area-riservata/documenti_personali";
|
||||
import {
|
||||
Credenza,
|
||||
CredenzaBody,
|
||||
|
|
@ -22,7 +23,6 @@ import {
|
|||
} from "../custom_ui/credenza";
|
||||
import LoadingButton from "../custom_ui/loading-button";
|
||||
import { Button } from "../ui/button";
|
||||
import { type UploadCallback, UploadModal } from "../upload_modal";
|
||||
|
||||
export const FileSection = ({ storageId }: { storageId: string }) => {
|
||||
const { data: fileInfos, isLoading } = api.storage.getFileInfos.useQuery({
|
||||
|
|
@ -134,40 +134,9 @@ const InvioConferma = ({ setOpen }: { setOpen: (value: boolean) => void }) => {
|
|||
);
|
||||
};
|
||||
|
||||
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 { userId, servizio, isAdmin } = useServizio();
|
||||
const utils = api.useUtils();
|
||||
const { mutate, isPending } = api.servizio.updateServizio.useMutation({
|
||||
onSuccess: async () => {
|
||||
|
|
@ -198,17 +167,15 @@ const DocCheckpoint = () => {
|
|||
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}
|
||||
<DocumentiUploadSection
|
||||
caricatoNote
|
||||
document={servizio.doc_motivazione}
|
||||
isAdmin={isAdmin}
|
||||
isPending={isPending}
|
||||
onUpload={handleUpload}
|
||||
title="Documento:"
|
||||
userId={userId}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -1,17 +1,12 @@
|
|||
import {
|
||||
CircleCheck,
|
||||
CircleUser,
|
||||
Navigation,
|
||||
Phone,
|
||||
TriangleAlert,
|
||||
} from "lucide-react";
|
||||
import { CircleUser, Navigation, Phone, TriangleAlert } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useMemo } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import { useServizio, useServizioAnnuncio } from "~/providers/ServizioProvider";
|
||||
import type { UsersStorageUserStorageId } from "~/schemas/public/UsersStorage";
|
||||
import { api } from "~/utils/api";
|
||||
import { DocumentiUploadSection } from "../area-riservata/documenti_personali";
|
||||
import {
|
||||
Credenza,
|
||||
CredenzaBody,
|
||||
|
|
@ -26,22 +21,32 @@ import {
|
|||
import { LoadingPage } from "../loading";
|
||||
import { WhatsAppIcon2 } from "../svgs";
|
||||
import { Button } from "../ui/button";
|
||||
import { type UploadCallback, UploadModal } from "../upload_modal";
|
||||
|
||||
export const ContattiProprietarioModal = () => {
|
||||
const { servizio } = useServizio();
|
||||
const [open, setOpen] = useState(false);
|
||||
const { data } = useServizioAnnuncio();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const isUnlocked = data.open_contatti_at != null;
|
||||
const needsDocuments =
|
||||
!servizio.skipControlloDoc &&
|
||||
(!servizio.doc_personale_fronte || !servizio.doc_personale_retro);
|
||||
const [showDocStep, setShowDocStep] = useState(
|
||||
open && (needsDocuments || !isUnlocked),
|
||||
);
|
||||
|
||||
return (
|
||||
<Credenza>
|
||||
<Credenza
|
||||
onOpenChange={(o) => {
|
||||
setOpen(o);
|
||||
if (o && (needsDocuments || !isUnlocked)) {
|
||||
setShowDocStep(true);
|
||||
}
|
||||
}}
|
||||
open={open}
|
||||
>
|
||||
<CredenzaTrigger asChild>
|
||||
{data.open_contatti_at != null ? (
|
||||
{isUnlocked ? (
|
||||
<Button
|
||||
aria-label="Vedi contatti proprietario"
|
||||
className="w-fit"
|
||||
|
|
@ -68,8 +73,8 @@ export const ContattiProprietarioModal = () => {
|
|||
{t.contatto.descrizione}
|
||||
</CredenzaDescription>
|
||||
</CredenzaHeader>
|
||||
{needsDocuments ? (
|
||||
<DocCheckpoint />
|
||||
{showDocStep ? (
|
||||
<DocCheckpoint setStep={setShowDocStep} />
|
||||
) : isUnlocked ? (
|
||||
<PostUnlock />
|
||||
) : (
|
||||
|
|
@ -80,40 +85,9 @@ export const ContattiProprietarioModal = () => {
|
|||
);
|
||||
};
|
||||
|
||||
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 DocCheckpoint = ({ setStep }: { setStep: (value: boolean) => void }) => {
|
||||
const { t } = useTranslation();
|
||||
const { userId, servizio } = useServizio();
|
||||
const { userId, servizio, isAdmin } = useServizio();
|
||||
const utils = api.useUtils();
|
||||
const { mutate, isPending } = api.users.editUserAnagrafica.useMutation({
|
||||
onSuccess: async () => {
|
||||
|
|
@ -143,33 +117,47 @@ const DocCheckpoint = () => {
|
|||
return (
|
||||
<>
|
||||
<CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
|
||||
<div className="space-y-5">
|
||||
<p>Devi ancora caricare un tuo documento</p>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span>Fronte documento:</span>
|
||||
<DocComponent
|
||||
cb={({ userStorageIds }) =>
|
||||
userStorageIds.length > 0 &&
|
||||
userStorageIds[0] &&
|
||||
handleUpload("doc_personale_fronte_ref", userStorageIds[0])
|
||||
}
|
||||
docInfo={servizio.doc_personale_fronte}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span>Retro documento:</span>
|
||||
<DocComponent
|
||||
cb={({ userStorageIds }) =>
|
||||
userStorageIds.length > 0 &&
|
||||
userStorageIds[0] &&
|
||||
handleUpload("doc_personale_retro_ref", userStorageIds[0])
|
||||
}
|
||||
docInfo={servizio.doc_personale_retro}
|
||||
/>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<p className="font-semibold">Carica i tuoi documenti</p>
|
||||
<p>
|
||||
se si ha una scansione unica fronte/retro dei doc, caricarla due
|
||||
volte.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<DocumentiUploadSection
|
||||
caricatoNote
|
||||
document={servizio.doc_personale_fronte}
|
||||
isAdmin={isAdmin}
|
||||
isPending={isPending}
|
||||
onRemove={() =>
|
||||
mutate({
|
||||
userId,
|
||||
data: { doc_personale_fronte_ref: null },
|
||||
})
|
||||
}
|
||||
onUpload={(id) => handleUpload("doc_personale_fronte_ref", id)}
|
||||
title="Documento d'identità - Fronte"
|
||||
userId={userId}
|
||||
/>
|
||||
|
||||
<DocumentiUploadSection
|
||||
caricatoNote
|
||||
document={servizio.doc_personale_retro}
|
||||
isAdmin={isAdmin}
|
||||
isPending={isPending}
|
||||
onRemove={() =>
|
||||
mutate({
|
||||
userId,
|
||||
data: { doc_personale_retro_ref: null },
|
||||
})
|
||||
}
|
||||
onUpload={(id) => handleUpload("doc_personale_retro_ref", id)}
|
||||
title="Documento d'identità - Retro"
|
||||
userId={userId}
|
||||
/>
|
||||
|
||||
<p className="text-muted-foreground text-sm">
|
||||
I tuoi dati saranno conservati solamente per la durata del servizio,
|
||||
in conformità con la nostra{" "}
|
||||
|
|
@ -180,6 +168,18 @@ const DocCheckpoint = () => {
|
|||
</div>
|
||||
</CredenzaBody>
|
||||
<CredenzaFooter>
|
||||
<Button
|
||||
aria-label="Procedi"
|
||||
disabled={
|
||||
isPending ||
|
||||
!servizio.doc_personale_fronte?.storageId ||
|
||||
!servizio.doc_personale_retro?.storageId
|
||||
}
|
||||
onClick={() => setStep(false)}
|
||||
variant="success"
|
||||
>
|
||||
Procedi
|
||||
</Button>
|
||||
<CredenzaClose asChild>
|
||||
<Button aria-label="Chiudi" disabled={isPending} variant="outline">
|
||||
{t.chiudi}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue