From 243148267bba79b913c064d6246042461680a37a Mon Sep 17 00:00:00 2001 From: Marco Pedone Date: Sun, 24 Aug 2025 15:47:08 +0200 Subject: [PATCH] feat: implement TabRicerca component for user service search and integrate collapsible functionality --- .../components/area-riservata/dashboard.tsx | 11 +- .../src/components/servizio/main.tsx | 269 +++++++++++++++++- .../components/servizio/servizio_actions.tsx | 55 +++- .../src/components/tables/ricerca-table.tsx | 109 +++++++ .../admin/user-view/ricerca/[userId].tsx | 13 +- apps/infoalloggi/src/styles/globals.css | 23 ++ 6 files changed, 464 insertions(+), 16 deletions(-) create mode 100644 apps/infoalloggi/src/components/tables/ricerca-table.tsx diff --git a/apps/infoalloggi/src/components/area-riservata/dashboard.tsx b/apps/infoalloggi/src/components/area-riservata/dashboard.tsx index 5e4b12f..d528620 100644 --- a/apps/infoalloggi/src/components/area-riservata/dashboard.tsx +++ b/apps/infoalloggi/src/components/area-riservata/dashboard.tsx @@ -1,7 +1,6 @@ import { api } from "~/utils/api"; import { LoadingPage } from "~/components/loading"; import type { UsersId } from "~/schemas/public/Users"; -import { ServizioContainer } from "~/components/servizio/main"; import { AccordionComp } from "~/components/accordionComp"; import { useTranslation } from "~/providers/I18nProvider"; import TimeserieBarChart from "~/components/timeserieBarChart"; @@ -13,6 +12,7 @@ import { CardTitle, } from "~/components/ui/card"; import TimeserieBarChartStacked from "~/components/timeserieBarChartStacked"; +import { TabRicerca } from "~/components/tables/ricerca-table"; export const AdminDashboard = () => { const { data: stats, isLoading } = api.stats.adminDashStats.useQuery(); @@ -66,8 +66,8 @@ export const AdminDashboard = () => { }; export const UserDashboard = ({ userId }: { userId: UsersId }) => { - const { data: servizi, isLoading: loadingServizi } = - api.servizio.getAllServizioAnnunci.useQuery({ userId }); + // const { data: servizi, isLoading: loadingServizi } = + // api.servizio.getAllServizioAnnunci.useQuery({ userId }); const { t } = useTranslation(); return (
@@ -79,7 +79,8 @@ export const UserDashboard = ({ userId }: { userId: UsersId }) => {
- {loadingServizi ? ( + + {/* {loadingServizi ? ( ) : ( servizi?.map((servizio, idx) => ( @@ -90,7 +91,7 @@ export const UserDashboard = ({ userId }: { userId: UsersId }) => { isAdmin={false} /> )) - )} + )} */}
{ + const { servizio, isAdmin, userId } = useServizio(); + const utils = api.useUtils(); + const { mutate: updateServizio } = api.servizio.updateServizio.useMutation({ + onSuccess: async () => { + toast.success("Servizio modificato con successo"); + await utils.servizio.getAllServizioAnnunci.invalidate({ userId }); + }, + onError: (error) => { + toast.error(error.message); + }, + }); + + const router = useRouter(); + useEffect(() => { + const id = router.asPath.split("#")[1]; + if (id) { + document.getElementById(id)?.scrollIntoView({ + behavior: "smooth", + }); + } + }, []); + + if (servizio.isInterrotto) { + return ( + +
+ + + Cerco Affitto {servizio.tipologia} + + + +

+ aggiunto il{" "} + {servizio.created_at.toLocaleDateString("it", { + year: "numeric", + month: "2-digit", + day: "2-digit", + })} +

+
+
+ + } + content={ + <> +

Servizio interrotto

+

+ Non è possibile riutilizzare questo servizio, poichè è stato + interrotto. +

+ + } + /> + ); + } + + if (!servizio.isOkAcconto || servizio.decorrenza === null) { + return ( + + {/*
+ + + Cerco Affitto {servizio.tipologia} + + +

Servizio non attivo

+
+
*/} + + Servizio non attivo + + + + } + content={ +
+
+ + + + {isAdmin && ( + + )} +
+ {isAdmin && ( + + )} +
+ } + /> + ); + } + const annuncioConfermato = servizio.annunci.filter( + (a) => a.accettato_conferma_at !== null, + ); + + if (servizio.isOkSaldo) { + return ( + + {/*
+ + + Cerco Affitto {servizio.tipologia} + + + +

+ aggiunto il{" "} + {servizio.created_at.toLocaleDateString("it", { + year: "numeric", + month: "2-digit", + day: "2-digit", + })} +

+
+
*/} + + + + } + content={ + <> + {annuncioConfermato.map((data) => { + return ( + + + + ); + })} + + } + /> + ); + } + + const openContattiCount = servizio.annunci.filter( + (a) => a.open_contatti_at !== null, + ).length; + + const annunciInConferma = servizio.annunci.filter( + (a) => a.user_confirmed_at !== null, + ); + const annunciNotInConferma = servizio.annunci.filter( + (a) => a.user_confirmed_at === null, + ); + + return ( + + {/*
+ + + Cerco Affitto {servizio.tipologia} + + + +

+ aggiunto il{" "} + {servizio.created_at.toLocaleDateString("it", { + year: "numeric", + month: "2-digit", + day: "2-digit", + })} +

+
+
*/} + + + + } + content={ + <> +
+
+
+ + Contatti sbloccati +
+ {openContattiCount} / 10 +
+ +
+ + + + {annuncioConfermato.length > 0 && ( +
+
+ + Saldi in attesa: +
+ {servizio.annunci + .filter((a) => a.accettato_conferma_at !== null) + .map((a) => ( +
+

+ {a.codice} - confermato il:{" "} + {new Date(a.accettato_conferma_at!).toLocaleDateString( + "it", + { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + }, + )} +

+ +
+ ))} +
+ )} + +
+ + 0} + annunci={annunciNotInConferma} + /> + +
+ + } + /> + ); +}; + const ServizioMain = () => { const { servizio, isAdmin, userId } = useServizio(); const utils = api.useUtils(); diff --git a/apps/infoalloggi/src/components/servizio/servizio_actions.tsx b/apps/infoalloggi/src/components/servizio/servizio_actions.tsx index 63dc077..2a7c3c7 100644 --- a/apps/infoalloggi/src/components/servizio/servizio_actions.tsx +++ b/apps/infoalloggi/src/components/servizio/servizio_actions.tsx @@ -25,7 +25,7 @@ import { AlertDialogTitle, AlertDialogTrigger, } from "~/components/ui/alert-dialog"; -import { Calculator, ClockAlert, Plus, Wrench } from "lucide-react"; +import { Bug, Calculator, ClockAlert, Plus, Wrench } from "lucide-react"; import { FormNewServizio, type FormValues } from "~/forms/FormNewServizio"; import { Credenza, @@ -45,6 +45,11 @@ import { FormEditServizio, type FormValues as EditFormValues, } from "~/forms/FormEditServizioAdmin"; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "~/components/ui/collapsible"; export const ServizioActions = () => { const { servizio, isAdmin, userId } = useServizio(); @@ -74,6 +79,36 @@ export const ServizioActions = () => { ); }; + +export const ServizioActions2 = () => { + const { servizio, isAdmin, userId } = useServizio(); + + const canUserEdit = + servizio.isOkAcconto && + servizio.decorrenza !== null && + !servizio.annunci.some((a) => a.user_confirmed_at !== null); + + if (!isAdmin && !canUserEdit) { + return null; // If the user is not an admin and cannot edit, do not render the actions + } + return ( +
+ {(isAdmin || canUserEdit) && ( +
+ Azioni: + + +
+ )} + {isAdmin && ( +
+ + +
+ )} +
+ ); +}; export const AddAnnuncio = ({ servizioId, userId, @@ -315,7 +350,7 @@ const EditPreferenze = () => { }; const EditServizioAdmin = () => { - const { servizioId, userId } = useServizio(); + const { servizioId, userId, servizio } = useServizio(); const [open, setOpen] = useState(false); const { data, isLoading } = api.servizio.getServizio.useQuery({ servizioId }); const utils = api.useUtils(); @@ -362,12 +397,26 @@ const EditServizioAdmin = () => { Modifica - + {isLoading ? ( ) : ( )} + + + + + + {(() => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { annunci, ...rest } = servizio; + return
{JSON.stringify(rest, null, 2)}
; + })()} +
+
diff --git a/apps/infoalloggi/src/components/tables/ricerca-table.tsx b/apps/infoalloggi/src/components/tables/ricerca-table.tsx new file mode 100644 index 0000000..1edc093 --- /dev/null +++ b/apps/infoalloggi/src/components/tables/ricerca-table.tsx @@ -0,0 +1,109 @@ +import type { UsersId } from "~/schemas/public/Users"; +import { api } from "~/utils/api"; +import { LoadingPage } from "~/components/loading"; +import { Package } from "lucide-react"; +import { ServizioProvider } from "~/providers/ServizioProvider"; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "~/components/ui/collapsible"; +import { useState } from "react"; +import type { ServizioData } from "~/server/controllers/servizio.controller"; +import { ServizioContent } from "~/components/servizio/main"; + +export const TabRicerca = ({ + userId, + isAdmin, +}: { + userId: UsersId; + isAdmin: boolean; +}) => { + const { data, isLoading } = api.servizio.getAllServizioAnnunci.useQuery({ + userId, + }); + + if (isLoading) return ; + if (!data || data.length === 0) { + return ( +
+ Nessun servizio attualmente inserito +
+ ); + } + + return ( +
+ {data.map((servizio, idx) => { + return ( + + ); + })} +
+ ); +}; + +const Row = ({ + servizio, + userId, + isAdmin, +}: { + servizio: ServizioData; + userId: UsersId; + isAdmin: boolean; +}) => { + const [isOpen, setIsOpen] = useState(false); + return ( + + +
+ +
+ {isOpen ? "👇" : "👉"} +
+
+ + Affitto {servizio.tipologia} +
+
+ {servizio.isInterrotto ? ( + Interrotto + ) : servizio.isOkAcconto && servizio.decorrenza !== null ? ( + Attivo + ) : ( + Inattivo + )} +
+
+ {servizio.created_at.toLocaleDateString("it", { + month: "short", + day: "2-digit", + })} +
+
+
+ + + + + + +
+
+ ); +}; diff --git a/apps/infoalloggi/src/pages/area-riservata/admin/user-view/ricerca/[userId].tsx b/apps/infoalloggi/src/pages/area-riservata/admin/user-view/ricerca/[userId].tsx index e75189f..427ac24 100644 --- a/apps/infoalloggi/src/pages/area-riservata/admin/user-view/ricerca/[userId].tsx +++ b/apps/infoalloggi/src/pages/area-riservata/admin/user-view/ricerca/[userId].tsx @@ -1,12 +1,10 @@ -import { LoadingPage } from "~/components/loading"; import { AreaRiservataLayoutUserView } from "~/components/Layout"; import type { GetStaticProps } from "next"; import type { NextPageWithLayout } from "~/pages/_app"; import type { UsersId } from "~/schemas/public/Users"; -import { api } from "~/utils/api"; import { zUserId } from "~/server/utils/zod_types"; -import { ServizioContainer } from "~/components/servizio/main"; import { AnnunciRichiesti } from "~/components/servizio/servizio_annunci_accordions"; +import { TabRicerca } from "~/components/tables/ricerca-table"; type RicercaUserProps = { userId: UsersId; @@ -15,8 +13,8 @@ type RicercaUserProps = { const RicercaUser: NextPageWithLayout = ({ userId, }: RicercaUserProps) => { - const { data: servizi, isLoading: loadingServizi } = - api.servizio.getAllServizioAnnunci.useQuery({ userId }); + // const { data: servizi, isLoading: loadingServizi } = + // api.servizio.getAllServizioAnnunci.useQuery({ userId }); return (
@@ -27,7 +25,8 @@ const RicercaUser: NextPageWithLayout = ({
- {loadingServizi ? ( + + {/* {loadingServizi ? ( ) : ( servizi?.map((servizio, idx) => ( @@ -38,7 +37,7 @@ const RicercaUser: NextPageWithLayout = ({ isAdmin /> )) - )} + )} */}
); diff --git a/apps/infoalloggi/src/styles/globals.css b/apps/infoalloggi/src/styles/globals.css index d824901..c55504a 100644 --- a/apps/infoalloggi/src/styles/globals.css +++ b/apps/infoalloggi/src/styles/globals.css @@ -100,8 +100,31 @@ } } + @keyframes collapsible-down { + 0% { + height: 0; + } + + 100% { + height: var(--radix-collapsible-content-height); + } + } + + @keyframes collapsible-up { + 0% { + height: var(--radix-collapsible-content-height); + } + + 100% { + height: 0; + } + } + --animate-accordion-down: accordion-down 0.3s ease-out; --animate-accordion-up: accordion-up 0.3s ease-out; + --animate-collapsible-down: collapsible-down 0.3s ease-out; + --animate-collapsible-up: collapsible-up 0.3s ease-in; + @keyframes caret-blink {