845 lines
21 KiB
TypeScript
845 lines
21 KiB
TypeScript
import { format } from "date-fns";
|
|
import {
|
|
CircleCheck,
|
|
ClipboardPaste,
|
|
FlaskConical,
|
|
Pen,
|
|
Trash2,
|
|
Wrench,
|
|
} from "lucide-react";
|
|
import Link from "next/link";
|
|
import { useState } from "react";
|
|
import toast from "react-hot-toast";
|
|
import { useDebounce } from "react-use";
|
|
import z from "zod";
|
|
import { it } from "~/i18n/it";
|
|
import { handleConsegna } from "~/lib/annuncio_details";
|
|
import { formatCurrency } from "~/lib/utils";
|
|
import { useTranslation } from "~/providers/I18nProvider";
|
|
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 { Confirm } from "../confirm";
|
|
import { Counter } from "../counter";
|
|
import {
|
|
Credenza,
|
|
CredenzaBody,
|
|
CredenzaClose,
|
|
CredenzaContent,
|
|
CredenzaDescription,
|
|
CredenzaFooter,
|
|
CredenzaHeader,
|
|
CredenzaTitle,
|
|
CredenzaTrigger,
|
|
} from "../custom_ui/credenza";
|
|
import { NumberInput } from "../custom_ui/InputNumber";
|
|
import {
|
|
type ListOption,
|
|
MultiSelect,
|
|
UnpackOptions,
|
|
} from "../custom_ui/multiselect";
|
|
import { LoadingPage } from "../loading";
|
|
import { Button } from "../ui/button";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardFooter,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "../ui/card";
|
|
import { Label } from "../ui/label";
|
|
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
|
import { Switch } from "../ui/switch";
|
|
import { UploadModal } from "../upload_modal";
|
|
import { DocCombo, DocInfo } from "./shared";
|
|
|
|
export const AdminLavoraConferma = () => {
|
|
const { servizio } = useServizio();
|
|
const { data } = useServizioAnnuncio();
|
|
|
|
return (
|
|
<Credenza>
|
|
<CredenzaTrigger asChild>
|
|
<Button
|
|
aria-label="Open Lavora Conferma Section"
|
|
className="w-fit"
|
|
variant={data.hasConfermaAdmin ? "success" : "secondary"}
|
|
>
|
|
{data.hasConfermaAdmin ? (
|
|
<CircleCheck className="size-6" />
|
|
) : (
|
|
<Wrench className="size-6" />
|
|
)}
|
|
Conferma
|
|
</Button>
|
|
</CredenzaTrigger>
|
|
<CredenzaContent className="max-h-[90vh] w-full px-3 sm:max-w-6xl">
|
|
<CredenzaHeader>
|
|
<CredenzaTitle>Lavorazione conferma</CredenzaTitle>
|
|
<CredenzaDescription className="sr-only">
|
|
Consegna status modal
|
|
</CredenzaDescription>
|
|
</CredenzaHeader>
|
|
<CredenzaBody className="max-h-[80vh] w-full overflow-y-auto pb-5">
|
|
<div className="flex flex-col gap-4">
|
|
<DocSection />
|
|
<Caparra />
|
|
{servizio.tipologia === TipologiaPosizioneEnum.Transitorio && (
|
|
<MotivazioneSection />
|
|
)}
|
|
<SendConferma />
|
|
</div>
|
|
</CredenzaBody>
|
|
|
|
<CredenzaFooter>
|
|
<DebugActions />
|
|
<CredenzaClose asChild>
|
|
<Button aria-label="Close Credenza" variant="outline">
|
|
Chiudi
|
|
</Button>
|
|
</CredenzaClose>
|
|
</CredenzaFooter>
|
|
</CredenzaContent>
|
|
</Credenza>
|
|
);
|
|
};
|
|
|
|
const DebugActions = () => {
|
|
const { servizioId, userId } = useServizio();
|
|
const { annuncioId } = useServizioAnnuncio();
|
|
const utils = api.useUtils();
|
|
const { mutate } = api.servizio.updateServizioAnnunci.useMutation({
|
|
onError: (error) => {
|
|
toast.error(error.message);
|
|
},
|
|
onSuccess: async () => {
|
|
await utils.servizio.getAllServizioAnnunci.invalidate({
|
|
userId: userId,
|
|
});
|
|
await utils.servizio.getServizio.invalidate({
|
|
servizioId,
|
|
});
|
|
|
|
toast.success("Dati salvati con successo");
|
|
},
|
|
});
|
|
|
|
return (
|
|
<Popover>
|
|
<PopoverTrigger asChild>
|
|
<Button>
|
|
<FlaskConical />
|
|
<span>Debug</span>
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent
|
|
align="end"
|
|
className="flex w-fit flex-col items-center gap-4"
|
|
>
|
|
<Confirm
|
|
description="Sei sicuro di voler eliminare l'annuncio?"
|
|
onConfirm={() => {
|
|
mutate({
|
|
annuncioId,
|
|
servizioId,
|
|
data: {
|
|
user_confirmed_at: null,
|
|
},
|
|
});
|
|
}}
|
|
title="Elimina annuncio"
|
|
>
|
|
<Button
|
|
aria-label="Delete Annuncio"
|
|
className="w-full"
|
|
size="sm"
|
|
variant="destructive"
|
|
>
|
|
<Trash2 />
|
|
<span>Elimina Conferma</span>
|
|
</Button>
|
|
</Confirm>
|
|
</PopoverContent>
|
|
</Popover>
|
|
);
|
|
};
|
|
|
|
const DocSection = () => {
|
|
const { userId } = useServizio();
|
|
const { data, updateServizioAnnunci } = useServizioAnnuncio();
|
|
|
|
const utils = api.useUtils();
|
|
// const { mutate: updateServizio } = api.servizio.UpdateConfermaDoc.useMutation(
|
|
// {
|
|
// onError: (error) => {
|
|
// toast.error(error.message);
|
|
// },
|
|
// onSuccess: async () => {
|
|
// await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
|
// await utils.servizio.getServizio.invalidate({
|
|
// servizioId,
|
|
// });
|
|
|
|
// toast.success("Dati salvati con successo");
|
|
// },
|
|
// },
|
|
// );
|
|
|
|
const { data: files, isLoading } = api.storage.getAll.useQuery();
|
|
|
|
const { mutate: setUserStorage } =
|
|
api.storage.addUserStorageEntry.useMutation({
|
|
onSuccess: async () => {
|
|
await utils.storage.retrieveUserFileData.invalidate({
|
|
userId,
|
|
});
|
|
await utils.storage.getAll.invalidate();
|
|
},
|
|
});
|
|
|
|
if (isLoading) return <LoadingPage />;
|
|
if (files === undefined) {
|
|
return <p>Errore nel caricamento dei documenti</p>;
|
|
}
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Documento di Conferma</CardTitle>
|
|
<CardDescription>
|
|
documento che l'utente vedra alla conferma
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
{data.doc_conferma_ref && (
|
|
<div className="flex flex-wrap items-start gap-3">
|
|
<DocInfo storageId={data.doc_conferma_ref}>
|
|
<Button
|
|
aria-label="Reset Conferma"
|
|
className="flex items-center gap-3"
|
|
onClick={async () => {
|
|
await updateServizioAnnunci({
|
|
doc_conferma_added: false,
|
|
doc_conferma_ref: null,
|
|
});
|
|
}}
|
|
variant="destructive"
|
|
>
|
|
<Trash2 />
|
|
</Button>
|
|
</DocInfo>
|
|
</div>
|
|
)}
|
|
<div className="flex flex-wrap items-center gap-3">
|
|
<DocCombo
|
|
current={data.doc_conferma_ref}
|
|
files={files}
|
|
onSelect={async (f) => {
|
|
await updateServizioAnnunci({
|
|
doc_conferma_added: true,
|
|
doc_conferma_ref: f.id,
|
|
});
|
|
|
|
setUserStorage({
|
|
storageId: f.id,
|
|
userId,
|
|
});
|
|
}}
|
|
/>
|
|
<UploadModal isAdmin userId={userId} />
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
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<typeof CaparraSchema>;
|
|
|
|
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;
|
|
}
|
|
console.error("Invalid caparra format:", parsed.error);
|
|
return undefined;
|
|
};
|
|
|
|
const Caparra = () => {
|
|
const { data, updateServizioAnnunci } = useServizioAnnuncio();
|
|
|
|
const [caparra, setCaparra] = useState<CaparraObj | undefined>({
|
|
caparra_causale: data.caparra_causale,
|
|
caparra_iban: data.caparra_iban,
|
|
caparra_importo: data.caparra_importo,
|
|
caparra_intestazione: data.caparra_intestazione,
|
|
});
|
|
const handleSave = async () => {
|
|
await updateServizioAnnunci({
|
|
caparra_causale: caparra?.caparra_causale || null,
|
|
caparra_iban: caparra?.caparra_iban || null,
|
|
caparra_importo: caparra?.caparra_importo || null,
|
|
caparra_intestazione: caparra?.caparra_intestazione || null,
|
|
});
|
|
};
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Dati Pagamento Caparra</CardTitle>
|
|
<CardDescription>
|
|
dati per il pagamento della caparra, da mostrare all'utente
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="flex flex-wrap items-center gap-3">
|
|
<Button
|
|
aria-label="Import Caparra"
|
|
onClick={async () => {
|
|
const clipboardText = await navigator.clipboard.readText();
|
|
|
|
setCaparra(parseCaparra(clipboardText));
|
|
}}
|
|
variant="info"
|
|
>
|
|
<ClipboardPaste className="size-4" />
|
|
Dal gestionale
|
|
</Button>
|
|
<Button
|
|
aria-label="Reset Caparra"
|
|
onClick={async () => {
|
|
setCaparra({
|
|
caparra_causale: null,
|
|
caparra_iban: null,
|
|
caparra_importo: null,
|
|
caparra_intestazione: null,
|
|
});
|
|
}}
|
|
variant="destructive"
|
|
>
|
|
<Trash2 className="size-4" />
|
|
</Button>
|
|
</div>
|
|
{caparra ? (
|
|
<div className="flex flex-col gap-2">
|
|
<p>
|
|
<span className="font-semibold">Intestazione: </span>
|
|
{caparra.caparra_intestazione}{" "}
|
|
<Button
|
|
aria-label="Edit Intestazione"
|
|
className="h-6 px-1.5 [&_svg]:size-4"
|
|
onClick={() => {
|
|
const newValue = prompt(
|
|
"Modifica l'intestazione della caparra:",
|
|
caparra.caparra_intestazione || "",
|
|
);
|
|
if (newValue !== null) {
|
|
setCaparra((prev) =>
|
|
prev
|
|
? { ...prev, caparra_intestazione: newValue }
|
|
: undefined,
|
|
);
|
|
}
|
|
}}
|
|
size="sm"
|
|
>
|
|
<Pen />
|
|
</Button>
|
|
</p>
|
|
<p>
|
|
<span className="font-semibold">IBAN: </span>
|
|
{caparra.caparra_iban}{" "}
|
|
<Button
|
|
aria-label="Edit IBAN"
|
|
className="h-6 px-1.5 [&_svg]:size-4"
|
|
onClick={() => {
|
|
const newValue = prompt(
|
|
"Modifica l'IBAN della caparra:",
|
|
caparra.caparra_iban || "",
|
|
);
|
|
if (newValue !== null) {
|
|
setCaparra((prev) =>
|
|
prev ? { ...prev, caparra_iban: newValue } : undefined,
|
|
);
|
|
}
|
|
}}
|
|
size="sm"
|
|
>
|
|
<Pen />
|
|
</Button>
|
|
</p>
|
|
<p>
|
|
<span className="font-semibold">Importo: </span>
|
|
{caparra.caparra_importo}{" "}
|
|
<Button
|
|
aria-label="Edit Importo"
|
|
className="h-6 px-1.5 [&_svg]:size-4"
|
|
onClick={() => {
|
|
const newValue = prompt(
|
|
"Modifica l'importo della caparra:",
|
|
caparra.caparra_importo || "",
|
|
);
|
|
if (newValue !== null) {
|
|
setCaparra((prev) =>
|
|
prev ? { ...prev, caparra_importo: newValue } : undefined,
|
|
);
|
|
}
|
|
}}
|
|
size="sm"
|
|
>
|
|
<Pen />
|
|
</Button>
|
|
</p>
|
|
<p>
|
|
<span className="font-semibold">Causale: </span>
|
|
{caparra.caparra_causale}{" "}
|
|
<Button
|
|
aria-label="Edit Causale"
|
|
className="h-6 px-1.5 [&_svg]:size-4"
|
|
onClick={() => {
|
|
const newValue = prompt(
|
|
"Modifica la causale della caparra:",
|
|
caparra.caparra_causale || "",
|
|
);
|
|
if (newValue !== null) {
|
|
setCaparra((prev) =>
|
|
prev ? { ...prev, caparra_causale: newValue } : undefined,
|
|
);
|
|
}
|
|
}}
|
|
size="sm"
|
|
>
|
|
<Pen />
|
|
</Button>
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<p>Inserisci la stringa dal gestionale e elabora</p>
|
|
)}
|
|
</CardContent>
|
|
<CardFooter>
|
|
<Button
|
|
aria-label="Save Caparra"
|
|
onClick={async () => {
|
|
await handleSave();
|
|
}}
|
|
variant="success"
|
|
>
|
|
Salva
|
|
</Button>
|
|
</CardFooter>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
const MotivazioneSection = () => {
|
|
const { servizioId } = useServizio();
|
|
const { t } = useTranslation();
|
|
|
|
const { data: servizio } = api.servizio.getServizio.useQuery({ servizioId });
|
|
|
|
if (!servizio) return null;
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Motivazione di transitorietà</CardTitle>
|
|
<CardDescription>
|
|
Informazioni relative alla motivazione di transitorietà inserite
|
|
dall'utente
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="flex flex-col gap-2">
|
|
<p>
|
|
<span className="font-semibold">Motivazione specificata: </span>
|
|
{servizio.motivazione_transitorio ? (
|
|
<span>
|
|
{
|
|
t.preferenze.motivazioni_mappings.find(
|
|
(m) => m.id === servizio.motivazione_transitorio,
|
|
)?.title
|
|
}
|
|
</span>
|
|
) : (
|
|
<span className="text-red-500 italic">Non inserita</span>
|
|
)}
|
|
</p>
|
|
<p>
|
|
<span className="font-semibold">
|
|
Data scadenza motivazione inserita:{" "}
|
|
</span>
|
|
{servizio.scadenza_motivazione_transitoria ? (
|
|
format(servizio.scadenza_motivazione_transitoria, "dd/MM/yyyy")
|
|
) : (
|
|
<span className="text-red-500 italic">Non inserita</span>
|
|
)}
|
|
</p>
|
|
<p>
|
|
<span className="font-semibold">Documento caricato: </span>
|
|
{servizio.doc_motivazione_ref ? (
|
|
<FileLink userStorageId={servizio.doc_motivazione_ref} />
|
|
) : (
|
|
<span className="text-red-500 italic">Non caricato</span>
|
|
)}
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
const FileLink = ({
|
|
userStorageId,
|
|
}: {
|
|
userStorageId: UsersStorageUserStorageId;
|
|
}) => {
|
|
const { data: storageId } =
|
|
api.storage.getStorageIdFromUserStorageId.useQuery({
|
|
userStorageId,
|
|
});
|
|
if (!storageId) return null;
|
|
return (
|
|
<Link
|
|
className="underline hover:text-primary"
|
|
href={`/area-riservata/allegato-view/${storageId}`}
|
|
rel="noreferrer"
|
|
target="_blank"
|
|
>
|
|
Vedi documento
|
|
</Link>
|
|
);
|
|
};
|
|
|
|
const TransitorioSection = () => {
|
|
const { servizio } = useServizio();
|
|
const { data } = useServizioAnnuncio();
|
|
const { t } = useTranslation();
|
|
const { servizioId, userId } = useServizio();
|
|
const utils = api.useUtils();
|
|
const { mutate: update } = api.servizio.updateServizio.useMutation({
|
|
onError: (error) => {
|
|
toast.error(error.message);
|
|
},
|
|
onSuccess: async () => {
|
|
toast.success("Servizio modificato con successo");
|
|
await utils.servizio.getUserServizi.invalidate();
|
|
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
|
},
|
|
});
|
|
|
|
const handlePermanenzaChange = (value: ListOption) => {
|
|
update({
|
|
servizioId,
|
|
data: {
|
|
permanenza: value.value !== "" ? parseInt(value.value) : null,
|
|
},
|
|
});
|
|
};
|
|
const preferenzeDescrizione = data.desc_it?.match(/Permanenza:.*$/m);
|
|
|
|
const permanenzaAnnuncio = data.permanenza
|
|
? `${data.permanenza.join(" - ")} mesi`
|
|
: (preferenzeDescrizione?.[0] ??
|
|
"errore: testo non trovato in descrizione");
|
|
|
|
return (
|
|
<div className="flex flex-col gap-2">
|
|
<div className="max-w-sm">
|
|
<Label className="text-base" htmlFor="permanenza">
|
|
Permanenza (da preferenze servizio):
|
|
</Label>
|
|
|
|
<MultiSelect
|
|
defaultValue={
|
|
servizio.permanenza
|
|
? {
|
|
label: t.preferenze.permanenza[servizio.permanenza] || "",
|
|
value: servizio.permanenza.toString(),
|
|
}
|
|
: undefined
|
|
}
|
|
elementId="permanenza"
|
|
elementName="permanenza"
|
|
isMulti={false}
|
|
onValueChange={handlePermanenzaChange}
|
|
options={UnpackOptions({
|
|
options: t.preferenze.permanenza,
|
|
})}
|
|
placeholder="Seleziona..."
|
|
/>
|
|
</div>
|
|
<p>
|
|
<span className="font-semibold">Permanenza in annuncio: </span>
|
|
{permanenzaAnnuncio}
|
|
</p>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const StabileSection = () => {
|
|
const { servizio, servizioId, userId } = useServizio();
|
|
const { data } = useServizioAnnuncio();
|
|
const [value, setValue] = useState(servizio.budget);
|
|
const utils = api.useUtils();
|
|
const { mutate: update } = api.servizio.updateServizio.useMutation({
|
|
onError: (error) => {
|
|
toast.error(error.message);
|
|
},
|
|
onSuccess: async () => {
|
|
toast.success("Servizio modificato con successo");
|
|
await utils.servizio.getUserServizi.invalidate();
|
|
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
|
},
|
|
});
|
|
|
|
useDebounce(
|
|
() => {
|
|
if (value === servizio.budget) return;
|
|
update({
|
|
servizioId,
|
|
data: {
|
|
budget: value,
|
|
},
|
|
});
|
|
},
|
|
1000,
|
|
[value],
|
|
);
|
|
|
|
return (
|
|
<div className="flex flex-col gap-2">
|
|
<div className="flex max-w-sm flex-col gap-2">
|
|
<span className="font-semibold">Budget (da preferenze servizio):</span>
|
|
<NumberInput
|
|
allowNegative={false}
|
|
defaultValue={value}
|
|
min={0}
|
|
onValueChange={(val) => {
|
|
if (val !== undefined) {
|
|
setValue(val);
|
|
}
|
|
}}
|
|
stepper={50}
|
|
suffix=" €"
|
|
/>
|
|
</div>
|
|
<p>
|
|
<span className="font-semibold">Prezzo in descrizione: </span>
|
|
{formatCurrency(data.prezzo / 100)}
|
|
</p>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const GeneralSection = () => {
|
|
const { servizio } = useServizio();
|
|
const { data } = useServizioAnnuncio();
|
|
const { t } = useTranslation();
|
|
|
|
const { servizioId, userId } = useServizio();
|
|
const utils = api.useUtils();
|
|
const { mutate: update } = api.servizio.updateServizio.useMutation({
|
|
onError: (error) => {
|
|
toast.error(error.message);
|
|
},
|
|
onSuccess: async () => {
|
|
toast.success("Servizio modificato con successo");
|
|
await utils.servizio.getUserServizi.invalidate();
|
|
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
|
},
|
|
});
|
|
|
|
const handleDisponibilitàChange = (value: ListOption) => {
|
|
update({
|
|
servizioId,
|
|
data: {
|
|
entromese: value.value !== "" ? parseInt(value.value) : null,
|
|
},
|
|
});
|
|
};
|
|
|
|
const handleAdultiChange = (value: number) => {
|
|
update({
|
|
servizioId,
|
|
data: {
|
|
n_adulti: value,
|
|
},
|
|
});
|
|
};
|
|
const handleMinoriChange = (value: number) => {
|
|
update({
|
|
servizioId,
|
|
data: {
|
|
n_minori: value,
|
|
},
|
|
});
|
|
};
|
|
|
|
const personeDescrizione = data.desc_it?.match(/Preferenza:.*$/m);
|
|
|
|
const personeAnnuncio = data.persone
|
|
? data.persone.join(", ").toUpperCase()
|
|
: (personeDescrizione?.[0] ?? "errore: testo non trovato in descrizione");
|
|
|
|
const dispAnnuncio = data.disponibile_da
|
|
? format(new Date(data.disponibile_da), "dd/MM/yyyy")
|
|
: handleConsegna({
|
|
consegna: data.consegna,
|
|
aggiornamento: it.card.in_aggiornamento,
|
|
|
|
consegna_da: it.card.consegna_da,
|
|
mesi: it.preferenze.mesi,
|
|
subito: it.card.consegna_subito,
|
|
});
|
|
|
|
return (
|
|
<>
|
|
<div className="flex flex-col gap-2">
|
|
<span className="font-semibold">Persone:</span>
|
|
<div className="flex w-full gap-4">
|
|
<div className="flex w-1/2 flex-col gap-2">
|
|
<Label htmlFor="n_adulti">{t.preferenze.nadulti_label}</Label>
|
|
<Counter
|
|
name="n_adulti"
|
|
onlyPositive
|
|
setValue={(v) => handleAdultiChange(Number(v))}
|
|
value={servizio.n_adulti || 0}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex w-1/2 flex-col gap-2">
|
|
<Label htmlFor="n_minori">{t.preferenze.nminori_label}</Label>
|
|
<Counter
|
|
name="n_minori"
|
|
onlyPositive
|
|
setValue={(v) => handleMinoriChange(Number(v))}
|
|
value={servizio.n_minori || 0}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<p>
|
|
<span className="font-semibold">Persone in annuncio: </span>
|
|
{personeAnnuncio}
|
|
</p>
|
|
</div>
|
|
<div className="flex flex-col gap-2">
|
|
<span className="font-semibold">Entro mese:</span>
|
|
<div className="max-w-sm">
|
|
<Label htmlFor="select-mesi">{t.preferenze.dalmese_label}</Label>
|
|
<MultiSelect
|
|
defaultValue={
|
|
servizio.entromese !== null
|
|
? {
|
|
// biome-ignore lint/style/noNonNullAssertion: <known size>
|
|
label: t.preferenze.mesi[servizio.entromese]!,
|
|
value: String(servizio.entromese),
|
|
}
|
|
: undefined
|
|
}
|
|
elementId="select-mesi"
|
|
elementName="entro_mese"
|
|
isMulti={false}
|
|
onValueChange={handleDisponibilitàChange}
|
|
options={UnpackOptions({
|
|
options: t.preferenze.mesi,
|
|
})}
|
|
placeholder="Seleziona..."
|
|
/>
|
|
</div>
|
|
|
|
<p>
|
|
<span className="font-semibold">Disponibilità in annuncio: </span>
|
|
{dispAnnuncio}
|
|
</p>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
const SendConferma = () => {
|
|
const { servizio } = useServizio();
|
|
const { data } = useServizioAnnuncio();
|
|
const [check, setCheck] = useState(data.hasConfermaAdmin);
|
|
const utils = api.useUtils();
|
|
const { mutate: handleUpdate } =
|
|
api.servizio.adminUpdateConfermaStatus.useMutation({
|
|
onSuccess: async () => {
|
|
await utils.servizio.getAllServizioAnnunci.invalidate();
|
|
await utils.servizio.getServizio.invalidate({
|
|
servizioId: servizio.servizio_id,
|
|
});
|
|
toast.success("Status aggiornato con successo");
|
|
},
|
|
onError: (error) => {
|
|
toast.error(`Errore durante l'aggiornamento: ${error.message}`);
|
|
},
|
|
});
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Lavorazione Conferma</CardTitle>
|
|
<CardDescription>
|
|
controlla i parametri di ricerca prima!
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-10">
|
|
<div className="flex flex-col gap-4">
|
|
<p>
|
|
<span className="font-semibold">Tipologia servizio: </span>
|
|
{servizio.tipologia}
|
|
</p>
|
|
{servizio.tipologia === TipologiaPosizioneEnum.Transitorio ? (
|
|
<TransitorioSection />
|
|
) : (
|
|
<StabileSection />
|
|
)}
|
|
<GeneralSection />
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<Switch
|
|
aria-label="Conferma Lavorata"
|
|
checked={check}
|
|
id="conferma"
|
|
onCheckedChange={(c) => {
|
|
setCheck(c);
|
|
}}
|
|
/>
|
|
<Label className="text-base" htmlFor="conferma">
|
|
Imposta Conferma come Lavorata
|
|
</Label>
|
|
</div>
|
|
</CardContent>
|
|
<CardFooter>
|
|
<Button
|
|
aria-label="Save Conferma Status"
|
|
onClick={() => {
|
|
handleUpdate({
|
|
servizioId: servizio.servizio_id,
|
|
annuncioId: data.id,
|
|
status: check,
|
|
});
|
|
}}
|
|
variant="success"
|
|
>
|
|
Salva
|
|
</Button>
|
|
</CardFooter>
|
|
</Card>
|
|
);
|
|
};
|