diff --git a/apps/infoalloggi/src/pages/area-riservata/admin/edit-annuncio/[id].tsx b/apps/infoalloggi/src/pages/area-riservata/admin/edit-annuncio/[id].tsx index 39436ae..806a8a2 100644 --- a/apps/infoalloggi/src/pages/area-riservata/admin/edit-annuncio/[id].tsx +++ b/apps/infoalloggi/src/pages/area-riservata/admin/edit-annuncio/[id].tsx @@ -1,15 +1,8 @@ -import { Eye } from "lucide-react"; +import { CalendarIcon, Eye, RotateCw } from "lucide-react"; import type { GetServerSideProps } from "next"; import Link from "next/link"; import { AreaRiservataLayout } from "~/components/Layout"; import Input from "~/components/custom_ui/input"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "~/components/ui/select"; import { Textarea } from "~/components/custom_ui/textarea"; import { LoadingPage } from "~/components/loading"; import { Status500 } from "~/components/status-page"; @@ -38,6 +31,22 @@ import toast from "react-hot-toast"; import type { Annunci, AnnunciId } from "~/schemas/public/Annunci"; import { DualInputLayout } from "~/components/custom_ui/inputLayouts"; import { PhoneInput } from "~/components/phone-input"; +import type { Caratteristiche } from "~/utils/kanel-types"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "~/components/ui/popover"; +import { format } from "date-fns"; +import { Calendar } from "~/components/ui/calendar"; +import { it } from "date-fns/locale"; +import { + MultiSelect, + type ListOption, +} from "~/components/custom_ui/multiselect"; +import { DevTool } from "@hookform/devtools"; +import { Switch } from "~/components/ui/switch"; +import { filteredCaratteristiche } from "~/hooks/schedaAnnuncioUtils"; type AnnuncioEditProps = { id: AnnunciId; @@ -46,7 +55,7 @@ type AnnuncioEditProps = { const AnnuncioEdit: NextPageWithLayout = ({ id, }: AnnuncioEditProps) => { - const { data, isLoading } = api.annunci.getAnnuncioById.useQuery( + const { data, isLoading } = api.annunci.getAnnuncioByIdForEdit.useQuery( { id, }, @@ -67,40 +76,87 @@ const AnnuncioEdit: NextPageWithLayout = ({ const AnnuncioEditForm = ({ data }: { data: Annunci }) => { const EdiAnnuncioSchema = z.object({ - annuncioId: zAnnuncioId, - titolo_it: z.string().nonempty("Inserisci un titolo valido"), - desc_it: z.string().nonempty("Inserisci una descrizione valida"), - titolo_en: z.string().nonempty("Inserisci un titolo valido"), - desc_en: z.string().nonempty("Inserisci una descrizione valida"), - status: z.string().nonempty("Seleziona uno stato"), + //BASE + id: zAnnuncioId, + titolo_it: z.string().nullable(), + desc_it: z.string().nullable(), + titolo_en: z.string().nullable(), + desc_en: z.string().nullable(), + stato: z.string().nullable(), + web: z.boolean().nullable(), + homepage: z.boolean().nullable(), + codice: z.string(), + + // DATI LOCATORE locatore: z.string().nullable(), - email: z.email().nullable(), + email: z.email().optional(), numero: z.string().nullable(), + + // DATI IMMOBILE + indirizzo: z.string().nullable(), + civico: z.string().nullable(), + comune: z.string().nullable(), + cap: z.string().nullable(), + provincia: z.string().nullable(), + regione: z.string().nullable(), + lat: z.string().nullable(), + lon: z.string().nullable(), + indirizzo_secondario: z.string().nullable(), + civico_secondario: z.string().nullable(), + lat_secondario: z.string().nullable(), + lon_secondario: z.string().nullable(), + + // DATI CONTRATTO + tipo: z.string().nullable(), + categorie: z.string().array().nullable(), + prezzo: z.number(), + disponibile_da: z.date().nullable(), + consegna: z.number().nullable(), + persone: z.string().array().nullable(), + permanenza: z.number().array().nullable(), + + // ALTRI DATI IMMOBILE + anno: z.string().nullable(), + classe: z.string().nullable(), + mq: z.string().nullable(), + piano: z.string().nullable(), + piano_palazzo: z.number().nullable(), + unita_condominio: z.number().nullable(), + numero_vani: z.number().nullable(), + numero_camere: z.number().nullable(), + numero_bagni: z.number().nullable(), + numero_balconi: z.number().nullable(), + numero_terrazzi: z.number().nullable(), + numero_box: z.number().nullable(), + numero_postiauto: z.number().nullable(), + accessori: z.string().array().nullable(), + caratteristiche: z.custom().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 EditAnnuncioFormValues = z.infer; + type FormValues = z.infer; 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.invalidate({ id: data.id }); + await utils.annunci.getAnnuncioByIdForEdit.invalidate({ id: data.id }); await utils.annunci.getAnnunciList.invalidate(); toast.success("Annuncio modificato con successo"); }, }); - const defaultValues: EditAnnuncioFormValues = { - annuncioId: data.id, - titolo_it: data.titolo_it || "", - desc_it: data.desc_it || "", - titolo_en: data.titolo_en || "", - desc_en: data.desc_en || "", - status: data.stato || "", - locatore: data.locatore || null, - email: data.email || null, - numero: data.numero || null, + const defaultValues: FormValues = { + ...data, + email: data.email || undefined, }; z.config(z.locales[locale]()); @@ -108,13 +164,64 @@ const AnnuncioEditForm = ({ data }: { data: Annunci }) => { const form = useZodForm(EdiAnnuncioSchema, { defaultValues: defaultValues, }); - function onSubmit(fields: EditAnnuncioFormValues) { - edit(fields); + + function onSubmit(fields: FormValues) { + edit({ + annuncioId: data.id, + data: { ...fields, email: fields.email || null }, + }); } + const personeOptions: ListOption[] = [ + "single", + "coppia", + "colleghi", + "famiglia", + ].map((p) => ({ + value: p, + label: p, + })); + + const permanenzaOptions: ListOption[] = [ + { value: "1", label: "1 mese" }, + { value: "3", label: "3 mesi" }, + { value: "6", label: "6 mesi" }, + { value: "9", label: "9 mesi" }, + { value: "12", label: "12 mesi" }, + { value: "18", label: "18 mesi" }, + { value: "24", label: "24 mesi" }, + ]; + const tipoOptions: ListOption[] = [ + "Transitorio", + "Stabile", + "Vendita", + "Cessione", + "Errore", + ].map((o) => ({ value: o, label: o })); + + const statoOptions = ["Attivo", "Sospeso", "Trattativa"].map((o) => ({ + value: o, + label: o, + })); + + const consegnaOptions: ListOption[] = [ + { value: "1", label: "Gennaio" }, + { value: "2", label: "Febbraio" }, + { value: "3", label: "Marzo" }, + { value: "4", label: "Aprile" }, + { value: "5", label: "Maggio" }, + { value: "6", label: "Giugno" }, + { value: "7", label: "Luglio" }, + { value: "8", label: "Agosto" }, + { value: "9", label: "Settembre" }, + { value: "10", label: "Ottobre" }, + { value: "11", label: "Novembre" }, + { value: "12", label: "Dicembre" }, + ]; return ( <>
+ { -
-
+
+
@@ -178,6 +285,7 @@ const AnnuncioEditForm = ({ data }: { data: Annunci }) => { placeholder="" {...field} id="titolo_it" + value={field.value || undefined} /> @@ -203,6 +311,7 @@ const AnnuncioEditForm = ({ data }: { data: Annunci }) => { className="min-h-64" {...field} id="desc_it" + value={field.value || undefined} /> @@ -238,6 +347,7 @@ const AnnuncioEditForm = ({ data }: { data: Annunci }) => { placeholder="" {...field} id="titolo_en" + value={field.value || undefined} /> @@ -263,6 +373,7 @@ const AnnuncioEditForm = ({ data }: { data: Annunci }) => { className="min-h-64" {...field} id="desc_en" + value={field.value || undefined} /> @@ -277,49 +388,84 @@ const AnnuncioEditForm = ({ data }: { data: Annunci }) => {
-
+
Status Annuncio - -
-
- ( - -
- -
+ + ( + +
+ Stato{" "} + +
- - - -
- )} - /> -
-
+ + + field.value?.includes(o.value), + ) + : undefined + } + onValueChange={async (value) => { + field.onChange(value.value); + }} + placeholder="Seleziona..." + isMulti={false} + /> + + + )} + /> + ( + +
+ Web + + + + +
+
+ )} + /> + ( + +
+ Homepage + + + + +
+
+ )} + />
@@ -328,7 +474,12 @@ const AnnuncioEditForm = ({ data }: { data: Annunci }) => { {data.url_immagini && data.url_immagini.length > 0 ? ( - + `/go-api/images/get/${v}`, + )} + /> ) : (
Nessuna immagine disponibile @@ -388,7 +539,11 @@ const AnnuncioEditForm = ({ data }: { data: Annunci }) => { id="email" value={field.value || undefined} onChange={(e) => - field.onChange(e.target.value || null) + field.onChange( + e.target.value && e.target.value !== "" + ? e.target.value + : null, + ) } /> @@ -427,6 +582,1157 @@ const AnnuncioEditForm = ({ data }: { data: Annunci }) => {

+ + + Dati Immobile + + + ( + +
+ Indirizzo{" "} + +
+ + + + +
+ )} + /> + } + children2={ + ( + +
+ Civico + +
+ + + + +
+ )} + /> + } + /> + ( + +
+ Comune{" "} + +
+ + + + +
+ )} + /> + } + children2={ + ( + +
+ Cap + +
+ + + + +
+ )} + /> + } + /> + ( + +
+ Provincia{" "} + +
+ + + + +
+ )} + /> + } + children2={ + ( + +
+ Regione + +
+ + + + +
+ )} + /> + } + /> + ( + +
+ Lat{" "} + +
+ + + + +
+ )} + /> + } + children2={ + ( + +
+ Lon + +
+ + + + +
+ )} + /> + } + /> +

+ + 🗺️ Vedi su maps + +

+ + ( + +
+ + Indirizzo Secondario + {" "} + +
+ + + + +
+ )} + /> + } + children2={ + ( + +
+ + Civico Secondario + + +
+ + + + +
+ )} + /> + } + /> + ( + +
+ + Lat Secondario + + +
+ + + + +
+ )} + /> + } + children2={ + ( + +
+ + Lon Secondario + + +
+ + + + +
+ )} + /> + } + /> +

+ + 🗺️ Vedi su maps + +

+
+
+ + + Dati Annuncio + + + ( + +
+ + Tipo annuncio + {" "} + +
+ + + + field.value?.includes(o.value), + ) + : undefined + } + onValueChange={async (value) => { + field.onChange(value.value); + }} + placeholder="Seleziona..." + isMulti={false} + /> + +
+ )} + /> + } + children2={ + ( + +
+ Categorie + +
+ +

+ {field.value?.join(", ")} +

+
+ )} + /> + } + /> + ( + +
+ Prezzo{" "} + +
+ + + + e.target.value === "" + ? field.onChange(null) + : field.onChange( + parseFloat(e.target.value) * 100, + ) + } + value={field.value / 100 || undefined} + /> + +
+ )} + /> + } + children2={ + ( + +
+ + Disponibile Da + + +
+ + + + + + + + + + +
+ )} + /> + } + /> + ( + +
+ + Consegna + + +
+ + + + field.value?.toString().includes(o.value), + ) + : undefined + } + onValueChange={async (value) => { + field.onChange(parseInt(value.value)); + }} + placeholder="Seleziona..." + isMulti={false} + /> + +
+ )} + /> + } + children2={ + ( + +
+ Persone + +
+ + + + field.value?.includes(o.value), + ) + : undefined + } + onValueChange={async (value) => { + field.onChange(value.map((v) => v.value)); + }} + placeholder="Seleziona..." + isMulti={true} + /> + +
+ )} + /> + } + /> + ( + +
+ Permanenza + +
+ + + + field.value?.includes(parseInt(o.value)), + ) + : undefined + } + onValueChange={async (value) => { + field.onChange(value.map((v) => parseInt(v.value))); + }} + placeholder="Seleziona..." + isMulti={true} + /> + +
+ )} + /> +
+
+ + + Altri Dati Immobile + + +
+ ( + +
+ Anno costruzione{" "} + +
+ + + + field.onChange( + e.target.value != "" ? e.target.value : null, + ) + } + /> + +
+ )} + /> + + ( + +
+ Classe{" "} + +
+ + + + field.onChange( + e.target.value != "" ? e.target.value : null, + ) + } + /> + +
+ )} + /> + + ( + +
+ Metri Quadri{" "} + +
+ + + + field.onChange( + e.target.value != "" ? e.target.value : null, + ) + } + /> + +
+ )} + /> + + ( + +
+ Piano{" "} + +
+ + + + field.onChange( + e.target.value != "" ? e.target.value : null, + ) + } + /> + +
+ )} + /> + + ( + +
+ + Piani Palazzo + + {field.value !== null && field.value != 0 && ( + + )} + +
+ + + + field.onChange( + e.target.value === "0" || e.target.value === "" + ? null + : parseInt(e.target.value), + ) + } + /> + +
+ )} + /> + + ( + +
+ + Unità Condominio + + {field.value !== null && field.value != 0 && ( + + )} + +
+ + + + field.onChange( + e.target.value === "0" || e.target.value === "" + ? null + : parseInt(e.target.value), + ) + } + /> + +
+ )} + /> + + ( + +
+ + Numero Vani + + {field.value !== null && field.value != 0 && ( + + )} + +
+ + + + field.onChange( + e.target.value === "0" || e.target.value === "" + ? null + : parseInt(e.target.value), + ) + } + /> + +
+ )} + /> + + ( + +
+ + Numero Camere + + {field.value !== null && field.value != 0 && ( + + )} + +
+ + + + field.onChange( + e.target.value === "0" || e.target.value === "" + ? null + : parseInt(e.target.value), + ) + } + /> + +
+ )} + /> + ( + +
+ + Numero Bagni + + {field.value !== null && field.value != 0 && ( + + )} + +
+ + + + field.onChange( + e.target.value === "0" || e.target.value === "" + ? null + : parseInt(e.target.value), + ) + } + /> + +
+ )} + /> + ( + +
+ + Numero Balconi + + {field.value !== null && field.value != 0 && ( + + )} + +
+ + + + field.onChange( + e.target.value === "0" || e.target.value === "" + ? null + : parseInt(e.target.value), + ) + } + /> + +
+ )} + /> + ( + +
+ + Numero Terrazzi + + {field.value !== null && field.value != 0 && ( + + )} + +
+ + + + field.onChange( + e.target.value === "0" || e.target.value === "" + ? null + : parseInt(e.target.value), + ) + } + /> + +
+ )} + /> + ( + +
+ + Numero Box Auto + + {field.value !== null && field.value != 0 && ( + + )} + +
+ + + + field.onChange( + e.target.value === "0" || e.target.value === "" + ? null + : parseInt(e.target.value), + ) + } + /> + +
+ )} + /> + ( + +
+ + Numero Posti Auto + + {field.value !== null && field.value != 0 && ( + + )} + +
+ + + + field.onChange( + e.target.value === "0" || e.target.value === "" + ? null + : parseInt(e.target.value), + ) + } + /> + +
+ )} + /> +
+ ( + +
+ Accessori + +
+ + +

+ {field.value?.join(", ")} +

+
+
+ )} + /> + ( + +
+ + Caratteristiche + + +
+ + +

+ {field.value + ? filteredCaratteristiche(field.value) + .map((v) => v.text) + .join(", ") + : ""} +

+
+
+ )} + /> +
+
+ + + Media + + +
+
+
@@ -449,7 +1755,7 @@ export const getServerSideProps = (async (context) => { const ssg = generateSSGHelper(); - await ssg.annunci.getAnnuncioById.prefetch({ id: check.data }); + await ssg.annunci.getAnnuncioByIdForEdit.prefetch({ id: check.data }); return { props: { diff --git a/apps/infoalloggi/src/server/api/routers/annunci.ts b/apps/infoalloggi/src/server/api/routers/annunci.ts index 27e6cab..558cf4b 100644 --- a/apps/infoalloggi/src/server/api/routers/annunci.ts +++ b/apps/infoalloggi/src/server/api/routers/annunci.ts @@ -1,4 +1,5 @@ import { z } from "zod/v4"; +import { type AnnunciUpdate } from "~/schemas/public/Annunci"; import { adminProcedure, createTRPCRouter, @@ -6,7 +7,6 @@ import { publicProcedure, } from "~/server/api/trpc"; import { - EdiAnnuncioSchema, editAnnuncioHandler, getProprietarioDataHandler, getCodici_AnnunciHandler, @@ -45,7 +45,7 @@ export const annunciRouter = createTRPCRouter({ .query(async ({ input }) => { return await getAnnunciMetaByCod({ ...input }); }), - getAnnuncioById: publicProcedure + getAnnuncioByIdForEdit: publicProcedure .input( z.object({ id: zAnnuncioId, @@ -88,7 +88,9 @@ export const annunciRouter = createTRPCRouter({ }), editAnnuncio: adminProcedure - .input(EdiAnnuncioSchema) + .input( + z.object({ annuncioId: zAnnuncioId, data: z.custom() }), + ) .mutation(async ({ input }) => { return await editAnnuncioHandler({ ...input, diff --git a/apps/infoalloggi/src/server/controllers/annunci.controller.ts b/apps/infoalloggi/src/server/controllers/annunci.controller.ts index 68e2213..35ed9e1 100644 --- a/apps/infoalloggi/src/server/controllers/annunci.controller.ts +++ b/apps/infoalloggi/src/server/controllers/annunci.controller.ts @@ -1,9 +1,11 @@ -import type { Annunci, AnnunciId } from "~/schemas/public/Annunci"; +import type { + Annunci, + AnnunciId, + AnnunciUpdate, +} from "~/schemas/public/Annunci"; import { TRPCError } from "@trpc/server"; import { createSrcset } from "~/server/services/imageServer"; import { AnnuncioObjectWithImages } from "~/server/services/annunci.service"; -import { zAnnuncioId } from "~/server/utils/zod_types"; -import { z } from "zod/v4"; import { db } from "~/server/db"; import type { ServizioServizioId } from "~/schemas/public/Servizio"; import { env } from "~/env.mjs"; @@ -132,7 +134,7 @@ export const getAnnunciById = async ({ }); } - return AnnuncioObjectWithImages(annuncio); + return annuncio; } catch (e) { throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", @@ -350,34 +352,18 @@ export const getOptions_AnnunciHandler = async () => { } }; -export const EdiAnnuncioSchema = z.object({ - annuncioId: zAnnuncioId, - titolo_it: z.string().nonempty("Inserisci un titolo valido"), - desc_it: z.string().nonempty("Inserisci una descrizione valida"), - titolo_en: z.string().nonempty("Inserisci un titolo valido"), - desc_en: z.string().nonempty("Inserisci una descrizione valida"), - status: z.string().nonempty("Seleziona uno stato"), -}); - -type EditAnnuncioFormValues = z.infer; - export const editAnnuncioHandler = async ({ annuncioId, - titolo_it, - desc_it, - titolo_en, - desc_en, - status, -}: EditAnnuncioFormValues) => { + data, +}: { + annuncioId: AnnunciId; + data: AnnunciUpdate; +}) => { try { await db .updateTable("annunci") .set({ - titolo_it: titolo_it, - desc_it: desc_it, - titolo_en: titolo_en, - desc_en: desc_en, - stato: status, + ...data, }) .where("id", "=", annuncioId) .execute();