diff options
Diffstat (limited to 'packages/web-util/src/hooks/useNotifications.ts')
-rw-r--r-- | packages/web-util/src/hooks/useNotifications.ts | 68 |
1 files changed, 55 insertions, 13 deletions
diff --git a/packages/web-util/src/hooks/useNotifications.ts b/packages/web-util/src/hooks/useNotifications.ts index 000abbc94..99f4f2699 100644 --- a/packages/web-util/src/hooks/useNotifications.ts +++ b/packages/web-util/src/hooks/useNotifications.ts @@ -1,4 +1,5 @@ import { + AbsoluteTime, Duration, OperationFail, OperationOk, @@ -20,12 +21,18 @@ export type NotificationMessage = ErrorNotification | InfoNotification; export interface ErrorNotification { type: "error"; title: TranslatedString; + ack?: boolean; + timeout?: boolean; description?: TranslatedString; debug?: any; + when: AbsoluteTime; } export interface InfoNotification { type: "info"; title: TranslatedString; + ack?: boolean; + timeout?: boolean; + when: AbsoluteTime; } const storage = memoryMap<Map<string, NotificationMessage>>(); @@ -35,11 +42,11 @@ export const GLOBAL_NOTIFICATION_TIMEOUT = Duration.fromSpec({ seconds: 5, }); -function removeFromStorage(n: NotificationMessage) { +function updateInStorage(n: NotificationMessage) { const h = hash(n); const mem = storage.get(NOTIFICATION_KEY) ?? new Map(); const newState = new Map(mem); - newState.delete(h); + newState.set(h, n); storage.set(NOTIFICATION_KEY, newState); } @@ -50,7 +57,8 @@ export function notify(notif: NotificationMessage): void { if (GLOBAL_NOTIFICATION_TIMEOUT.d_ms !== "forever") { setTimeout(() => { - removeFromStorage(notif); + notif.timeout = true; + updateInStorage(notif); }, GLOBAL_NOTIFICATION_TIMEOUT.d_ms); } @@ -66,6 +74,7 @@ export function notifyError( title, description, debug, + when: AbsoluteTime.now(), }); } export function notifyException(title: TranslatedString, ex: Error) { @@ -74,34 +83,40 @@ export function notifyException(title: TranslatedString, ex: Error) { title, description: ex.message as TranslatedString, debug: ex.stack, + when: AbsoluteTime.now(), }); } export function notifyInfo(title: TranslatedString) { notify({ type: "info" as const, title, + when: AbsoluteTime.now(), }); } export type Notification = { message: NotificationMessage; - remove: () => void; + acknowledge: () => void; }; export function useNotifications(): Notification[] { - const [value, setter] = useState<Map<string, NotificationMessage>>(new Map()); + const [, setLastUpdate] = useState<number>(); + const value = storage.get(NOTIFICATION_KEY) ?? new Map(); + useEffect(() => { return storage.onUpdate(NOTIFICATION_KEY, () => { - const mem = storage.get(NOTIFICATION_KEY) ?? new Map(); - setter(structuredClone(mem)); + setLastUpdate(Date.now()) + // const mem = storage.get(NOTIFICATION_KEY) ?? new Map(); + // setter(structuredClone(mem)); }); }); return Array.from(value.values()).map((message, idx) => { return { message, - remove: () => { - removeFromStorage(message); + acknowledge: () => { + message.ack = true; + updateInStorage(message); }, }; }); @@ -141,6 +156,7 @@ function errorMap<T extends OperationFail<unknown>>( title: map(resp.case), description: resp.detail.hint as TranslatedString, debug: resp.detail, + when: AbsoluteTime.now(), }); } @@ -165,7 +181,7 @@ export function useLocalNotification(): [ ? undefined : { message: value, - remove: () => { + acknowledge: () => { setter(undefined); }, }; @@ -175,7 +191,7 @@ export function useLocalNotification(): [ return await cb(errorMap); } catch (error: unknown) { if (error instanceof TalerError) { - notify(buildRequestErrorMessage(i18n, error)); + notify(buildUnifiedRequestErrorMessage(i18n, error)); } else { notifyError( i18n.str`Operation failed, please report`, @@ -212,7 +228,7 @@ export function useLocalNotificationHandler(): [ ? undefined : { message: value, - remove: () => { + acknowledge: () => { setter(undefined); }, }; @@ -241,18 +257,39 @@ export function useLocalNotificationHandler(): [ return [notif, makeHandler, setter]; } -export function buildRequestErrorMessage( +export function buildUnifiedRequestErrorMessage( i18n: InternationalizationAPI, cause: TalerError, ): ErrorNotification { let result: ErrorNotification; switch (cause.errorDetail.code) { + case TalerErrorCode.GENERIC_TIMEOUT: { + result = { + type: "error", + title: i18n.str`Request timeout`, + description: cause.message as TranslatedString, + debug: JSON.stringify(cause.errorDetail, undefined, 2), + when: AbsoluteTime.now(), + }; + break; + } + case TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR: { + result = { + type: "error", + title: i18n.str`Request cancelled`, + description: cause.message as TranslatedString, + debug: JSON.stringify(cause.errorDetail, undefined, 2), + when: AbsoluteTime.now(), + }; + break; + } case TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT: { result = { type: "error", title: i18n.str`Request timeout`, description: cause.message as TranslatedString, debug: JSON.stringify(cause.errorDetail, undefined, 2), + when: AbsoluteTime.now(), }; break; } @@ -262,6 +299,7 @@ export function buildRequestErrorMessage( title: i18n.str`Request throttled`, description: cause.message as TranslatedString, debug: JSON.stringify(cause.errorDetail, undefined, 2), + when: AbsoluteTime.now(), }; break; } @@ -271,6 +309,7 @@ export function buildRequestErrorMessage( title: i18n.str`Malformed response`, description: cause.message as TranslatedString, debug: JSON.stringify(cause.errorDetail, undefined, 2), + when: AbsoluteTime.now(), }; break; } @@ -280,6 +319,7 @@ export function buildRequestErrorMessage( title: i18n.str`Network error`, description: cause.message as TranslatedString, debug: JSON.stringify(cause.errorDetail, undefined, 2), + when: AbsoluteTime.now(), }; break; } @@ -289,6 +329,7 @@ export function buildRequestErrorMessage( title: i18n.str`Unexpected request error`, description: cause.message as TranslatedString, debug: JSON.stringify(cause.errorDetail, undefined, 2), + when: AbsoluteTime.now(), }; break; } @@ -298,6 +339,7 @@ export function buildRequestErrorMessage( title: i18n.str`Unexpected error`, description: cause.message as TranslatedString, debug: JSON.stringify(cause.errorDetail, undefined, 2), + when: AbsoluteTime.now(), }; break; } |