Refactor session handling: implement useEnforcedSession for better session validation across components
This commit is contained in:
parent
1d70ce9a44
commit
485bcda0d3
11 changed files with 85 additions and 46 deletions
|
|
@ -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 (
|
||||
<div className="flex h-full min-h-screen flex-col text-clip">
|
||||
<SiteHeader />
|
||||
|
||||
<main className="flex h-full flex-1 overflow-auto">
|
||||
<div className="flex h-auto w-full flex-col md:flex-row">
|
||||
<LoadingPage />;
|
||||
</div>
|
||||
</main>
|
||||
{!noFooter && <MiniFooter />}
|
||||
</div>
|
||||
);
|
||||
if (session.status !== "success" || !session.user) {
|
||||
window.location.reload();
|
||||
return (
|
||||
<div className="flex h-full min-h-screen flex-col text-clip">
|
||||
<SiteHeader />
|
||||
|
||||
<main className="flex h-full flex-1 overflow-auto">
|
||||
<div className="flex h-auto w-full flex-col md:flex-row">
|
||||
<LoadingPage />;
|
||||
</div>
|
||||
</main>
|
||||
{!noFooter && <MiniFooter />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-full min-h-screen flex-col text-clip">
|
||||
<SiteHeader />
|
||||
|
|
@ -77,9 +111,11 @@ export const AreaRiservataLayout = ({
|
|||
<main className="flex h-full flex-1 overflow-auto">
|
||||
<div className="flex h-auto w-full flex-col md:flex-row">
|
||||
{noSidebar ? null : (
|
||||
<Sidebar isAdmin={session.user?.isAdmin || false} />
|
||||
<Sidebar isAdmin={session.user.isAdmin || false} />
|
||||
)}
|
||||
{children}
|
||||
<EnforcedSessionContext.Provider value={session as ValidSession}>
|
||||
{children}
|
||||
</EnforcedSessionContext.Provider>
|
||||
</div>
|
||||
</main>
|
||||
{!noFooter && <MiniFooter />}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,12 @@ const AdminChats: NextPageWithLayout = () => {
|
|||
isLoadingInactiveUsers
|
||||
)
|
||||
return <LoadingPage />;
|
||||
if (!session || !session.user || !activeChats || !inactiveUsers)
|
||||
return <Status500 />;
|
||||
|
||||
if (session.status !== "success" || !session.user) {
|
||||
window.location.reload();
|
||||
return <LoadingPage />;
|
||||
}
|
||||
if (!activeChats || !inactiveUsers) return <Status500 />;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -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 <LoadingPage />;
|
||||
if (!session || !session.user) return <Status500 />;
|
||||
const session = useEnforcedSession();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -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<AllegatoViewProps> = ({
|
|||
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<AllegatoViewProps> = ({
|
|||
},
|
||||
});
|
||||
|
||||
if (session.status === "pending" || isLoading) return <LoadingPage />;
|
||||
if (!session || !session.user) {
|
||||
console.error("Session not found or user not authenticated", session);
|
||||
if (isLoading) return <LoadingPage />;
|
||||
|
||||
return <Status500 />;
|
||||
}
|
||||
if (!fileInfos) return <DocNotFoundPage />;
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ export const getServerSideProps = (async (context) => {
|
|||
}
|
||||
return {
|
||||
redirect: {
|
||||
destination: "/login",
|
||||
destination: "/login?",
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 <LoadingPage />;
|
||||
if (!session || !session.user) return <Status500 />;
|
||||
const session = useEnforcedSession();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -23,7 +18,7 @@ const Comunicazioni: NextPageWithLayout = () => {
|
|||
|
||||
<div className="mx-auto max-w-7xl grow p-4">
|
||||
<div className="p-1">
|
||||
<h1 className="text-2xl font-bold text-primary">Comunicazioni</h1>
|
||||
<h1 className="text-primary text-2xl font-bold">Comunicazioni</h1>
|
||||
</div>
|
||||
|
||||
<EmailAccordion userId={session.user.id} />
|
||||
|
|
|
|||
|
|
@ -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 <LoadingPage />;
|
||||
if (!session || !session.user) return <Status500 />;
|
||||
const session = useEnforcedSession();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -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 <LoadingPage />;
|
||||
if (!session.user) return <Status500 />;
|
||||
const session = useEnforcedSession();
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
|
|
|
|||
|
|
@ -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 <LoadingPage />;
|
||||
if (!userData || !session.user) return <Status500 />;
|
||||
if (!userData) return <Status500 />;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -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<ValidSession | undefined>(
|
||||
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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,6 +36,11 @@ export const sessionSchema = z.object({
|
|||
|
||||
export type Session = z.infer<typeof sessionSchema>;
|
||||
|
||||
export type ValidSession = {
|
||||
user: Session;
|
||||
status: "success";
|
||||
};
|
||||
|
||||
interface CreateInnerContextOptions extends Partial<CreateNextContextOptions> {
|
||||
session: Session | null;
|
||||
res?: NextApiResponse;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue