diff options
author | Sebastian <sebasjm@gmail.com> | 2023-09-19 08:31:08 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2023-09-25 14:50:38 -0300 |
commit | a5406c5a5dc437e036168eb068db11d88e05bb0f (patch) | |
tree | 74ad5e0d858a5afb3e76ac0c692fdba866fed38f /packages/demobank-ui/src/pages | |
parent | e628ca1af851259e609a16d0b53b8d7abfc33716 (diff) | |
download | wallet-core-a5406c5a5dc437e036168eb068db11d88e05bb0f.tar.xz |
some ui
Diffstat (limited to 'packages/demobank-ui/src/pages')
-rw-r--r-- | packages/demobank-ui/src/pages/AccountPage/views.tsx | 93 | ||||
-rw-r--r-- | packages/demobank-ui/src/pages/BankFrame.tsx | 266 | ||||
-rw-r--r-- | packages/demobank-ui/src/pages/PaymentOptions.tsx | 100 | ||||
-rw-r--r-- | packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx | 581 | ||||
-rw-r--r-- | packages/demobank-ui/src/pages/Test.tsx | 5 | ||||
-rw-r--r-- | packages/demobank-ui/src/pages/WalletWithdrawForm.tsx | 8 |
6 files changed, 627 insertions, 426 deletions
diff --git a/packages/demobank-ui/src/pages/AccountPage/views.tsx b/packages/demobank-ui/src/pages/AccountPage/views.tsx index b476759b4..f2cbbba6c 100644 --- a/packages/demobank-ui/src/pages/AccountPage/views.tsx +++ b/packages/demobank-ui/src/pages/AccountPage/views.tsx @@ -21,54 +21,67 @@ import { Transactions } from "../../components/Transactions/index.js"; import { PaymentOptions } from "../PaymentOptions.js"; import { State } from "./index.js"; import { CopyButton } from "../../components/CopyButton.js"; +import { bankUiSettings } from "../../settings.js"; -export function InvalidIbanView({error}:State.InvalidIban) { - return ( - <div>Payto from server is not valid "{error.data.paytoUri}"</div> - ); +export function InvalidIbanView({ error }: State.InvalidIban) { + return ( + <div>Payto from server is not valid "{error.data.paytoUri}"</div> + ); } -export function ReadyView({ account, balance, balanceIsDebit, limit, payto }: State.Ready): VNode<{}> { +const IS_PUBLIC_ACCOUNT_ENABLED = false + +function ImportantMessage(): VNode { const { i18n } = useTranslationContext(); - return <Fragment> - <div> - <h1 class="nav welcome-text"> - <i18n.Translate> - Welcome, {account} (<a href={stringifyPaytoUri(payto)}>{payto.iban}</a>)! <CopyButton getContent={() => stringifyPaytoUri(payto)} /> - </i18n.Translate> - </h1> - </div> + return <div aria-live="assertive" class="pointer-events-none flex items-end px-4 py-6 sm:items-start sm:p-6"> + <div class="flex w-full flex-col items-center space-y-4 "> + <div class="pointer-events-auto flex w-full max-w-md rounded-lg bg-white shadow-lg ring-1 ring-black ring-opacity-5"> + <div class="w-0 flex-1 p-4"> + <div class="flex items-start"> + <div class="ml-3 w-0 flex-1"> + <p class="text-sm font-medium text-gray-900"> + <i18n.Translate> + Welcome, "account" + </i18n.Translate> - <section id="assets"> - <div class="asset-summary"> - <h2>{i18n.str`Bank account balance`}</h2> - {!balance ? ( - <div class="large-amount" style={{ color: "gray" }}> - Waiting server response... + </p> + <p class="mt-1 text-sm text-gray-500"> + {bankUiSettings.showDemoNav && + <p> + {IS_PUBLIC_ACCOUNT_ENABLED ? ( + <i18n.Translate> + This part of the demo shows how a bank that supports Taler + directly would work. In addition to using your own bank + account, you can also see the transaction history of some{" "} + <a href="/public-accounts">Public Accounts</a>. + </i18n.Translate> + ) : ( + <i18n.Translate> + This part of the demo shows how a bank that supports Taler + directly would work. + </i18n.Translate> + )} + </p> + }</p> + </div> </div> - ) : ( - <div class="large-amount amount"> - {balanceIsDebit ? <b>-</b> : null} - <span class="value">{`${Amounts.stringifyValue(balance)}`}</span> - - <span class="currency">{`${balance.currency}`}</span> - </div> - )} - </div> - </section> - <section id="payments"> - <div class="payments"> - <h2>{i18n.str`Payments`}</h2> - <PaymentOptions limit={limit} /> + </div> + <div class="flex border-l border-gray-200"> + <button type="button" class="flex w-full items-center justify-center rounded-none rounded-r-lg border border-transparent p-4 text-sm font-medium text-indigo-600 hover:text-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500"> + Dismiss + </button> + </div> </div> - </section> + </div> + </div> - <section style={{ marginTop: "2em" }}> - <div class="active"> - <h3>{i18n.str`Latest transactions`}</h3> - <Transactions account={account} /> - </div> - </section> +} + +export function ReadyView({ account, balance, balanceIsDebit, limit, payto }: State.Ready): VNode<{}> { + const { i18n } = useTranslationContext(); + return <Fragment> + <PaymentOptions limit={limit} /> + <Transactions account={account} /> </Fragment>; } diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx index dc61f1302..5b6d95ade 100644 --- a/packages/demobank-ui/src/pages/BankFrame.tsx +++ b/packages/demobank-ui/src/pages/BankFrame.tsx @@ -14,7 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { Logger, TranslatedString } from "@gnu-taler/taler-util"; +import { Logger, PaytoUriIBAN, TranslatedString, parsePaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { ComponentChildren, Fragment, h, VNode } from "preact"; import { StateUpdater, useEffect, useState } from "preact/hooks"; @@ -25,6 +25,7 @@ import { useBusinessAccountDetails } from "../hooks/circuit.js"; import { bankUiSettings } from "../settings.js"; import { useSettings } from "../hooks/settings.js"; import { ErrorMessage, onNotificationUpdate } from "../hooks/notification.js"; +import { CopyButton, CopyIcon } from "../components/CopyButton.js"; const IS_PUBLIC_ACCOUNT_ENABLED = false; const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined; @@ -70,6 +71,7 @@ export function BankFrame({ const { i18n } = useTranslationContext(); const backend = useBackendContext(); const [settings, updateSettings] = useSettings(); + const [open, setOpen] = useState(false) const demo_sites = []; for (const i in bankUiSettings.demoSites) @@ -79,83 +81,165 @@ export function BankFrame({ </a>, ); - return ( - <Fragment> - <header - class="demobar" - style="display: flex; flex-direction: row; justify-content: space-between;" - > - <a href="#main" class="skip">{i18n.str`Skip to main content`}</a> - <div style="max-width: 50em; margin-left: 2em; margin-right: 2em;"> - <h1> - <span class="it"> - <a href="/">{bankUiSettings.bankName}</a> - </span> - </h1> - {maybeDemoContent( - <p> - {IS_PUBLIC_ACCOUNT_ENABLED ? ( - <i18n.Translate> - This part of the demo shows how a bank that supports Taler - directly would work. In addition to using your own bank - account, you can also see the transaction history of some{" "} - <a href="/public-accounts">Public Accounts</a>. - </i18n.Translate> - ) : ( - <i18n.Translate> - This part of the demo shows how a bank that supports Taler - directly would work. - </i18n.Translate> - )} - </p>, - )} + return (<div class="min-h-full"> + <div class="bg-indigo-600 pb-32"> + <nav class="border-b border-indigo-300 border-opacity-25 bg-indigo-600 lg:border-none"> + <div class="mx-auto max-w-7xl px-2 sm:px-4 lg:px-8"> + <div class="relative flex h-16 items-center justify-between lg:border-b lg:border-indigo-400 lg:border-opacity-25"> + <div class="flex items-center px-2 lg:px-0"> + <div class="flex-shrink-0"> + <img class="block h-8 w-8" src="https://tailwindui.com/img/logos/mark.svg?color=indigo&shade=300" alt="Your Company" /> + </div> + <div class="hidden lg:ml-10 lg:block"> + <div class="flex space-x-4"> + {/* <!-- Current: "bg-indigo-700 text-white", Default: "text-white hover:bg-indigo-500 hover:bg-opacity-75" --> */} + {bankUiSettings.demoSites.map(([name, url]) => { + return <a href={url} class="text-white hover:bg-indigo-500 hover:bg-opacity-75 rounded-md py-2 px-3 text-sm font-medium">{name}</a> + })} + </div> + </div> + </div> + + <div class="flex lg:hidden"> + {/* <!-- Mobile menu button --> */} + <button type="button" class="relative inline-flex items-center justify-center rounded-md bg-indigo-600 p-2 text-indigo-200 hover:bg-indigo-500 hover:bg-opacity-75 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-indigo-600" aria-controls="mobile-menu" aria-expanded="false" + onClick={(e) => { + setOpen(!open) + }}> + <span class="absolute -inset-0.5"></span> + <span class="sr-only">Open main menu</span> + {/* <!-- Menu open: "hidden", Menu closed: "block" --> */} + <svg class="block h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true"> + <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" /> + </svg> + {/* <!-- Menu open: "block", Menu closed: "hidden" --> */} + <svg class="hidden h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true"> + <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /> + </svg> + </button> + </div> + </div> </div> - </header> - <div style="display:flex; flex-direction: column;" class="navcontainer"> - <nav class="demolist"> - {maybeDemoContent(<Fragment>{demo_sites}</Fragment>)} - {backend.state.status === "loggedIn" ? ( - <Fragment> - {goToBusinessAccount && !backend.state.isUserAdministrator ? ( - <MaybeBusinessButton - account={backend.state.username} - onClick={goToBusinessAccount} - /> - ) : undefined} - <LangSelector /> + {/* <!-- Mobile menu, show/hide based on menu state. --> */} + {open && + <div class="lg:hidden" id="mobile-menu"> + <div class="space-y-1 px-2 pb-3 pt-2"> + {/* <!-- Current: "bg-indigo-700 text-white", Default: "text-white hover:bg-indigo-500 hover:bg-opacity-75" --> */} + {bankUiSettings.demoSites.map(([name, url]) => { + return <a href={url} class="text-white hover:bg-indigo-500 hover:bg-opacity-75 block rounded-md py-2 px-3 text-base font-medium">{name}</a> + })} + </div> - <a - href="#" - class="pure-button logout-button" - onClick={() => { - backend.logOut(); - updateSettings("currentWithdrawalOperationId", undefined); - }} - >{i18n.str`Logout`}</a> - </Fragment> - ) : undefined} - </nav> - </div> - <section id="main" class="content"> - <StatusBanner /> - {children} - </section> - <section id="footer" class="footer"> - <hr /> - <div> - <p> - You can learn more about GNU Taler on our{" "} - <a href="https://taler.net">main website</a>. - </p> + </div> + } + </nav > + <header class="py-10"> + + <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8"> + <div class=" flex flex-wrap items-center justify-between sm:flex-nowrap"> + {/* <h1 class="text-base font-semibold leading-6 text-gray-900"></h1> */} + <h1 class="text-3xl font-bold tracking-tight text-white"><WelcomeAccount /></h1> + <div> + + <h2 class="text-3xl font-bold tracking-tight text-white">KUDOS 100.00</h2> + </div> + {/* <div class="ml-4 mt-2 flex-shrink-0"> + <button type="button" class="relative inline-flex items-center 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">Create new job</button> + </div> */} + </div> </div> - <div style="flex-grow:1" /> - <p> - Copyright © 2014—2022 Taler Systems SA. {versionText}{" "} - <TestingTag /> - </p> - </section> - </Fragment> + </header> + </div > + + <main class="-mt-32"> + <div class="mx-auto max-w-7xl px-4 pb-12 sm:px-6 lg:px-8"> + <div class="rounded-lg bg-white px-5 py-6 shadow sm:px-6"> + {/* <!-- Your content --> */} + {children} + </div> + </div> + </main> + + <Footer /> + </div > + + // <Fragment> + // <header + // class="demobar" + // style="display: flex; flex-direction: row; justify-content: space-between;" + // > + // <a href="#main" class="skip">{i18n.str`Skip to main content`}</a> + // <div style="max-width: 50em; margin-left: 2em; margin-right: 2em;"> + // <h1> + // <span class="it"> + // <a href="/">{bankUiSettings.bankName}</a> + // </span> + // </h1> + // {maybeDemoContent( + // <p> + // {IS_PUBLIC_ACCOUNT_ENABLED ? ( + // <i18n.Translate> + // This part of the demo shows how a bank that supports Taler + // directly would work. In addition to using your own bank + // account, you can also see the transaction history of some{" "} + // <a href="/public-accounts">Public Accounts</a>. + // </i18n.Translate> + // ) : ( + // <i18n.Translate> + // This part of the demo shows how a bank that supports Taler + // directly would work. + // </i18n.Translate> + // )} + // </p>, + // )} + // </div> + // </header> + // <div style="display:flex; flex-direction: column;" class="navcontainer"> + // <nav class="demolist"> + // {maybeDemoContent(<Fragment>{demo_sites}</Fragment>)} + // {backend.state.status === "loggedIn" ? ( + // <Fragment> + // {goToBusinessAccount && !backend.state.isUserAdministrator ? ( + // <MaybeBusinessButton + // account={backend.state.username} + // onClick={goToBusinessAccount} + // /> + // ) : undefined} + + // <LangSelector /> + + // <a + // href="#" + // class="pure-button logout-button" + // onClick={() => { + // backend.logOut(); + // updateSettings("currentWithdrawalOperationId", undefined); + // }} + // >{i18n.str`Logout`}</a> + // </Fragment> + // ) : undefined} + // </nav> + // </div> + // <section id="main" class="content"> + // <StatusBanner /> + // {children} + // </section> + // <section id="footer" class="footer"> + // <hr /> + // <div> + // <p> + // You can learn more about GNU Taler on our{" "} + // <a href="https://taler.net">main website</a>. + // </p> + // </div> + // <div style="flex-grow:1" /> + // <p> + // Copyright © 2014—2022 Taler Systems SA. {versionText}{" "} + // <TestingTag /> + // </p> + // </section> + // </Fragment> ); } @@ -290,7 +374,7 @@ function TestingTag(): VNode { const testingUrl = localStorage.getItem("bank-base-url"); if (!testingUrl) return <Fragment />; return ( - <span style={{ color: "gray" }}> + <p class="text-xs leading-5 text-gray-300"> Testing with {testingUrl}{" "} <a href="" @@ -302,6 +386,36 @@ function TestingTag(): VNode { > stop testing </a> - </span> + </p> ); } + +function Footer() { + return ( + <footer class="absolute bottom-4"> + <div class="mt-8 mx-8 md:order-1 md:mt-0"> + <div> + <p class="text-xs leading-5 text-gray-400"> + You can learn more about GNU Taler on our{" "} + <a class="font-semibold text-gray-500 hover:text-gray-400" href="https://taler.net">main website</a>. + </p> + </div> + <div style="flex-grow:1" /> + <p class="text-xs leading-5 text-gray-400"> + Copyright © 2014—2022 Taler Systems SA. {versionText}{" "} + <TestingTag /> + </p> + </div> + </footer> + ); +} + +function WelcomeAccount(): VNode { + const { i18n } = useTranslationContext(); + const account = "Sebastian" + const payto: PaytoUriIBAN = parsePaytoUri("payto://iban/bank.localhost/DE955922") as PaytoUriIBAN + return <i18n.Translate> + Welcome, {account} (<a href={stringifyPaytoUri(payto)}>{payto.iban}</a>)! <CopyButton getContent={() => stringifyPaytoUri(payto)} /> + </i18n.Translate> + +}
\ No newline at end of file diff --git a/packages/demobank-ui/src/pages/PaymentOptions.tsx b/packages/demobank-ui/src/pages/PaymentOptions.tsx index 3552da7b4..cf3f41deb 100644 --- a/packages/demobank-ui/src/pages/PaymentOptions.tsx +++ b/packages/demobank-ui/src/pages/PaymentOptions.tsx @@ -31,11 +31,77 @@ export function PaymentOptions({ limit }: { limit: AmountJson }): VNode { const { i18n } = useTranslationContext(); const [settings, updateSettings] = useSettings(); - const [tab, setTab] = useState<"charge-wallet" | "wire-transfer">( - "charge-wallet", - ); + const [tab, setTab] = useState<"charge-wallet" | "wire-transfer" | undefined>(undefined); - return ( + return (<fieldset> + <legend class="px-4 text-base font-semibold leading-6 text-gray-900"> + <i18n.Translate>Send money to</i18n.Translate> + </legend> + + <div class="px-4 mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-2 sm:gap-x-4"> + {/* <!-- Active: "border-indigo-600 ring-2 ring-indigo-600", Not Active: "border-gray-300" --> */} + <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (tab === "charge-wallet" ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}> + <input type="radio" name="project-type" value="Newsletter" class="sr-only" aria-labelledby="project-type-0-label" aria-describedby="project-type-0-description-0 project-type-0-description-1" onChange={() => { + setTab("charge-wallet") + }} /> + <span class="flex flex-1"> + <span class="flex flex-col"> + <span id="project-type-0-label" class="block text-sm font-semibold font-medium text-gray-900"> + <i18n.Translate>a Taler Wallet</i18n.Translate> + </span> + <span id="project-type-0-description-0" class="mt-1 flex items-center text-sm text-gray-500"> + <i18n.Translate>Withdraw digital money into your mobile wallet or browser extension</i18n.Translate> + </span> + </span> + </span> + {/* <!-- Not Checked: "invisible" --> */} + <svg class="h-5 w-5 text-indigo-600" style={{ visibility: tab === "charge-wallet" ? "visible" : "hidden" }} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"> + <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" /> + </svg> + </label> + + + {/* <!-- Active: "border-indigo-600 ring-2 ring-indigo-600", Not Active: "border-gray-300" --> */} + <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (tab === "wire-transfer" ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}> + <input type="radio" name="project-type" value="Existing Customers" class="sr-only" aria-labelledby="project-type-1-label" aria-describedby="project-type-1-description-0 project-type-1-description-1" onChange={() => { + setTab("wire-transfer") + }} /> + <span class="flex flex-1"> + <span class="flex flex-col"> + <span id="project-type-1-label" class="block text-sm font-semibold font-medium text-gray-900"> + <i18n.Translate>another bank account</i18n.Translate> + </span> + <span id="project-type-1-description-0" class="mt-1 flex items-center text-sm text-gray-500"> + <i18n.Translate>Make a wire transfer to an account which you know the address.</i18n.Translate> + </span> + </span> + </span> + <svg class="h-5 w-5 text-indigo-600" style={{ visibility: tab === "wire-transfer" ? "visible" : "hidden" }} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"> + <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" /> + </svg> + </label> + </div> + {tab === "charge-wallet" && ( + <WalletWithdrawForm + focus + limit={limit} + onSuccess={(id) => { + updateSettings("currentWithdrawalOperationId", id); + }} + /> + )} + {tab === "wire-transfer" && ( + <PaytoWireTransferForm + focus + limit={limit} + onSuccess={() => { + notifyInfo(i18n.str`Wire transfer created!`); + }} + /> + )} + + </fieldset>) + {/* return ( <article> <div class="payments"> <div class="tab"> @@ -56,31 +122,7 @@ export function PaymentOptions({ limit }: { limit: AmountJson }): VNode { {i18n.str`Wire transfer`} </button> </div> - {tab === "charge-wallet" && ( - <div id="charge-wallet" class="tabcontent active"> - <h3>{i18n.str`Obtain digital cash`}</h3> - <WalletWithdrawForm - focus - limit={limit} - onSuccess={(id) => { - updateSettings("currentWithdrawalOperationId", id); - }} - /> - </div> - )} - {tab === "wire-transfer" && ( - <div id="wire-transfer" class="tabcontent active"> - <h3>{i18n.str`Transfer to bank account`}</h3> - <PaytoWireTransferForm - focus - limit={limit} - onSuccess={() => { - notifyInfo(i18n.str`Wire transfer created!`); - }} - /> - </div> - )} </div> </article> - ); + ); */} } diff --git a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx index d16dc70f8..1107360bd 100644 --- a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx +++ b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx @@ -17,26 +17,24 @@ import { AmountJson, Amounts, - buildPayto, HttpStatusCode, Logger, - parsePaytoUri, - stringifyPaytoUri, + parsePaytoUri } from "@gnu-taler/taler-util"; import { RequestError, useTranslationContext, } from "@gnu-taler/web-util/browser"; -import { h, VNode } from "preact"; +import { h, VNode, Fragment } from "preact"; import { useEffect, useRef, useState } from "preact/hooks"; -import { notifyError } from "../hooks/notification.js"; +import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js"; import { useAccessAPI } from "../hooks/access.js"; +import { notifyError } from "../hooks/notification.js"; import { buildRequestErrorMessage, undefinedIfEmpty, validateIBAN, } from "../utils.js"; -import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js"; const logger = new Logger("PaytoWireTransferForm"); @@ -72,293 +70,322 @@ export function PaytoWireTransferForm({ iban: !iban ? i18n.str`Missing IBAN` : !IBAN_REGEX.test(iban) - ? i18n.str`IBAN should have just uppercased letters and numbers` - : validateIBAN(iban, i18n), + ? i18n.str`IBAN should have just uppercased letters and numbers` + : validateIBAN(iban, i18n), subject: !subject ? i18n.str`Missing subject` : undefined, amount: !trimmedAmountStr ? i18n.str`Missing amount` : !parsedAmount - ? i18n.str`Amount is not valid` - : Amounts.isZero(parsedAmount) - ? i18n.str`Should be greater than 0` - : Amounts.cmp(limit, parsedAmount) === -1 - ? i18n.str`balance is not enough` - : undefined, + ? i18n.str`Amount is not valid` + : Amounts.isZero(parsedAmount) + ? i18n.str`Should be greater than 0` + : Amounts.cmp(limit, parsedAmount) === -1 + ? i18n.str`balance is not enough` + : undefined, }); const { createTransaction } = useAccessAPI(); - if (!isRawPayto) - return ( - <div> - <form - class="pure-form" - name="wire-transfer-form" - onSubmit={(e) => { - e.preventDefault(); - }} - autoCapitalize="none" - autoCorrect="off" - > - <label for="iban">{i18n.str`Receiver IBAN:`}</label> - <input - ref={ref} - type="text" - id="iban" - name="iban" - value={iban ?? ""} - placeholder="CC0123456789" - required - pattern={ibanRegex} - onInput={(e): void => { - setIban(e.currentTarget.value); - }} - /> - <ShowInputErrorLabel - message={errorsWire?.iban} - isDirty={iban !== undefined} - /> - <label for="subject">{i18n.str`Transfer subject:`}</label> - <input - type="text" - name="subject" - id="subject" - placeholder="subject" - value={subject ?? ""} - required - onInput={(e): void => { - setSubject(e.currentTarget.value); - }} - /> - <ShowInputErrorLabel - message={errorsWire?.subject} - isDirty={subject !== undefined} - /> - <label for="amount">{i18n.str`Amount:`}</label> - <div style={{ width: "max-content", display: "flex" }}> - <input - type="text" - readonly - class="currency-indicator" - size={limit.currency.length} - maxLength={limit.currency.length} - tabIndex={-1} - style={{ - borderTopRightRadius: 0, - borderBottomRightRadius: 0, - borderRight: 0, - }} - value={limit.currency} - /> - <input - type="number" - name="amount" - id="amount" - placeholder="amount" - required - style={{ - borderTopLeftRadius: 0, - borderBottomLeftRadius: 0, - borderLeft: 0, - width: 150, - }} - value={amount ?? ""} - onInput={(e): void => { - setAmount(e.currentTarget.value); - }} - /> - </div> - <ShowInputErrorLabel - message={errorsWire?.amount} - isDirty={amount !== undefined} - /> - <p style={{ display: "flex", justifyContent: "space-between" }}> - <input - type="submit" - class="pure-button pure-button-primary" - disabled={!!errorsWire} - value="Send" - onClick={async (e) => { - e.preventDefault(); - if (!(iban && subject && amount)) { - return; - } - const ibanPayto = buildPayto("iban", iban, undefined); - ibanPayto.params.message = encodeURIComponent(subject); - const paytoUri = stringifyPaytoUri(ibanPayto); - - try { - await createTransaction({ - paytoUri, - amount: `${limit.currency}:${amount}`, - }); - onSuccess(); - setAmount(undefined); - setIban(undefined); - setSubject(undefined); - } catch (error) { - if (error instanceof RequestError) { - notifyError( - buildRequestErrorMessage(i18n, error.cause, { - onClientError: (status) => - status === HttpStatusCode.BadRequest - ? i18n.str`The request was invalid or the payto://-URI used unacceptable features.` - : undefined, - }), - ); - } else { - notifyError({ - title: i18n.str`Operation failed, please report`, - description: - error instanceof Error - ? error.message - : JSON.stringify(error), - }); - } - } - }} - /> - <input - type="button" - class="pure-button" - value="Clear" - onClick={async (e) => { - e.preventDefault(); - setAmount(undefined); - setIban(undefined); - setSubject(undefined); - }} - /> - </p> - </form> - <p> - <a - href="#" - onClick={(e) => { - setIsRawPayto(true); - e.preventDefault(); - }} - > - {i18n.str`Want to try the raw payto://-format?`} - </a> - </p> - </div> - ); - const parsed = !rawPaytoInput ? undefined : parsePaytoUri(rawPaytoInput); const errorsPayto = undefinedIfEmpty({ rawPaytoInput: !rawPaytoInput ? i18n.str`required` : !parsed - ? i18n.str`does not follow the pattern` - : !parsed.params.amount - ? i18n.str`use the "amount" parameter to specify the amount to be transferred` - : Amounts.parse(parsed.params.amount) === undefined - ? i18n.str`the amount is not valid` - : !parsed.params.message - ? i18n.str`use the "message" parameter to specify a reference text for the transfer` - : !parsed.isKnown || parsed.targetType !== "iban" - ? i18n.str`only "IBAN" target are supported` - : !IBAN_REGEX.test(parsed.iban) - ? i18n.str`IBAN should have just uppercased letters and numbers` - : validateIBAN(parsed.iban, i18n), + ? i18n.str`does not follow the pattern` + : !parsed.params.amount + ? i18n.str`use the "amount" parameter to specify the amount to be transferred` + : Amounts.parse(parsed.params.amount) === undefined + ? i18n.str`the amount is not valid` + : !parsed.params.message + ? i18n.str`use the "message" parameter to specify a reference text for the transfer` + : !parsed.isKnown || parsed.targetType !== "iban" + ? i18n.str`only "IBAN" target are supported` + : !IBAN_REGEX.test(parsed.iban) + ? i18n.str`IBAN should have just uppercased letters and numbers` + : validateIBAN(parsed.iban, i18n), }); + // if (!isRawPayto) { + return (<div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 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"><i18n.Translate>Transfer details</i18n.Translate></h2> + <div> + <div class="px-4 mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-2 sm:gap-x-4"> + {/* <!-- Active: "border-indigo-600 ring-2 ring-indigo-600", Not Active: "border-gray-300" --> */} + <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (!isRawPayto ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}> + <input type="radio" name="project-type" value="Newsletter" class="sr-only" aria-labelledby="project-type-0-label" aria-describedby="project-type-0-description-0 project-type-0-description-1" onChange={() => { + setIsRawPayto(false) + }} /> + <span class="flex flex-1"> + <span class="flex flex-col"> + <span id="project-type-0-label" class="block text-sm font-medium text-gray-900"> + <i18n.Translate>form</i18n.Translate> + </span> + </span> + </span> + </label> - return ( - <div> - <p>{i18n.str`Transfer money to account identified by payto:// URI:`}</p> - <form - class="pure-form" - name="payto-form" - onSubmit={(e) => { - e.preventDefault(); - }} - autoCapitalize="none" - autoCorrect="off" - > - <p> - <label for="address">{i18n.str`payto URI:`}</label> - <input - name="address" - type="text" - size={50} - ref={ref} - id="address" - value={rawPaytoInput ?? ""} - required - placeholder={i18n.str`payto address`} - // pattern={`payto://iban/[A-Z][A-Z][0-9]+?message=[a-zA-Z0-9 ]+&amount=${currency}:[0-9]+(.[0-9]+)?`} - onInput={(e): void => { - rawPaytoInputSetter(e.currentTarget.value); - }} - /> - <ShowInputErrorLabel - message={errorsPayto?.rawPaytoInput} - isDirty={rawPaytoInput !== undefined} - /> - <br /> - <div style={{ fontSize: "small", marginTop: 4 }}> - Hint: - <code> - payto://iban/[receiver-iban]?message=[subject]&amount=[ - {limit.currency} - :X.Y] - </code> - </div> - </p> - <p> - <input - class="pure-button pure-button-primary" - type="button" - disabled={!!errorsPayto} - value={i18n.str`Send`} - onClick={async () => { - if (!rawPaytoInput) { - logger.error("Didn't get any raw Payto string!"); - return; - } - try { - await createTransaction({ - paytoUri: rawPaytoInput, - }); - onSuccess(); - rawPaytoInputSetter(undefined); - } catch (error) { - if (error instanceof RequestError) { - notifyError( - buildRequestErrorMessage(i18n, error.cause, { - onClientError: (status) => - status === HttpStatusCode.BadRequest - ? i18n.str`The request was invalid or the payto://-URI used unacceptable features.` - : undefined, - }), - ); - } else { - notifyError({ - title: i18n.str`Operation failed, please report`, - description: - error instanceof Error - ? error.message - : JSON.stringify(error), - }); - } - } - }} - /> - </p> - <p> - <a - href="/account" - onClick={() => { - setIsRawPayto(false); - }} - > - {i18n.str`Use wire-transfer form?`} - </a> - </p> - </form> + {/* <!-- Active: "border-indigo-600 ring-2 ring-indigo-600", Not Active: "border-gray-300" --> */} + <label class={"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" + (isRawPayto ? "border-indigo-600 ring-2 ring-indigo-600" : "border-gray-300")}> + <input type="radio" name="project-type" value="Existing Customers" class="sr-only" aria-labelledby="project-type-1-label" aria-describedby="project-type-1-description-0 project-type-1-description-1" onChange={() => { + setIsRawPayto(true) + }} /> + <span class="flex flex-1"> + <span class="flex flex-col"> + <span id="project-type-1-label" class="block text-sm font-medium text-gray-900"> + <i18n.Translate>payto://</i18n.Translate> + </span> + </span> + </span> + </label> + </div> + </div> </div> - ); + + <form 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"> + {!isRawPayto ? + <Fragment> + + <div class="sm:col-span-3"> + <label for="first-name" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Account number`}</label> + <div class="mt-2"> + <input + ref={ref} + type="text" + 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" + id="iban" + name="iban" + value={iban ?? ""} + placeholder="CC0123456789" + required + pattern={ibanRegex} + onInput={(e): void => { + setIban(e.currentTarget.value); + }} + /> + <ShowInputErrorLabel + message={errorsWire?.iban} + isDirty={iban !== undefined} + /> + </div> + <p class="mt-2 text-sm text-gray-500" id="email-description">the receiver of the money</p> + </div> + + <div class="sm:col-span-3"> + </div> + + <div class="sm:col-span-3"> + <label for="first-name" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Transfer subject`}</label> + <div class="mt-2"> + + <input + type="text" + 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" + name="subject" + id="subject" + placeholder="subject" + value={subject ?? ""} + required + onInput={(e): void => { + setSubject(e.currentTarget.value); + }} + /> + <ShowInputErrorLabel + message={errorsWire?.subject} + isDirty={subject !== undefined} + /> + </div> + <p class="mt-2 text-sm text-gray-500" id="email-description">some text to identify the transfer</p> + + </div> + + <div class="sm:col-span-3"> + </div> + + <div class="sm:col-span-3"> + <label for="first-name" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Amount`}</label> + <div class="mt-2"> + <input type="text" name="first-name" id="first-name" autocomplete="given-name" 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" /> + </div> + </div> + + <div class="sm:col-span-3"> + </div> + </Fragment> : + <Fragment> + <div class="sm:col-span-6"> + <label for="first-name" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`payto URI:`}</label> + <div class="mt-2"> + <input + name="address" + type="text" + size={50} + 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" ref={ref} + id="address" + value={rawPaytoInput ?? ""} + required + placeholder={i18n.str`payto://iban/[receiver-iban]?message=[subject]&amount=[${limit.currency}:X.Y]`} + // pattern={`payto://iban/[A-Z][A-Z][0-9]+?message=[a-zA-Z0-9 ]+&amount=${currency}:[0-9]+(.[0-9]+)?`} + onInput={(e): void => { + rawPaytoInputSetter(e.currentTarget.value); + }} + /> + <ShowInputErrorLabel + message={errorsPayto?.rawPaytoInput} + isDirty={rawPaytoInput !== undefined} + /> + </div> + </div> + + </Fragment> + } + </div> + </div> + <div class="flex items-center justify-end 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">Cancel</button> + <button type="submit" class="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>Send</i18n.Translate> + </button> + </div> + </form> + </div > + ) + // } + // return ( + // <div> + // <form + // class="pure-form" + // name="wire-transfer-form" + // onSubmit={(e) => { + // e.preventDefault(); + // }} + // autoCapitalize="none" + // autoCorrect="off" + // > + // <label for="iban">{i18n.str`Receiver IBAN:`}</label> + + // <label for="subject">{i18n.str`Transfer subject:`}</label> + + // <label for="amount">{i18n.str`Amount:`}</label> + // <div style={{ width: "max-content", display: "flex" }}> + // <input + // type="text" + // readonly + // class="currency-indicator" + // size={limit.currency.length} + // maxLength={limit.currency.length} + // tabIndex={-1} + // style={{ + // borderTopRightRadius: 0, + // borderBottomRightRadius: 0, + // borderRight: 0, + // }} + // value={limit.currency} + // /> + // <input + // type="number" + // name="amount" + // id="amount" + // placeholder="amount" + // required + // style={{ + // borderTopLeftRadius: 0, + // borderBottomLeftRadius: 0, + // borderLeft: 0, + // width: 150, + // }} + // value={amount ?? ""} + // onInput={(e): void => { + // setAmount(e.currentTarget.value); + // }} + // /> + // </div> + // <ShowInputErrorLabel + // message={errorsWire?.amount} + // isDirty={amount !== undefined} + // /> + // <p style={{ display: "flex", justifyContent: "space-between" }}> + // <input + // type="submit" + // class="pure-button pure-button-primary" + // disabled={!!errorsWire} + // value="Send" + // onClick={async (e) => { + // e.preventDefault(); + // if (!(iban && subject && amount)) { + // return; + // } + // const ibanPayto = buildPayto("iban", iban, undefined); + // ibanPayto.params.message = encodeURIComponent(subject); + // const paytoUri = stringifyPaytoUri(ibanPayto); + + // try { + // await createTransaction({ + // paytoUri, + // amount: `${limit.currency}:${amount}`, + // }); + // onSuccess(); + // setAmount(undefined); + // setIban(undefined); + // setSubject(undefined); + // } catch (error) { + // if (error instanceof RequestError) { + // notifyError( + // buildRequestErrorMessage(i18n, error.cause, { + // onClientError: (status) => + // status === HttpStatusCode.BadRequest + // ? i18n.str`The request was invalid or the payto://-URI used unacceptable features.` + // : undefined, + // }), + // ); + // } else { + // notifyError({ + // title: i18n.str`Operation failed, please report`, + // description: + // error instanceof Error + // ? error.message + // : JSON.stringify(error), + // }); + // } + // } + // }} + // /> + // <input + // type="button" + // class="pure-button" + // value="Clear" + // onClick={async (e) => { + // e.preventDefault(); + // setAmount(undefined); + // setIban(undefined); + // setSubject(undefined); + // }} + // /> + // </p> + // </form> + // <p> + // <a + // href="#" + // onClick={(e) => { + // setIsRawPayto(true); + // e.preventDefault(); + // }} + // > + // {i18n.str`Want to try the raw payto://-format?`} + // </a> + // </p> + // </div> + // ); + + + + // return ( + // <div> + // <p>{i18n.str`Transfer money to account identified by payto:// URI:`}</p> + + // </div> + // ); } diff --git a/packages/demobank-ui/src/pages/Test.tsx b/packages/demobank-ui/src/pages/Test.tsx new file mode 100644 index 000000000..874f7fe68 --- /dev/null +++ b/packages/demobank-ui/src/pages/Test.tsx @@ -0,0 +1,5 @@ +import { VNode, h } from "preact"; + +export function Test(): VNode { + return <div >hola</div> +}
\ No newline at end of file diff --git a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx index 83be99d6f..da624f61b 100644 --- a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx +++ b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx @@ -65,10 +65,10 @@ export function WalletWithdrawForm({ trimmedAmountStr == null ? i18n.str`required` : !parsedAmount - ? i18n.str`invalid` - : Amounts.cmp(limit, parsedAmount) === -1 - ? i18n.str`balance is not enough` - : undefined, + ? i18n.str`invalid` + : Amounts.cmp(limit, parsedAmount) === -1 + ? i18n.str`balance is not enough` + : undefined, }); return ( |