2025-10-30 19:39:35 +01:00
|
|
|
import { format } from "date-fns";
|
|
|
|
|
import { it } from "date-fns/locale";
|
2026-03-30 14:58:24 +02:00
|
|
|
import { CalendarIcon, Check, SlidersHorizontal } from "lucide-react";
|
2026-03-24 17:01:40 +01:00
|
|
|
import { useState } from "react";
|
|
|
|
|
import toast from "react-hot-toast";
|
2025-08-07 14:50:40 +02:00
|
|
|
import { z } from "zod/v4";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { Counter } from "~/components/counter";
|
2026-03-24 17:01:40 +01:00
|
|
|
import {
|
|
|
|
|
Credenza,
|
|
|
|
|
CredenzaBody,
|
|
|
|
|
CredenzaContent,
|
|
|
|
|
CredenzaDescription,
|
|
|
|
|
CredenzaHeader,
|
|
|
|
|
CredenzaTitle,
|
|
|
|
|
CredenzaTrigger,
|
|
|
|
|
} from "~/components/custom_ui/credenza";
|
2025-08-04 17:45:44 +02:00
|
|
|
import {
|
2025-08-28 18:27:07 +02:00
|
|
|
Form,
|
|
|
|
|
FormControl,
|
|
|
|
|
FormDescription,
|
|
|
|
|
FormField,
|
|
|
|
|
FormItem,
|
|
|
|
|
FormLabel,
|
|
|
|
|
FormMessage,
|
2025-08-04 17:45:44 +02:00
|
|
|
} from "~/components/custom_ui/form";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { MultiSelect, UnpackOptions } from "~/components/custom_ui/multiselect";
|
|
|
|
|
import { Badge } from "~/components/ui/badge";
|
2025-08-04 17:45:44 +02:00
|
|
|
import { Button } from "~/components/ui/button";
|
2025-10-30 19:39:35 +01:00
|
|
|
import { Calendar } from "~/components/ui/calendar";
|
2026-03-24 17:01:40 +01:00
|
|
|
import {
|
|
|
|
|
Dialog,
|
|
|
|
|
DialogContent,
|
|
|
|
|
DialogDescription,
|
|
|
|
|
DialogHeader,
|
|
|
|
|
DialogTitle,
|
|
|
|
|
DialogTrigger,
|
|
|
|
|
} from "~/components/ui/dialog";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { Label } from "~/components/ui/label";
|
2025-10-30 19:39:35 +01:00
|
|
|
import {
|
|
|
|
|
Popover,
|
|
|
|
|
PopoverContent,
|
|
|
|
|
PopoverTrigger,
|
|
|
|
|
} from "~/components/ui/popover";
|
2025-08-04 17:45:44 +02:00
|
|
|
import { Slider } from "~/components/ui/slider";
|
|
|
|
|
import { Switch } from "~/components/ui/switch";
|
2026-03-24 17:01:40 +01:00
|
|
|
import { FieldResetButton } from "~/forms/comps";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { cn } from "~/lib/utils";
|
|
|
|
|
import { useZodForm } from "~/lib/zodForm";
|
|
|
|
|
import { useTranslation } from "~/providers/I18nProvider";
|
2026-03-24 17:01:40 +01:00
|
|
|
import { useServizio } from "~/providers/ServizioProvider";
|
2025-08-04 17:45:44 +02:00
|
|
|
import type { Servizio } from "~/schemas/public/Servizio";
|
2025-08-28 18:27:07 +02:00
|
|
|
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
|
2026-03-24 17:01:40 +01:00
|
|
|
import type { UsersId } from "~/schemas/public/Users";
|
|
|
|
|
import { api } from "~/utils/api";
|
|
|
|
|
import { DEFAULT_SERVIZIO_INTERRUZIONE_DURATION_DAYS } from "~/utils/config";
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-07 14:50:40 +02:00
|
|
|
const Schema = z
|
2025-08-28 18:27:07 +02:00
|
|
|
.object({
|
2025-08-29 16:18:32 +02:00
|
|
|
animali: z.boolean(),
|
|
|
|
|
arredato: z.boolean(),
|
|
|
|
|
ascensore: z.boolean(),
|
2025-08-28 18:27:07 +02:00
|
|
|
budget: z.number(),
|
|
|
|
|
entromese: z.number().nullable(),
|
2025-08-29 16:18:32 +02:00
|
|
|
fumatori: z.boolean(),
|
|
|
|
|
giardino: z.boolean(),
|
|
|
|
|
motivazione_transitorio: z.string().nullable(),
|
2025-08-28 18:27:07 +02:00
|
|
|
n_adulti: z.number().min(1),
|
|
|
|
|
n_minori: z.number(),
|
2025-08-29 16:18:32 +02:00
|
|
|
parcheggio: z.boolean(),
|
2025-08-28 18:27:07 +02:00
|
|
|
permanenza: z.number().nullable(),
|
2025-08-29 16:18:32 +02:00
|
|
|
pianoterra: z.boolean(),
|
2025-08-28 18:27:07 +02:00
|
|
|
reddito: z.string().nullable(),
|
|
|
|
|
terrazzo: z.boolean(),
|
2025-08-29 16:18:32 +02:00
|
|
|
tipologia: z.custom<TipologiaPosizioneEnum>(),
|
2025-10-30 19:39:35 +01:00
|
|
|
scadenza_motivazione_transitoria: z.date().nullable(),
|
|
|
|
|
skipPayment: z.boolean(),
|
|
|
|
|
skipControlloDoc: z.boolean(),
|
|
|
|
|
skipDocMotivazione: z.boolean(),
|
2026-03-24 17:01:40 +01:00
|
|
|
interruzioneDays: z.number().min(0),
|
|
|
|
|
acceptedInterr: z.boolean(),
|
2025-08-28 18:27:07 +02:00
|
|
|
})
|
|
|
|
|
.superRefine(({ n_adulti }, refinementContext) => {
|
|
|
|
|
if (n_adulti <= 0) {
|
|
|
|
|
refinementContext.issues.push({
|
|
|
|
|
code: "custom",
|
2025-08-29 16:18:32 +02:00
|
|
|
input: "",
|
2025-08-28 18:27:07 +02:00
|
|
|
message: "Inserisci il numero di persone",
|
|
|
|
|
path: ["npersone"],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2026-03-24 17:01:40 +01:00
|
|
|
type FormValues = z.infer<typeof Schema>;
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2026-03-24 17:01:40 +01:00
|
|
|
const FormServizio = ({
|
2025-08-28 18:27:07 +02:00
|
|
|
initialData,
|
|
|
|
|
onSubmit,
|
|
|
|
|
isLimited,
|
2026-03-30 14:58:24 +02:00
|
|
|
setOpen,
|
2025-08-04 17:45:44 +02:00
|
|
|
}: {
|
2025-08-28 18:27:07 +02:00
|
|
|
initialData: Servizio | undefined;
|
|
|
|
|
onSubmit: (fields: FormValues) => void;
|
|
|
|
|
isLimited: boolean;
|
2026-03-30 14:58:24 +02:00
|
|
|
setOpen?: (open: boolean) => void;
|
2025-08-04 17:45:44 +02:00
|
|
|
}) => {
|
2025-08-28 18:27:07 +02:00
|
|
|
// This can come from your database or API.
|
|
|
|
|
let defaultValues: FormValues;
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
if (initialData) {
|
|
|
|
|
defaultValues = {
|
|
|
|
|
...initialData,
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
defaultValues = {
|
2025-08-29 16:18:32 +02:00
|
|
|
animali: false,
|
|
|
|
|
arredato: false,
|
|
|
|
|
ascensore: false,
|
2025-08-28 18:27:07 +02:00
|
|
|
budget: 0,
|
|
|
|
|
entromese: null,
|
2025-08-29 16:18:32 +02:00
|
|
|
fumatori: false,
|
|
|
|
|
giardino: false,
|
|
|
|
|
motivazione_transitorio: "",
|
2025-08-28 18:27:07 +02:00
|
|
|
n_adulti: 1,
|
|
|
|
|
n_minori: 0,
|
2025-08-29 16:18:32 +02:00
|
|
|
parcheggio: false,
|
2025-08-28 18:27:07 +02:00
|
|
|
permanenza: null,
|
2025-08-29 16:18:32 +02:00
|
|
|
pianoterra: false,
|
2025-08-28 18:27:07 +02:00
|
|
|
reddito: "",
|
|
|
|
|
terrazzo: false,
|
2025-08-29 16:18:32 +02:00
|
|
|
tipologia: TipologiaPosizioneEnum.Transitorio,
|
2025-10-30 19:39:35 +01:00
|
|
|
scadenza_motivazione_transitoria: null,
|
|
|
|
|
skipPayment: false,
|
2025-12-30 15:27:24 +01:00
|
|
|
skipControlloDoc: true,
|
|
|
|
|
skipDocMotivazione: true,
|
2026-03-24 17:01:40 +01:00
|
|
|
interruzioneDays: DEFAULT_SERVIZIO_INTERRUZIONE_DURATION_DAYS, // default value for interruzioneDays
|
|
|
|
|
acceptedInterr: false,
|
2025-08-28 18:27:07 +02:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
const { locale, t } = useTranslation();
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
z.config(z.locales[locale]());
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const form = useZodForm(Schema, {
|
|
|
|
|
defaultValues: defaultValues,
|
|
|
|
|
});
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
type altrePrefMappingType = [
|
|
|
|
|
["animali", string],
|
|
|
|
|
["fumatori", string],
|
|
|
|
|
["giardino", string],
|
|
|
|
|
["parcheggio", string],
|
|
|
|
|
["terrazzo", string],
|
|
|
|
|
["ascensore", string],
|
|
|
|
|
["pianoterra", string],
|
|
|
|
|
];
|
2025-12-18 12:11:08 +01:00
|
|
|
const altrePrefMapping = t.altriParamsMapping as altrePrefMappingType;
|
2025-08-28 18:27:07 +02:00
|
|
|
const tipologia = form.watch("tipologia");
|
|
|
|
|
return (
|
|
|
|
|
<Form {...form}>
|
2025-08-29 16:18:32 +02:00
|
|
|
<form className="space-y-8 px-0.5" onSubmit={form.handleSubmit(onSubmit)}>
|
2025-08-28 18:27:07 +02:00
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="tipologia"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="select-tipologia">Tipologia</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
{isLimited ? (
|
|
|
|
|
<div className="space-y-0">
|
2025-10-10 16:18:43 +02:00
|
|
|
<p className="font-semibold text-lg">{field.value}</p>
|
2025-08-28 18:27:07 +02:00
|
|
|
<p className="text-muted-foreground text-sm">
|
|
|
|
|
La tipologia non può essere modificata. Contatta il supporto
|
|
|
|
|
se necessario.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<MultiSelect
|
|
|
|
|
defaultValue={
|
|
|
|
|
field.value === TipologiaPosizioneEnum.Transitorio
|
|
|
|
|
? {
|
|
|
|
|
label: "Transitorio",
|
2025-08-29 16:18:32 +02:00
|
|
|
value: TipologiaPosizioneEnum.Transitorio,
|
2025-08-28 18:27:07 +02:00
|
|
|
}
|
|
|
|
|
: {
|
|
|
|
|
label: "Stabile",
|
2025-08-29 16:18:32 +02:00
|
|
|
value: TipologiaPosizioneEnum.Stabile,
|
2025-08-28 18:27:07 +02:00
|
|
|
}
|
|
|
|
|
}
|
2025-08-29 16:18:32 +02:00
|
|
|
elementId="select-tipologia"
|
|
|
|
|
elementName="tipologia"
|
|
|
|
|
isMulti={false}
|
|
|
|
|
onValueChange={(value) => {
|
|
|
|
|
field.onChange(value.value);
|
|
|
|
|
form.setValue("motivazione_transitorio", null);
|
|
|
|
|
form.setValue("reddito", null);
|
|
|
|
|
}}
|
2025-08-28 18:27:07 +02:00
|
|
|
options={[
|
|
|
|
|
{
|
|
|
|
|
label: "Transitorio",
|
2025-08-29 16:18:32 +02:00
|
|
|
value: TipologiaPosizioneEnum.Transitorio,
|
2025-08-28 18:27:07 +02:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "Stabile",
|
2025-08-29 16:18:32 +02:00
|
|
|
value: TipologiaPosizioneEnum.Stabile,
|
2025-08-28 18:27:07 +02:00
|
|
|
},
|
|
|
|
|
]}
|
2025-08-29 16:18:32 +02:00
|
|
|
placeholder={t.seleziona_placeholder}
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="budget"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2 pb-1">
|
|
|
|
|
<FormLabel htmlFor="budgetslider">
|
2025-12-18 12:11:08 +01:00
|
|
|
{`${t.parametri.budget_label1} - ${field.value.toLocaleString("it")},00 ${
|
|
|
|
|
t.parametri.budget_label2
|
2025-08-28 18:27:07 +02:00
|
|
|
}`}
|
|
|
|
|
</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Slider
|
|
|
|
|
defaultValue={[field.value]}
|
2026-03-20 17:03:35 +01:00
|
|
|
disabled={isLimited}
|
2025-08-29 16:18:32 +02:00
|
|
|
id="budgetslider"
|
|
|
|
|
max={2000}
|
|
|
|
|
min={0}
|
2025-08-28 18:27:07 +02:00
|
|
|
onValueChange={(vals) => {
|
|
|
|
|
field.onChange(Number(vals[0]));
|
|
|
|
|
}}
|
2025-08-29 16:18:32 +02:00
|
|
|
step={50}
|
2025-08-28 18:27:07 +02:00
|
|
|
value={[form.getValues("budget")]}
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
2026-03-20 17:03:35 +01:00
|
|
|
{!isLimited && (
|
|
|
|
|
<FormDescription>{t.parametri.budget_desc}</FormDescription>
|
|
|
|
|
)}
|
2025-08-28 18:27:07 +02:00
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
2026-03-30 14:58:24 +02:00
|
|
|
<div className="grid w-full grid-cols-1 items-start gap-4 sm:grid-cols-2">
|
2025-08-28 18:27:07 +02:00
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="entromese"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem className="w-full">
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="select-mesi">
|
2025-12-18 12:11:08 +01:00
|
|
|
{t.parametri.dalmese_label}...
|
2025-08-28 18:27:07 +02:00
|
|
|
</FormLabel>
|
|
|
|
|
{field.value !== null && !initialData && (
|
2026-01-16 17:11:53 +01:00
|
|
|
<FieldResetButton
|
2025-08-28 18:27:07 +02:00
|
|
|
onClick={() => form.setValue("entromese", null)}
|
2026-01-16 17:11:53 +01:00
|
|
|
/>
|
2025-08-28 18:27:07 +02:00
|
|
|
)}
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<MultiSelect
|
|
|
|
|
defaultValue={
|
|
|
|
|
field.value !== null
|
|
|
|
|
? {
|
|
|
|
|
// biome-ignore lint/style/noNonNullAssertion: <known size>
|
2025-12-18 12:11:08 +01:00
|
|
|
label: t.parametri.mesi[field.value]!,
|
2025-08-29 16:18:32 +02:00
|
|
|
value: String(field.value),
|
2025-08-28 18:27:07 +02:00
|
|
|
}
|
|
|
|
|
: undefined
|
|
|
|
|
}
|
2026-03-20 17:03:35 +01:00
|
|
|
disabled={isLimited}
|
2025-08-29 16:18:32 +02:00
|
|
|
elementId="select-mesi"
|
|
|
|
|
elementName="entro_mese"
|
|
|
|
|
isMulti={false}
|
2026-01-16 17:11:53 +01:00
|
|
|
key={field.value}
|
2025-08-28 18:27:07 +02:00
|
|
|
onValueChange={(value) => {
|
|
|
|
|
field.onChange(
|
|
|
|
|
value.value !== "" ? parseInt(value.value) : null,
|
|
|
|
|
);
|
|
|
|
|
}}
|
2025-08-29 16:18:32 +02:00
|
|
|
options={UnpackOptions({
|
2025-12-18 12:11:08 +01:00
|
|
|
options: t.parametri.mesi,
|
2025-08-29 16:18:32 +02:00
|
|
|
})}
|
2025-08-28 18:27:07 +02:00
|
|
|
placeholder="Seleziona..."
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
disabled={tipologia !== TipologiaPosizioneEnum.Transitorio}
|
2025-08-29 16:18:32 +02:00
|
|
|
name="permanenza"
|
2025-08-28 18:27:07 +02:00
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem className="w-full">
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
2026-01-16 17:11:53 +01:00
|
|
|
<FormLabel
|
|
|
|
|
className={cn(
|
|
|
|
|
tipologia !== TipologiaPosizioneEnum.Transitorio &&
|
|
|
|
|
"opacity-50",
|
|
|
|
|
)}
|
|
|
|
|
htmlFor="permanenza"
|
|
|
|
|
>
|
2025-12-18 12:11:08 +01:00
|
|
|
{t.parametri.permanenza_label}
|
2025-08-28 18:27:07 +02:00
|
|
|
</FormLabel>
|
|
|
|
|
{field.value !== null && !initialData && (
|
2026-01-16 17:11:53 +01:00
|
|
|
<FieldResetButton
|
2025-08-28 18:27:07 +02:00
|
|
|
onClick={() => form.setValue("permanenza", null)}
|
2026-01-16 17:11:53 +01:00
|
|
|
/>
|
2025-08-28 18:27:07 +02:00
|
|
|
)}
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<FormControl>
|
|
|
|
|
<MultiSelect
|
|
|
|
|
defaultValue={
|
2026-03-12 16:26:01 +01:00
|
|
|
field.value !== null
|
2025-08-28 18:27:07 +02:00
|
|
|
? {
|
2025-12-18 12:11:08 +01:00
|
|
|
label: t.parametri.permanenza[field.value] || "",
|
2025-08-29 16:18:32 +02:00
|
|
|
value: field.value.toString(),
|
2025-08-28 18:27:07 +02:00
|
|
|
}
|
|
|
|
|
: undefined
|
|
|
|
|
}
|
2026-03-20 17:03:35 +01:00
|
|
|
disabled={
|
|
|
|
|
isLimited ||
|
|
|
|
|
tipologia !== TipologiaPosizioneEnum.Transitorio
|
|
|
|
|
}
|
2025-08-29 16:18:32 +02:00
|
|
|
elementId="permanenza"
|
|
|
|
|
elementName="permanenza"
|
|
|
|
|
isMulti={false}
|
2026-01-16 17:11:53 +01:00
|
|
|
key={field.value}
|
2025-08-28 18:27:07 +02:00
|
|
|
onValueChange={(value) => {
|
|
|
|
|
field.onChange(
|
|
|
|
|
value.value !== "" ? parseInt(value.value) : null,
|
|
|
|
|
);
|
|
|
|
|
}}
|
2025-08-29 16:18:32 +02:00
|
|
|
options={UnpackOptions({
|
2025-12-18 12:11:08 +01:00
|
|
|
options: t.parametri.permanenza,
|
2025-08-29 16:18:32 +02:00
|
|
|
})}
|
2025-08-28 18:27:07 +02:00
|
|
|
placeholder="Seleziona..."
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
2026-03-20 17:03:35 +01:00
|
|
|
{tipologia === TipologiaPosizioneEnum.Transitorio &&
|
|
|
|
|
!isLimited && (
|
|
|
|
|
<FormDescription>
|
|
|
|
|
{t.parametri.permanenza_desc}
|
|
|
|
|
</FormDescription>
|
|
|
|
|
)}
|
2025-08-28 18:27:07 +02:00
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex w-full items-center justify-between gap-x-4">
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="n_adulti"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem className={cn("w-full")}>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel
|
2025-10-10 16:18:43 +02:00
|
|
|
className={cn("font-semibold text-base")}
|
2025-08-28 18:27:07 +02:00
|
|
|
htmlFor="n_adulti"
|
|
|
|
|
>
|
2025-12-18 12:11:08 +01:00
|
|
|
{t.parametri.nadulti_label}
|
2025-08-28 18:27:07 +02:00
|
|
|
</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Counter
|
2026-03-20 17:03:35 +01:00
|
|
|
disabled={isLimited}
|
2025-08-28 18:27:07 +02:00
|
|
|
name="n_adulti"
|
|
|
|
|
onlyPositive
|
2025-08-29 16:18:32 +02:00
|
|
|
setValue={(value) => field.onChange(Number(value))}
|
|
|
|
|
value={Number(field.value)}
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="n_minori"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem className={cn("w-full")}>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel
|
2025-10-10 16:18:43 +02:00
|
|
|
className={cn("font-semibold text-base")}
|
2025-08-28 18:27:07 +02:00
|
|
|
htmlFor="n_minori"
|
|
|
|
|
>
|
2025-12-18 12:11:08 +01:00
|
|
|
{t.parametri.nminori_label}
|
2025-08-28 18:27:07 +02:00
|
|
|
</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Counter
|
2026-03-20 17:03:35 +01:00
|
|
|
disabled={isLimited}
|
2025-08-28 18:27:07 +02:00
|
|
|
name="n_minori"
|
|
|
|
|
onlyPositive
|
2025-08-29 16:18:32 +02:00
|
|
|
setValue={(value) => field.onChange(Number(value))}
|
|
|
|
|
value={Number(field.value)}
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="arredato"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem className="w-full">
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="arredato">
|
2025-12-18 12:11:08 +01:00
|
|
|
{t.parametri.arredato_label}
|
2025-08-28 18:27:07 +02:00
|
|
|
</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Switch
|
|
|
|
|
className="data-[state=checked]:bg-neutral-700"
|
2026-02-24 10:40:07 +01:00
|
|
|
defaultChecked={field.value}
|
2026-03-20 17:03:35 +01:00
|
|
|
disabled={isLimited}
|
2025-08-29 16:18:32 +02:00
|
|
|
id="arredato"
|
|
|
|
|
onCheckedChange={field.onChange}
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-12-18 12:11:08 +01:00
|
|
|
<FormDescription>{t.parametri.arredato_desc}</FormDescription>
|
2025-08-28 18:27:07 +02:00
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
{tipologia === TipologiaPosizioneEnum.Transitorio ? (
|
2025-10-30 19:39:35 +01:00
|
|
|
<div className="items-top flex w-full flex-col justify-between gap-4 sm:flex-row">
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
key={tipologia}
|
|
|
|
|
name="motivazione_transitorio"
|
|
|
|
|
render={({ field }) => {
|
2025-12-18 12:11:08 +01:00
|
|
|
const existingValue = t.parametri.motivazioni_mappings.find(
|
2025-10-30 19:39:35 +01:00
|
|
|
(m) => m.id === field.value,
|
|
|
|
|
);
|
|
|
|
|
return (
|
|
|
|
|
<FormItem className="w-full">
|
|
|
|
|
<div className="flex w-full flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="motivazione_transitorio">
|
2025-12-18 12:11:08 +01:00
|
|
|
{t.parametri.motivazione_label}
|
2025-10-30 19:39:35 +01:00
|
|
|
</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
{isLimited ? (
|
|
|
|
|
<div className="space-y-0">
|
|
|
|
|
<p className="font-semibold text-lg">
|
|
|
|
|
{existingValue?.title}
|
|
|
|
|
</p>
|
|
|
|
|
<p className="text-muted-foreground text-sm">
|
|
|
|
|
La motivazione non può essere modificata. Contatta il
|
|
|
|
|
supporto se necessario.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<MultiSelect
|
|
|
|
|
defaultValue={
|
|
|
|
|
existingValue
|
|
|
|
|
? {
|
|
|
|
|
label: existingValue.title,
|
|
|
|
|
value: existingValue.id,
|
|
|
|
|
}
|
|
|
|
|
: undefined
|
|
|
|
|
}
|
|
|
|
|
elementId="select-motivazione_transitorio"
|
|
|
|
|
elementName="motivazione_transitorio"
|
|
|
|
|
isMulti={false}
|
|
|
|
|
onValueChange={(value) => {
|
|
|
|
|
field.onChange(value.value);
|
|
|
|
|
}}
|
2025-12-18 12:11:08 +01:00
|
|
|
options={t.parametri.motivazioni_mappings.map(
|
2025-10-30 19:39:35 +01:00
|
|
|
(option) => ({
|
|
|
|
|
label: option.title,
|
|
|
|
|
value: option.id,
|
|
|
|
|
}),
|
|
|
|
|
)}
|
|
|
|
|
placeholder={t.seleziona_placeholder}
|
|
|
|
|
/>
|
|
|
|
|
<FormDescription>
|
2025-12-18 12:11:08 +01:00
|
|
|
{t.parametri.motivazione_desc}
|
2025-10-30 19:39:35 +01:00
|
|
|
</FormDescription>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</FormItem>
|
|
|
|
|
);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="scadenza_motivazione_transitoria"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem className="flex w-full flex-col">
|
2025-08-28 18:27:07 +02:00
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
2025-10-30 19:39:35 +01:00
|
|
|
<FormLabel htmlFor="scadenza_motivazione_transitoria">
|
|
|
|
|
Scadenza motivazione
|
2025-08-28 18:27:07 +02:00
|
|
|
</FormLabel>
|
2025-12-01 12:33:32 +01:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
2025-11-04 19:18:13 +01:00
|
|
|
{isLimited ? (
|
|
|
|
|
<div className="space-y-0">
|
|
|
|
|
<p className="font-semibold text-lg">
|
|
|
|
|
{field.value
|
|
|
|
|
? format(field.value, "dd/MM/yyyy")
|
|
|
|
|
: "Errore data invalida"}
|
|
|
|
|
</p>
|
|
|
|
|
<p className="text-muted-foreground text-sm">
|
|
|
|
|
La scadenza non può essere modificata. Contatta il
|
|
|
|
|
supporto se necessario.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<Popover>
|
|
|
|
|
<PopoverTrigger asChild>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Button
|
|
|
|
|
className={cn(
|
2026-03-12 12:11:41 +01:00
|
|
|
"h-10 w-full bg-card pl-3 text-left font-medium",
|
2025-11-04 19:18:13 +01:00
|
|
|
!field.value && "text-muted-foreground",
|
2025-11-14 17:21:21 +01:00
|
|
|
"rounded-lg border border-neutral-300 shadow-xs outline-hidden file:border-0 file:bg-transparent file:font-medium file:text-sm disabled:cursor-not-allowed disabled:opacity-50 dark:focus:border-transparent",
|
2025-11-04 19:18:13 +01:00
|
|
|
)}
|
|
|
|
|
id="scadenza_motivazione_transitoria"
|
|
|
|
|
variant={"outline"}
|
|
|
|
|
>
|
|
|
|
|
{field.value ? (
|
|
|
|
|
format(field.value, "PPP", {
|
|
|
|
|
locale: it,
|
|
|
|
|
})
|
|
|
|
|
) : (
|
|
|
|
|
<span>{t.anagrafica.scegli_data}</span>
|
|
|
|
|
)}
|
|
|
|
|
<CalendarIcon className="ml-auto size-4 opacity-50" />
|
|
|
|
|
</Button>
|
|
|
|
|
</FormControl>
|
|
|
|
|
</PopoverTrigger>
|
2026-03-17 18:44:53 +01:00
|
|
|
<PopoverContent align="end" className="w-auto p-0">
|
2025-11-04 19:18:13 +01:00
|
|
|
<Calendar
|
|
|
|
|
autoFocus
|
|
|
|
|
captionLayout="dropdown"
|
|
|
|
|
defaultMonth={field.value || new Date()}
|
|
|
|
|
endMonth={new Date(2050, 12)}
|
|
|
|
|
locale={it}
|
|
|
|
|
mode="single"
|
|
|
|
|
onSelect={field.onChange}
|
|
|
|
|
selected={field.value || undefined}
|
|
|
|
|
/>
|
|
|
|
|
</PopoverContent>
|
|
|
|
|
</Popover>
|
|
|
|
|
)}
|
2025-12-01 12:33:32 +01:00
|
|
|
<FormDescription>
|
|
|
|
|
es. scadenza contratto di lavoro, fine corso di studi, ecc.
|
|
|
|
|
</FormDescription>
|
2025-08-28 18:27:07 +02:00
|
|
|
</FormItem>
|
2025-10-30 19:39:35 +01:00
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2025-08-28 18:27:07 +02:00
|
|
|
) : (
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
2025-08-29 16:18:32 +02:00
|
|
|
key={tipologia}
|
2025-08-28 18:27:07 +02:00
|
|
|
name="reddito"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="select-reddito">
|
2025-12-18 12:11:08 +01:00
|
|
|
{t.parametri.reddito_label}
|
2025-08-28 18:27:07 +02:00
|
|
|
</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<MultiSelect
|
2025-08-29 16:18:32 +02:00
|
|
|
defaultValue={undefined}
|
2026-03-20 17:03:35 +01:00
|
|
|
disabled={isLimited}
|
2025-08-28 18:27:07 +02:00
|
|
|
elementId="select-reddito"
|
|
|
|
|
elementName="reddito"
|
|
|
|
|
isMulti={false}
|
|
|
|
|
onValueChange={(value) => {
|
|
|
|
|
field.onChange(value.value);
|
|
|
|
|
}}
|
2025-08-29 16:18:32 +02:00
|
|
|
options={UnpackOptions({
|
2025-12-18 12:11:08 +01:00
|
|
|
options: t.parametri.reddito_options,
|
2025-08-29 16:18:32 +02:00
|
|
|
})}
|
|
|
|
|
placeholder={t.seleziona_placeholder}
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<div className="flex flex-col space-y-2">
|
|
|
|
|
<Label htmlFor="altrePrefDialogButton">
|
2025-12-18 12:11:08 +01:00
|
|
|
{t.parametri.altriparams_label}
|
2025-08-28 18:27:07 +02:00
|
|
|
</Label>
|
2026-03-20 17:03:35 +01:00
|
|
|
{!isLimited && (
|
|
|
|
|
<FormDescription>{t.parametri.altriparams_desc}</FormDescription>
|
|
|
|
|
)}
|
2025-08-28 18:27:07 +02:00
|
|
|
<div className="mt-2 flex flex-wrap gap-2">
|
2025-10-28 11:55:01 +01:00
|
|
|
{altrePrefMapping.map((pair) => {
|
2025-08-28 18:27:07 +02:00
|
|
|
if (pair) {
|
|
|
|
|
return (
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
2025-10-28 11:55:01 +01:00
|
|
|
key={pair[0]}
|
2025-08-28 18:27:07 +02:00
|
|
|
name={pair[0]}
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Badge
|
2026-03-20 17:03:35 +01:00
|
|
|
className={cn(
|
|
|
|
|
"text-sm",
|
|
|
|
|
isLimited ? "cursor-default" : "cursor-pointer",
|
|
|
|
|
)}
|
2025-08-29 16:18:32 +02:00
|
|
|
onClick={() => {
|
2026-03-20 17:03:35 +01:00
|
|
|
if (isLimited) return;
|
2025-08-29 16:18:32 +02:00
|
|
|
field.onChange(!field.value);
|
|
|
|
|
}}
|
2026-03-30 14:58:24 +02:00
|
|
|
variant={field.value ? "default" : "outline"}
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
2026-03-30 14:58:24 +02:00
|
|
|
{field.value && <Check />}
|
2025-08-28 18:27:07 +02:00
|
|
|
{pair[1]}
|
|
|
|
|
</Badge>
|
|
|
|
|
</FormControl>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-03-24 17:01:40 +01:00
|
|
|
|
2026-03-20 17:03:35 +01:00
|
|
|
{/*
|
2025-10-30 19:39:35 +01:00
|
|
|
<Separator />
|
2026-03-20 17:03:35 +01:00
|
|
|
{!isLimited && (
|
2025-11-11 15:22:21 +01:00
|
|
|
<div className="flex w-full flex-col items-start justify-between gap-4 sm:flex-row">
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="skipPayment"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem className="w-full">
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="skipPayment">Salta Pagamento</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Switch
|
|
|
|
|
className="data-[state=checked]:bg-neutral-700"
|
2026-02-24 10:40:07 +01:00
|
|
|
defaultChecked={field.value}
|
2025-11-11 15:22:21 +01:00
|
|
|
id="skipPayment"
|
|
|
|
|
onCheckedChange={field.onChange}
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormDescription>
|
|
|
|
|
Salta la richiesta di pagamento al cliente (per tutti i
|
|
|
|
|
pagamenti)
|
|
|
|
|
</FormDescription>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="skipControlloDoc"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem className="w-full">
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="skipControlloDoc">
|
|
|
|
|
Salta controllo documento
|
|
|
|
|
</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Switch
|
|
|
|
|
className="data-[state=checked]:bg-neutral-700"
|
2026-02-24 10:40:07 +01:00
|
|
|
defaultChecked={field.value}
|
2025-11-11 15:22:21 +01:00
|
|
|
id="skipControlloDoc"
|
|
|
|
|
onCheckedChange={field.onChange}
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormDescription>
|
|
|
|
|
Salta la richiesta del documento del cliente al momento
|
|
|
|
|
dello sblocco contatti
|
|
|
|
|
</FormDescription>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="skipDocMotivazione"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem className="w-full">
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="skipDocMotivazione">
|
|
|
|
|
Salta documento motivazione
|
|
|
|
|
</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Switch
|
|
|
|
|
className="data-[state=checked]:bg-neutral-700"
|
2026-02-24 10:40:07 +01:00
|
|
|
defaultChecked={field.value}
|
2025-11-11 15:22:21 +01:00
|
|
|
id="skipDocMotivazione"
|
|
|
|
|
onCheckedChange={field.onChange}
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
2025-10-30 19:39:35 +01:00
|
|
|
|
2025-11-11 15:22:21 +01:00
|
|
|
<FormDescription>
|
|
|
|
|
Salta l'invio del documento di motivazione al cliente
|
|
|
|
|
al momento della conferma annuncio
|
|
|
|
|
</FormDescription>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2026-03-20 17:03:35 +01:00
|
|
|
)} */}
|
2026-03-30 14:58:24 +02:00
|
|
|
<div className="flex w-full justify-end gap-2">
|
|
|
|
|
{!isLimited && (
|
|
|
|
|
<Button type="submit" variant="success">
|
|
|
|
|
Salva
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
disabled={isLimited || form.formState.isDirty}
|
|
|
|
|
onClick={() => setOpen?.(false)}
|
|
|
|
|
type="button"
|
|
|
|
|
variant="outline"
|
|
|
|
|
>
|
|
|
|
|
Chiudi
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
2025-08-28 18:27:07 +02:00
|
|
|
</form>
|
|
|
|
|
</Form>
|
|
|
|
|
);
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
2026-03-24 17:01:40 +01:00
|
|
|
export const NewServizioModal = ({ userId }: { userId: UsersId }) => {
|
|
|
|
|
const [open, setOpen] = useState(false);
|
|
|
|
|
const utils = api.useUtils();
|
|
|
|
|
|
|
|
|
|
const { mutate: add } = api.servizio.addServizio.useMutation({
|
|
|
|
|
onError: (error) => {
|
|
|
|
|
toast.error(error.message);
|
|
|
|
|
},
|
|
|
|
|
onSuccess: async () => {
|
|
|
|
|
toast.success("Servizio creato con successo");
|
|
|
|
|
await utils.servizio.invalidate();
|
|
|
|
|
|
|
|
|
|
setOpen(false);
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function onSubmit(fields: FormValues) {
|
|
|
|
|
add({ data: { ...fields, user_id: userId } });
|
|
|
|
|
}
|
|
|
|
|
return (
|
|
|
|
|
<Dialog onOpenChange={setOpen} open={open}>
|
|
|
|
|
<DialogTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setOpen(true);
|
|
|
|
|
}}
|
|
|
|
|
variant="outline"
|
|
|
|
|
>
|
|
|
|
|
Nuovo Servizio
|
|
|
|
|
</Button>
|
|
|
|
|
</DialogTrigger>
|
|
|
|
|
<DialogContent className="max-h-[80%] w-full overflow-auto p-4 sm:max-w-5xl">
|
|
|
|
|
<DialogHeader>
|
|
|
|
|
<DialogTitle>Creazione Servizio</DialogTitle>
|
|
|
|
|
<DialogDescription className="sr-only">desc</DialogDescription>
|
|
|
|
|
</DialogHeader>
|
|
|
|
|
<div className="overflow-y-auto">
|
|
|
|
|
<FormServizio
|
|
|
|
|
initialData={undefined}
|
|
|
|
|
isLimited={false}
|
|
|
|
|
onSubmit={onSubmit}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</DialogContent>
|
|
|
|
|
</Dialog>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const EditServizioModal = () => {
|
|
|
|
|
const { servizioId, isAdmin, servizio } = useServizio();
|
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
const [openEditParametri, setOpenEditParametri] = useState(false);
|
|
|
|
|
|
|
|
|
|
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.invalidate();
|
|
|
|
|
|
|
|
|
|
setOpenEditParametri(false);
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function onSubmit(fields: FormValues) {
|
|
|
|
|
update({
|
|
|
|
|
data: {
|
|
|
|
|
...fields,
|
|
|
|
|
},
|
|
|
|
|
servizioId,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Credenza onOpenChange={setOpenEditParametri} open={openEditParametri}>
|
|
|
|
|
<CredenzaTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
aria-label="Parametri di ricerca"
|
|
|
|
|
className="w-full"
|
|
|
|
|
disabled={
|
|
|
|
|
!isAdmin &&
|
|
|
|
|
(servizio.isInterrotto ||
|
|
|
|
|
servizio.annunci.some((a) => a.hasConfermaAdmin))
|
|
|
|
|
}
|
|
|
|
|
variant="secondary"
|
|
|
|
|
>
|
|
|
|
|
<SlidersHorizontal />
|
|
|
|
|
{t.servizio.parametri.btn}
|
|
|
|
|
</Button>
|
|
|
|
|
</CredenzaTrigger>
|
2026-03-30 14:58:24 +02:00
|
|
|
<CredenzaContent
|
|
|
|
|
className="max-h-[90vh] w-full **:data-[slot=dialog-close]:hidden sm:max-w-5xl"
|
|
|
|
|
onInteractOutside={(e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
}}
|
|
|
|
|
>
|
2026-03-24 17:01:40 +01:00
|
|
|
<CredenzaHeader>
|
|
|
|
|
<CredenzaTitle>{t.servizio.parametri.title}</CredenzaTitle>
|
|
|
|
|
<CredenzaDescription className="sr-only">
|
|
|
|
|
{t.servizio.parametri.title}
|
|
|
|
|
</CredenzaDescription>
|
|
|
|
|
</CredenzaHeader>
|
2026-03-30 14:58:24 +02:00
|
|
|
<CredenzaBody className="w-full max-w-3xl overflow-y-auto pb-5 sm:max-w-5xl">
|
2026-03-24 17:01:40 +01:00
|
|
|
<FormServizio
|
|
|
|
|
initialData={servizio}
|
|
|
|
|
isLimited={!isAdmin}
|
|
|
|
|
onSubmit={onSubmit}
|
2026-03-30 14:58:24 +02:00
|
|
|
setOpen={setOpenEditParametri}
|
2026-03-24 17:01:40 +01:00
|
|
|
/>
|
|
|
|
|
</CredenzaBody>
|
|
|
|
|
</CredenzaContent>
|
|
|
|
|
</Credenza>
|
|
|
|
|
);
|
|
|
|
|
};
|