/* This file is part of GNU Taler (C) 2022 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Taler 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 General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ import { Amounts, HttpStatusCode, TalerError, TalerErrorCode, TranslatedString } from "@gnu-taler/taler-util"; import { Attention, Loading, LocalNotificationBanner, ShowInputErrorLabel, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; import { format } from "date-fns"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; import { mutate } from "swr"; import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js"; import { useBankCoreApiContext } from "../../context/config.js"; import { useBackendState } from "../../hooks/backend.js"; import { useCashoutDetails, useConversionInfo } from "../../hooks/circuit.js"; import { undefinedIfEmpty } from "../../utils.js"; import { RenderAmount } from "../PaytoWireTransferForm.js"; import { assertUnreachable } from "../WithdrawalOperationPage.js"; interface Props { id: string; onCancel: () => void; } export function ShowCashoutDetails({ id, onCancel, }: Props): VNode { const { i18n } = useTranslationContext(); const { state } = useBackendState(); const creds = state.status !== "loggedIn" ? undefined : state const { api } = useBankCoreApiContext() const cid = Number.parseInt(id, 10) const result = useCashoutDetails(Number.isNaN(cid) ? undefined : cid); const [code, setCode] = useState(undefined); const [notification, notify, handleError] = useLocalNotification() const info = useConversionInfo(); if (Number.isNaN(cid)) { //TODO: better error message return
cashout id should be a number
} if (!result) { return } if (result instanceof TalerError) { return } if (result.type === "fail") { switch (result.case) { case HttpStatusCode.NotFound: return case HttpStatusCode.NotImplemented: return default: assertUnreachable(result) } } if (!info) { return } if (info instanceof TalerError) { return } const errors = undefinedIfEmpty({ code: !code ? i18n.str`required` : undefined, }); /** * @deprecated */ const isPending = String(result.body.status).toUpperCase() === "PENDING"; const { fiat_currency_specification, regional_currency_specification } = info.body // won't implement in retry in old API 3:0:3 since request_uid is missing async function doAbortCashout() { if (!creds) return; await handleError(async () => { const resp = await api.abortCashoutById(creds, cid); if (resp.type === "ok") { onCancel(); } else { switch (resp.case) { case HttpStatusCode.NotFound: return notify({ type: "error", title: i18n.str`Cashout not found. It may be also mean that it was already aborted.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }) case HttpStatusCode.Conflict: return notify({ type: "error", title: i18n.str`Cashout was already confimed.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }) case HttpStatusCode.NotImplemented: return notify({ type: "error", title: i18n.str`Cashout operation is not supported.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }) default: { assertUnreachable(resp) } } } }) } async function doConfirmCashout() { if (!creds || !code) return; await handleError(async () => { const resp = await api.confirmCashoutById(creds, cid, { tan: code, }); if (resp.type === "ok") { mutate(() => true)//clean cashout state } else { switch (resp.case) { case HttpStatusCode.NotFound: return notify({ type: "error", title: i18n.str`Cashout not found. It may be also mean that it was already aborted.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }) case TalerErrorCode.BANK_UNALLOWED_DEBIT: return notify({ type: "error", title: i18n.str`The account does not have sufficient funds`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }); case TalerErrorCode.BANK_BAD_CONVERSION: return notify({ type: "error", title: i18n.str`The conversion rate was incorrectly applied`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }); case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return notify({ type: "error", title: i18n.str`The cashout operation is already aborted.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }); case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return notify({ type: "error", title: i18n.str`Missing destination account.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }) case HttpStatusCode.TooManyRequests: return notify({ type: "error", title: i18n.str`Too many failed attempts.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }) case HttpStatusCode.NotImplemented: return notify({ type: "error", title: i18n.str`Cashout operation is not supported.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }) case TalerErrorCode.BANK_TAN_CHALLENGE_FAILED: return notify({ type: "error", title: i18n.str`The code for this cashout is invalid.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }) default: assertUnreachable(resp) } } }) } return (

Cashout detail

Subject
{result.body.subject}
Status
{result.body.status}
{result.body.creation_time.t_s !== "never" ?
Created
{format(result.body.creation_time.t_s * 1000, "dd/MM/yyyy HH:mm:ss")}
: undefined}
Debited
Credited
{result.body.confirmation_time && result.body.confirmation_time.t_s !== "never" ?
Confirmed
{format(result.body.confirmation_time.t_s * 1000, "dd/MM/yyyy HH:mm:ss")}
: undefined}
{!isPending ? undefined :
{ e.preventDefault() }} >
{ setCode(e.currentTarget.value) }} />
}

); }