Files
sign/packages/lib/client-only/providers/session.tsx

112 lines
2.5 KiB
TypeScript
Raw Normal View History

2025-02-17 22:46:36 +11:00
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
2025-01-02 15:33:37 +11:00
import React from 'react';
2025-02-17 22:46:36 +11:00
import { useLocation } from 'react-router';
import { authClient } from '@documenso/auth/client';
2025-01-02 15:33:37 +11:00
import type { SessionUser } from '@documenso/auth/server/lib/session/session';
2025-02-17 22:46:36 +11:00
import { type TGetTeamsResponse } from '@documenso/lib/server-only/team/get-teams';
2025-01-02 15:33:37 +11:00
import type { Session } from '@documenso/prisma/client';
2025-02-17 22:46:36 +11:00
import { trpc } from '@documenso/trpc/client';
2025-01-02 15:33:37 +11:00
export type AppSession = {
session: Session;
user: SessionUser;
teams: TGetTeamsResponse;
};
interface SessionProviderProps {
children: React.ReactNode;
2025-02-17 22:46:36 +11:00
initialSession: AppSession | null;
}
interface SessionContextValue {
sessionData: AppSession | null;
refresh: () => Promise<void>;
2025-01-02 15:33:37 +11:00
}
2025-02-17 22:46:36 +11:00
const SessionContext = createContext<SessionContextValue | null>(null);
2025-01-02 15:33:37 +11:00
export const useSession = () => {
const context = useContext(SessionContext);
if (!context) {
throw new Error('useSession must be used within a SessionProvider');
}
2025-02-17 22:46:36 +11:00
if (!context.sessionData) {
throw new Error('Session not found');
}
return {
...context.sessionData,
2025-02-19 16:07:04 +11:00
refreshSession: context.refresh,
2025-02-17 22:46:36 +11:00
};
2025-01-02 15:33:37 +11:00
};
export const useOptionalSession = () => {
2025-02-17 22:46:36 +11:00
const context = useContext(SessionContext);
if (!context) {
throw new Error('useOptionalSession must be used within a SessionProvider');
}
return context;
2025-01-02 15:33:37 +11:00
};
2025-02-17 22:46:36 +11:00
export const SessionProvider = ({ children, initialSession }: SessionProviderProps) => {
const [session, setSession] = useState<AppSession | null>(initialSession);
const location = useLocation();
const refreshSession = useCallback(async () => {
const newSession = await authClient.getSession();
if (!newSession.isAuthenticated) {
setSession(null);
return;
}
const teams = await trpc.team.getTeams.query().catch(() => {
2025-02-19 16:07:04 +11:00
// Todo: (RR7) Log
2025-02-17 22:46:36 +11:00
return [];
});
setSession({
session: newSession.session,
user: newSession.user,
teams,
});
}, []);
useEffect(() => {
const onFocus = () => {
void refreshSession();
};
window.addEventListener('focus', onFocus);
return () => {
window.removeEventListener('focus', onFocus);
};
}, [refreshSession]);
/**
* Refresh session in background on navigation.
*/
useEffect(() => {
void refreshSession();
}, [location.pathname]);
return (
<SessionContext.Provider
value={{
sessionData: session,
refresh: refreshSession,
}}
>
{children}
</SessionContext.Provider>
);
2025-01-02 15:33:37 +11:00
};