diff options
Diffstat (limited to 'packages/bank-ui')
11 files changed, 456 insertions, 135 deletions
diff --git a/packages/bank-ui/src/components/Transactions/state.ts b/packages/bank-ui/src/components/Transactions/state.ts index e792ddfa0..4e4552a82 100644 --- a/packages/bank-ui/src/components/Transactions/state.ts +++ b/packages/bank-ui/src/components/Transactions/state.ts @@ -55,7 +55,7 @@ export function useComponentState({ : cp.targetType === "x-taler-bank" ? cp.account : cp.targetType === "bitcoin" - ? `${cp.targetPath.substring(0, 6)}...` + ? `${cp.address.substring(0, 6)}...` : undefined) ?? "unknown"; const when = AbsoluteTime.fromProtocolTimestamp(tx.date); diff --git a/packages/bank-ui/src/components/Transactions/views.tsx b/packages/bank-ui/src/components/Transactions/views.tsx index da64efdb2..4397651e2 100644 --- a/packages/bank-ui/src/components/Transactions/views.tsx +++ b/packages/bank-ui/src/components/Transactions/views.tsx @@ -120,7 +120,7 @@ export function ReadyView({ <Time format="HH:mm:ss" timestamp={item.when} - // relative={Duration.fromSpec({ days: 1 })} + // relative={Duration.fromSpec({ days: 1 })} /> </div> <dl class="font-normal sm:hidden"> diff --git a/packages/bank-ui/src/pages/PaytoWireTransferForm.tsx b/packages/bank-ui/src/pages/PaytoWireTransferForm.tsx index d5bb5f88f..7812a1da0 100644 --- a/packages/bank-ui/src/pages/PaytoWireTransferForm.tsx +++ b/packages/bank-ui/src/pages/PaytoWireTransferForm.tsx @@ -78,7 +78,6 @@ export function PaytoWireTransferForm({ onAuthorizationRequired, limit, }: Props): VNode { - const [inputType, setInputType] = useState<"form" | "payto" | "qr">("form"); const isRawPayto = inputType !== "form"; @@ -150,7 +149,7 @@ export function PaytoWireTransferForm({ : p.targetType === "iban" ? p.iban : p.targetType === "bitcoin" - ? p.targetPath + ? p.address : p.targetType === "x-taler-bank" ? p.account : assertUnreachable(p); @@ -215,7 +214,8 @@ export function PaytoWireTransferForm({ case TalerErrorCode.BANK_UNKNOWN_CREDITOR: return notify({ type: "error", - title: i18n.str`The destination account "${acName ?? puri}" was not found.`, + title: i18n.str`The destination account "${acName ?? puri + }" was not found.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, when: AbsoluteTime.now(), @@ -351,106 +351,168 @@ export function PaytoWireTransferForm({ <i18n.Translate>Input wire transfer detail</i18n.Translate> </legend> <div class="-space-y-px rounded-md "> - <label data-checked={inputType === "form"} class="group rounded-tl-md rounded-tr-md relative flex cursor-pointer border p-4 focus:outline-none bg-white data-[checked=true]:z-10 data-[checked=true]:border-indigo-200 data-[checked=true]:bg-indigo-50"> - <input type="radio" name="input-type" onChange={() => { - if (parsed && parsed.isKnown) { - switch (parsed.targetType) { - case "iban": { - setAccount(parsed.iban); - break; - } - case "x-taler-bank": { - setAccount(parsed.account); - break; - } - case "bitcoin": { - break; + <label + data-checked={inputType === "form"} + class="group rounded-tl-md rounded-tr-md relative flex cursor-pointer border p-4 focus:outline-none bg-white data-[checked=true]:z-10 data-[checked=true]:border-indigo-200 data-[checked=true]:bg-indigo-50" + > + <input + type="radio" + name="input-type" + onChange={() => { + if (parsed && parsed.isKnown) { + switch (parsed.targetType) { + case "iban": { + setAccount(parsed.iban); + break; + } + case "x-taler-bank": { + setAccount(parsed.account); + break; + } + case "bitcoin": { + break; + } + default: { + assertUnreachable(parsed); + } } - default: { - assertUnreachable(parsed); + const amountStr = !parsed.params + ? undefined + : parsed.params["amount"]; + if (amountStr) { + const amount = Amounts.parse(amountStr); + if (amount) { + setAmount(Amounts.stringifyValue(amount)); + } } - } - const amountStr = !parsed.params - ? undefined - : parsed.params["amount"]; - if (amountStr) { - const amount = Amounts.parse(amountStr); - if (amount) { - setAmount(Amounts.stringifyValue(amount)); + const subject = parsed.params["message"]; + if (subject) { + setSubject(subject); } } - const subject = parsed.params["message"]; - if (subject) { - setSubject(subject); - } - } - setInputType("form") - }} checked={inputType === "form"} value="form" class="mt-0.5 h-4 w-4 shrink-0 cursor-pointer text-indigo-600 border-gray-300 focus:ring-indigo-600 active:ring-2 active:ring-offset-2 active:ring-indigo-600" /> + setInputType("form"); + }} + checked={inputType === "form"} + value="form" + class="mt-0.5 h-4 w-4 shrink-0 cursor-pointer text-indigo-600 border-gray-300 focus:ring-indigo-600 active:ring-2 active:ring-offset-2 active:ring-indigo-600" + /> <span class="ml-3 flex flex-col"> {/* <!-- Checked: "text-indigo-900", Not Checked: "text-gray-900" --> */} - <span data-checked={inputType === "form"} class="block text-sm font-medium data-[checked=true]:text-indigo-900"> + <span + data-checked={inputType === "form"} + class="block text-sm font-medium data-[checked=true]:text-indigo-900" + > <i18n.Translate>Using a form</i18n.Translate> </span> </span> </label> - {sendingToFixedAccount ? undefined : (<Fragment> - <label data-checked={inputType === "payto"} class="relative flex cursor-pointer border p-4 focus:outline-none bg-white data-[checked=true]:z-10 data-[checked=true]:border-indigo-200 data-[checked=true]:bg-indigo-50"> - <input type="radio" name="input-type" onChange={() => { - if (account) { - let payto; - switch (paytoType) { - case "x-taler-bank": { - payto = buildPayto("x-taler-bank", url.host, account); - if (parsedAmount) { - payto.params["amount"] = - Amounts.stringify(parsedAmount); - } - if (subject) { - payto.params["message"] = subject; - } - break; - } - case "iban": { - payto = buildPayto("iban", account, undefined); - if (parsedAmount) { - payto.params["amount"] = - Amounts.stringify(parsedAmount); - } - if (subject) { - payto.params["message"] = subject; + {sendingToFixedAccount ? undefined : ( + <Fragment> + <label + data-checked={inputType === "payto"} + class="relative flex cursor-pointer border p-4 focus:outline-none bg-white data-[checked=true]:z-10 data-[checked=true]:border-indigo-200 data-[checked=true]:bg-indigo-50" + > + <input + type="radio" + name="input-type" + onChange={() => { + if (account) { + let payto; + switch (paytoType) { + case "x-taler-bank": { + payto = buildPayto( + "x-taler-bank", + url.host, + account, + ); + if (parsedAmount) { + payto.params["amount"] = + Amounts.stringify(parsedAmount); + } + if (subject) { + payto.params["message"] = subject; + } + break; + } + case "iban": { + payto = buildPayto("iban", account, undefined); + if (parsedAmount) { + payto.params["amount"] = + Amounts.stringify(parsedAmount); + } + if (subject) { + payto.params["message"] = subject; + } + break; + } + default: + assertUnreachable(paytoType); } - break; + rawPaytoInputSetter(stringifyPaytoUri(payto)); } - default: - assertUnreachable(paytoType); - } - rawPaytoInputSetter(stringifyPaytoUri(payto)); - } setInputType("payto") - }} checked={inputType === "payto"} value="payto" class="mt-0.5 h-4 w-4 shrink-0 cursor-pointer text-indigo-600 border-gray-300 focus:ring-indigo-600 active:ring-2 active:ring-offset-2 active:ring-indigo-600" /> - <span class="ml-3 flex flex-col"> - <span data-checked={inputType === "payto"} class="block font-medium data-[checked=true]:text-indigo-900">payto:// URI</span> - <span data-checked={inputType === "payto"} class="block text-sm text-gray-500 data-[checked=true]:text-indigo-600"> - <i18n.Translate>A special URI that indicate the transfer amount and account target.</i18n.Translate> - </span> - </span> - </label> - { //FIXME: add QR support - false && <label data-checked={inputType === "qr"} class="rounded-bl-md rounded-br-md relative flex cursor-pointer border p-4 focus:outline-none bg-white data-[checked=true]:z-10 data-[checked=true]:border-indigo-200 data-[checked=true]:bg-indigo-50"> - <input type="radio" name="input-type" onChange={() => { - setInputType("qr") - }} checked={inputType === "qr"} value="qr" class="mt-0.5 h-4 w-4 shrink-0 cursor-pointer text-indigo-600 border-gray-300 focus:ring-indigo-600 active:ring-2 active:ring-offset-2 active:ring-indigo-600" /> + setInputType("payto"); + }} + checked={inputType === "payto"} + value="payto" + class="mt-0.5 h-4 w-4 shrink-0 cursor-pointer text-indigo-600 border-gray-300 focus:ring-indigo-600 active:ring-2 active:ring-offset-2 active:ring-indigo-600" + /> <span class="ml-3 flex flex-col"> - <span data-checked={inputType === "qr"} class="block font-medium data-[checked=true]:text-indigo-900"> - <i18n.Translate>QR code</i18n.Translate> + <span + data-checked={inputType === "payto"} + class="block font-medium data-[checked=true]:text-indigo-900" + > + payto:// URI </span> - <span data-checked={inputType === "qr"} class="block text-sm text-gray-500 data-[checked=true]:text-indigo-600"> - <i18n.Translate>If you have a camera in this device you can import a payto:// URI from a QR code.</i18n.Translate> + <span + data-checked={inputType === "payto"} + class="block text-sm text-gray-500 data-[checked=true]:text-indigo-600" + > + <i18n.Translate> + A special URI that indicate the transfer amount and + account target. + </i18n.Translate> </span> </span> </label> - } - </Fragment>)} - + { + //FIXME: add QR support + false && ( + <label + data-checked={inputType === "qr"} + class="rounded-bl-md rounded-br-md relative flex cursor-pointer border p-4 focus:outline-none bg-white data-[checked=true]:z-10 data-[checked=true]:border-indigo-200 data-[checked=true]:bg-indigo-50" + > + <input + type="radio" + name="input-type" + onChange={() => { + setInputType("qr"); + }} + checked={inputType === "qr"} + value="qr" + class="mt-0.5 h-4 w-4 shrink-0 cursor-pointer text-indigo-600 border-gray-300 focus:ring-indigo-600 active:ring-2 active:ring-offset-2 active:ring-indigo-600" + /> + <span class="ml-3 flex flex-col"> + <span + data-checked={inputType === "qr"} + class="block font-medium data-[checked=true]:text-indigo-900" + > + <i18n.Translate>QR code</i18n.Translate> + </span> + <span + data-checked={inputType === "qr"} + class="block text-sm text-gray-500 data-[checked=true]:text-indigo-600" + > + <i18n.Translate> + If you have a camera in this device you can import a + payto:// URI from a QR code. + </i18n.Translate> + </span> + </span> + </label> + ) + } + </Fragment> + )} </div> {routeCashout ? ( <a @@ -461,11 +523,9 @@ export function PaytoWireTransferForm({ <i18n.Translate>Cashout</i18n.Translate> </a> ) : undefined} - </fieldset> </div> - <form class="bg-white shadow-sm ring-1 ring-gray-900/5 rounded-md sm:rounded-xl md:col-span-2 w-fit mx-auto" autoCapitalize="none" diff --git a/packages/bank-ui/src/pages/SolveChallengePage.tsx b/packages/bank-ui/src/pages/SolveChallengePage.tsx index 23f3de1d2..30ca122bf 100644 --- a/packages/bank-ui/src/pages/SolveChallengePage.tsx +++ b/packages/bank-ui/src/pages/SolveChallengePage.tsx @@ -264,7 +264,6 @@ export function SolveChallengePage({ authentication channel you provided. </i18n.Translate> </p> - <span></span> </div> <div class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"> diff --git a/packages/bank-ui/src/pages/WalletWithdrawForm.tsx b/packages/bank-ui/src/pages/WalletWithdrawForm.tsx index 8e9529190..2aa0338ad 100644 --- a/packages/bank-ui/src/pages/WalletWithdrawForm.tsx +++ b/packages/bank-ui/src/pages/WalletWithdrawForm.tsx @@ -105,12 +105,12 @@ function OldWithdrawalForm({ class="font-semibold text-yellow-700 hover:text-yellow-600" name="complete operation" href={url} - // onClick={(e) => { - // e.preventDefault() - // walletInegrationApi.publishTalerAction(uri, () => { - // navigateTo(url) - // }) - // }} + // onClick={(e) => { + // e.preventDefault() + // walletInegrationApi.publishTalerAction(uri, () => { + // navigateTo(url) + // }) + // }} > <i18n.Translate>this page</i18n.Translate> </a> @@ -392,7 +392,7 @@ export function WalletWithdrawForm({ routeClose={routeCancel} routeHere={routeOperationDetails} onAbort={onOperationAborted} - // route={routeCancel} + // route={routeCancel} /> )} </div> diff --git a/packages/bank-ui/src/pages/WithdrawalConfirmationQuestion.tsx b/packages/bank-ui/src/pages/WithdrawalConfirmationQuestion.tsx index 965650eb0..c7bdaaf21 100644 --- a/packages/bank-ui/src/pages/WithdrawalConfirmationQuestion.tsx +++ b/packages/bank-ui/src/pages/WithdrawalConfirmationQuestion.tsx @@ -222,10 +222,21 @@ export function WithdrawalConfirmationQuestion({ <div class="mt-6 border-t border-gray-100"> <dl class="divide-y divide-gray-100"> {((): VNode => { + if (!details.account.isKnown) { + 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"> + <i18n.Translate> + Payment provider's account + </i18n.Translate> + </dt> + <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0"> + {details.account.targetPath} + </dd> + </div> + } switch (details.account.targetType) { case "iban": { - const p = details.account as PaytoUriIBAN; - const name = p.params["receiver-name"]; + const name = details.account.params["receiver-name"]; return ( <Fragment> <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> @@ -235,7 +246,7 @@ export function WithdrawalConfirmationQuestion({ </i18n.Translate> </dt> <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0"> - {p.iban} + {details.account.iban} </dd> </div> {name && ( @@ -254,18 +265,27 @@ export function WithdrawalConfirmationQuestion({ ); } case "x-taler-bank": { - const p = details.account as PaytoUriTalerBank; - const name = p.params["receiver-name"]; + const name = details.account.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"> <i18n.Translate> + Payment provider's account bank hostname + </i18n.Translate> + </dt> + <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0"> + {details.account.host} + </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"> + <i18n.Translate> Payment provider's account id </i18n.Translate> </dt> <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0"> - {p.account} + {details.account.account} </dd> </div> {name && ( @@ -283,19 +303,39 @@ export function WithdrawalConfirmationQuestion({ </Fragment> ); } - default: + case "bitcoin": { + const name = details.account.params["receiver-name"]; 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"> - <i18n.Translate> - Payment provider's account - </i18n.Translate> - </dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0"> - {details.account.targetPath} - </dd> - </div> + <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"> + <i18n.Translate> + Payment provider's account address + </i18n.Translate> + </dt> + <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0"> + {details.account.address} + </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"> + <i18n.Translate> + Payment provider's name + </i18n.Translate> + </dt> + <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0"> + {name} + </dd> + </div> + )} + </Fragment> ); + } + default: { + assertUnreachable(details.account) + } + } })()} <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> diff --git a/packages/bank-ui/src/pages/account/ShowAccountDetails.tsx b/packages/bank-ui/src/pages/account/ShowAccountDetails.tsx index e81d46d77..13685c2c8 100644 --- a/packages/bank-ui/src/pages/account/ShowAccountDetails.tsx +++ b/packages/bank-ui/src/pages/account/ShowAccountDetails.tsx @@ -19,10 +19,13 @@ import { TalerCorebankApi, TalerError, TalerErrorCode, + TalerRevenueHttpClient, TranslatedString, assertUnreachable, + parsePaytoUri, } from "@gnu-taler/taler-util"; import { + CopyButton, Loading, LocalNotificationBanner, notifyInfo, @@ -67,7 +70,7 @@ export function ShowAccountDetails({ const { i18n } = useTranslationContext(); const { state: credentials } = useSessionState(); const creds = credentials.status !== "loggedIn" ? undefined : credentials; - const { bank: api } = useBankCoreApiContext(); + const { bank } = useBankCoreApiContext(); const accountIsTheCurrentUser = credentials.status === "loggedIn" ? credentials.username === account @@ -99,7 +102,7 @@ export function ShowAccountDetails({ async function doUpdate() { if (!submitAccount || !creds) return; await handleError(async () => { - const resp = await api.updateAccount( + const resp = await bank.updateAccount( { token: creds.token, username: account, @@ -186,6 +189,31 @@ export function ShowAccountDetails({ }); } + + const url = bank.getRevenueAPI(account) + url.username = account; + const baseURL = url.href; + + const ac = parsePaytoUri(result.body.payto_uri); + const payto = !ac?.isKnown ? undefined : ac; + let accountLetter: string | undefined = undefined; + if (payto) { + switch (payto.targetType) { + case "iban": { + accountLetter = `account-info-url=${url.href}\naccount-type=${payto.targetType}\niban=${payto.iban}\nreceiver-name=${result.body.name}\n`; + break; + } + case "x-taler-bank": { + accountLetter = `account-info-url=${url.href}\naccount-type=${payto.targetType}\naccount=${payto.account}\nhost=${payto.host}\nreceiver-name=${result.body.name}\n`; + break; + } + case "bitcoin": { + accountLetter = `account-info-url=${url.href}\naccount-type=${payto.targetType}\naddress=${payto.address}\nreceiver-name=${result.body.name}\n`; + break; + } + } + } + return ( <Fragment> <LocalNotificationBanner notification={notification} showDebug={true} /> @@ -247,6 +275,198 @@ export function ShowAccountDetails({ </div> </AccountForm> </div> + <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg"> + <div class="px-4 sm:px-0"> + <h2 class="text-base font-semibold leading-7 text-gray-900"> + <div class="flex items-center justify-between"> + <span class="flex flex-grow flex-col"> + <span + class="text-sm text-black font-semibold leading-6 " + id="availability-label" + > + <i18n.Translate>Merchant integration</i18n.Translate> + </span> + </span> + </div> + </h2> + <p class="mt-2 text-sm text-gray-500"> + <i18n.Translate> + Use this information to link your Taler Merchant Backoffice account + with the current bank account. You can start by copying the values, + then go to your merchant backoffice service provider, login into + your account and look for the "import" button in the "bank account" section. + </i18n.Translate> + </p> + </div> + + {payto !== undefined && + <div class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"> + <div class="px-4 py-6 sm:p-8"> + <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6"> + <div class="sm:col-span-5"> + <label + class="block text-sm font-medium leading-6 text-gray-900" + for="account-type" + > + {i18n.str`Account type`} + </label> + <div class="mt-2"> + <input + type="text" + class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + name="account-type" + id="account-type" + disabled={true} + value={account} + autocomplete="off" + /> + </div> + <p class="mt-2 text-sm text-gray-500"> + <i18n.Translate>Method to use for wire transfer.</i18n.Translate> + </p> + </div> + {((payto) => { + switch (payto.targetType) { + case "iban": { + return <div class="sm:col-span-5"> + <label + class="block text-sm font-medium leading-6 text-gray-900" + for="iban" + > + {i18n.str`IBAN`} + </label> + <div class="mt-2"> + <input + type="text" + class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + name="iban" + id="iban" + disabled={true} + value={payto.iban} + autocomplete="off" + /> + </div> + <p class="mt-2 text-sm text-gray-500"> + <i18n.Translate>International Bank Account Number.</i18n.Translate> + </p> + </div> + } + case "x-taler-bank": { + return <div class="sm:col-span-5"> + <label + class="block text-sm font-medium leading-6 text-gray-900" + for="iban" + > + {i18n.str`IBAN`} + </label> + <div class="mt-2"> + <input + type="text" + class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + name="iban" + id="iban" + disabled={true} + value={payto.account} + autocomplete="off" + /> + </div> + <p class="mt-2 text-sm text-gray-500"> + <i18n.Translate>International Bank Account Number.</i18n.Translate> + </p> + </div> + } + case "bitcoin": { + return <div class="sm:col-span-5"> + <label + class="block text-sm font-medium leading-6 text-gray-900" + for="iban" + > + {i18n.str`Address`} + </label> + <div class="mt-2"> + <input + type="text" + class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + name="iban" + id="iban" + disabled={true} + value={"DE1231231231"} + autocomplete="off" + /> + </div> + <p class="mt-2 text-sm text-gray-500"> + <i18n.Translate>International Bank Account Number.</i18n.Translate> + </p> + </div> + } + } + })(payto)} + + <div class="sm:col-span-5"> + <label + class="block text-sm font-medium leading-6 text-gray-900" + for="iban" + > + {i18n.str`Owner's name`} + </label> + <div class="mt-2"> + <input + type="text" + class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + name="iban" + id="iban" + disabled={true} + value={result.body.name} + autocomplete="off" + /> + </div> + <p class="mt-2 text-sm text-gray-500"> + <i18n.Translate>Legal name of the person holding the account.</i18n.Translate> + </p> + </div> + <div class="sm:col-span-5"> + <label + class="block text-sm font-medium leading-6 text-gray-900" + for="iban" + > + {i18n.str`Account info URL`} + </label> + <div class="mt-2"> + <input + type="text" + class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + name="iban" + id="iban" + disabled={true} + value={baseURL} + autocomplete="off" + /> + </div> + <p class="mt-2 text-sm text-gray-500"> + <i18n.Translate>From where the merchant can download information about incoming wire transfers to this account.</i18n.Translate> + </p> + </div> + </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"> + <a + href={routeClose.url({})} + name="cancel" + class="text-sm font-semibold leading-6 text-gray-900" + > + <i18n.Translate>Cancel</i18n.Translate> + </a> + <CopyButton + getContent={() => accountLetter ?? ""} + class="flex text-center 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"> + <i18n.Translate>Copy</i18n.Translate> + </CopyButton> + </div> + </div> + } + + </div> + </Fragment> ); } diff --git a/packages/bank-ui/src/pages/admin/DownloadStats.tsx b/packages/bank-ui/src/pages/admin/DownloadStats.tsx index 078435fe9..bef12c580 100644 --- a/packages/bank-ui/src/pages/admin/DownloadStats.tsx +++ b/packages/bank-ui/src/pages/admin/DownloadStats.tsx @@ -460,9 +460,9 @@ async function fetchAllStatus( // await delay() const previous = options.compareWithPrevious ? await api.getMonitor(token, { - timeframe: frame.timeframe, - which: frame.moment.previous, - }) + timeframe: frame.timeframe, + which: frame.moment.previous, + }) : undefined; if (previous && previous.type === "fail" && options.endOnFirstFail) { diff --git a/packages/bank-ui/src/pages/regional/ConversionConfig.tsx b/packages/bank-ui/src/pages/regional/ConversionConfig.tsx index 8602580a0..014142e97 100644 --- a/packages/bank-ui/src/pages/regional/ConversionConfig.tsx +++ b/packages/bank-ui/src/pages/regional/ConversionConfig.tsx @@ -519,8 +519,8 @@ function useComponentState({ </div> {cashoutCalc && - status.status === "ok" && - Amounts.cmp(status.result.amount, cashoutCalc.credit) < + status.status === "ok" && + Amounts.cmp(status.result.amount, cashoutCalc.credit) < 0 ? ( <div class="p-4"> <Attention diff --git a/packages/bank-ui/src/pages/regional/CreateCashout.tsx b/packages/bank-ui/src/pages/regional/CreateCashout.tsx index 8f16e31be..20d6b0bff 100644 --- a/packages/bank-ui/src/pages/regional/CreateCashout.tsx +++ b/packages/bank-ui/src/pages/regional/CreateCashout.tsx @@ -198,7 +198,8 @@ export function CreateCashout({ * depending on the isDebit flag */ const inputAmount = Amounts.parseOrThrow( - `${form.isDebit ? regional_currency : fiat_currency}:${!form.amount ? "0" : form.amount + `${form.isDebit ? regional_currency : fiat_currency}:${ + !form.amount ? "0" : form.amount }`, ); @@ -239,11 +240,12 @@ export function CreateCashout({ : Amounts.cmp(limit, calc.debit) === -1 ? i18n.str`Balance is not enough` : form.isDebit && - Amounts.cmp(inputAmount, conversionInfo.cashout_min_amount) < 1 - ? i18n.str`Needs to be higher than ${Amounts.stringifyValueWithSpec( - Amounts.parseOrThrow(conversionInfo.cashout_min_amount), - regional_currency_specification, - ).normal + Amounts.cmp(inputAmount, conversionInfo.cashout_min_amount) < 1 + ? i18n.str`Needs to be higher than ${ + Amounts.stringifyValueWithSpec( + Amounts.parseOrThrow(conversionInfo.cashout_min_amount), + regional_currency_specification, + ).normal }` : calculationResult === "amount-is-too-small" ? i18n.str`Amount needs to be higher` @@ -611,9 +613,9 @@ export function CreateCashout({ cashoutDisabled ? undefined : (value) => { - form.amount = value; - updateForm(structuredClone(form)); - } + form.amount = value; + updateForm(structuredClone(form)); + } } /> <ShowInputErrorLabel @@ -654,7 +656,7 @@ export function CreateCashout({ </dd> </div> {Amounts.isZero(sellFee) || - Amounts.isZero(calc.beforeFee) ? undefined : ( + Amounts.isZero(calc.beforeFee) ? undefined : ( <div class="flex items-center justify-between border-t-2 afu pt-4"> <dt class="flex items-center text-sm text-gray-600"> <span> @@ -687,7 +689,7 @@ export function CreateCashout({ {/* channel, not shown if new cashout api */} {!OLD_CASHOUT_API ? undefined : config.supported_tan_channels - .length === 0 ? ( + .length === 0 ? ( <div class="sm:col-span-5"> <Attention type="warning" @@ -759,7 +761,7 @@ export function CreateCashout({ )} {config.supported_tan_channels.indexOf(TanChannel.SMS) === - -1 ? undefined : ( + -1 ? undefined : ( <label onClick={() => { if (!resultAccount.body.contact_data?.phone) return; diff --git a/packages/bank-ui/src/pages/regional/ShowCashoutDetails.tsx b/packages/bank-ui/src/pages/regional/ShowCashoutDetails.tsx index 0f9f2d1b7..849da77aa 100644 --- a/packages/bank-ui/src/pages/regional/ShowCashoutDetails.tsx +++ b/packages/bank-ui/src/pages/regional/ShowCashoutDetails.tsx @@ -138,7 +138,7 @@ export function ShowCashoutDetails({ id, routeClose }: Props): VNode { timestamp={AbsoluteTime.fromProtocolTimestamp( result.body.creation_time, )} - // relative={Duration.fromSpec({ days: 1 })} + // relative={Duration.fromSpec({ days: 1 })} /> </dd> </div> |