use new local storage api

This commit is contained in:
Sebastian 2023-05-29 14:53:06 -03:00
parent d4dd82eda1
commit be9d3dad83
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
3 changed files with 72 additions and 33 deletions

View File

@ -14,11 +14,20 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/ */
import { canonicalizeBaseUrl } from "@gnu-taler/taler-util"; import {
Codec,
buildCodecForObject,
buildCodecForUnion,
canonicalizeBaseUrl,
codecForBoolean,
codecForConstString,
codecForString,
} from "@gnu-taler/taler-util";
import { import {
ErrorType, ErrorType,
HttpError, HttpError,
RequestError, RequestError,
buildStorageKey,
useLocalStorage, useLocalStorage,
} from "@gnu-taler/web-util/browser"; } from "@gnu-taler/web-util/browser";
import { import {
@ -51,6 +60,26 @@ interface LoggedOut {
status: "loggedOut"; status: "loggedOut";
} }
export const codecForBackendStateLoggedIn = (): Codec<LoggedIn> =>
buildCodecForObject<LoggedIn>()
.property("status", codecForConstString("loggedIn"))
.property("username", codecForString())
.property("password", codecForString())
.property("isUserAdministrator", codecForBoolean())
.build("BackendState.LoggedIn");
export const codecForBackendStateLoggedOut = (): Codec<LoggedOut> =>
buildCodecForObject<LoggedOut>()
.property("status", codecForConstString("loggedOut"))
.build("BackendState.LoggedOut");
export const codecForBackendState = (): Codec<BackendState> =>
buildCodecForUnion<BackendState>()
.discriminateOn("status")
.alternative("loggedIn", codecForBackendStateLoggedIn())
.alternative("loggedOut", codecForBackendStateLoggedOut())
.build("BackendState");
export function getInitialBackendBaseURL(): string { export function getInitialBackendBaseURL(): string {
const overrideUrl = const overrideUrl =
typeof localStorage !== "undefined" typeof localStorage !== "undefined"
@ -79,29 +108,27 @@ export interface BackendStateHandler {
logOut(): void; logOut(): void;
logIn(info: BackendCredentials): void; logIn(info: BackendCredentials): void;
} }
const BACKEND_STATE_KEY = buildStorageKey(
"backend-state",
codecForBackendState(),
);
/** /**
* Return getters and setters for * Return getters and setters for
* login credentials and backend's * login credentials and backend's
* base URL. * base URL.
*/ */
export function useBackendState(): BackendStateHandler { export function useBackendState(): BackendStateHandler {
const { value, update } = useLocalStorage( const { value: state, update } = useLocalStorage(
"backend-state", BACKEND_STATE_KEY,
JSON.stringify(defaultState), defaultState,
); );
let parsed;
try {
parsed = JSON.parse(value!);
} catch {
parsed = undefined;
}
const state: BackendState = !parsed?.status ? defaultState : parsed;
return { return {
state, state,
logOut() { logOut() {
update(JSON.stringify({ ...defaultState })); update(defaultState);
}, },
logIn(info) { logIn(info) {
//admin is defined by the username //admin is defined by the username
@ -110,7 +137,7 @@ export function useBackendState(): BackendStateHandler {
...info, ...info,
isUserAdministrator: info.username === "admin", isUserAdministrator: info.username === "admin",
}; };
update(JSON.stringify(nextState)); update(nextState);
}, },
}; };
} }

View File

@ -20,7 +20,8 @@
*/ */
import { StateUpdater } from "preact/hooks"; import { StateUpdater } from "preact/hooks";
import { useLocalStorage } from "@gnu-taler/web-util/browser"; import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser";
import { codecForBoolean } from "@gnu-taler/taler-util";
export type ValueOrFunction<T> = T | ((p: T) => T); export type ValueOrFunction<T> = T | ((p: T) => T);
const calculateRootPath = () => { const calculateRootPath = () => {
@ -31,11 +32,14 @@ const calculateRootPath = () => {
return rootPath; return rootPath;
}; };
const BACKEND_URL_KEY = buildStorageKey("backend-url");
const TRIED_LOGIN_KEY = buildStorageKey("tried-login", codecForBoolean());
export function useBackendURL( export function useBackendURL(
url?: string, url?: string,
): [string, boolean, StateUpdater<string>, () => void] { ): [string, boolean, StateUpdater<string>, () => void] {
const { value, update: setter } = useLocalStorage( const { value, update: setter } = useLocalStorage(
"backend-url", BACKEND_URL_KEY,
url || calculateRootPath(), url || calculateRootPath(),
); );
@ -43,10 +47,10 @@ export function useBackendURL(
value: triedToLog, value: triedToLog,
update: setTriedToLog, update: setTriedToLog,
reset: resetBackend, reset: resetBackend,
} = useLocalStorage("tried-login"); } = useLocalStorage(TRIED_LOGIN_KEY);
const checkedSetter = (v: ValueOrFunction<string>) => { const checkedSetter = (v: ValueOrFunction<string>) => {
setTriedToLog("yes"); setTriedToLog(true);
const computedValue = const computedValue =
v instanceof Function ? v(value) : v.replace(/\/$/, ""); v instanceof Function ? v(value) : v.replace(/\/$/, "");
return setter(computedValue); return setter(computedValue);

View File

@ -14,36 +14,44 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/ */
import { useLocalStorage } from "@gnu-taler/web-util/browser"; import {
Codec,
buildCodecForObject,
codecForString,
codecOptional,
} from "@gnu-taler/taler-util";
import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser";
interface Settings { interface Settings {
currentWithdrawalOperationId: string | undefined; currentWithdrawalOperationId: string | undefined;
} }
export const codecForSettings = (): Codec<Settings> =>
buildCodecForObject<Settings>()
.property("currentWithdrawalOperationId", codecOptional(codecForString()))
.build("Settings");
const defaultSettings: Settings = { const defaultSettings: Settings = {
currentWithdrawalOperationId: undefined, currentWithdrawalOperationId: undefined,
}; };
function parse_json_or_undefined<T>(str: string | undefined): T | undefined { const DEMOBANK_SETTINGS_KEY = buildStorageKey(
if (str === undefined) return undefined; "demobank-settings",
try { codecForSettings(),
return JSON.parse(str); );
} catch {
return undefined;
}
}
export function useSettings(): [ export function useSettings(): [
Readonly<Settings>, Readonly<Settings>,
<T extends keyof Settings>(key: T, value: Settings[T]) => void, <T extends keyof Settings>(key: T, value: Settings[T]) => void,
] { ] {
const { value, update } = useLocalStorage("demobank-settings"); const { value, update } = useLocalStorage(
DEMOBANK_SETTINGS_KEY,
defaultSettings,
);
const parsed: Settings = parse_json_or_undefined(value) ?? defaultSettings;
function updateField<T extends keyof Settings>(k: T, v: Settings[T]) { function updateField<T extends keyof Settings>(k: T, v: Settings[T]) {
const newValue = { ...parsed, [k]: v }; const newValue = { ...value, [k]: v };
const json = JSON.stringify(newValue); update(newValue);
update(json);
} }
return [parsed, updateField]; return [value, updateField];
} }