summaryrefslogtreecommitdiff
path: root/packages/challenger-ui/src/hooks/session.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/challenger-ui/src/hooks/session.ts')
-rw-r--r--packages/challenger-ui/src/hooks/session.ts143
1 files changed, 143 insertions, 0 deletions
diff --git a/packages/challenger-ui/src/hooks/session.ts b/packages/challenger-ui/src/hooks/session.ts
new file mode 100644
index 000000000..ed7ea8986
--- /dev/null
+++ b/packages/challenger-ui/src/hooks/session.ts
@@ -0,0 +1,143 @@
+/*
+ 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 {
+ ChallengerApi,
+ Codec,
+ buildCodecForObject,
+ codecForBoolean,
+ codecForChallengeStatus,
+ codecForNumber,
+ codecForString,
+ codecForStringURL,
+ codecOptional,
+} 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 SessionId = {
+ clientId: string;
+ redirectURL: string;
+ state: string;
+};
+
+export type LastChallengeResponse = {
+ attemptsLeft: number;
+ nextSend: string;
+ transmitted: boolean;
+};
+
+export type SessionState = SessionId & {
+ lastTry: LastChallengeResponse | undefined;
+ lastStatus: ChallengerApi.ChallengeStatus | undefined;
+ completedURL: string | undefined;
+};
+export const codecForLastChallengeResponse = (): Codec<LastChallengeResponse> =>
+ buildCodecForObject<LastChallengeResponse>()
+ .property("attemptsLeft", codecForNumber())
+ .property("nextSend", codecForString())
+ .property("transmitted", codecForBoolean())
+ .build("LastChallengeResponse");
+
+export const codecForSessionState = (): Codec<SessionState> =>
+ buildCodecForObject<SessionState>()
+ .property("clientId", codecForString())
+ .property("redirectURL", codecForStringURL())
+ .property("completedURL", codecOptional(codecForStringURL()))
+ .property("state", codecForString())
+ .property("lastStatus", codecOptional(codecForChallengeStatus()))
+ .property("lastTry", codecOptional(codecForLastChallengeResponse()))
+ .build("SessionState");
+
+export interface SessionStateHandler {
+ state: SessionState | undefined;
+ start(s: SessionId): void;
+ accepted(l: LastChallengeResponse): void;
+ completed(e: URL): void;
+ updateStatus(s: ChallengerApi.ChallengeStatus): void;
+}
+
+const SESSION_STATE_KEY = buildStorageKey(
+ "challenger-session",
+ 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);
+
+ return {
+ state,
+ start(info) {
+ update({
+ ...info,
+ lastTry: undefined,
+ completedURL: undefined,
+ lastStatus: undefined,
+ });
+ cleanAllCache();
+ },
+ accepted(lastTry) {
+ if (!state) return;
+ update({
+ ...state,
+ lastTry,
+ });
+ },
+ completed(url) {
+ if (!state) return;
+ update({
+ ...state,
+ completedURL: url.href,
+ });
+ },
+ updateStatus(st: ChallengerApi.ChallengeStatus) {
+ if (!state) return;
+ if (!state.lastStatus) {
+ update({
+ ...state,
+ lastStatus: st,
+ });
+ return;
+ }
+ // current status
+ const ls = state.lastStatus;
+ if (
+ ls.changes_left !== st.changes_left ||
+ ls.fix_address !== st.fix_address ||
+ ls.last_address !== st.last_address
+ ) {
+ update({
+ ...state,
+ lastStatus: st,
+ });
+ return;
+ }
+ },
+ };
+}
+
+function cleanAllCache(): void {
+ mutate(() => true, undefined, { revalidate: false });
+}