2025-08-07 14:50:40 +02:00
|
|
|
import { z } from "zod/v4";
|
2025-08-04 17:45:44 +02:00
|
|
|
import {
|
|
|
|
|
Form,
|
|
|
|
|
FormControl,
|
|
|
|
|
FormField,
|
|
|
|
|
FormItem,
|
|
|
|
|
FormLabel,
|
|
|
|
|
FormMessage,
|
|
|
|
|
} from "~/components/custom_ui/form";
|
|
|
|
|
import { useZodForm } from "~/lib/zodForm";
|
|
|
|
|
import Input from "~/components/custom_ui/input";
|
|
|
|
|
import { Button } from "~/components/ui/button";
|
|
|
|
|
import { MultiSelect, UnpackOptions } from "~/components/custom_ui/multiselect";
|
|
|
|
|
import type {
|
|
|
|
|
Prezziario,
|
|
|
|
|
PrezziarioIdprezziario,
|
|
|
|
|
} from "~/schemas/public/Prezziario";
|
|
|
|
|
import { api } from "~/utils/api";
|
|
|
|
|
import { Switch } from "~/components/ui/switch";
|
|
|
|
|
import { Textarea } from "~/components/custom_ui/textarea";
|
|
|
|
|
import {
|
|
|
|
|
Select,
|
|
|
|
|
SelectContent,
|
|
|
|
|
SelectItem,
|
|
|
|
|
SelectTrigger,
|
|
|
|
|
SelectValue,
|
|
|
|
|
} from "~/components/ui/select";
|
|
|
|
|
import { useEffect } from "react";
|
|
|
|
|
|
|
|
|
|
type FormPrezzoProps = {
|
|
|
|
|
initialValues: Prezziario | null;
|
|
|
|
|
submitMutation: (values: Omit<Prezziario, "nome" | "descrizione">) => void;
|
|
|
|
|
};
|
|
|
|
|
export const FormPrezzo = ({
|
|
|
|
|
initialValues,
|
|
|
|
|
submitMutation,
|
|
|
|
|
}: FormPrezzoProps) => {
|
|
|
|
|
const { data: stringhe_condizioni } =
|
|
|
|
|
api.settings.getStringheCondizioni.useQuery();
|
|
|
|
|
|
|
|
|
|
const stringhe_condizioni_options = [
|
|
|
|
|
"",
|
|
|
|
|
...(stringhe_condizioni
|
|
|
|
|
? stringhe_condizioni.map((v) => String(v.stinga_id))
|
|
|
|
|
: []),
|
|
|
|
|
];
|
|
|
|
|
const PrezzoSchema = z
|
|
|
|
|
.object({
|
|
|
|
|
idprezziario: z.custom<PrezziarioIdprezziario>(),
|
2025-08-22 16:23:00 +02:00
|
|
|
prezzo_cent: z.number().min(0),
|
2025-08-04 17:45:44 +02:00
|
|
|
testo_condizioni: z.string().nullable(),
|
|
|
|
|
isAcconto: z.boolean(),
|
|
|
|
|
isSaldo: z.boolean(),
|
|
|
|
|
isConsulenza: z.boolean(),
|
|
|
|
|
isActive: z.boolean(),
|
|
|
|
|
nome_it: z.string(),
|
|
|
|
|
desc_it: z.string(),
|
|
|
|
|
nome_en: z.string(),
|
|
|
|
|
desc_en: z.string(),
|
|
|
|
|
sconto: z.number().min(0).max(100),
|
|
|
|
|
isTransitorio: z.boolean(),
|
|
|
|
|
isStabile: z.boolean(),
|
|
|
|
|
})
|
2025-08-07 14:50:40 +02:00
|
|
|
.superRefine(({ testo_condizioni }, ctx) => {
|
2025-08-04 17:45:44 +02:00
|
|
|
if (testo_condizioni) {
|
|
|
|
|
if (
|
|
|
|
|
stringhe_condizioni_options.length > 0 &&
|
|
|
|
|
!stringhe_condizioni_options.includes(testo_condizioni)
|
|
|
|
|
) {
|
|
|
|
|
console.log("testo_condizioni", testo_condizioni);
|
|
|
|
|
console.log(
|
|
|
|
|
"stringhe_condizioni_options",
|
|
|
|
|
stringhe_condizioni_options,
|
|
|
|
|
);
|
2025-08-07 14:50:40 +02:00
|
|
|
|
|
|
|
|
ctx.addIssue({
|
|
|
|
|
code: "custom",
|
2025-08-04 17:45:44 +02:00
|
|
|
message: "Testo condizioni non valido",
|
2025-08-07 14:50:40 +02:00
|
|
|
input: testo_condizioni,
|
2025-08-04 17:45:44 +02:00
|
|
|
path: ["testo_condizioni"],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
type PrezzoFormValues = z.infer<typeof PrezzoSchema>;
|
|
|
|
|
|
|
|
|
|
// This can come from your database or API.
|
|
|
|
|
const defaultValues: PrezzoFormValues = initialValues || {
|
|
|
|
|
idprezziario: "" as PrezziarioIdprezziario,
|
|
|
|
|
prezzo_cent: 0,
|
|
|
|
|
testo_condizioni: "",
|
|
|
|
|
isAcconto: false,
|
|
|
|
|
isSaldo: false,
|
|
|
|
|
isConsulenza: false,
|
|
|
|
|
isActive: false,
|
|
|
|
|
nome_it: "",
|
|
|
|
|
desc_it: "",
|
|
|
|
|
nome_en: "",
|
|
|
|
|
desc_en: "",
|
|
|
|
|
sconto: 0,
|
|
|
|
|
isTransitorio: false,
|
|
|
|
|
isStabile: false,
|
|
|
|
|
};
|
|
|
|
|
|
2025-08-07 14:50:40 +02:00
|
|
|
z.config(z.locales.it());
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-07 14:50:40 +02:00
|
|
|
const form = useZodForm(PrezzoSchema, {
|
2025-08-04 17:45:44 +02:00
|
|
|
defaultValues: defaultValues,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function onSubmit(fields: PrezzoFormValues) {
|
|
|
|
|
submitMutation({
|
|
|
|
|
...fields,
|
|
|
|
|
testo_condizioni: fields.testo_condizioni || null,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { watch } = form;
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const subscription = watch((value, { name, type }) =>
|
|
|
|
|
console.log(value, name, type),
|
|
|
|
|
);
|
|
|
|
|
return () => subscription.unsubscribe();
|
|
|
|
|
}, [watch]);
|
|
|
|
|
|
|
|
|
|
const scontoWch = watch(["sconto", "prezzo_cent"]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<Form {...form}>
|
|
|
|
|
<form
|
|
|
|
|
onSubmit={form.handleSubmit(onSubmit)}
|
2025-08-22 15:55:43 +02:00
|
|
|
className="space-y-4 px-0.5"
|
2025-08-04 17:45:44 +02:00
|
|
|
>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="idprezziario"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="idprezziario">Codice</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Input
|
|
|
|
|
placeholder=""
|
|
|
|
|
{...field}
|
|
|
|
|
id="idprezziario"
|
|
|
|
|
disabled={initialValues != null}
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="nome_it"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="nome_it">Nome IT</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Input placeholder="" {...field} id="nome_it" />
|
|
|
|
|
</FormControl>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="desc_it"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel
|
|
|
|
|
className="text-base font-medium"
|
|
|
|
|
htmlFor="desc_it"
|
|
|
|
|
>
|
|
|
|
|
Descrizione IT
|
|
|
|
|
</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Textarea className="min-h-[150px]" {...field} id="desc_it" />
|
|
|
|
|
</FormControl>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="nome_en"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="nome_en">Nome EN</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Input placeholder="" {...field} id="nome_en" />
|
|
|
|
|
</FormControl>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="desc_en"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel
|
|
|
|
|
className="text-base font-medium"
|
|
|
|
|
htmlFor="desc_en"
|
|
|
|
|
>
|
|
|
|
|
Descrizione EN
|
|
|
|
|
</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Textarea className="min-h-[150px]" {...field} id="desc_en" />
|
|
|
|
|
</FormControl>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="prezzo_cent"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="prezzo">Prezzo</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Input
|
|
|
|
|
{...field}
|
|
|
|
|
type="number"
|
|
|
|
|
id="prezzo"
|
2025-08-07 14:50:40 +02:00
|
|
|
value={Number(field.value) / 100}
|
2025-08-04 17:45:44 +02:00
|
|
|
onChange={(v) => {
|
2025-08-22 15:55:43 +02:00
|
|
|
field.onChange(parseInt(v.target.value) * 100);
|
2025-08-04 17:45:44 +02:00
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="isAcconto"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="isAcconto">Acconto</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Switch
|
|
|
|
|
checked={field.value}
|
|
|
|
|
onCheckedChange={field.onChange}
|
|
|
|
|
id="isAcconto"
|
|
|
|
|
className="data-[state=checked]:bg-neutral-700"
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="isSaldo"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="isSaldo">Saldo</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Switch
|
|
|
|
|
checked={field.value}
|
|
|
|
|
onCheckedChange={field.onChange}
|
|
|
|
|
id="isSaldo"
|
|
|
|
|
className="data-[state=checked]:bg-neutral-700"
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="isConsulenza"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="isConsulenza">Consulenza</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Switch
|
|
|
|
|
checked={field.value}
|
|
|
|
|
onCheckedChange={field.onChange}
|
|
|
|
|
id="isConsulenza"
|
|
|
|
|
className="data-[state=checked]:bg-neutral-700"
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="isTransitorio"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="isTransitorio">Transitorio</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Switch
|
|
|
|
|
checked={field.value}
|
|
|
|
|
onCheckedChange={field.onChange}
|
|
|
|
|
id="isTransitorio"
|
|
|
|
|
className="data-[state=checked]:bg-neutral-700"
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="isStabile"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="isStabile">Stabile</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Switch
|
|
|
|
|
checked={field.value}
|
|
|
|
|
onCheckedChange={field.onChange}
|
|
|
|
|
id="isStabile"
|
|
|
|
|
className="data-[state=checked]:bg-neutral-700"
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="testo_condizioni"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel
|
|
|
|
|
className="text-base font-medium"
|
|
|
|
|
htmlFor="select-testo-condizioni"
|
|
|
|
|
>
|
|
|
|
|
ID Testo Condizioni
|
|
|
|
|
</FormLabel>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<MultiSelect
|
|
|
|
|
elementId="select-testo-condizioni"
|
|
|
|
|
elementName="testo_condizioni"
|
|
|
|
|
isMulti={false}
|
|
|
|
|
placeholder="Seleziona..."
|
|
|
|
|
options={UnpackOptions({
|
|
|
|
|
options: stringhe_condizioni_options,
|
|
|
|
|
})}
|
|
|
|
|
defaultValue={
|
|
|
|
|
field.value
|
|
|
|
|
? { value: field.value, label: field.value }
|
|
|
|
|
: {
|
|
|
|
|
value: "",
|
|
|
|
|
label: "",
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
onValueChange={async (value) => {
|
|
|
|
|
if (value.value == "") {
|
|
|
|
|
field.onChange(undefined);
|
|
|
|
|
} else {
|
|
|
|
|
field.onChange(
|
|
|
|
|
stringhe_condizioni_options[
|
|
|
|
|
Number.parseInt(value.value)
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await form.trigger("testo_condizioni");
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="isActive"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="isActive">Attivo</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Switch
|
|
|
|
|
checked={field.value}
|
|
|
|
|
onCheckedChange={field.onChange}
|
|
|
|
|
id="isActive"
|
|
|
|
|
className="data-[state=checked]:bg-neutral-700"
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="sconto"
|
|
|
|
|
render={({ field }) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-x-2">
|
|
|
|
|
<FormLabel htmlFor="sconto">Sconto</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<Select
|
|
|
|
|
name="sconto"
|
|
|
|
|
defaultValue={String(field.value)}
|
|
|
|
|
onValueChange={(value) => {
|
|
|
|
|
field.onChange(Number.parseInt(value));
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<SelectTrigger className="w-[180px]">
|
|
|
|
|
<SelectValue placeholder="Sconto" />
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
<SelectContent>
|
|
|
|
|
{[
|
|
|
|
|
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65,
|
|
|
|
|
70, 75, 80, 85, 90, 95, 100,
|
|
|
|
|
].map((v) => {
|
|
|
|
|
return (
|
|
|
|
|
<SelectItem key={v} value={String(v)}>
|
|
|
|
|
{v}%
|
|
|
|
|
</SelectItem>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</SelectContent>
|
|
|
|
|
</Select>
|
|
|
|
|
</FormControl>
|
|
|
|
|
<FormMessage />
|
|
|
|
|
</div>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
{scontoWch && scontoWch[0] !== 0 && (
|
|
|
|
|
<span className="text-sm text-gray-500">
|
|
|
|
|
Prezzo scontato:{" "}
|
|
|
|
|
{(((1 - scontoWch[0] / 100) * scontoWch[1]) / 100).toFixed(2)}€
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-row gap-4">
|
|
|
|
|
<Button type="submit">
|
|
|
|
|
{initialValues ? "Aggiorna" : "Crea Prezzo"}
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
</Form>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
};
|