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 type { UsersId } from "~/schemas/public/Users";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useSession } from "~/providers/SessionProvider";
|
import {
|
||||||
|
useSession,
|
||||||
|
EnforcedSessionContext,
|
||||||
|
} from "~/providers/SessionProvider";
|
||||||
import { WhatsAppIcon } from "~/components/svgs";
|
import { WhatsAppIcon } from "~/components/svgs";
|
||||||
|
import { LoadingPage } from "~/components/loading";
|
||||||
|
import type { ValidSession } from "~/server/api/trpc";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
|
@ -66,6 +71,35 @@ export const AreaRiservataLayout = ({
|
||||||
});
|
});
|
||||||
const session = useSession();
|
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 (
|
return (
|
||||||
<div className="flex h-full min-h-screen flex-col text-clip">
|
<div className="flex h-full min-h-screen flex-col text-clip">
|
||||||
<SiteHeader />
|
<SiteHeader />
|
||||||
|
|
@ -77,9 +111,11 @@ export const AreaRiservataLayout = ({
|
||||||
<main className="flex h-full flex-1 overflow-auto">
|
<main className="flex h-full flex-1 overflow-auto">
|
||||||
<div className="flex h-auto w-full flex-col md:flex-row">
|
<div className="flex h-auto w-full flex-col md:flex-row">
|
||||||
{noSidebar ? null : (
|
{noSidebar ? null : (
|
||||||
<Sidebar isAdmin={session.user?.isAdmin || false} />
|
<Sidebar isAdmin={session.user.isAdmin || false} />
|
||||||
)}
|
)}
|
||||||
|
<EnforcedSessionContext.Provider value={session as ValidSession}>
|
||||||
{children}
|
{children}
|
||||||
|
</EnforcedSessionContext.Provider>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
{!noFooter && <MiniFooter />}
|
{!noFooter && <MiniFooter />}
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,12 @@ const AdminChats: NextPageWithLayout = () => {
|
||||||
isLoadingInactiveUsers
|
isLoadingInactiveUsers
|
||||||
)
|
)
|
||||||
return <LoadingPage />;
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
import { useTranslation } from "~/providers/I18nProvider";
|
import { useTranslation } from "~/providers/I18nProvider";
|
||||||
import type { NextPageWithLayout } from "~/pages/_app";
|
import type { NextPageWithLayout } from "~/pages/_app";
|
||||||
import { useSession } from "~/providers/SessionProvider";
|
import { useEnforcedSession } from "~/providers/SessionProvider";
|
||||||
import { LoadingPage } from "~/components/loading";
|
|
||||||
import { Status500 } from "~/components/status-page";
|
|
||||||
import { AreaRiservataLayout } from "~/components/Layout";
|
import { AreaRiservataLayout } from "~/components/Layout";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { AllegatiComp } from "~/components/area-riservata/allegati";
|
import { AllegatiComp } from "~/components/area-riservata/allegati";
|
||||||
const Allegati: NextPageWithLayout = () => {
|
const Allegati: NextPageWithLayout = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const session = useSession();
|
const session = useEnforcedSession();
|
||||||
|
|
||||||
if (session.status === "pending") return <LoadingPage />;
|
|
||||||
if (!session || !session.user) return <Status500 />;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,9 @@ import Head from "next/head";
|
||||||
import { useState, type FormEvent } from "react";
|
import { useState, type FormEvent } from "react";
|
||||||
import { AreaRiservataLayout } from "~/components/Layout";
|
import { AreaRiservataLayout } from "~/components/Layout";
|
||||||
import { LoadingPage } from "~/components/loading";
|
import { LoadingPage } from "~/components/loading";
|
||||||
import { Status500 } from "~/components/status-page";
|
|
||||||
import { Button } from "~/components/ui/button";
|
import { Button } from "~/components/ui/button";
|
||||||
import type { NextPageWithLayout } from "~/pages/_app";
|
import type { NextPageWithLayout } from "~/pages/_app";
|
||||||
import { useSession } from "~/providers/SessionProvider";
|
import { useEnforcedSession } from "~/providers/SessionProvider";
|
||||||
import type { StorageindexId } from "~/schemas/public/Storageindex";
|
import type { StorageindexId } from "~/schemas/public/Storageindex";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
|
|
@ -37,7 +36,7 @@ const AllegatoView: NextPageWithLayout<AllegatoViewProps> = ({
|
||||||
allegatoId,
|
allegatoId,
|
||||||
}: AllegatoViewProps) => {
|
}: AllegatoViewProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const session = useSession();
|
const session = useEnforcedSession();
|
||||||
const { mutateAsync: getToken } = api.storage.getStorageToken.useMutation();
|
const { mutateAsync: getToken } = api.storage.getStorageToken.useMutation();
|
||||||
const { data: fileInfos, isLoading } = api.storage.getStorageFromId.useQuery({
|
const { data: fileInfos, isLoading } = api.storage.getStorageFromId.useQuery({
|
||||||
storageId: allegatoId,
|
storageId: allegatoId,
|
||||||
|
|
@ -63,12 +62,8 @@ const AllegatoView: NextPageWithLayout<AllegatoViewProps> = ({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (session.status === "pending" || isLoading) return <LoadingPage />;
|
if (isLoading) return <LoadingPage />;
|
||||||
if (!session || !session.user) {
|
|
||||||
console.error("Session not found or user not authenticated", session);
|
|
||||||
|
|
||||||
return <Status500 />;
|
|
||||||
}
|
|
||||||
if (!fileInfos) return <DocNotFoundPage />;
|
if (!fileInfos) return <DocNotFoundPage />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ export const getServerSideProps = (async (context) => {
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
destination: "/login",
|
destination: "/login?",
|
||||||
permanent: false,
|
permanent: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { useTranslation } from "~/providers/I18nProvider";
|
import { useTranslation } from "~/providers/I18nProvider";
|
||||||
import { useSession } from "~/providers/SessionProvider";
|
import { useEnforcedSession } from "~/providers/SessionProvider";
|
||||||
import { AreaRiservataLayout } from "~/components/Layout";
|
import { AreaRiservataLayout } from "~/components/Layout";
|
||||||
import type { NextPageWithLayout } from "~/pages/_app";
|
import type { NextPageWithLayout } from "~/pages/_app";
|
||||||
import { Status500 } from "~/components/status-page";
|
|
||||||
import { LoadingPage } from "~/components/loading";
|
|
||||||
import { EmailAccordion } from "~/components/area-riservata/comunicazioni";
|
import { EmailAccordion } from "~/components/area-riservata/comunicazioni";
|
||||||
|
|
||||||
const Comunicazioni: NextPageWithLayout = () => {
|
const Comunicazioni: NextPageWithLayout = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const session = useSession();
|
const session = useEnforcedSession();
|
||||||
|
|
||||||
if (session.status === "pending") return <LoadingPage />;
|
|
||||||
if (!session || !session.user) return <Status500 />;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -23,7 +18,7 @@ const Comunicazioni: NextPageWithLayout = () => {
|
||||||
|
|
||||||
<div className="mx-auto max-w-7xl grow p-4">
|
<div className="mx-auto max-w-7xl grow p-4">
|
||||||
<div className="p-1">
|
<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>
|
</div>
|
||||||
|
|
||||||
<EmailAccordion userId={session.user.id} />
|
<EmailAccordion userId={session.user.id} />
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { useTranslation } from "~/providers/I18nProvider";
|
import { useTranslation } from "~/providers/I18nProvider";
|
||||||
import { useSession } from "~/providers/SessionProvider";
|
import { useEnforcedSession } from "~/providers/SessionProvider";
|
||||||
import { AreaRiservataLayout } from "~/components/Layout";
|
import { AreaRiservataLayout } from "~/components/Layout";
|
||||||
import type { NextPageWithLayout } from "~/pages/_app";
|
import type { NextPageWithLayout } from "~/pages/_app";
|
||||||
import { Status500 } from "~/components/status-page";
|
|
||||||
import { LoadingPage } from "~/components/loading";
|
|
||||||
import {
|
import {
|
||||||
AdminDashboard,
|
AdminDashboard,
|
||||||
UserDashboard,
|
UserDashboard,
|
||||||
|
|
@ -12,10 +10,7 @@ import {
|
||||||
|
|
||||||
const Dashboard: NextPageWithLayout = () => {
|
const Dashboard: NextPageWithLayout = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const session = useSession();
|
const session = useEnforcedSession();
|
||||||
|
|
||||||
if (session.status === "pending") return <LoadingPage />;
|
|
||||||
if (!session || !session.user) return <Status500 />;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,13 @@ import Head from "next/head";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
import type { NextPageWithLayout } from "~/pages/_app";
|
import type { NextPageWithLayout } from "~/pages/_app";
|
||||||
import { Status500 } from "~/components/status-page";
|
import { Status500 } from "~/components/status-page";
|
||||||
import { useSession } from "~/providers/SessionProvider";
|
import { useEnforcedSession } from "~/providers/SessionProvider";
|
||||||
import type { UsersId } from "~/schemas/public/Users";
|
import type { UsersId } from "~/schemas/public/Users";
|
||||||
import { OrdiniTable } from "~/components/tables/orders-table";
|
import { OrdiniTable } from "~/components/tables/orders-table";
|
||||||
|
|
||||||
const Ordini: NextPageWithLayout = () => {
|
const Ordini: NextPageWithLayout = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const session = useSession();
|
const session = useEnforcedSession();
|
||||||
|
|
||||||
if (session.status == "pending") return <LoadingPage />;
|
|
||||||
if (!session.user) return <Status500 />;
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { LoadingPage } from "~/components/loading";
|
|
||||||
import { useTranslation } from "~/providers/I18nProvider";
|
import { useTranslation } from "~/providers/I18nProvider";
|
||||||
import { AreaRiservataLayout } from "~/components/Layout";
|
import { AreaRiservataLayout } from "~/components/Layout";
|
||||||
import type { NextPageWithLayout } from "~/pages/_app";
|
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 { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";
|
||||||
import { ProfileFormAccount } from "~/forms/FormProfilo_Account";
|
import { ProfileFormAccount } from "~/forms/FormProfilo_Account";
|
||||||
import { ProfileFormAnagrafica } from "~/forms/FormProfilo_Anagrafica";
|
import { ProfileFormAnagrafica } from "~/forms/FormProfilo_Anagrafica";
|
||||||
import { useSession } from "~/providers/SessionProvider";
|
import { useEnforcedSession } from "~/providers/SessionProvider";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
|
|
@ -18,15 +17,16 @@ import {
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "~/components/ui/card";
|
} from "~/components/ui/card";
|
||||||
import { UserAvatar } from "~/components/user_avatar";
|
import { UserAvatar } from "~/components/user_avatar";
|
||||||
|
import { LoadingPage } from "~/components/loading";
|
||||||
|
|
||||||
const Dashboard: NextPageWithLayout = () => {
|
const Dashboard: NextPageWithLayout = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { data: userData, isLoading } = api.users.getClientProfilo.useQuery({
|
const { data: userData, isLoading } = api.users.getClientProfilo.useQuery({
|
||||||
id: undefined,
|
id: undefined,
|
||||||
});
|
});
|
||||||
const session = useSession();
|
const session = useEnforcedSession();
|
||||||
if (isLoading) return <LoadingPage />;
|
if (isLoading) return <LoadingPage />;
|
||||||
if (!userData || !session.user) return <Status500 />;
|
if (!userData) return <Status500 />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import {
|
||||||
type FC,
|
type FC,
|
||||||
type ReactNode,
|
type ReactNode,
|
||||||
} from "react";
|
} from "react";
|
||||||
import type { Session } from "~/server/api/trpc";
|
import type { Session, ValidSession } from "~/server/api/trpc";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
type SessionStatus = "pending" | "success" | "error";
|
type SessionStatus = "pending" | "success" | "error";
|
||||||
export type SessionContextType = {
|
export type SessionContextType = {
|
||||||
|
|
@ -66,3 +66,20 @@ export const SessionProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSession = () => useContext(SessionContext);
|
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 Session = z.infer<typeof sessionSchema>;
|
||||||
|
|
||||||
|
export type ValidSession = {
|
||||||
|
user: Session;
|
||||||
|
status: "success";
|
||||||
|
};
|
||||||
|
|
||||||
interface CreateInnerContextOptions extends Partial<CreateNextContextOptions> {
|
interface CreateInnerContextOptions extends Partial<CreateNextContextOptions> {
|
||||||
session: Session | null;
|
session: Session | null;
|
||||||
res?: NextApiResponse;
|
res?: NextApiResponse;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue