feat: add EditServizioAdmin component and integrate into ServizioActions

This commit is contained in:
Marco Pedone 2025-08-23 17:13:43 +02:00
parent 47ff703be8
commit 4982d064e3
2 changed files with 343 additions and 2 deletions

View file

@ -25,7 +25,7 @@ import {
AlertDialogTitle, AlertDialogTitle,
AlertDialogTrigger, AlertDialogTrigger,
} from "~/components/ui/alert-dialog"; } from "~/components/ui/alert-dialog";
import { Calculator, ClockAlert, Plus } from "lucide-react"; import { Calculator, ClockAlert, Plus, Wrench } from "lucide-react";
import { FormNewServizio, type FormValues } from "~/forms/FormNewServizio"; import { FormNewServizio, type FormValues } from "~/forms/FormNewServizio";
import { import {
Credenza, Credenza,
@ -41,6 +41,10 @@ import { useState } from "react";
import { useServizio } from "~/providers/ServizioProvider"; import { useServizio } from "~/providers/ServizioProvider";
import type { ServizioServizioId } from "~/schemas/public/Servizio"; import type { ServizioServizioId } from "~/schemas/public/Servizio";
import type { UsersId } from "~/schemas/public/Users"; import type { UsersId } from "~/schemas/public/Users";
import {
FormEditServizio,
type FormValues as EditFormValues,
} from "~/forms/FormEditServizioAdmin";
export const ServizioActions = () => { export const ServizioActions = () => {
const { servizio, isAdmin, userId } = useServizio(); const { servizio, isAdmin, userId } = useServizio();
@ -62,7 +66,10 @@ export const ServizioActions = () => {
</> </>
)} )}
{isAdmin && ( {isAdmin && (
<>
<AddAnnuncio servizioId={servizio.servizio_id} userId={userId} /> <AddAnnuncio servizioId={servizio.servizio_id} userId={userId} />
<EditServizioAdmin />
</>
)} )}
</div> </div>
); );
@ -306,3 +313,63 @@ const EditPreferenze = () => {
</Credenza> </Credenza>
); );
}; };
const EditServizioAdmin = () => {
const { servizioId, userId } = useServizio();
const [open, setOpen] = useState(false);
const { data, isLoading } = api.servizio.getServizio.useQuery({ servizioId });
const utils = api.useUtils();
const { mutate: update } = api.servizio.updateServizio.useMutation({
onSuccess: async () => {
toast.success("Servizio modificato con successo");
await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
await utils.servizio.getServizio.invalidate({ servizioId });
await utils.servizio.getCompatibileAnnunci.invalidate({
servizioId,
});
setOpen(false);
},
onError: (error) => {
toast.error(error.message);
},
});
function onSubmit(fields: EditFormValues) {
update({
servizioId,
data: {
...fields,
},
});
}
return (
<Credenza open={open} onOpenChange={setOpen}>
<CredenzaTrigger asChild>
<Button
aria-label="Modifica Servizio Admin"
className="items-center gap-2"
>
<Wrench />
Admin
</Button>
</CredenzaTrigger>
<CredenzaContent className="max-h-[90vh] w-full sm:max-w-5xl">
<CredenzaHeader>
<CredenzaTitle>Modifica Servizio Admin</CredenzaTitle>
<CredenzaDescription className="sr-only">
Modifica
</CredenzaDescription>
</CredenzaHeader>
<CredenzaBody className="max-h-[80vh] w-full overflow-y-auto pb-5">
{isLoading ? (
<LoadingPage />
) : (
<FormEditServizio initialData={data} onSubmit={onSubmit} />
)}
</CredenzaBody>
</CredenzaContent>
</Credenza>
);
};

View file

@ -0,0 +1,274 @@
import { z } from "zod/v4";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "~/components/custom_ui/form";
import { useZodForm } from "~/lib/zodForm";
import { Button } from "~/components/ui/button";
import { useTranslation } from "~/providers/I18nProvider";
import { cn } from "~/lib/utils";
import { Switch } from "~/components/ui/switch";
import type { Servizio } from "~/schemas/public/Servizio";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "~/components/ui/popover";
import { format } from "date-fns";
import { CalendarIcon, X } from "lucide-react";
import { Calendar } from "~/components/ui/calendar";
import { enUS, it } from "date-fns/locale";
import { Label } from "~/components/ui/label";
const Schema = z.object({
isSent: z.boolean(),
decorrenza: z.date().nullable(),
isInterrotto: z.boolean(),
isOkAcconto: z.boolean(),
isOkSaldo: z.boolean(),
isOkConsulenza: z.boolean(),
});
export type FormValues = z.infer<typeof Schema>;
export const FormEditServizio = ({
initialData,
onSubmit,
}: {
initialData: Servizio | undefined;
onSubmit: (fields: FormValues) => void;
}) => {
// This can come from your database or API.
let defaultValues: FormValues;
if (initialData) {
defaultValues = {
...initialData,
};
} else {
defaultValues = {
isSent: false,
decorrenza: null,
isInterrotto: false,
isOkAcconto: false,
isOkSaldo: false,
isOkConsulenza: false,
};
}
const { locale, t } = useTranslation();
z.config(z.locales[locale]());
const form = useZodForm(Schema, {
defaultValues: defaultValues,
});
const DatePickerLocale = locale === "it" ? it : enUS;
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 px-0.5">
<div className="flex w-full flex-col items-start justify-between gap-4 sm:flex-row">
<FormField
control={form.control}
name="isSent"
render={({ field }) => (
<FormItem className="w-full">
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="isSent">Inviato</FormLabel>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
id="isSent"
className="data-[state=checked]:bg-neutral-700"
/>
</FormControl>
<FormMessage />
</div>
<FormDescription>
La mail di benvenuto al cliente è stata inviata
</FormDescription>
</FormItem>
)}
/>
<FormField
control={form.control}
name="isInterrotto"
render={({ field }) => (
<FormItem className="w-full">
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="isInterrotto">Interrotto</FormLabel>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
id="isInterrotto"
className="data-[state=checked]:bg-neutral-700"
/>
</FormControl>
<FormMessage />
</div>
<FormDescription>Il servizio è interrotto</FormDescription>
</FormItem>
)}
/>
</div>
<div className="flex w-full flex-col items-start justify-between gap-4 sm:flex-row">
<FormField
control={form.control}
name="decorrenza"
render={({ field }) => (
<FormItem className="flex w-full flex-col">
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="decorrenza">
Decorrenza Servizio
</FormLabel>
<FormMessage />
</div>
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
variant={"outline"}
id="decorrenza"
className={cn(
"h-[42px] w-full pl-3 text-left font-medium",
!field.value && "text-muted-foreground",
`text-primary dark:bg-primary rounded-lg border border-neutral-300 bg-white shadow-xs outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium hover:border-neutral-400 focus:border-neutral-400 disabled:cursor-not-allowed disabled:opacity-50 aria-expanded:border-neutral-400 dark:border-neutral-500 dark:text-white dark:placeholder:text-neutral-400 dark:hover:border-neutral-400 dark:focus:border-transparent dark:aria-expanded:border-neutral-400`,
)}
>
{field.value ? (
format(field.value, "PPP", {
locale: DatePickerLocale,
})
) : (
<span>{t.anagrafica.scegli_data}</span>
)}
<CalendarIcon className="ml-auto size-4 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
locale={DatePickerLocale}
endMonth={new Date()}
mode="single"
defaultMonth={field.value || new Date()}
captionLayout="dropdown"
selected={field.value || undefined}
onSelect={field.onChange}
disabled={(date) =>
date > new Date() || date < new Date("1900-01-01")
}
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
/>
</PopoverContent>
</Popover>
</FormItem>
)}
/>
<div className="flex flex-col items-start gap-2">
<Label htmlFor="reset_decorrenza">Reset Decorrenza</Label>
<Button
type="button"
variant="destructive"
id="reset_decorrenza"
onClick={() => form.setValue("decorrenza", null)}
className="flex items-center gap-2"
>
<X className="size-5" />
Reset Decorrenza
</Button>
</div>
</div>
<div className="flex w-full flex-col items-start justify-between gap-4 sm:flex-row">
<FormField
control={form.control}
name="isOkAcconto"
render={({ field }) => (
<FormItem className="w-full">
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="isOkAcconto">Acconto Pagato</FormLabel>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
id="isOkAcconto"
className="data-[state=checked]:bg-neutral-700"
/>
</FormControl>
<FormMessage />
</div>
<FormDescription>
I&apos;acconto è stato pagato o attivato manualmente
</FormDescription>
</FormItem>
)}
/>
<FormField
control={form.control}
name="isOkSaldo"
render={({ field }) => (
<FormItem className="w-full">
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="isOkSaldo">Saldo Pagato</FormLabel>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
id="isOkSaldo"
className="data-[state=checked]:bg-neutral-700"
/>
</FormControl>
<FormMessage />
</div>
<FormDescription>
Il saldo è stato pagato o attivato manualmente
</FormDescription>
</FormItem>
)}
/>
<FormField
control={form.control}
name="isOkConsulenza"
render={({ field }) => (
<FormItem className="w-full">
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="isOkConsulenza">
Consulenza Pagata
</FormLabel>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
id="isOkConsulenza"
className="data-[state=checked]:bg-neutral-700"
/>
</FormControl>
<FormMessage />
</div>
<FormDescription>
La consulenza è stata pagata o attivata manualmente
</FormDescription>
</FormItem>
)}
/>
</div>
<Button type="submit">Salva</Button>
</form>
</Form>
);
};