diff --git a/apps/infoalloggi/src/components/schedaAnnuncioStampabile.tsx b/apps/infoalloggi/src/components/schedaAnnuncioStampabile.tsx new file mode 100644 index 0000000..f903d81 --- /dev/null +++ b/apps/infoalloggi/src/components/schedaAnnuncioStampabile.tsx @@ -0,0 +1,262 @@ +"use client"; + +import { useRef } from "react"; +import { useReactToPrint } from "react-to-print"; +import { Button } from "~/components/ui/button"; +import { Card } from "~/components/ui/card"; +import { filteredCaratteristiche } from "~/hooks/schedaAnnuncioUtils"; +import { it } from "~/i18n/it"; +import { handleConsegna } from "~/lib/annuncio_details"; +import { replaceWithBr } from "~/lib/newlineToBr"; +import type { Annunci } from "~/schemas/public/Annunci"; +import { IconMatrix } from "./IconComponents"; +import { LogoSvg } from "./svgs"; +import { Separator } from "./ui/separator"; + +//todo finire +export function SchedaAnnuncioStampabile({ data }: { data: Annunci }) { + const contentRef = useRef(null); + const reactToPrintFn = useReactToPrint({ + contentRef, + //print: async (target) => {console.log("Printing...", target.contentDocument);}, + }); + + return ( +
+
+
+

Scheda Annuncio Stampabile

+ + +
+
+ +
+
+
+ ); +} + +function SchedaAnnuncio({ data }: { data: Annunci }) { + const companyAddress = + "Via Beata Giovanna, 1 a Bassano del Grappa (VI)\nTel. +39 0424529869\nEmail: arca@infoalloggi.it"; + + const footer = + "Arcenia Srl. | Tel. +39 0424529869 | Email: arca@infoalloggi.it"; + return ( + +
+
+
+ +
+ +
+

Arcenia Srl

+

+ {companyAddress} +

+
+
+ {/* Property Header */} +
+

+ {data.titolo_it || "Immobile in Affitto"} +

+

+ Riferimento: {data.codice} +

+
+ + {/* Property Details Grid */} +
+ {/* Location Details */} +
+

+ 📍 Ubicazione +

+
+

+ Comune: {data.comune} ( + {data.provincia}) +

+

+ CAP: {data.cap} +

+

+ Indirizzo: {data.indirizzo} + , {data.civico} +

+ {data.piano_palazzo && ( +

+ Piano:{" "} + {data.piano_palazzo} +

+ )} +
+
+ + {/* Property Characteristics */} +
+

+ 🏠 Caratteristiche +

+
+ {data.mq && ( +

+ mq: {data.mq} mq +

+ )} + {data.numero_vani && ( +

+ Locali:{" "} + {data.numero_vani} +

+ )} + {data.numero_camere && ( +

+ Camere:{" "} + {data.numero_camere} +

+ )} + {data.numero_bagni && ( +

+ Bagni:{" "} + {data.numero_bagni} +

+ )} +
+
+
+ + {/* Pricing Information */} + +
+
+ {data.tipo && ( +
+

Tipologia

+

Affitto {data.tipo}

+
+ )} + {data.prezzo && ( +
+

Canone Mensile

+

+ € {data.prezzo.toLocaleString()} +

+
+ )} + {(data.disponibile_da || data.consegna) && ( +
+

Disponibile da

+

+ {data.disponibile_da + ? new Date(data.disponibile_da).toLocaleDateString() + : data.consegna && + handleConsegna({ + aggiornamento: it.card.in_aggiornamento, + consegna: data.consegna, + consegna_da: it.card.consegna_da, + mesi: it.preferenze.mesi, + subito: it.card.consegna_subito, + })} +

+
+ )} +
+
+ + {/* Additional Features */} + +
+

+ ✨ Dotazioni e Servizi +

+
+ {data.caratteristiche && + filteredCaratteristiche(data.caratteristiche).map( + (item, index) => { + if (!item.value) return null; + return ( +
+ + + + + {item.text}: {item.value} + +
+ ); + }, + )} +
+
+ + {/* Description */} + {data.desc_it && ( + <> +
+

+ 📝 Descrizione +

+
+

+
+
+ + )} + + {/* Energy Information */} + {data.classe && ( + <> + +
+

+ ⚡ Prestazione Energetica +

+
+ {data.classe && ( +

+ Classe Energetica:{" "} + {data.classe} +

+ )} +
+
+ + )} + + {/* Contact Information */} + +
+

+ 📞 Contatti +

+
+

{data.locatore}

+ {data.numero &&

Tel. {data.numero}

} +
+
+ + + +
+

{footer}

+

+ Documento generato in data: {new Date().toLocaleDateString("it-IT")} +

+
+
+
+ ); +} diff --git a/apps/infoalloggi/src/components/servizio/annuncio_card.tsx b/apps/infoalloggi/src/components/servizio/annuncio_card.tsx index 250f0f6..ac4f884 100644 --- a/apps/infoalloggi/src/components/servizio/annuncio_card.tsx +++ b/apps/infoalloggi/src/components/servizio/annuncio_card.tsx @@ -24,6 +24,7 @@ import { CarouselPrevious, } from "~/components/ui/carousel"; import { handleConsegna } from "~/lib/annuncio_details"; +import { replaceWithBr } from "~/lib/newlineToBr"; import { cn, formatCurrency } from "~/lib/utils"; import { useTranslation } from "~/providers/I18nProvider"; import { useServizioAnnuncio } from "~/providers/ServizioProvider"; @@ -166,9 +167,7 @@ const AnnuncioDettaglio = ({ >; }) => { const { locale, t } = useTranslation(); - function replaceWithBr(text: string) { - return text.replace(/\n/g, "
"); - } + return ( @@ -261,7 +260,7 @@ const AnnuncioDettaglio = ({ className="text-base" dangerouslySetInnerHTML={{ __html: replaceWithBr( - (locale === "it" ? data.desc_it : data.desc_it) || "", + (locale === "it" ? data.desc_it : data.desc_en) || "", ), }} /> diff --git a/apps/infoalloggi/src/forms/FormEditAnnuncio.tsx b/apps/infoalloggi/src/forms/FormEditAnnuncio.tsx index 752ec8a..191915b 100644 --- a/apps/infoalloggi/src/forms/FormEditAnnuncio.tsx +++ b/apps/infoalloggi/src/forms/FormEditAnnuncio.tsx @@ -1,6 +1,6 @@ import { format } from "date-fns"; import { it } from "date-fns/locale"; -import { CalendarIcon, Eye, RotateCw } from "lucide-react"; +import { CalendarIcon, Eye, Printer, RotateCw } from "lucide-react"; import Link from "next/link"; import toast from "react-hot-toast"; import z from "zod"; @@ -115,7 +115,9 @@ export const AnnuncioEditForm = ({ data }: { data: Annunci }) => { const { mutate: edit } = api.annunci.editAnnuncio.useMutation({ onSettled: async () => { await utils.annunci.getAnnuncio.invalidate({ cod: data.codice }); - await utils.annunci.getAnnuncioByIdForEdit.invalidate({ id: data.id }); + await utils.annunci.getAnnuncioById_rawImgUrls.invalidate({ + id: data.id, + }); await utils.annunci.getAnnunciList.invalidate(); toast.success("Annuncio modificato con successo"); }, @@ -202,17 +204,30 @@ export const AnnuncioEditForm = ({ data }: { data: Annunci }) => { - + + +
- -
diff --git a/apps/infoalloggi/src/hooks/schedaAnnuncioUtils.ts b/apps/infoalloggi/src/hooks/schedaAnnuncioUtils.ts index 9d7ed69..43ad0bb 100644 --- a/apps/infoalloggi/src/hooks/schedaAnnuncioUtils.ts +++ b/apps/infoalloggi/src/hooks/schedaAnnuncioUtils.ts @@ -6,77 +6,52 @@ import type { Caratteristiche } from "~/utils/kanel-types"; export type CaratteristicheFiltered = ReturnType< typeof filteredCaratteristiche >; -export const filteredCaratteristiche = (caratteristiche: Caratteristiche) => { - const { - Scheda_Grado, - Scheda_OneriUrbanizzazione, - Scheda_AffittoMuriAnno, - Scheda_ScadenzaContratto, - Scheda_CanoniAnticipati, - Scheda_OrariApertura, - Scheda_PossibilitàAcquistoMuri, - Scheda_SpCondominialiAnno, - Scheda_Cauzione, - Scheda_IncassoAnnuo, - Scheda_NumeroVetrine, - Scheda_NumeroDipendenti, - Scheda_PostiSedere, - Scheda_TipoGestione, - Scheda_TipoRegistr, - Scheda_TipoContratto, - Scheda_Destinazione, - Scheda_Pavimento, - Scheda_PavimentoCucina, - Scheda_PavimentoBagno, - Scheda_PavimentoNotte, - Scheda_PavimentoGiorno, - Scheda_LatiLiberi, - Scheda_ElettricitaGas, - Scheda_IndiceEdificabilita, - Scheda_CambioBiancheria, - Scheda_Categoria, - Scheda_Panorama, - Scheda_TipoSaracinesca, - Scheda_Appartamenti, - - ...rest - } = caratteristiche; - +export const filteredCaratteristiche = (c: Caratteristiche) => { const filtered = [ { icon: "heater" as IconType, text: "Tipo Impianto", - value: rest.Scheda_TipoImpianto, + value: c.Scheda_TipoImpianto, }, { icon: "thermometer-sun" as IconType, text: "Riscaldamento", - value: rest.Scheda_Riscaldamento, + value: c.Scheda_Riscaldamento, }, { icon: "sofa" as IconType, text: "Arredi", - value: rest.Scheda_Arredi, + value: c.Scheda_Arredi, }, { icon: "building" as IconType, text: "Piano", - value: rest.Scheda_Piano, + value: c.Scheda_Piano, }, { icon: "building2" as IconType, text: "Piani Edificio", - value: rest.Scheda_TotalePiani, + value: c.Scheda_TotalePiani, }, { icon: "dot" as IconType, text: "Orientamento", - value: rest.Scheda_Orientamento, + value: c.Scheda_Orientamento, }, { icon: "wifi" as IconType, text: "Internet", - value: rest.Scheda_Internet, + value: c.Scheda_Internet, + }, + { + icon: "accessibility" as IconType, + text: "Accesso Disabili", + value: c.Scheda_AccessoDisabili, + }, + { + icon: "dot" as IconType, + text: "Spazio Parcheggio", + value: c.Scheda_SpazioParcheggio, }, ]; return filtered; diff --git a/apps/infoalloggi/src/lib/newlineToBr.ts b/apps/infoalloggi/src/lib/newlineToBr.ts new file mode 100644 index 0000000..b52ed4a --- /dev/null +++ b/apps/infoalloggi/src/lib/newlineToBr.ts @@ -0,0 +1,3 @@ +export function replaceWithBr(text: string) { + return text.replace(/\n/g, "
"); +} diff --git a/apps/infoalloggi/src/pages/annuncio/[cod].tsx b/apps/infoalloggi/src/pages/annuncio/[cod].tsx index affddb6..36e6def 100644 --- a/apps/infoalloggi/src/pages/annuncio/[cod].tsx +++ b/apps/infoalloggi/src/pages/annuncio/[cod].tsx @@ -51,6 +51,7 @@ import { } from "~/hooks/schedaAnnuncioUtils"; import { useMediaQuery } from "~/hooks/use-media-query"; import { handleConsegna } from "~/lib/annuncio_details"; +import { replaceWithBr } from "~/lib/newlineToBr"; import { cn } from "~/lib/utils"; import { AnnuncioContext } from "~/providers/AnnuncioProvider"; import { useTranslation } from "~/providers/I18nProvider"; @@ -330,9 +331,6 @@ const TestiAnnuncio = ({ }[] | null; }) => { - function replaceWithBr(text: string) { - return text.replace(/\n/g, "
"); - } return ( <>

{titolo}

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 ae900e4..db77147 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 @@ -18,7 +18,7 @@ type AnnuncioEditProps = { const AnnuncioEdit: NextPageWithLayout = ({ id, }: AnnuncioEditProps) => { - const { data, isLoading } = api.annunci.getAnnuncioByIdForEdit.useQuery( + const { data, isLoading } = api.annunci.getAnnuncioById_rawImgUrls.useQuery( { id, }, @@ -29,7 +29,7 @@ const AnnuncioEdit: NextPageWithLayout = ({ if (!data) { return ; } - //todo avere scheda di condivizione scaricabile + return ( <> @@ -52,7 +52,7 @@ export const getServerSideProps = (async (context) => { const ssg = generateSSGHelper(); - await ssg.annunci.getAnnuncioByIdForEdit.prefetch({ id: check.data }); + await ssg.annunci.getAnnuncioById_rawImgUrls.prefetch({ id: check.data }); return { props: { diff --git a/apps/infoalloggi/src/pages/area-riservata/admin/scheda-annuncio-stampa/[id].tsx b/apps/infoalloggi/src/pages/area-riservata/admin/scheda-annuncio-stampa/[id].tsx new file mode 100644 index 0000000..0328f0a --- /dev/null +++ b/apps/infoalloggi/src/pages/area-riservata/admin/scheda-annuncio-stampa/[id].tsx @@ -0,0 +1,91 @@ +import type { GetServerSideProps } from "next"; +import { AreaRiservataLayout } from "~/components/Layout"; +import { LoadingPage } from "~/components/loading"; +import { SchedaAnnuncioStampabile } from "~/components/schedaAnnuncioStampabile"; +import { Status500 } from "~/components/status-page"; +import type { NextPageWithLayout } from "~/pages/_app"; +import type { AnnunciId } from "~/schemas/public/Annunci"; +import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper"; +import { zAnnuncioId } from "~/server/utils/zod_types"; +import { api } from "~/utils/api"; + +type PageProps = { + id: AnnunciId; +}; + +const SchedaAnnuncioPage: NextPageWithLayout = ({ + id, +}: PageProps) => { + const { data, isLoading } = api.annunci.getAnnuncioById_rawImgUrls.useQuery({ + id, + }); + + if (isLoading) { + return ; + } + if (!data) { + return ; + } + return ( +
+ +
+ ); +}; + +SchedaAnnuncioPage.getLayout = function getLayout(page) { + return ( + + {page} + + ); +}; + +export default SchedaAnnuncioPage; + +export const getServerSideProps = (async (context) => { + const id = context.params?.id; + + if (typeof id !== "string") { + console.error("Error: id is not a string"); + return { + redirect: { + destination: "/500", + permanent: false, + }, + }; + } + + const parsed = zAnnuncioId.safeParse(parseInt(id)); + if (!parsed.success) { + console.error("Error parsing ordineId", parsed.error); + return { + redirect: { + destination: "/500", + permanent: false, + }, + }; + } + + const access_token = context.req.cookies.access_token; + + const helper = await TrpcAuthedFetchingIstance({ access_token }); + if (helper) { + await helper.trpc.annunci.getAnnuncioById_rawImgUrls.prefetch({ + id: parsed.data, + }); + + return { + props: { + id: parsed.data, + trpcState: helper.trpc.dehydrate(), + }, + }; + } + return { + redirect: { + destination: "/500", + permanent: false, + }, + }; +}) satisfies GetServerSideProps; diff --git a/apps/infoalloggi/src/server/api/routers/annunci.ts b/apps/infoalloggi/src/server/api/routers/annunci.ts index 1c521c0..091dc8f 100644 --- a/apps/infoalloggi/src/server/api/routers/annunci.ts +++ b/apps/infoalloggi/src/server/api/routers/annunci.ts @@ -10,7 +10,7 @@ import { editAnnuncioHandler, get_AnnunciPositionsHandler, getAnnunciByCod, - getAnnunciById, + getAnnunciById_rawImgUrls, getAnnunciListHandler, getAnnunciMetaByCod, getCodici_AnnunciHandler, @@ -45,15 +45,16 @@ export const annunciRouter = createTRPCRouter({ .query(async ({ input }) => { return await getAnnunciByCod({ ...input }); }), - getAnnuncioByIdForEdit: publicProcedure + getAnnuncioById_rawImgUrls: publicProcedure .input( z.object({ id: zAnnuncioId, }), ) .query(async ({ input }) => { - return await getAnnunciById({ ...input }); + return await getAnnunciById_rawImgUrls({ ...input }); }), + getAnnuncioMeta: publicProcedure .input( z.object({ diff --git a/apps/infoalloggi/src/server/controllers/annunci.controller.ts b/apps/infoalloggi/src/server/controllers/annunci.controller.ts index 406d595..0773ac1 100644 --- a/apps/infoalloggi/src/server/controllers/annunci.controller.ts +++ b/apps/infoalloggi/src/server/controllers/annunci.controller.ts @@ -116,7 +116,7 @@ export const getAnnunciMetaByCod = async ({ cod }: { cod: string }) => { } }; -export const getAnnunciById = async ({ +export const getAnnunciById_rawImgUrls = async ({ id, }: { id: AnnunciId;