diff --git a/packages/design-system/organisms/masthead/Authed.tsx b/packages/design-system/organisms/masthead/Authed.tsx index 7b176cc..bb21c09 100644 --- a/packages/design-system/organisms/masthead/Authed.tsx +++ b/packages/design-system/organisms/masthead/Authed.tsx @@ -32,7 +32,7 @@ export const Authed = (props: Props) => { - + ( - + - + + +
+ Quick Settings: + + + +
+ + ); +}; + +export default SetApi; diff --git a/packages/web/src/session-context/SessionContext.tsx b/packages/web/src/session-context/SessionContext.tsx new file mode 100644 index 0000000..0c859b5 --- /dev/null +++ b/packages/web/src/session-context/SessionContext.tsx @@ -0,0 +1,113 @@ +import { SessionData } from '@roleypoly/types'; +import * as React from 'react'; +import { useApiContext } from '../api-context/ApiContext'; + +type SessionContextT = { + session?: Omit, 'tokens'>; + setSession: (session?: SessionContextT['session']) => void; + authedFetch: (url: string, opts?: RequestInit) => Promise; +}; + +const SessionContext = React.createContext({ + setSession: () => {}, + authedFetch: async () => { + return new Response(); + }, +}); + +export const useSessionContext = () => React.useContext(SessionContext); + +export const SessionContextProvider = (props: { children: React.ReactNode }) => { + const api = useApiContext(); + const [session, setSession] = React.useState(undefined); + + const sessionContextValue: SessionContextT = React.useMemo( + () => ({ + session, + setSession, + authedFetch: (url: string, opts?: RequestInit) => { + return api.fetch(url, { + ...opts, + headers: { + ...opts?.headers, + authorization: session?.sessionID + ? `Bearer ${session?.sessionID}` + : undefined, + }, + }); + }, + }), + [session, api] + ); + + React.useEffect(() => { + // No session is set, do we have one available? + if (!sessionContextValue.session || !sessionContextValue.session.sessionID) { + // We may have the full state in session storage... + const storedSessionData = sessionStorage.getItem('rp_session_data'); + if (storedSessionData) { + try { + setSession(JSON.parse(storedSessionData)); + return; + } catch (e) { + // Oops, this data is wrong. + } + } + + // But if not, we have the key, maybe? + const storedSessionID = localStorage.getItem('rp_session_key'); + if (storedSessionID && storedSessionID !== '') { + setSession({ sessionID: storedSessionID }); + return; + } + + // If we hit here, we're definitely not authenticated. + return; + } + + // If a session is set and it's not stored, set it now. + if ( + localStorage.getItem('rp_session_key') !== + sessionContextValue.session.sessionID + ) { + localStorage.setItem( + 'rp_session_key', + sessionContextValue.session.sessionID || '' + ); + } + + // Session is set, but we don't have data. Server sup? + if (sessionContextValue.session.sessionID && !sessionContextValue.session.user) { + const syncSession = async () => { + const response = await sessionContextValue.authedFetch('/get-session'); + if (response.status !== 200) { + console.error('get-session failed', { response }); + clearSessionData(); + return; + } + + const serverSession: SessionContextT['session'] = await response.json(); + + setSession(serverSession); + sessionStorage.setItem('rp_session_data', JSON.stringify(serverSession)); + }; + + syncSession(); + } + }, [ + sessionContextValue.session?.user, + sessionContextValue.session?.sessionID, + sessionContextValue, + ]); + + return ( + + {props.children} + + ); +}; + +const clearSessionData = () => { + sessionStorage.removeItem('rp_session_data'); + localStorage.removeItem('rp_session_key'); +};