-
Notifications
You must be signed in to change notification settings - Fork 154
/
Copy pathSessionContext.tsx
84 lines (73 loc) · 2.14 KB
/
SessionContext.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { memoize } from 'lodash-es';
import React, { createContext, useContext, useState } from 'react';
import InvariantViolated from '@/errors/InvariantViolated';
import loginWithRefreshToken from '@/utils/login/withRefreshToken';
import {
clear as _clearSession,
load as _loadSession,
save as _saveSession,
type LoggedInSession,
type Session,
} from '@/utils/session';
export type SessionContextType = {
session: Session;
setSession: (newSession: LoggedInSession) => void;
clearSession: () => void;
};
// Null only occurs before the component is loaded (it should never occur)
export const SessionContext = createContext<SessionContextType | null>(null);
export function SessionContextProvider({
children,
}: {
children: React.ReactNode;
}) {
const [session, _setSession] = useState<Session>(_loadSession());
const setSession = (newSession: LoggedInSession) => {
_setSession(newSession);
_saveSession(newSession);
};
const clearSession = () => {
_setSession({ loggedIn: false });
_clearSession();
};
return (
<SessionContext.Provider
value={{
session,
setSession,
clearSession,
}}>
{children}
</SessionContext.Provider>
);
}
/**
* Get the current session from the context.
*
* @returns The current session object
*/
export const useSession = function () {
const context = useContext(SessionContext);
if (!context) throw new InvariantViolated('Session context missing');
return context.session;
};
/**
* Refresh the session by exchanging the refreshToken for a new accessToken.
*
* Note that this function is memoized to prevent multiple calls using the same refreshToken, with
* repeated calls returning the same promise.
*
* @param session The current session context object
*/
export const refreshSession = memoize(
async function ({
session,
setSession,
}: SessionContextType): Promise<Session> {
if (!session.loggedIn) return session;
const newSession = await loginWithRefreshToken(session.refreshToken);
setSession(newSession);
return newSession;
},
({ session }) => (session.loggedIn ? session.refreshToken : null),
);