infoalloggi-monorepo/apps/infoalloggi/src/forms/FormEditAnnuncio.tsx

1854 lines
54 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { format } from "date-fns";
import { it } from "date-fns/locale";
import {
CalendarIcon,
CodeSquare,
Eye,
Printer,
RefreshCcw,
RotateCw,
TriangleAlert,
} from "lucide-react";
import Link from "next/link";
import toast from "react-hot-toast";
import z from "zod";
import { CarouselAnnuncio } from "~/components/annuncio_card";
import { Confirm } from "~/components/confirm";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "~/components/custom_ui/form";
import { NumberInput } from "~/components/custom_ui/InputNumber";
import Input from "~/components/custom_ui/input";
import { DualInputLayout } from "~/components/custom_ui/inputLayouts";
import {
type ListOption,
MultiSelect,
} from "~/components/custom_ui/multiselect";
import { Textarea } from "~/components/custom_ui/textarea";
import { PhoneInput } from "~/components/phone-input";
import { Button } from "~/components/ui/button";
import { Calendar } from "~/components/ui/calendar";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "~/components/ui/popover";
import { Switch } from "~/components/ui/switch";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";
import { filteredCaratteristiche } from "~/hooks/schedaAnnuncioUtils";
import { NullableStringOnChange } from "~/lib/form_utils";
import { cn } from "~/lib/utils";
import { useZodForm } from "~/lib/zodForm";
import { StatusBadge } from "~/pages/area-riservata/admin/edit-annuncio/[id]";
import { useTranslation } from "~/providers/I18nProvider";
import type { AnnunciWithMedia } from "~/server/controllers/annunci.controller";
import { zAnnuncioId } from "~/server/utils/zod_types";
import { api } from "~/utils/api";
import type { Caratteristiche } from "~/utils/kanel-types";
export const AnnuncioEditForm = ({ data }: { data: AnnunciWithMedia }) => {
const schema = z.object({
accessori: z.string().array().nullable(),
// ALTRI DATI IMMOBILE
anno: z.string().nullable(),
cap: z.string().nullable(),
caratteristiche: z.custom<Caratteristiche>().nullable(),
categorie: z.string().array().nullable(),
civico: z.string().nullable(),
civico_secondario: z.string().nullable(),
classe: z.string().nullable(),
codice: z.string(),
comune: z.string().nullable(),
consegna: z.number().nullable(),
desc_en: z.string().nullable(),
desc_it: z.string().nullable(),
disponibile_da: z.date().nullable(),
email: z.email().nullable(),
homepage: z.boolean().nullable(),
//BASE
id: zAnnuncioId,
// DATI IMMOBILE
indirizzo: z.string().nullable(),
indirizzo_secondario: z.string().nullable(),
lat: z.string().nullable(),
lat_secondario: z.string().nullable(),
// DATI LOCATORE
locatore: z.string().nullable(),
lon: z.string().nullable(),
lon_secondario: z.string().nullable(),
mq: z.number().nullable(),
numero: z.string().nullable(),
numero_bagni: z.number().nullable(),
numero_balconi: z.number().nullable(),
numero_box: z.number().nullable(),
numero_camere: z.number().nullable(),
numero_postiauto: z.number().nullable(),
numero_terrazzi: z.number().nullable(),
numero_vani: z.number().nullable(),
permanenza: z.number().array().nullable(),
persone: z.string().array().nullable(),
piano: z.string().nullable(),
piano_palazzo: z.number().nullable(),
prezzo: z.number(),
provincia: z.string().nullable(),
regione: z.string().nullable(),
stato: z.string().nullable(),
// DATI CONTRATTO
tipo: z.string().nullable(),
titolo_en: z.string().nullable(),
titolo_it: z.string().nullable(),
unita_condominio: z.number().nullable(),
web: z.boolean().nullable(),
// MEDIA
//url_immagini: z.string().array().nullable(),
//url_video: z.string().array().nullable(),
//og_url: z.string().nullable(),
//creato_il: z.date().nullable(),
//modificato_il: z.date().nullable(),
});
type FormValues = z.infer<typeof schema>;
const { locale } = useTranslation();
const utils = api.useUtils();
const { mutate: edit } = api.annunci.editAnnuncio.useMutation({
onSettled: async () => {
await utils.annunci.getAnnuncio.invalidate({ cod: data.codice });
await utils.annunci.getAnnuncioById_rawImgUrls.invalidate({
id: data.id,
});
await utils.annunci.getAnnunciList.invalidate();
toast.success("Annuncio modificato con successo");
},
});
const { mutateAsync: revalidate } =
api.revalidation.revalidateAnnuncio.useMutation({
onSettled: async () => {
await utils.annunci.getAnnuncio.invalidate({ cod: data.codice });
await utils.annunci.getAnnuncioById_rawImgUrls.invalidate({
id: data.id,
});
toast.success("Revalidazione completata");
},
});
const { mutateAsync: update } = api.revalidation.updateAnnuncio.useMutation({
onSettled: async () => {
await utils.annunci.getAnnuncio.invalidate({ cod: data.codice });
await utils.annunci.getAnnuncioById_rawImgUrls.invalidate({
id: data.id,
});
toast.success(
"L'aggiornamento dell'annuncio è stata richiesta con successo,\n potrebbero volerci alcuni minuti prima che le modifiche siano visibili.",
{
duration: 5000,
},
);
},
});
const defaultValues: FormValues = {
...data,
mq: Number(data.mq) || null,
};
z.config(z.locales[locale]());
const form = useZodForm(schema, {
defaultValues: defaultValues,
});
function onSubmit(fields: FormValues) {
edit({
annuncioId: data.id,
data: fields,
});
}
const personeOptions: ListOption[] = [
"single",
"coppia",
"colleghi",
"famiglia",
].map((p) => ({
label: p,
value: p,
}));
const permanenzaOptions: ListOption[] = [
{ label: "1 mese", value: "1" },
{ label: "3 mesi", value: "3" },
{ label: "6 mesi", value: "6" },
{ label: "9 mesi", value: "9" },
{ label: "12 mesi", value: "12" },
{ label: "18 mesi", value: "18" },
{ label: "24 mesi", value: "24" },
];
const tipoOptions: ListOption[] = [
"Transitorio",
"Stabile",
"Vendita",
"Cessione",
"Errore",
].map((o) => ({ label: o, value: o }));
const statoOptions = ["Attivo", "Sospeso", "Trattativa"].map((o) => ({
label: o,
value: o,
}));
const consegnaOptions: ListOption[] = [
{ label: "Gennaio", value: "1" },
{ label: "Febbraio", value: "2" },
{ label: "Marzo", value: "3" },
{ label: "Aprile", value: "4" },
{ label: "Maggio", value: "5" },
{ label: "Giugno", value: "6" },
{ label: "Luglio", value: "7" },
{ label: "Agosto", value: "8" },
{ label: "Settembre", value: "9" },
{ label: "Ottobre", value: "10" },
{ label: "Novembre", value: "11" },
{ label: "Dicembre", value: "12" },
];
return (
<>
<Form {...form}>
<form
className="mt-3 grid flex-1 items-start gap-4 p-2 sm:px-4 sm:py-0 md:gap-8"
onSubmit={form.handleSubmit(onSubmit)}
>
<div className="mx-auto grid w-full flex-1 auto-rows-max gap-4">
<div className="flex flex-col gap-2">
<div className="flex flex-wrap items-center gap-2">
<h1 className="whitespace-nowrap font-semibold text-2xl tracking-tight">
Annuncio {data.codice}
</h1>
<StatusBadge status={data.stato} />
<span>{data.media_updated_at?.toLocaleString("it-IT")}</span>
<div className="ml-auto flex items-center gap-2">
<Button className="bg-green-500" size="sm" type="submit">
Salva
</Button>
</div>
</div>
<div className="flex flex-wrap items-center gap-2">
<Link href={`/annuncio/${data.codice}`} target="_blank">
<Button size="sm" type="button" variant="outline">
<Eye /> pubblica
</Button>
</Link>
<Link
href={`/area-riservata/admin/scheda-annuncio-stampa/${data.id}`}
target="_blank"
>
<Button size="sm" type="button" variant="outline">
<Printer /> Scheda
</Button>
</Link>
<Popover>
<PopoverTrigger asChild>
<Button size="sm" type="button">
<CodeSquare /> Strumenti
</Button>
</PopoverTrigger>
<PopoverContent className="flex w-fit items-center gap-2">
<Button
className="bg-purple-500"
onClick={async () => {
await revalidate({
cod: data.codice,
});
}}
size="sm"
type="button"
>
<RefreshCcw /> Rigenera pagina
</Button>
<Confirm
description="Sei sicuro di voler richiedere l'aggiornamento dell'annuncio? Questa operazione potrebbe richiedere alcuni minuti prima che le modifiche siano visibili e resetterà eventuali modifiche effettuate dopo la sincronizzazione giornaliera."
onConfirm={async () => {
await update({ cod: data.codice });
}}
title="Aggiornamento Annuncio"
>
<Button size="sm" type="button" variant="warning">
<TriangleAlert /> Aggiorna
</Button>
</Confirm>
</PopoverContent>
</Popover>
</div>
</div>
<div className="grid h-max gap-3 md:grid-cols-[1fr_250px] lg:grid-cols-3">
<div className="h-full items-start gap-3 lg:col-span-2">
<Card className="h-full py-4">
<CardContent className="h-full w-full grow px-4">
<Tabs defaultValue="ita">
<TabsList className="grid h-full w-full grid-cols-2">
<TabsTrigger value="ita">Italiano</TabsTrigger>
<TabsTrigger value="eng">Inglese</TabsTrigger>
</TabsList>
<TabsContent value="ita">
<Card>
<CardHeader>
<CardTitle>Descrizione ITA</CardTitle>
</CardHeader>
<CardContent>
<div className="grid gap-6">
<div className="grid gap-3">
<FormField
control={form.control}
name="titolo_it"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="titolo_it">
Titolo ITA
</FormLabel>
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="titolo_it"
onChange={(e) =>
NullableStringOnChange(
e,
field.onChange,
)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
</div>
<div className="grid gap-3">
<FormField
control={form.control}
name="desc_it"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="desc_it">
Descrizione ITA
</FormLabel>
<FormMessage />
</div>
<FormControl>
<Textarea
className="min-h-64"
placeholder=""
{...field}
id="desc_it"
onChange={(e) =>
NullableStringOnChange(
e,
field.onChange,
)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
</div>
</div>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="eng">
<Card>
<CardHeader>
<CardTitle>Descrizione ENG</CardTitle>
</CardHeader>
<CardContent>
<div className="grid gap-6">
<div className="grid gap-3">
<FormField
control={form.control}
name="titolo_en"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="titolo_en">
Titolo ENG
</FormLabel>
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="titolo_en"
onChange={(e) =>
NullableStringOnChange(
e,
field.onChange,
)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
</div>
<div className="grid gap-3">
<FormField
control={form.control}
name="desc_en"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="desc_en">
Descrizione ENG
</FormLabel>
<FormMessage />
</div>
<FormControl>
<Textarea
className="min-h-64"
placeholder=""
{...field}
id="desc_en"
onChange={(e) =>
NullableStringOnChange(
e,
field.onChange,
)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
</div>
</div>
</CardContent>
</Card>
</TabsContent>
</Tabs>
</CardContent>
</Card>
</div>
<div className="grid auto-rows-max items-start gap-3 lg:gap-8">
<Card>
<CardHeader>
<CardTitle>Status Annuncio</CardTitle>
</CardHeader>
<CardContent className="space-y-2">
<FormField
control={form.control}
name="stato"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="select-stato">Stato</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<MultiSelect
defaultValue={
field.value
? statoOptions.filter((o) =>
field.value?.includes(o.value),
)
: undefined
}
elementId="select-stato"
elementName="stato"
isMulti={false}
onValueChange={async (value) => {
field.onChange(value.value);
}}
options={statoOptions}
placeholder="Seleziona..."
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="web"
render={({ field }) => (
<FormItem className="mt-6 w-full px-4">
<div className="flex w-full items-center justify-between gap-x-4">
<FormLabel htmlFor="web">Web</FormLabel>
<FormControl>
<Switch
checked={field.value || false}
className="data-[state=checked]:bg-neutral-700"
id="web"
onCheckedChange={field.onChange}
/>
</FormControl>
<FormMessage />
</div>
</FormItem>
)}
/>
<FormField
control={form.control}
name="homepage"
render={({ field }) => (
<FormItem className="mt-6 w-full px-4">
<div className="flex items-center justify-between gap-x-4">
<FormLabel htmlFor="homepage">Homepage</FormLabel>
<FormControl>
<Switch
checked={field.value || false}
className="data-[state=checked]:bg-neutral-700"
id="homepage"
onCheckedChange={field.onChange}
/>
</FormControl>
<FormMessage />
</div>
</FormItem>
)}
/>
</CardContent>
</Card>
<Card className="overflow-hidden">
<CardHeader>
<CardTitle>Imagini Annuncio</CardTitle>
</CardHeader>
<CardContent>
<CarouselAnnuncio
immagini={data.images}
single
updated_at={data.media_updated_at}
videos={data.videos}
/>
</CardContent>
</Card>
</div>
</div>
<Card>
<CardHeader>
<CardTitle>Dati di contatto</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<FormField
control={form.control}
name="locatore"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="locatore">
Locatore o incaricato
</FormLabel>
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="locatore"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
<DualInputLayout
children1={
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="email">Email</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<Input
placeholder="esempio@email.com"
{...field}
autoComplete="off"
id="email"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
children2={
<FormField
control={form.control}
name="numero"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="numero">Telefono</FormLabel>
<FormMessage />
</div>
<FormControl>
<PhoneInput
{...field}
id="numero"
onChange={(n) => field.onChange(n || null)}
value={field.value || undefined}
/>
</FormControl>
</FormItem>
)}
/>
}
/>
<p>
Indirizo: {data.indirizzo}, {data.civico} {data.comune} (
{data.provincia})
</p>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Dati Immobile</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<DualInputLayout
children1={
<FormField
control={form.control}
name="indirizzo"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="indirizzo">Indirizzo</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="indirizzo"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
children2={
<FormField
control={form.control}
name="civico"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="civico">Civico</FormLabel>
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="civico"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
/>
<DualInputLayout
children1={
<FormField
control={form.control}
name="comune"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="comune">Comune</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="comune"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
children2={
<FormField
control={form.control}
name="cap"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="cap">Cap</FormLabel>
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="cap"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
/>
<DualInputLayout
children1={
<FormField
control={form.control}
name="provincia"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="provincia">Provincia</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="provincia"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
children2={
<FormField
control={form.control}
name="regione"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="regione">Regione</FormLabel>
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="regione"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
/>
<DualInputLayout
children1={
<FormField
control={form.control}
name="lat"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="lat">Lat</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="lat"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
children2={
<FormField
control={form.control}
name="lon"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="lon">Lon</FormLabel>
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="lon"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
/>
<p>
<Link
href={`https://www.google.com/maps/place/${form.getValues("lat")},${form.getValues("lon")}`}
target="_blank"
>
🗺 <span className="underline">Vedi su maps</span>
</Link>
</p>
<DualInputLayout
children1={
<FormField
control={form.control}
name="indirizzo_secondario"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="indirizzo_secondario">
Indirizzo Secondario
</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="indirizzo_secondario"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
children2={
<FormField
control={form.control}
name="civico_secondario"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="civico_secondario">
Civico Secondario
</FormLabel>
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="civico_secondario"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
/>
<DualInputLayout
children1={
<FormField
control={form.control}
name="lat_secondario"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="lat_secondario">
Lat Secondario
</FormLabel>
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="lat_secondario"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
children2={
<FormField
control={form.control}
name="lon_secondario"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="lon_secondario">
Lon Secondario
</FormLabel>
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="lon_secondario"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
}
/>
<p>
<Link
href={`https://www.google.com/maps/place/${form.getValues("lat_secondario")},${form.getValues("lon_secondario")}`}
target="_blank"
>
🗺 <span className="underline">Vedi su maps</span>
</Link>
</p>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Dati Annuncio</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<DualInputLayout
children1={
<FormField
control={form.control}
name="tipo"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="select-tipo">
Tipo annuncio
</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<MultiSelect
defaultValue={
field.value
? tipoOptions.filter((o) =>
field.value?.includes(o.value),
)
: undefined
}
elementId="select-tipo"
elementName="tipo"
isMulti={false}
onValueChange={async (value) => {
field.onChange(value.value);
}}
options={tipoOptions}
placeholder="Seleziona..."
/>
</FormControl>
</FormItem>
)}
/>
}
children2={
<FormField
control={form.control}
name="categorie"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<span className="font-medium text-sm leading-none">
Categorie
</span>
<FormMessage />
</div>
<p className="h-[42px]">{field.value?.join(", ")}</p>
</FormItem>
)}
/>
}
/>
<DualInputLayout
children1={
<FormField
control={form.control}
name="prezzo"
render={({ field }) => {
const { value, onChange, ...rest } = field;
return (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="prezzo">Prezzo</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<NumberInput
decimalScale={2}
{...rest}
decimalSeparator=","
defaultValue={Number(value) / 100}
fixedDecimalScale
id="prezzo"
min={0}
onValueChange={(v) => {
onChange((Number(v) || 0) * 100);
}}
suffix=" €"
/>
</FormControl>
</FormItem>
);
}}
/>
}
children2={
<FormField
control={form.control}
name="disponibile_da"
render={({ field }) => (
<FormItem>
<div className="relative flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="disponibile_da">
Disponibile Da
</FormLabel>
<FormMessage />
{field.value !== null && (
<Button
className="-top-2 absolute right-0 flex items-center gap-1"
onClick={() => {
form.setValue("disponibile_da", null);
}}
size="sm"
type="button"
variant="link"
>
<RotateCw className="size-4" />
Reset
</Button>
)}
</div>
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
className={cn(
"h-[42px] w-full pl-3 text-left font-medium",
!field.value && "text-muted-foreground",
"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",
)}
id="disponibile_da"
variant={"outline"}
>
{field.value ? (
format(field.value, "PPP", {
locale: it,
})
) : (
<span>Scegli</span>
)}
<CalendarIcon className="ml-auto size-4 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent
align="start"
className="w-auto p-0"
>
<Calendar
autoFocus
captionLayout="dropdown"
defaultMonth={field.value || undefined}
endMonth={new Date(2050, 12)}
locale={it}
mode="single"
onSelect={field.onChange}
selected={field.value || undefined}
/>
</PopoverContent>
</Popover>
</FormItem>
)}
/>
}
/>
<DualInputLayout
children1={
<FormField
control={form.control}
name="consegna"
render={({ field: { value, onChange } }) => {
const currVal =
value !== null
? consegnaOptions.filter(
(o) => value.toString() === o.value,
)[0]
: undefined;
return (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="select-consegna">
Consegna
</FormLabel>
<FormMessage />
</div>
<FormControl>
<MultiSelect
defaultValue={currVal}
elementId="select-consegna"
elementName="consegna"
isMulti={false}
onValueChange={async (value) => {
onChange(parseInt(value.value));
}}
options={consegnaOptions}
placeholder="Seleziona..."
/>
</FormControl>
</FormItem>
);
}}
/>
}
children2={
<FormField
control={form.control}
name="persone"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="select-pers">Persone</FormLabel>
<FormMessage />
</div>
<FormControl>
<MultiSelect
defaultValue={
field.value
? personeOptions.filter((o) =>
field.value?.includes(o.value),
)
: undefined
}
elementId="select-pers"
elementName="persone"
isMulti={true}
onValueChange={async (value) => {
field.onChange(value.map((v) => v.value));
}}
options={personeOptions}
placeholder="Seleziona..."
/>
</FormControl>
</FormItem>
)}
/>
}
/>
<FormField
control={form.control}
name="permanenza"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="select-perm">Permanenza</FormLabel>
<FormMessage />
</div>
<FormControl>
<MultiSelect
defaultValue={
field.value
? permanenzaOptions.filter((o) =>
field.value?.includes(parseInt(o.value)),
)
: undefined
}
elementId="select-perm"
elementName="permanenza"
isMulti={true}
onValueChange={async (value) => {
field.onChange(value.map((v) => parseInt(v.value)));
}}
options={permanenzaOptions}
placeholder="Seleziona..."
/>
</FormControl>
</FormItem>
)}
/>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Altri Dati Immobile</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex w-full flex-col flex-wrap items-start justify-between gap-4 sm:flex-row">
<FormField
control={form.control}
name="anno"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="anno">Anno costruzione</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="anno"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="classe"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="classe">Classe</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="classe"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="mq"
render={({ field }) => {
const { value, onChange, ...rest } = field;
const mqValue =
typeof value === "string" ? parseFloat(value) : value;
return (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="mq">Metri Quadri</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<NumberInput
decimalScale={2}
{...rest}
decimalSeparator=","
defaultValue={mqValue || undefined}
fixedDecimalScale
id="mq"
min={0}
onValueChange={(v) => {
onChange(v || null);
}}
/>
</FormControl>
</FormItem>
);
}}
/>
<FormField
control={form.control}
name="piano"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="piano">Piano</FormLabel>{" "}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
{...field}
id="piano"
onChange={(e) =>
NullableStringOnChange(e, field.onChange)
}
value={field.value || ""}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="piano_palazzo"
render={({ field }) => (
<FormItem>
<div className="relative flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="piano_palazzo">
Piani Palazzo
</FormLabel>
{field.value !== null && field.value !== 0 && (
<Button
className="-top-2 absolute right-0 flex items-center gap-1"
onClick={() => {
form.setValue("piano_palazzo", null);
}}
size="sm"
type="button"
variant="link"
>
<RotateCw className="size-4" />
Reset
</Button>
)}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
type="number"
{...field}
id="piano_palazzo"
onChange={(e) =>
field.onChange(
e.target.value === "0" || e.target.value === ""
? null
: parseInt(e.target.value),
)
}
value={field.value || 0}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="unita_condominio"
render={({ field }) => (
<FormItem>
<div className="relative flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="unita_condominio">
Unità Condominio
</FormLabel>
{field.value !== null && field.value !== 0 && (
<Button
className="-top-2 absolute right-0 flex items-center gap-1"
onClick={() => {
form.setValue("unita_condominio", null);
}}
size="sm"
type="button"
variant="link"
>
<RotateCw className="size-4" />
Reset
</Button>
)}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
type="number"
{...field}
id="unita_condominio"
onChange={(e) =>
field.onChange(
e.target.value === "0" || e.target.value === ""
? null
: parseInt(e.target.value),
)
}
value={field.value || 0}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="numero_vani"
render={({ field }) => (
<FormItem>
<div className="relative flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="numero_vani">
Numero Vani
</FormLabel>
{field.value !== null && field.value !== 0 && (
<Button
className="-top-2 absolute right-0 flex items-center gap-1"
onClick={() => {
form.setValue("numero_vani", null);
}}
size="sm"
type="button"
variant="link"
>
<RotateCw className="size-4" />
Reset
</Button>
)}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
type="number"
{...field}
id="numero_vani"
onChange={(e) =>
field.onChange(
e.target.value === "0" || e.target.value === ""
? null
: parseInt(e.target.value),
)
}
value={field.value || 0}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="numero_camere"
render={({ field }) => (
<FormItem>
<div className="relative flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="numero_camere">
Numero Camere
</FormLabel>
{field.value !== null && field.value !== 0 && (
<Button
className="-top-2 absolute right-0 flex items-center gap-1"
onClick={() => {
form.setValue("numero_camere", null);
}}
size="sm"
type="button"
variant="link"
>
<RotateCw className="size-4" />
Reset
</Button>
)}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
type="number"
{...field}
id="numero_camere"
onChange={(e) =>
field.onChange(
e.target.value === "0" || e.target.value === ""
? null
: parseInt(e.target.value),
)
}
value={field.value || 0}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="numero_bagni"
render={({ field }) => (
<FormItem>
<div className="relative flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="numero_bagni">
Numero Bagni
</FormLabel>
{field.value !== null && field.value !== 0 && (
<Button
className="-top-2 absolute right-0 flex items-center gap-1"
onClick={() => {
form.setValue("numero_bagni", null);
}}
size="sm"
type="button"
variant="link"
>
<RotateCw className="size-4" />
Reset
</Button>
)}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
type="number"
{...field}
id="numero_bagni"
onChange={(e) =>
field.onChange(
e.target.value === "0" || e.target.value === ""
? null
: parseInt(e.target.value),
)
}
value={field.value || 0}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="numero_balconi"
render={({ field }) => (
<FormItem>
<div className="relative flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="numero_balconi">
Numero Balconi
</FormLabel>
{field.value !== null && field.value !== 0 && (
<Button
className="-top-2 absolute right-0 flex items-center gap-1"
onClick={() => {
form.setValue("numero_balconi", null);
}}
size="sm"
type="button"
variant="link"
>
<RotateCw className="size-4" />
Reset
</Button>
)}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
type="number"
{...field}
id="numero_balconi"
onChange={(e) =>
field.onChange(
e.target.value === "0" || e.target.value === ""
? null
: parseInt(e.target.value),
)
}
value={field.value || 0}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="numero_terrazzi"
render={({ field }) => (
<FormItem>
<div className="relative flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="numero_terrazzi">
Numero Terrazzi
</FormLabel>
{field.value !== null && field.value !== 0 && (
<Button
className="-top-2 absolute right-0 flex items-center gap-1"
onClick={() => {
form.setValue("numero_terrazzi", null);
}}
size="sm"
type="button"
variant="link"
>
<RotateCw className="size-4" />
Reset
</Button>
)}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
type="number"
{...field}
id="numero_terrazzi"
onChange={(e) =>
field.onChange(
e.target.value === "0" || e.target.value === ""
? null
: parseInt(e.target.value),
)
}
value={field.value || 0}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="numero_box"
render={({ field }) => (
<FormItem>
<div className="relative flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="numero_box">
Numero Box Auto
</FormLabel>
{field.value !== null && field.value !== 0 && (
<Button
className="-top-2 absolute right-0 flex items-center gap-1"
onClick={() => {
form.setValue("numero_box", null);
}}
size="sm"
type="button"
variant="link"
>
<RotateCw className="size-4" />
Reset
</Button>
)}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
type="number"
{...field}
id="numero_box"
onChange={(e) =>
field.onChange(
e.target.value === "0" || e.target.value === ""
? null
: parseInt(e.target.value),
)
}
value={field.value || 0}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="numero_postiauto"
render={({ field }) => (
<FormItem>
<div className="relative flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="numero_postiauto">
Numero Posti Auto
</FormLabel>
{field.value !== null && field.value !== 0 && (
<Button
className="-top-2 absolute right-0 flex items-center gap-1"
onClick={() => {
form.setValue("numero_postiauto", null);
}}
size="sm"
type="button"
variant="link"
>
<RotateCw className="size-4" />
Reset
</Button>
)}
<FormMessage />
</div>
<FormControl>
<Input
placeholder=""
type="number"
{...field}
id="numero_postiauto"
onChange={(e) =>
field.onChange(
e.target.value === "0" || e.target.value === ""
? null
: parseInt(e.target.value),
)
}
value={field.value || 0}
/>
</FormControl>
</FormItem>
)}
/>
</div>
<FormField
control={form.control}
name="accessori"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<span className="font-medium text-sm leading-none">
Accessori
</span>
<FormMessage />
</div>
<FormControl>
<p className="h-[42px]">{field.value?.join(", ")}</p>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="caratteristiche"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<span className="font-medium text-sm leading-none">
Caratteristiche
</span>
<FormMessage />
</div>
<FormControl>
<p className="h-[42px]">
{field.value
? filteredCaratteristiche(field.value)
.map((v) => v.text)
.join(", ")
: ""}
</p>
</FormControl>
</FormItem>
)}
/>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Media</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex w-full flex-col items-start justify-between gap-4 sm:flex-row"></div>
</CardContent>
</Card>
</div>
</form>
</Form>
</>
);
};