From ac1859e88f2e00074f6ac7c290ae4a4124ebfa0c Mon Sep 17 00:00:00 2001 From: Marco Pedone Date: Wed, 25 Feb 2026 15:30:53 +0100 Subject: [PATCH] feat: add service management features and update Italian translations - Introduced new service status translations in Italian. - Added service detail and management components for user and admin views. - Implemented API endpoints for fetching service data and announcements. - Enhanced service data handling with improved date parsing and formatting. - Created new pages for service details accessible by both users and admins. - Updated database queries to support new service functionalities. --- .../annuncio_interactions.tsx | 53 ++- .../components/area-riservata/dashboard.tsx | 14 +- .../area-riservata/documenti_personali.tsx | 53 ++- .../src/components/chat/chat-bottombar.tsx | 2 +- .../src/components/chat/chat-sidebar.tsx | 2 +- .../components/servizio/annuncio_actions.tsx | 138 ++++-- .../src/components/servizio/annuncio_card.tsx | 4 +- .../servizio/annuncio_dettaglio.tsx | 13 +- .../servizio/compatibili_dialog.tsx | 21 +- .../src/components/servizio/conferma.tsx | 38 +- .../src/components/servizio/main.tsx | 372 --------------- .../components/servizio/modale_contatti.tsx | 35 +- .../components/servizio/servizi_header.tsx | 3 +- .../src/components/servizio/servizio.tsx | 448 ++++++++++++++++++ .../components/servizio/servizio_actions.tsx | 298 +++++------- .../servizio/servizio_annunci_accordions.tsx | 3 +- .../src/components/tables/ricerca-table.tsx | 104 ---- apps/infoalloggi/src/i18n/en.ts | 41 ++ apps/infoalloggi/src/i18n/it.ts | 42 ++ apps/infoalloggi/src/i18n/locales.ts | 39 ++ .../admin/user-view/ricerca/[userId].tsx | 12 +- .../admin/user-view/servizio/[...slug].tsx | 108 +++++ .../area-riservata/servizio/[servizioId].tsx | 99 ++++ .../src/server/api/routers/servizio.ts | 10 + .../server/controllers/servizio.controller.ts | 270 ++++++++++- apps/infoalloggi/src/server/db.ts | 1 + apps/infoalloggi/src/utils/kysely-helper.ts | 9 + 27 files changed, 1446 insertions(+), 786 deletions(-) delete mode 100644 apps/infoalloggi/src/components/servizio/main.tsx create mode 100644 apps/infoalloggi/src/components/servizio/servizio.tsx delete mode 100644 apps/infoalloggi/src/components/tables/ricerca-table.tsx create mode 100644 apps/infoalloggi/src/pages/area-riservata/admin/user-view/servizio/[...slug].tsx create mode 100644 apps/infoalloggi/src/pages/area-riservata/servizio/[servizioId].tsx diff --git a/apps/infoalloggi/src/components/annuncio-interactions/annuncio_interactions.tsx b/apps/infoalloggi/src/components/annuncio-interactions/annuncio_interactions.tsx index 0f80258..eeb466c 100644 --- a/apps/infoalloggi/src/components/annuncio-interactions/annuncio_interactions.tsx +++ b/apps/infoalloggi/src/components/annuncio-interactions/annuncio_interactions.tsx @@ -5,6 +5,7 @@ import { ContattoAnnuncio } from "~/components/annuncio-interactions/contatto_mo import LoadingButton from "~/components/custom_ui/loading-button"; import { Button } from "~/components/ui/button"; import { useAnnuncio } from "~/providers/AnnuncioProvider"; +import { useTranslation } from "~/providers/I18nProvider"; import { useServizio } from "~/providers/ServizioProvider"; import type { SessionContextType } from "~/providers/SessionProvider"; import type { AnnunciId } from "~/schemas/public/Annunci"; @@ -19,11 +20,13 @@ export const AnnuncioInteractions = ({ disabled?: boolean; }) => { const { id, tipo } = useAnnuncio(); - + const { locale } = useTranslation(); if (disabled) { return (
- Richieste Temporaneamente disattivate + {locale === "it" + ? "Richieste Temporaneamente disattivate" + : "Requests Temporarily Disabled"}
); } @@ -37,7 +40,7 @@ export const AnnuncioInteractions = ({ userId={session.user.id} /> ) : ( - Errore + {locale === "it" ? "Errore" : "Error"} ) ) : (
@@ -70,6 +73,7 @@ const ServizioInteraction = ({ tipologia: string; annuncioId: AnnunciId; }) => { + const { locale } = useTranslation(); const { data: servizio, isLoading } = api.servizio.AnnuncioServizioTipologiaMatch.useQuery({ annuncioId, @@ -85,7 +89,11 @@ const ServizioInteraction = ({ ) { return (
-

Non hai un servizio attivo

+

+ {locale === "it" + ? "Non hai un servizio attivo" + : "You do not have an active service"} +

); } @@ -94,14 +102,21 @@ const ServizioInteraction = ({ return (
- Annuncio già salvato! + {locale === "it" ? "Annuncio già salvato!" : "Listing already saved!"}
@@ -116,6 +131,7 @@ const InteressatoButtonUserOnly = ({ }: { annuncioId: AnnunciId; }) => { + const { locale } = useTranslation(); const { data: hasInterest, isLoading } = api.intrests.hasUserInterest.useQuery({ annuncioId, @@ -126,7 +142,11 @@ const InteressatoButtonUserOnly = ({ await utils.intrests.hasUserInterest.invalidate({ annuncioId, }); - toast.success("Richiesta di interesse inviata con successo!"); + toast.success( + locale === "it" + ? "Richiesta di interesse inviata con successo!" + : "Interest request sent successfully!", + ); }, }); @@ -134,7 +154,7 @@ const InteressatoButtonUserOnly = ({ return ( ); } @@ -142,14 +162,16 @@ const InteressatoButtonUserOnly = ({ return ( - Hai già mandato una richiesta + {locale === "it" + ? "Hai già mandato una richiesta" + : "You have already sent a request"} ); } return ( ); }; @@ -171,6 +193,7 @@ export const InteressatoButtonServizio = ({ annuncioId: AnnunciId; }) => { const { isAdmin, servizioId, userId } = useServizio(); + const { locale } = useTranslation(); const utils = api.useUtils(); const invalidateAll = async () => { @@ -227,7 +250,11 @@ export const InteressatoButtonServizio = ({ variant="info" > - {isAdmin ? "Aggiungi" : "Sono interessato"} + {isAdmin + ? "Aggiungi" + : locale === "it" + ? "Sono interessato" + : "I'm interested"} ); }; diff --git a/apps/infoalloggi/src/components/area-riservata/dashboard.tsx b/apps/infoalloggi/src/components/area-riservata/dashboard.tsx index ce59cd1..10637db 100644 --- a/apps/infoalloggi/src/components/area-riservata/dashboard.tsx +++ b/apps/infoalloggi/src/components/area-riservata/dashboard.tsx @@ -2,7 +2,6 @@ import { CircleHelp } from "lucide-react"; import dynamic from "next/dynamic"; import { AccordionComp } from "~/components/accordionComp"; import { LoadingPage } from "~/components/loading"; -import { TabRicerca } from "~/components/tables/ricerca-table"; import { Card, CardContent, @@ -22,13 +21,14 @@ import { CredenzaTitle, CredenzaTrigger, } from "../custom_ui/credenza"; +import { ServizioList } from "../servizio/servizio"; import { Button } from "../ui/button"; const TimeserieBarChart = dynamic( () => import("~/components/timeserieBarChart").then((mod) => mod.default), { ssr: false, - loading: () =>
, + loading: () =>
, }, ); @@ -37,7 +37,7 @@ const TimeserieBarChartStacked = dynamic( import("~/components/timeserieBarChartStacked").then((mod) => mod.default), { ssr: false, - loading: () =>
, + loading: () =>
, }, ); @@ -94,12 +94,18 @@ export const AdminDashboard = () => { export const UserDashboard = ({ userId }: { userId: UsersId }) => { const { t } = useTranslation(); + const { data, isLoading } = api.servizio.getAllServizioAnnunci.useQuery({ + userId, + }); + + if (isLoading) return ; + return (

Le tue ricerche

- +
diff --git a/apps/infoalloggi/src/components/area-riservata/documenti_personali.tsx b/apps/infoalloggi/src/components/area-riservata/documenti_personali.tsx index 1bb8ba5..ff2a961 100644 --- a/apps/infoalloggi/src/components/area-riservata/documenti_personali.tsx +++ b/apps/infoalloggi/src/components/area-riservata/documenti_personali.tsx @@ -4,6 +4,7 @@ import Link from "next/link"; import { useState } from "react"; import toast from "react-hot-toast"; import { getStorageUrl } from "~/lib/storage_utils"; +import { useTranslation } from "~/providers/I18nProvider"; import { useSession } from "~/providers/SessionProvider"; import type { UsersId } from "~/schemas/public/Users"; import type { UsersStorageUserStorageId } from "~/schemas/public/UsersStorage"; @@ -29,6 +30,7 @@ export const DocumentiPersonali = ({ userData: CompleteUserData; }) => { const utils = api.useUtils(); + const { locale } = useTranslation(); const { mutate, isPending } = api.users.editUserAnagrafica.useMutation({ onSuccess: async () => { await utils.users.getClientProfilo.invalidate({ @@ -56,12 +58,19 @@ export const DocumentiPersonali = ({ return ( - Documenti personali + + {locale === "it" ? "Documenti personali" : "Personal Documents"} + -

I tuoi documenti sono necessari per usufruire del servizio.

- Nel caso di un unico documento (es: scansione fronte e retro del - documento) caricarlo 2 volte. + {locale === "it" + ? "I tuoi documenti sono necessari per usufruire del servizio." + : "Your documents are required to use the service."} +

+

+ {locale === "it" + ? "Nel caso di un unico documento (es: scansione fronte e retro del documento) caricarlo 2 volte." + : "In case of a single document (e.g., front and back scan of the document), upload it twice."}

@@ -100,10 +109,11 @@ export const DocumentiPersonali = ({

- I tuoi dati saranno conservati solamente per la durata del servizio, - in conformità con la nostra{" "} + {locale === "it" + ? "I tuoi dati saranno conservati solamente per la durata del servizio, in conformità con la nostra " + : "Your data will be stored only for the duration of the service, in accordance with our "} - Informativa sulla Privacy + {locale === "it" ? "Informativa sulla Privacy" : "Privacy Policy"}

@@ -133,6 +143,7 @@ export const DocumentiUploadSection = ({ isPending: boolean; caricatoNote?: boolean; }) => { + const { locale } = useTranslation(); const [imageError, setImageError] = useState(false); if (document?.storageId) { return ( @@ -141,7 +152,9 @@ export const DocumentiUploadSection = ({ {caricatoNote && (
- Documento caricato + + {locale === "it" ? "Documento caricato" : "Document uploaded"} +
)}
@@ -165,7 +178,11 @@ export const DocumentiUploadSection = ({ src={getStorageUrl({ storageId: document.storageId })} title="doc" > -

Il tuo browser non supporta gli iframe.

+

+ {locale === "it" + ? "Il tuo browser non supporta gli iframe." + : "Your browser does not support iframes."} +

)} @@ -175,23 +192,31 @@ export const DocumentiUploadSection = ({ target="_blank" > {onRemove && ( diff --git a/apps/infoalloggi/src/components/chat/chat-bottombar.tsx b/apps/infoalloggi/src/components/chat/chat-bottombar.tsx index 70182bd..8fbe306 100644 --- a/apps/infoalloggi/src/components/chat/chat-bottombar.tsx +++ b/apps/infoalloggi/src/components/chat/chat-bottombar.tsx @@ -94,7 +94,7 @@ export default function ChatBottombar({ const isMobile = useMediaQuery("(min-width: 426px)"); return ( -
+
diff --git a/apps/infoalloggi/src/components/chat/chat-sidebar.tsx b/apps/infoalloggi/src/components/chat/chat-sidebar.tsx index 2f8adde..d354aec 100644 --- a/apps/infoalloggi/src/components/chat/chat-sidebar.tsx +++ b/apps/infoalloggi/src/components/chat/chat-sidebar.tsx @@ -144,7 +144,7 @@ export const ChatSidebar = ({ chatId }: { chatId: ChatsChatid | null }) => { />
-