diff options
Diffstat (limited to 'packages/demobank-ui/src/hooks/session.ts')
-rw-r--r-- | packages/demobank-ui/src/hooks/session.ts | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/packages/demobank-ui/src/hooks/session.ts b/packages/demobank-ui/src/hooks/session.ts new file mode 100644 index 000000000..35f87e1be --- /dev/null +++ b/packages/demobank-ui/src/hooks/session.ts @@ -0,0 +1,131 @@ +/* + This file is part of GNU Taler + (C) 2022-2024 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { + AccessToken, + Codec, + buildCodecForObject, + buildCodecForUnion, + codecForBoolean, + codecForConstString, + codecForString, +} from "@gnu-taler/taler-util"; +import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser"; +import { mutate } from "swr"; + +/** + * Has the information to reach and + * authenticate at the bank's backend. + */ +export type SessionState = LoggedIn | LoggedOut | Expired; + +interface LoggedIn { + status: "loggedIn"; + isUserAdministrator: boolean; + username: string; + token: AccessToken; +} +interface Expired { + status: "expired"; + isUserAdministrator: boolean; + username: string; +} +interface LoggedOut { + status: "loggedOut"; +} + +export const codecForSessionStateLoggedIn = (): Codec<LoggedIn> => + buildCodecForObject<LoggedIn>() + .property("status", codecForConstString("loggedIn")) + .property("username", codecForString()) + .property("token", codecForString() as Codec<AccessToken>) + .property("isUserAdministrator", codecForBoolean()) + .build("SessionState.LoggedIn"); + +export const codecForSessionStateExpired = (): Codec<Expired> => + buildCodecForObject<Expired>() + .property("status", codecForConstString("expired")) + .property("username", codecForString()) + .property("isUserAdministrator", codecForBoolean()) + .build("SessionState.Expired"); + +export const codecForSessionStateLoggedOut = (): Codec<LoggedOut> => + buildCodecForObject<LoggedOut>() + .property("status", codecForConstString("loggedOut")) + .build("SessionState.LoggedOut"); + +export const codecForSessionState = (): Codec<SessionState> => + buildCodecForUnion<SessionState>() + .discriminateOn("status") + .alternative("loggedIn", codecForSessionStateLoggedIn()) + .alternative("loggedOut", codecForSessionStateLoggedOut()) + .alternative("expired", codecForSessionStateExpired()) + .build("SessionState"); + +export const defaultState: SessionState = { + status: "loggedOut", +}; + +export interface SessionStateHandler { + state: SessionState; + logOut(): void; + expired(): void; + logIn(info: { username: string; token: AccessToken }): void; +} + +const SESSION_STATE_KEY = buildStorageKey("bank-state", codecForSessionState()); + +/** + * Return getters and setters for + * login credentials and backend's + * base URL. + */ +export function useSessionState(): SessionStateHandler { + const { value: state, update } = useLocalStorage( + SESSION_STATE_KEY, + defaultState, + ); + + return { + state, + logOut() { + update(defaultState); + }, + expired() { + if (state.status === "loggedOut") return; + const nextState: SessionState = { + status: "expired", + username: state.username, + isUserAdministrator: state.username === "admin", + }; + update(nextState); + }, + logIn(info) { + // admin is defined by the username + const nextState: SessionState = { + status: "loggedIn", + ...info, + isUserAdministrator: info.username === "admin", + }; + update(nextState); + cleanAllCache(); + }, + }; +} + +function cleanAllCache(): void { + mutate(() => true, undefined, { revalidate: false }); +} |