aboutsummaryrefslogtreecommitdiff
path: root/packages/demobank-ui/src/pages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-09-19 08:31:08 -0300
committerSebastian <sebasjm@gmail.com>2023-09-25 14:50:38 -0300
commita5406c5a5dc437e036168eb068db11d88e05bb0f (patch)
tree74ad5e0d858a5afb3e76ac0c692fdba866fed38f /packages/demobank-ui/src/pages
parente628ca1af851259e609a16d0b53b8d7abfc33716 (diff)
downloadwallet-core-a5406c5a5dc437e036168eb068db11d88e05bb0f.tar.xz
some ui
Diffstat (limited to 'packages/demobank-ui/src/pages')
-rw-r--r--packages/demobank-ui/src/pages/AccountPage/views.tsx93
-rw-r--r--packages/demobank-ui/src/pages/BankFrame.tsx266
-rw-r--r--packages/demobank-ui/src/pages/PaymentOptions.tsx100
-rw-r--r--packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx581
-rw-r--r--packages/demobank-ui/src/pages/Test.tsx5
-rw-r--r--packages/demobank-ui/src/pages/WalletWithdrawForm.tsx8
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 &quot;{error.data.paytoUri}&quot;</div>
- );
+export function InvalidIbanView({ error }: State.InvalidIban) {
+ return (
+ <div>Payto from server is not valid &quot;{error.data.paytoUri}&quot;</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>
- &nbsp;
- <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 &copy; 2014&mdash;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 &copy; 2014&mdash;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 &copy; 2014&mdash;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>&nbsp;
- <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>&nbsp;
- <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>&nbsp;
- <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>&nbsp;
- <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>&nbsp;
+
+ // <label for="subject">{i18n.str`Transfer subject:`}</label>&nbsp;
+
+ // <label for="amount">{i18n.str`Amount:`}</label>&nbsp;
+ // <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 (