aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/context
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-01-09 20:20:09 -0300
committerSebastian <sebasjm@gmail.com>2023-01-09 20:20:09 -0300
commit4a781bd0dd8828ce152f6ab2c3f1bbd6b5e826f7 (patch)
tree5c16976f99eb973ff62d78ed64107ca01df57b99 /packages/taler-wallet-webextension/src/context
parent8a70edb2f8e235c3462127b0aa4e1b65aa1aee0b (diff)
downloadwallet-core-4a781bd0dd8828ce152f6ab2c3f1bbd6b5e826f7.tar.xz
fix #7153: more error handling
if handler do not trap error then fail at compile time, all safe handlers push alert on error errors are typed so they render good information
Diffstat (limited to 'packages/taler-wallet-webextension/src/context')
-rw-r--r--packages/taler-wallet-webextension/src/context/alert.ts98
-rw-r--r--packages/taler-wallet-webextension/src/context/devContext.ts17
2 files changed, 89 insertions, 26 deletions
diff --git a/packages/taler-wallet-webextension/src/context/alert.ts b/packages/taler-wallet-webextension/src/context/alert.ts
index cc98ec1e0..e67d94671 100644
--- a/packages/taler-wallet-webextension/src/context/alert.ts
+++ b/packages/taler-wallet-webextension/src/context/alert.ts
@@ -19,19 +19,26 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { TranslatedString } from "@gnu-taler/taler-util";
+import { TalerErrorDetail, TranslatedString } from "@gnu-taler/taler-util";
import { ComponentChildren, createContext, h, VNode } from "preact";
import { useContext, useState } from "preact/hooks";
+import { HookError } from "../hooks/useAsyncAsHook.js";
+import { SafeHandler, withSafe } from "../mui/handlers.js";
+import { BackgroundError } from "../wxApi.js";
export type AlertType = "info" | "warning" | "error" | "success";
-export interface Alert {
+export interface InfoAlert {
message: TranslatedString;
description: TranslatedString | VNode;
- type: AlertType;
+ type: "info" | "warning" | "success";
}
-export interface ErrorAlert extends Alert {
+export type Alert = InfoAlert | ErrorAlert;
+
+export interface ErrorAlert {
+ message: TranslatedString;
+ description: TranslatedString | VNode;
type: "error";
context: object;
cause: any;
@@ -41,10 +48,14 @@ type Type = {
alerts: Alert[];
pushAlert: (n: Alert) => void;
removeAlert: (n: Alert) => void;
+ pushAlertOnError: <T>(h: (p: T) => Promise<void>) => SafeHandler<T>;
};
const initial: Type = {
alerts: [],
+ pushAlertOnError: () => {
+ throw Error("alert context not initialized");
+ },
pushAlert: () => {
null;
},
@@ -80,8 +91,17 @@ export const AlertProvider = ({ children }: Props): VNode => {
setAlerts((ns: AlertWithDate[]) => ns.filter((n) => n !== alert));
};
+ function pushAlertOnError<T>(
+ handler: (p: T) => Promise<void>,
+ ): SafeHandler<T> {
+ return withSafe(handler, (e) => {
+ const a = alertFromError(e.message as TranslatedString, e);
+ pushAlert(a);
+ });
+ }
+
return h(Context.Provider, {
- value: { alerts, pushAlert, removeAlert },
+ value: { alerts, pushAlert, removeAlert, pushAlertOnError },
children,
});
};
@@ -90,29 +110,71 @@ export const useAlertContext = (): Type => useContext(Context);
export function alertFromError(
message: TranslatedString,
- error: unknown,
+ error: HookError,
...context: any[]
-): ErrorAlert {
- let description = "" as TranslatedString;
+): ErrorAlert;
- const isObject = typeof error === "object" &&
- error !== null;
- const hasMessage =
- isObject &&
- "message" in error &&
- typeof error.message === "string";
+export function alertFromError(
+ message: TranslatedString,
+ error: Error,
+ ...context: any[]
+): ErrorAlert;
- if (hasMessage) {
- description = error.message as TranslatedString;
+export function alertFromError(
+ message: TranslatedString,
+ error: TalerErrorDetail,
+ ...context: any[]
+): ErrorAlert;
+
+export function alertFromError(
+ message: TranslatedString,
+ error: HookError | TalerErrorDetail | Error,
+ ...context: any[]
+): ErrorAlert {
+ let description: TranslatedString;
+ let cause: any;
+
+ if (typeof error === "object" && error !== null) {
+ if ("code" in error) {
+ //TalerErrorDetail
+ description = (error.hint ??
+ `Error code: ${error.code}`) as TranslatedString;
+ cause = {
+ details: error,
+ };
+ } else if ("hasError" in error) {
+ //HookError
+ description = error.message as TranslatedString;
+ if (error.type === "taler") {
+ cause = {
+ details: error.details,
+ };
+ }
+ } else {
+ if (error instanceof BackgroundError) {
+ description = (error.errorDetail.hint ??
+ `Error code: ${error.errorDetail.code}`) as TranslatedString;
+ cause = {
+ details: error.errorDetail,
+ stack: error.stack,
+ };
+ } else {
+ description = error.message as TranslatedString;
+ cause = {
+ stack: error.stack,
+ };
+ }
+ }
} else {
- description = `Unknown error: ${String(error)}` as TranslatedString;
+ description = "" as TranslatedString;
+ cause = error;
}
return {
type: "error",
message,
description,
- cause: error,
+ cause,
context,
};
}
diff --git a/packages/taler-wallet-webextension/src/context/devContext.ts b/packages/taler-wallet-webextension/src/context/devContext.ts
index 99301df52..e2ad2914b 100644
--- a/packages/taler-wallet-webextension/src/context/devContext.ts
+++ b/packages/taler-wallet-webextension/src/context/devContext.ts
@@ -22,16 +22,15 @@
import { createContext, h, VNode } from "preact";
import { useContext } from "preact/hooks";
import { useWalletDevMode } from "../hooks/useWalletDevMode.js";
-import { ToggleHandler } from "../mui/handlers.js";
interface Type {
devMode: boolean;
- devModeToggle: ToggleHandler;
+ toggle: () => Promise<void>;
}
const Context = createContext<Type>({
devMode: false,
- devModeToggle: {
- button: {},
+ toggle: async () => {
+ null;
},
});
@@ -47,9 +46,8 @@ export const DevContextProviderForTesting = ({
return h(Context.Provider, {
value: {
devMode: !!value,
- devModeToggle: {
- value,
- button: {},
+ toggle: async () => {
+ null;
},
},
children,
@@ -58,7 +56,10 @@ export const DevContextProviderForTesting = ({
export const DevContextProvider = ({ children }: { children: any }): VNode => {
const devModeToggle = useWalletDevMode();
- const value: Type = { devMode: !!devModeToggle.value, devModeToggle };
+ const value: Type = {
+ devMode: !!devModeToggle.value,
+ toggle: devModeToggle.toggle,
+ };
//support for function as children, useful for getting the value right away
children =
children.length === 1 && typeof children === "function"