diff options
Diffstat (limited to 'packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx')
-rw-r--r-- | packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx | 165 |
1 files changed, 83 insertions, 82 deletions
diff --git a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx index 28f00169d..80e7a78ac 100644 --- a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx +++ b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx @@ -20,24 +20,23 @@ import { HttpStatusCode, Logger, PaytoUri, - PaytoUriGeneric, PaytoUriIBAN, PaytoUriTalerBank, TranslatedString, - WithdrawUriResult, + WithdrawUriResult } from "@gnu-taler/taler-util"; import { RequestError, notify, notifyError, + notifyInfo, useTranslationContext, } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useMemo, useState } from "preact/hooks"; +import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js"; import { useAccessAnonAPI } from "../hooks/access.js"; import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js"; -import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js"; -import { Amount } from "./PaytoWireTransferForm.js"; const logger = new Logger("WithdrawalConfirmationQuestion"); @@ -71,6 +70,7 @@ export function WithdrawalConfirmationQuestion({ const { confirmWithdrawal, abortWithdrawal } = useAccessAnonAPI(); const [captchaAnswer, setCaptchaAnswer] = useState<string | undefined>(); const answer = parseInt(captchaAnswer ?? "", 10); + const [busy, setBusy] = useState<Record<string, undefined>>() const errors = undefinedIfEmpty({ answer: !captchaAnswer ? i18n.str`Answer the question before continue` @@ -79,13 +79,15 @@ export function WithdrawalConfirmationQuestion({ : answer !== captchaNumbers.a + captchaNumbers.b ? i18n.str`The answer "${answer}" to "${captchaNumbers.a} + ${captchaNumbers.b}" is wrong.` : undefined, - }); + }) ?? busy; async function doTransfer() { try { + setBusy({}) await confirmWithdrawal( withdrawUri.withdrawalOperationId, ); + notifyInfo(i18n.str`Wire transfer completed!`) } catch (error) { if (error instanceof RequestError) { notify( @@ -107,10 +109,12 @@ export function WithdrawalConfirmationQuestion({ ) } } + setBusy(undefined) } async function doCancel() { try { + setBusy({}) await abortWithdrawal(withdrawUri.withdrawalOperationId); onAborted(); } catch (error) { @@ -132,6 +136,7 @@ export function WithdrawalConfirmationQuestion({ ) } } + setBusy(undefined) } return ( @@ -142,68 +147,6 @@ export function WithdrawalConfirmationQuestion({ <i18n.Translate>Confirm the withdrawal operation</i18n.Translate> </h3> <div class="mt-2 max-w-xl text-sm text-gray-500"> - <div class="px-4 mt-4 "> - <div class="w-full"> - <div class="px-4 sm:px-0"> - <p><i18n.Translate>Wire transfer details</i18n.Translate></p> - </div> - <div class="mt-6 border-t border-gray-100"> - <dl class="divide-y divide-gray-100"> - {((): VNode => { - switch (details.account.targetType) { - case "iban": { - const p = details.account as PaytoUriIBAN - const name = p.params["receiver-name"] - return <Fragment> - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Exchange account</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.iban}</dd> - </div> - {name && - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Exchange name</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.params["receiver-name"]}</dd> - </div> - } - </Fragment> - } - case "x-taler-bank": { - const p = details.account as PaytoUriTalerBank - const name = p.params["receiver-name"] - return <Fragment> - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Exchange account</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.account}</dd> - </div> - {name && - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Exchange name</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.params["receiver-name"]}</dd> - </div> - } - </Fragment> - } - default: - return <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Exchange account</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{details.account.targetPath}</dd> - </div> - - } - })()} - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Withdrawal identification</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{details.reserve}</dd> - </div> - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Amount</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{Amounts.stringifyValue(details.amount)}</dd> - </div> - </dl> - </div> - </div> - - </div> <div class="px-4 mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-3 sm:gap-x-3"> <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-noneborder-indigo-600 ring-2 ring-indigo-600"}> @@ -285,36 +228,32 @@ export function WithdrawalConfirmationQuestion({ aria-describedby="answer" autoFocus class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" - // value={username ?? ""} + value={captchaAnswer ?? ""} required name="answer" id="answer" autocomplete="off" - // value={value ?? ""} - // disabled={!onChange} - // onInput={(e): void => { - // if (onChange) { - // onChange(e.currentTarget.value); - // } - // }} + onChange={(e): void => { + setCaptchaAnswer(e.currentTarget.value) + }} /> </div> - <ShowInputErrorLabel message={errors?.answer} isDirty={false} /> + <ShowInputErrorLabel message={errors?.answer} isDirty={captchaAnswer !== undefined} /> </div> </div> <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8"> <button type="button" class="text-sm font-semibold leading-6 text-gray-900" - // onClick={onCancel} + onClick={doCancel} > <i18n.Translate>Cancel</i18n.Translate></button> <button type="submit" class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" - // disabled={isRawPayto ? !!errorsPayto : !!errorsWire} - // onClick={(e) => { - // e.preventDefault() - // doStart() - // }} + disabled={!!errors} + onClick={(e) => { + e.preventDefault() + doTransfer() + }} > <i18n.Translate>Transfer</i18n.Translate> </button> @@ -323,6 +262,68 @@ export function WithdrawalConfirmationQuestion({ </form> </div> </div> + <div class="px-4 mt-4 "> + <div class="w-full"> + <div class="px-4 sm:px-0"> + <p><i18n.Translate>Wire transfer details</i18n.Translate></p> + </div> + <div class="mt-6 border-t border-gray-100"> + <dl class="divide-y divide-gray-100"> + {((): VNode => { + switch (details.account.targetType) { + case "iban": { + const p = details.account as PaytoUriIBAN + const name = p.params["receiver-name"] + return <Fragment> + <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> + <dt class="text-sm font-medium leading-6 text-gray-900">Exchange account</dt> + <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.iban}</dd> + </div> + {name && + <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> + <dt class="text-sm font-medium leading-6 text-gray-900">Exchange name</dt> + <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.params["receiver-name"]}</dd> + </div> + } + </Fragment> + } + case "x-taler-bank": { + const p = details.account as PaytoUriTalerBank + const name = p.params["receiver-name"] + return <Fragment> + <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> + <dt class="text-sm font-medium leading-6 text-gray-900">Exchange account</dt> + <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.account}</dd> + </div> + {name && + <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> + <dt class="text-sm font-medium leading-6 text-gray-900">Exchange name</dt> + <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.params["receiver-name"]}</dd> + </div> + } + </Fragment> + } + default: + return <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> + <dt class="text-sm font-medium leading-6 text-gray-900">Exchange account</dt> + <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{details.account.targetPath}</dd> + </div> + + } + })()} + <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> + <dt class="text-sm font-medium leading-6 text-gray-900">Withdrawal identification</dt> + <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{details.reserve}</dd> + </div> + <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> + <dt class="text-sm font-medium leading-6 text-gray-900">Amount</dt> + <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{Amounts.stringifyValue(details.amount)}</dd> + </div> + </dl> + </div> + </div> + + </div> </div> </div> |