summaryrefslogtreecommitdiff
path: root/packages/demobank-ui/src/pages/OperationState/state.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/demobank-ui/src/pages/OperationState/state.ts')
-rw-r--r--packages/demobank-ui/src/pages/OperationState/state.ts162
1 files changed, 98 insertions, 64 deletions
diff --git a/packages/demobank-ui/src/pages/OperationState/state.ts b/packages/demobank-ui/src/pages/OperationState/state.ts
index 4be680377..148571ec9 100644
--- a/packages/demobank-ui/src/pages/OperationState/state.ts
+++ b/packages/demobank-ui/src/pages/OperationState/state.ts
@@ -14,20 +14,26 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { Amounts, HttpStatusCode, TranslatedString, parsePaytoUri, parseWithdrawUri, stringifyWithdrawUri } from "@gnu-taler/taler-util";
+import { Amounts, HttpStatusCode, TalerError, TranslatedString, parsePaytoUri, parseWithdrawUri, stringifyWithdrawUri } from "@gnu-taler/taler-util";
import { RequestError, notify, notifyError, notifyInfo, useTranslationContext, utils } from "@gnu-taler/web-util/browser";
import { useEffect, useState } from "preact/hooks";
-import { useAccessAPI, useAccessAnonAPI, useWithdrawalDetails } from "../../hooks/access.js";
-import { getInitialBackendBaseURL } from "../../hooks/backend.js";
+import { useBankCoreApiContext } from "../../context/config.js";
+import { useWithdrawalDetails } from "../../hooks/access.js";
+import { useBackendState } from "../../hooks/backend.js";
import { useSettings } from "../../hooks/settings.js";
import { buildRequestErrorMessage } from "../../utils.js";
import { Props, State } from "./index.js";
+import { assertUnreachable } from "../HomePage.js";
+import { mutate } from "swr";
export function useComponentState({ currency, onClose }: Props): utils.RecursiveState<State> {
const { i18n } = useTranslationContext();
const [settings, updateSettings] = useSettings()
- const { createWithdrawal } = useAccessAPI();
- const { abortWithdrawal, confirmWithdrawal } = useAccessAnonAPI();
+ const { state: credentials } = useBackendState()
+ const creds = credentials.status !== "loggedIn" ? undefined : credentials
+ const { api } = useBankCoreApiContext()
+ // const { createWithdrawal } = useAccessAPI();
+ // const { abortWithdrawal, confirmWithdrawal } = useAccessAnonAPI();
const [busy, setBusy] = useState<Record<string, undefined>>()
const amount = settings.maxWithdrawalAmount
@@ -37,27 +43,33 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive
const parsedAmount = Amounts.parseOrThrow(`${currency}:${amount}`)
try {
- const result = await createWithdrawal({
+ if (!creds) return;
+ const resp = await api.createWithdrawal(creds, {
amount: Amounts.stringify(parsedAmount),
});
- const uri = parseWithdrawUri(result.data.taler_withdraw_uri);
+ if (resp.type === "fail") {
+ switch (resp.case) {
+ case "insufficient-funds": return notify({
+ type: "error",
+ title: i18n.str`The operation was rejected due to insufficient funds`,
+ description: resp.detail.hint as TranslatedString,
+ debug: resp.detail,
+ });
+ default: assertUnreachable(resp.case)
+ }
+ }
+
+ const uri = parseWithdrawUri(resp.body.taler_withdraw_uri);
if (!uri) {
return notifyError(
i18n.str`Server responded with an invalid withdraw URI`,
- i18n.str`Withdraw URI: ${result.data.taler_withdraw_uri}`);
+ i18n.str`Withdraw URI: ${resp.body.taler_withdraw_uri}`);
} else {
updateSettings("currentWithdrawalOperationId", uri.withdrawalOperationId)
}
} catch (error) {
- if (error instanceof RequestError) {
- notify(
- buildRequestErrorMessage(i18n, error.cause, {
- onClientError: (status) =>
- status === HttpStatusCode.Forbidden
- ? i18n.str`The operation was rejected due to insufficient funds`
- : undefined,
- }),
- );
+ if (error instanceof TalerError) {
+ notify(buildRequestErrorMessage(i18n, error))
} else {
notifyError(
i18n.str`Operation failed, please report`,
@@ -76,8 +88,6 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive
}
}, [settings.fastWithdrawal, amount])
- const baseUrl = getInitialBackendBaseURL()
-
if (!withdrawalOperationId) {
return {
status: "loading",
@@ -90,18 +100,24 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive
async function doAbort() {
try {
setBusy({})
- await abortWithdrawal(wid);
- onClose();
+ const resp = await api.abortWithdrawalById(wid);
+ setBusy(undefined)
+ if (resp.type === "ok") {
+ onClose();
+ } else {
+ switch (resp.case) {
+ case "previously-confirmed": return notify({
+ type: "error",
+ title: i18n.str`The reserve operation has been confirmed previously and can't be aborted`,
+ description: resp.detail.hint as TranslatedString,
+ debug: resp.detail,
+ })
+ default: assertUnreachable(resp.case)
+ }
+ }
} catch (error) {
- if (error instanceof RequestError) {
- notify(
- buildRequestErrorMessage(i18n, error.cause, {
- onClientError: (status) =>
- status === HttpStatusCode.Conflict
- ? i18n.str`The reserve operation has been confirmed previously and can't be aborted`
- : undefined,
- }),
- );
+ if (error instanceof TalerError) {
+ notify(buildRequestErrorMessage(i18n, error))
} else {
notifyError(
i18n.str`Operation failed, please report`,
@@ -111,28 +127,38 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive
)
}
}
- setBusy(undefined)
}
async function doConfirm() {
try {
setBusy({})
- await confirmWithdrawal(wid);
- if (!settings.showWithdrawalSuccess) {
- notifyInfo(i18n.str`Wire transfer completed!`)
+ const resp = await api.confirmWithdrawalById(wid);
+ if (resp.type === "ok") {
+ mutate(() => true)//clean withdrawal state
+ if (!settings.showWithdrawalSuccess) {
+ notifyInfo(i18n.str`Wire transfer completed!`)
+ }
+ setBusy(undefined)
+ } else {
+ switch (resp.case) {
+ case "previously-aborted": return notify({
+ type: "error",
+ title: i18n.str`The withdrawal has been aborted previously and can't be confirmed`,
+ description: resp.detail.hint as TranslatedString,
+ debug: resp.detail,
+ })
+ case "no-exchange-or-reserve-selected": return notify({
+ type: "error",
+ title: i18n.str`The withdraw operation cannot be confirmed because no exchange and reserve public key selection happened before`,
+ description: resp.detail.hint as TranslatedString,
+ debug: resp.detail,
+ })
+ default: assertUnreachable(resp)
+ }
}
} catch (error) {
- if (error instanceof RequestError) {
- notify(
- buildRequestErrorMessage(i18n, error.cause, {
- onClientError: (status) =>
- status === HttpStatusCode.Conflict
- ? i18n.str`The withdrawal has been aborted previously and can't be confirmed`
- : status === HttpStatusCode.UnprocessableEntity
- ? i18n.str`The withdraw operation cannot be confirmed because no exchange and reserve public key selection happened before`
- : undefined,
- }),
- );
+ if (error instanceof TalerError) {
+ notify(buildRequestErrorMessage(i18n, error))
} else {
notifyError(
i18n.str`Operation failed, please report`,
@@ -142,11 +168,10 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive
)
}
}
- setBusy(undefined)
}
- const bankIntegrationApiBaseUrl = `${baseUrl}/taler-integration`
+
const uri = stringifyWithdrawUri({
- bankIntegrationApiBaseUrl,
+ bankIntegrationApiBaseUrl: api.getIntegrationAPI().baseUrl,
withdrawalOperationId,
});
const parsedUri = parseWithdrawUri(uri);
@@ -161,32 +186,43 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive
return (): utils.RecursiveState<State> => {
const result = useWithdrawalDetails(withdrawalOperationId);
- const shouldCreateNewOperation = !result.ok && !result.loading && result.info.status === HttpStatusCode.NotFound
+ const shouldCreateNewOperation = result && !(result instanceof TalerError)
useEffect(() => {
if (shouldCreateNewOperation) {
doSilentStart()
}
}, [])
- if (!result.ok) {
- if (result.loading) {
- return {
- status: "loading",
- error: undefined
- }
- }
- if (result.info.status === HttpStatusCode.NotFound) {
- return {
- status: "loading",
- error: undefined,
- }
+ if (!result) {
+ return {
+ status: "loading",
+ error: undefined
}
+ }
+ if (result instanceof TalerError) {
return {
status: "loading-error",
error: result
}
}
- const { data } = result;
+
+ if (result.type === "fail") {
+ switch (result.case) {
+ case "not-found": {
+ return {
+ status: "aborted",
+ error: undefined,
+ onClose: async () => {
+ updateSettings("currentWithdrawalOperationId", undefined)
+ onClose()
+ },
+ }
+ }
+ default: assertUnreachable(result.case)
+ }
+ }
+
+ const { body: data } = result;
if (data.aborted) {
return {
status: "aborted",
@@ -247,8 +283,6 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive
}
}
-
- // goToConfirmOperation(withdrawalOperationId)
return {
status: "need-confirmation",
error: undefined,