From 485bcda0d36efd460eb880a35ffff02a30f1d235 Mon Sep 17 00:00:00 2001 From: Marco Pedone Date: Wed, 20 Aug 2025 14:04:23 +0200 Subject: [PATCH] Refactor session handling: implement useEnforcedSession for better session validation across components --- apps/infoalloggi/src/components/Layout.tsx | 42 +++++++++++++++++-- .../src/pages/area-riservata/admin/chats.tsx | 8 +++- .../src/pages/area-riservata/allegati.tsx | 9 +--- .../allegato-view/[allegatoId].tsx | 11 ++--- .../src/pages/area-riservata/chat.tsx | 2 +- .../pages/area-riservata/comunicazioni.tsx | 11 ++--- .../src/pages/area-riservata/dashboard.tsx | 9 +--- .../src/pages/area-riservata/ordini.tsx | 7 +--- .../src/pages/area-riservata/profilo.tsx | 8 ++-- .../src/providers/SessionProvider.tsx | 19 ++++++++- apps/infoalloggi/src/server/api/trpc.ts | 5 +++ 11 files changed, 85 insertions(+), 46 deletions(-) diff --git a/apps/infoalloggi/src/components/Layout.tsx b/apps/infoalloggi/src/components/Layout.tsx index 7eb96a2..a2c8180 100644 --- a/apps/infoalloggi/src/components/Layout.tsx +++ b/apps/infoalloggi/src/components/Layout.tsx @@ -24,8 +24,13 @@ import { Sidebar } from "~/components/area-riservata/sidebar"; import type { UsersId } from "~/schemas/public/Users"; import toast from "react-hot-toast"; import { useRouter } from "next/router"; -import { useSession } from "~/providers/SessionProvider"; +import { + useSession, + EnforcedSessionContext, +} from "~/providers/SessionProvider"; import { WhatsAppIcon } from "~/components/svgs"; +import { LoadingPage } from "~/components/loading"; +import type { ValidSession } from "~/server/api/trpc"; interface Props { children: ReactNode; @@ -66,6 +71,35 @@ export const AreaRiservataLayout = ({ }); const session = useSession(); + if (session.status === "pending") + return ( +
+ + +
+
+ ; +
+
+ {!noFooter && } +
+ ); + if (session.status !== "success" || !session.user) { + window.location.reload(); + return ( +
+ + +
+
+ ; +
+
+ {!noFooter && } +
+ ); + } + return (
@@ -77,9 +111,11 @@ export const AreaRiservataLayout = ({
{noSidebar ? null : ( - + )} - {children} + + {children} +
{!noFooter && } diff --git a/apps/infoalloggi/src/pages/area-riservata/admin/chats.tsx b/apps/infoalloggi/src/pages/area-riservata/admin/chats.tsx index dcbbdf6..767eb0f 100644 --- a/apps/infoalloggi/src/pages/area-riservata/admin/chats.tsx +++ b/apps/infoalloggi/src/pages/area-riservata/admin/chats.tsx @@ -25,8 +25,12 @@ const AdminChats: NextPageWithLayout = () => { isLoadingInactiveUsers ) return ; - if (!session || !session.user || !activeChats || !inactiveUsers) - return ; + + if (session.status !== "success" || !session.user) { + window.location.reload(); + return ; + } + if (!activeChats || !inactiveUsers) return ; return ( <> diff --git a/apps/infoalloggi/src/pages/area-riservata/allegati.tsx b/apps/infoalloggi/src/pages/area-riservata/allegati.tsx index 5940e1d..62a87b4 100644 --- a/apps/infoalloggi/src/pages/area-riservata/allegati.tsx +++ b/apps/infoalloggi/src/pages/area-riservata/allegati.tsx @@ -1,17 +1,12 @@ import { useTranslation } from "~/providers/I18nProvider"; import type { NextPageWithLayout } from "~/pages/_app"; -import { useSession } from "~/providers/SessionProvider"; -import { LoadingPage } from "~/components/loading"; -import { Status500 } from "~/components/status-page"; +import { useEnforcedSession } from "~/providers/SessionProvider"; import { AreaRiservataLayout } from "~/components/Layout"; import Head from "next/head"; import { AllegatiComp } from "~/components/area-riservata/allegati"; const Allegati: NextPageWithLayout = () => { const { t } = useTranslation(); - const session = useSession(); - - if (session.status === "pending") return ; - if (!session || !session.user) return ; + const session = useEnforcedSession(); return ( <> diff --git a/apps/infoalloggi/src/pages/area-riservata/allegato-view/[allegatoId].tsx b/apps/infoalloggi/src/pages/area-riservata/allegato-view/[allegatoId].tsx index 436ff1d..02d0d1d 100644 --- a/apps/infoalloggi/src/pages/area-riservata/allegato-view/[allegatoId].tsx +++ b/apps/infoalloggi/src/pages/area-riservata/allegato-view/[allegatoId].tsx @@ -4,10 +4,9 @@ import Head from "next/head"; import { useState, type FormEvent } from "react"; import { AreaRiservataLayout } from "~/components/Layout"; import { LoadingPage } from "~/components/loading"; -import { Status500 } from "~/components/status-page"; import { Button } from "~/components/ui/button"; import type { NextPageWithLayout } from "~/pages/_app"; -import { useSession } from "~/providers/SessionProvider"; +import { useEnforcedSession } from "~/providers/SessionProvider"; import type { StorageindexId } from "~/schemas/public/Storageindex"; import { api } from "~/utils/api"; import toast from "react-hot-toast"; @@ -37,7 +36,7 @@ const AllegatoView: NextPageWithLayout = ({ allegatoId, }: AllegatoViewProps) => { const { t } = useTranslation(); - const session = useSession(); + const session = useEnforcedSession(); const { mutateAsync: getToken } = api.storage.getStorageToken.useMutation(); const { data: fileInfos, isLoading } = api.storage.getStorageFromId.useQuery({ storageId: allegatoId, @@ -63,12 +62,8 @@ const AllegatoView: NextPageWithLayout = ({ }, }); - if (session.status === "pending" || isLoading) return ; - if (!session || !session.user) { - console.error("Session not found or user not authenticated", session); + if (isLoading) return ; - return ; - } if (!fileInfos) return ; return ( diff --git a/apps/infoalloggi/src/pages/area-riservata/chat.tsx b/apps/infoalloggi/src/pages/area-riservata/chat.tsx index 63f2b68..5984933 100644 --- a/apps/infoalloggi/src/pages/area-riservata/chat.tsx +++ b/apps/infoalloggi/src/pages/area-riservata/chat.tsx @@ -76,7 +76,7 @@ export const getServerSideProps = (async (context) => { } return { redirect: { - destination: "/login", + destination: "/login?", permanent: false, }, }; diff --git a/apps/infoalloggi/src/pages/area-riservata/comunicazioni.tsx b/apps/infoalloggi/src/pages/area-riservata/comunicazioni.tsx index fa77f8d..12aa7ab 100644 --- a/apps/infoalloggi/src/pages/area-riservata/comunicazioni.tsx +++ b/apps/infoalloggi/src/pages/area-riservata/comunicazioni.tsx @@ -1,18 +1,13 @@ import Head from "next/head"; import { useTranslation } from "~/providers/I18nProvider"; -import { useSession } from "~/providers/SessionProvider"; +import { useEnforcedSession } from "~/providers/SessionProvider"; import { AreaRiservataLayout } from "~/components/Layout"; import type { NextPageWithLayout } from "~/pages/_app"; -import { Status500 } from "~/components/status-page"; -import { LoadingPage } from "~/components/loading"; import { EmailAccordion } from "~/components/area-riservata/comunicazioni"; const Comunicazioni: NextPageWithLayout = () => { const { t } = useTranslation(); - const session = useSession(); - - if (session.status === "pending") return ; - if (!session || !session.user) return ; + const session = useEnforcedSession(); return ( <> @@ -23,7 +18,7 @@ const Comunicazioni: NextPageWithLayout = () => {
-

Comunicazioni

+

Comunicazioni

diff --git a/apps/infoalloggi/src/pages/area-riservata/dashboard.tsx b/apps/infoalloggi/src/pages/area-riservata/dashboard.tsx index 938e747..13cd689 100644 --- a/apps/infoalloggi/src/pages/area-riservata/dashboard.tsx +++ b/apps/infoalloggi/src/pages/area-riservata/dashboard.tsx @@ -1,10 +1,8 @@ import Head from "next/head"; import { useTranslation } from "~/providers/I18nProvider"; -import { useSession } from "~/providers/SessionProvider"; +import { useEnforcedSession } from "~/providers/SessionProvider"; import { AreaRiservataLayout } from "~/components/Layout"; import type { NextPageWithLayout } from "~/pages/_app"; -import { Status500 } from "~/components/status-page"; -import { LoadingPage } from "~/components/loading"; import { AdminDashboard, UserDashboard, @@ -12,10 +10,7 @@ import { const Dashboard: NextPageWithLayout = () => { const { t } = useTranslation(); - const session = useSession(); - - if (session.status === "pending") return ; - if (!session || !session.user) return ; + const session = useEnforcedSession(); return ( <> diff --git a/apps/infoalloggi/src/pages/area-riservata/ordini.tsx b/apps/infoalloggi/src/pages/area-riservata/ordini.tsx index f8a3c85..b733995 100644 --- a/apps/infoalloggi/src/pages/area-riservata/ordini.tsx +++ b/apps/infoalloggi/src/pages/area-riservata/ordini.tsx @@ -5,16 +5,13 @@ import Head from "next/head"; import { api } from "~/utils/api"; import type { NextPageWithLayout } from "~/pages/_app"; import { Status500 } from "~/components/status-page"; -import { useSession } from "~/providers/SessionProvider"; +import { useEnforcedSession } from "~/providers/SessionProvider"; import type { UsersId } from "~/schemas/public/Users"; import { OrdiniTable } from "~/components/tables/orders-table"; const Ordini: NextPageWithLayout = () => { const { t } = useTranslation(); - const session = useSession(); - - if (session.status == "pending") return ; - if (!session.user) return ; + const session = useEnforcedSession(); return ( <> diff --git a/apps/infoalloggi/src/pages/area-riservata/profilo.tsx b/apps/infoalloggi/src/pages/area-riservata/profilo.tsx index 0d6ceee..8c7b0cc 100644 --- a/apps/infoalloggi/src/pages/area-riservata/profilo.tsx +++ b/apps/infoalloggi/src/pages/area-riservata/profilo.tsx @@ -1,5 +1,4 @@ import Head from "next/head"; -import { LoadingPage } from "~/components/loading"; import { useTranslation } from "~/providers/I18nProvider"; import { AreaRiservataLayout } from "~/components/Layout"; import type { NextPageWithLayout } from "~/pages/_app"; @@ -9,7 +8,7 @@ import { Status500 } from "~/components/status-page"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs"; import { ProfileFormAccount } from "~/forms/FormProfilo_Account"; import { ProfileFormAnagrafica } from "~/forms/FormProfilo_Anagrafica"; -import { useSession } from "~/providers/SessionProvider"; +import { useEnforcedSession } from "~/providers/SessionProvider"; import { Card, CardContent, @@ -18,15 +17,16 @@ import { CardTitle, } from "~/components/ui/card"; import { UserAvatar } from "~/components/user_avatar"; +import { LoadingPage } from "~/components/loading"; const Dashboard: NextPageWithLayout = () => { const { t } = useTranslation(); const { data: userData, isLoading } = api.users.getClientProfilo.useQuery({ id: undefined, }); - const session = useSession(); + const session = useEnforcedSession(); if (isLoading) return ; - if (!userData || !session.user) return ; + if (!userData) return ; return ( <> diff --git a/apps/infoalloggi/src/providers/SessionProvider.tsx b/apps/infoalloggi/src/providers/SessionProvider.tsx index d58f056..7a3cb07 100644 --- a/apps/infoalloggi/src/providers/SessionProvider.tsx +++ b/apps/infoalloggi/src/providers/SessionProvider.tsx @@ -6,7 +6,7 @@ import { type FC, type ReactNode, } from "react"; -import type { Session } from "~/server/api/trpc"; +import type { Session, ValidSession } from "~/server/api/trpc"; import { api } from "~/utils/api"; type SessionStatus = "pending" | "success" | "error"; export type SessionContextType = { @@ -66,3 +66,20 @@ export const SessionProvider: FC<{ children: ReactNode }> = ({ children }) => { }; export const useSession = () => useContext(SessionContext); + +export const EnforcedSessionContext = createContext( + undefined, +); +/** + * AreaRiservata specific session context. It ensures that the session is valid. + */ + +export const useEnforcedSession = () => { + const session = useContext(EnforcedSessionContext); + if (!session) { + throw new Error( + "useValidSession must be used within a ValidSessionProvider", + ); + } + return session; +}; diff --git a/apps/infoalloggi/src/server/api/trpc.ts b/apps/infoalloggi/src/server/api/trpc.ts index cbc7cbf..b8020df 100644 --- a/apps/infoalloggi/src/server/api/trpc.ts +++ b/apps/infoalloggi/src/server/api/trpc.ts @@ -36,6 +36,11 @@ export const sessionSchema = z.object({ export type Session = z.infer; +export type ValidSession = { + user: Session; + status: "success"; +}; + interface CreateInnerContextOptions extends Partial { session: Session | null; res?: NextApiResponse;