diff options
-rw-r--r-- | packages/web-util/src/hooks/index.ts | 6 | ||||
-rw-r--r-- | packages/web-util/src/hooks/useLocalStorage.ts | 2 | ||||
-rw-r--r-- | packages/web-util/src/hooks/useMemoryStorage.ts | 75 | ||||
-rw-r--r-- | packages/web-util/src/hooks/useNotifications.ts | 67 |
4 files changed, 149 insertions, 1 deletions
diff --git a/packages/web-util/src/hooks/index.ts b/packages/web-util/src/hooks/index.ts index e5cb54e21..ae8872497 100644 --- a/packages/web-util/src/hooks/index.ts +++ b/packages/web-util/src/hooks/index.ts @@ -1,5 +1,11 @@ export { useLang } from "./useLang.js"; export { useLocalStorage } from "./useLocalStorage.js"; +export { useMemoryStorage } from "./useMemoryStorage.js"; +export { + useNotifications, + notifyError, + notifyInfo, +} from "./useNotifications.js"; export { useAsyncAsHook, HookError, diff --git a/packages/web-util/src/hooks/useLocalStorage.ts b/packages/web-util/src/hooks/useLocalStorage.ts index 495c9b0f8..131825736 100644 --- a/packages/web-util/src/hooks/useLocalStorage.ts +++ b/packages/web-util/src/hooks/useLocalStorage.ts @@ -70,7 +70,7 @@ export function useLocalStorage( }, []); const setValue = (value?: string): void => { - if (!value) { + if (value === undefined) { storage.delete(key); } else { storage.set(key, value); diff --git a/packages/web-util/src/hooks/useMemoryStorage.ts b/packages/web-util/src/hooks/useMemoryStorage.ts new file mode 100644 index 000000000..7160b035e --- /dev/null +++ b/packages/web-util/src/hooks/useMemoryStorage.ts @@ -0,0 +1,75 @@ +/* + This file is part of GNU Anastasis + (C) 2021-2022 Anastasis SARL + + GNU Anastasis is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Anastasis 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { useEffect, useState } from "preact/hooks"; +import { + ObservableMap, + browserStorageMap, + localStorageMap, + memoryMap, +} from "../utils/observable.js"; + +export interface LocalStorageState { + value?: string; + update: (s: string) => void; + reset: () => void; +} + +const storage: ObservableMap<string, string> = memoryMap<string>(); + +export function useMemoryStorage( + key: string, + initialValue: string, +): Required<LocalStorageState>; +export function useMemoryStorage(key: string): LocalStorageState; +export function useMemoryStorage( + key: string, + initialValue?: string, +): LocalStorageState { + const [storedValue, setStoredValue] = useState<string | undefined>( + (): string | undefined => { + return storage.get(key) ?? initialValue; + }, + ); + + useEffect(() => { + return storage.onUpdate(key, () => { + const newValue = storage.get(key); + setStoredValue(newValue ?? initialValue); + }); + }, []); + + const setValue = (value?: string): void => { + if (value === undefined) { + storage.delete(key); + } else { + storage.set(key, value); + } + }; + + return { + value: storedValue, + update: setValue, + reset: () => { + setValue(initialValue); + }, + }; +} diff --git a/packages/web-util/src/hooks/useNotifications.ts b/packages/web-util/src/hooks/useNotifications.ts new file mode 100644 index 000000000..deaa7a7c1 --- /dev/null +++ b/packages/web-util/src/hooks/useNotifications.ts @@ -0,0 +1,67 @@ +import { TranslatedString } from "@gnu-taler/taler-util"; +import { StateUpdater, useEffect, useState } from "preact/hooks"; +import { memoryMap } from "../index.browser.js"; + +export type NotificationMessage = ErrorNotification | InfoNotification; + +interface ErrorNotification { + type: "error"; + title: TranslatedString; + description?: TranslatedString; + debug?: string; +} +interface InfoNotification { + type: "info"; + title: TranslatedString; +} + +const storage = memoryMap<NotificationMessage[]>(); +const NOTIFICATION_KEY = "notification"; + +export function notifyError( + title: TranslatedString, + description: TranslatedString | undefined, + debug?: any, +) { + const currentState: NotificationMessage[] = + storage.get(NOTIFICATION_KEY) ?? []; + const newState = currentState.concat({ + type: "error", + title, + description, + debug, + }); + storage.set(NOTIFICATION_KEY, newState); +} +export function notifyInfo(title: TranslatedString) { + const currentState: NotificationMessage[] = + storage.get(NOTIFICATION_KEY) ?? []; + const newState = currentState.concat({ type: "info", title }); + storage.set(NOTIFICATION_KEY, newState); +} + +type Notification = { + message: NotificationMessage; + remove: () => void; +}; + +export function useNotifications(): Notification[] { + const [value, setter] = useState<NotificationMessage[]>([]); + useEffect(() => { + return storage.onUpdate(NOTIFICATION_KEY, () => { + const mem = storage.get(NOTIFICATION_KEY) ?? []; + setter(mem); + }); + }); + return value.map((message, idx) => { + return { + message, + remove: () => { + const mem = storage.get(NOTIFICATION_KEY) ?? []; + const newState = Array.from(mem); + newState.splice(idx, 1); + storage.set(NOTIFICATION_KEY, newState); + }, + }; + }); +} |