aboutsummaryrefslogtreecommitdiff
path: root/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx')
-rw-r--r--packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx268
1 files changed, 159 insertions, 109 deletions
diff --git a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
index 5f5a6ce3b..785dc4264 100644
--- a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
+++ b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
@@ -55,10 +55,11 @@ export function PaytoWireTransferForm({
onCancel: (() => void) | undefined;
limit: AmountJson;
}): VNode {
- const [isRawPayto, setIsRawPayto] = useState(false);
- const [iban, setIban] = useState<string | undefined>(undefined);
- const [subject, setSubject] = useState<string | undefined>(undefined);
- const [amount, setAmount] = useState<string | undefined>(undefined);
+ const [isRawPayto, setIsRawPayto] = useState(true);
+ // FIXME: remove this
+ const [iban, setIban] = useState<string | undefined>("DE4745461198061");
+ const [subject, setSubject] = useState<string | undefined>("ASD");
+ const [amount, setAmount] = useState<string | undefined>("1.00001");
const [rawPaytoInput, rawPaytoInputSetter] = useState<string | undefined>(
undefined,
@@ -76,17 +77,17 @@ export function PaytoWireTransferForm({
const errorsWire = undefinedIfEmpty({
iban: !iban
- ? i18n.str`Missing IBAN`
+ ? i18n.str`required`
: !IBAN_REGEX.test(iban)
? i18n.str`IBAN should have just uppercased letters and numbers`
: validateIBAN(iban, i18n),
- subject: !subject ? i18n.str`Missing subject` : undefined,
+ subject: !subject ? i18n.str`required` : undefined,
amount: !trimmedAmountStr
- ? i18n.str`Missing amount`
+ ? i18n.str`required`
: !parsedAmount
- ? i18n.str`Amount is not valid`
+ ? i18n.str`not valid`
: Amounts.isZero(parsedAmount)
- ? i18n.str`Should be greater than 0`
+ ? i18n.str`should be greater than 0`
: Amounts.cmp(limit, parsedAmount) === -1
? i18n.str`balance is not enough`
: undefined,
@@ -101,14 +102,14 @@ export function PaytoWireTransferForm({
? 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`
+ : !parsed.isKnown || parsed.targetType !== "iban"
+ ? i18n.str`only "IBAN" target are supported`
+ : !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`
: !IBAN_REGEX.test(parsed.iban)
? i18n.str`IBAN should have just uppercased letters and numbers`
: validateIBAN(parsed.iban, i18n),
@@ -159,6 +160,9 @@ export function PaytoWireTransferForm({
}
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">
+ {/**
+ * FIXME: Scan a qr code
+ */}
<div class="px-4 sm:px-0">
<h2 class="text-base font-semibold leading-7 text-gray-900">
{title}
@@ -167,6 +171,17 @@ export function PaytoWireTransferForm({
<div class="px-4 mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-1 sm:gap-x-4">
<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={() => {
+ if (parsed && parsed.isKnown && parsed.targetType === "iban") {
+ setIban(parsed.iban)
+ const amount = Amounts.parse(parsed.params["amount"])
+ if (amount) {
+ setAmount(Amounts.stringifyValue(amount))
+ }
+ const subject = parsed.params["subject"]
+ if (subject) {
+ setSubject(subject)
+ }
+ }
setIsRawPayto(false)
}} />
<span class="flex flex-1">
@@ -180,12 +195,22 @@ export function PaytoWireTransferForm({
<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={() => {
+ if (iban) {
+ const payto = buildPayto("iban", iban, undefined)
+ if (parsedAmount) {
+ payto.params["amount"] = Amounts.stringify(parsedAmount)
+ }
+ if (subject) {
+ payto.params["message"] = subject
+ }
+ rawPaytoInputSetter(stringifyPaytoUri(payto))
+ }
setIsRawPayto(true)
}} />
<span class="flex flex-1">
<span class="flex flex-col">
<span class="block text-sm font-medium text-gray-900">
- <i18n.Translate>using the payto:// format</i18n.Translate>
+ <i18n.Translate>Import payto:// URI</i18n.Translate>
</span>
</span>
</span>
@@ -195,7 +220,7 @@ export function PaytoWireTransferForm({
</div>
<form
- class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
+ class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2 w-fit mx-auto"
autoCapitalize="none"
autoCorrect="off"
onSubmit={e => {
@@ -203,105 +228,106 @@ export function PaytoWireTransferForm({
}}
>
<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-5">
- <label for="iban" 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"
- name="iban"
- id="iban"
- value={iban ?? ""}
- placeholder="CC0123456789"
- autocomplete="off"
- 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" >the receiver of the money</p>
- </div>
+ {!isRawPayto ?
+ <div class="grid max-w-xs grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <div class="sm:col-span-5">
- <label for="subject" 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"
- autocomplete="off"
- 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" >some text to identify the transfer</p>
+ <div class="sm:col-span-5">
+ <label for="iban" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Recipient`}</label>
+ <div class="mt-2">
+ <input
+ ref={focus ? doAutoFocus : undefined}
+ 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="iban"
+ id="iban"
+ value={iban ?? ""}
+ placeholder="CC0123456789"
+ autocomplete="off"
+ required
+ pattern={ibanRegex}
+ onInput={(e): void => {
+ setIban(e.currentTarget.value.toUpperCase());
+ }}
+ />
+ <ShowInputErrorLabel
+ message={errorsWire?.iban}
+ isDirty={iban !== undefined}
+ />
</div>
+ <p class="mt-2 text-sm text-gray-500" >
+ <i18n.Translate>IBAN of the recipient's account</i18n.Translate>
+ </p>
+ </div>
- <div class="sm:col-span-5">
- <label for="amount" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Amount`}</label>
- <Amount
- name="amount"
- currency={limit.currency}
- value={trimmedAmountStr}
- onChange={(d) => {
- setAmount(d)
+ <div class="sm:col-span-5">
+ <label for="subject" 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"
+ autocomplete="off"
+ placeholder="subject"
+ value={subject ?? ""}
+ required
+ onInput={(e): void => {
+ setSubject(e.currentTarget.value);
}}
/>
<ShowInputErrorLabel
message={errorsWire?.subject}
isDirty={subject !== undefined}
/>
- <p class="mt-2 text-sm text-gray-500" >amount to transfer</p>
</div>
+ <p class="mt-2 text-sm text-gray-500" >some text to identify the transfer</p>
+ </div>
- </Fragment> :
- <Fragment>
- <div class="sm:col-span-6">
- <label for="address" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`payto URI:`}</label>
- <div class="mt-2">
- <input
- name="address"
- id="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}
- value={rawPaytoInput ?? ""}
- required
- placeholder={i18n.str`payto://iban/[receiver-iban]?message=[subject]&amount=[${limit.currency}:X.Y]`}
- onInput={(e): void => {
- rawPaytoInputSetter(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errorsPayto?.rawPaytoInput}
- isDirty={rawPaytoInput !== undefined}
- />
- </div>
- </div>
+ <div class="sm:col-span-5">
+ <label for="amount" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Amount`}</label>
+ <Amount
+ name="amount"
+ left
+ currency={limit.currency}
+ value={trimmedAmountStr}
+ onChange={(d) => {
+ setAmount(d)
+ }}
+ />
+ <ShowInputErrorLabel
+ message={errorsWire?.amount}
+ isDirty={subject !== undefined}
+ />
+ <p class="mt-2 text-sm text-gray-500" >amount to transfer</p>
+ </div>
- </Fragment>
- }
- </div>
+ </div> :
+ <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6 w-full">
+ <div class="sm:col-span-6">
+ <label for="address" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`payto URI:`}</label>
+ <div class="mt-2">
+ <textarea
+ ref={focus ? doAutoFocus : undefined}
+ name="address"
+ id="address"
+ type="textarea"
+ rows={3}
+ class="block overflow-hidden w-64 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+ value={rawPaytoInput ?? ""}
+ required
+ placeholder={i18n.str`payto://iban/[receiver-iban]?message=[subject]&amount=[${limit.currency}:X.Y]`}
+ onInput={(e): void => {
+ rawPaytoInputSetter(e.currentTarget.value);
+ }}
+ />
+ <ShowInputErrorLabel
+ message={errorsPayto?.rawPaytoInput}
+ isDirty={rawPaytoInput !== undefined}
+ />
+ </div>
+ </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">
{onCancel ?
@@ -328,17 +354,37 @@ export function PaytoWireTransferForm({
)
}
+
+/**
+ * Show the element when the load ended
+ * @param element
+ */
+export function doAutoFocus(element: HTMLElement | null) {
+ if (element) {
+ window.requestIdleCallback(() => {
+ element.focus()
+ element.scrollIntoView({
+ behavior: "smooth",
+ block: "center",
+ inline: "center"
+ })
+ })
+ }
+}
+
export function Amount(
{
currency,
name,
value,
error,
+ left,
onChange,
}: {
error?: string;
currency: string;
name: string;
+ left?: boolean | undefined,
value: string | undefined;
onChange?: (s: string) => void;
},
@@ -346,13 +392,16 @@ export function Amount(
): VNode {
return (
<div class="mt-2">
- <div class="relative rounded-md shadow-sm">
- <div class="pointer-events-none absolute inset-y-0 flex items-center pl-3">
+ <div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
+ <div
+ class="pointer-events-none inset-y-0 flex items-center px-3"
+ >
<span class="text-gray-500 sm:text-sm">{currency}</span>
</div>
<input
type="number"
- class="text-right block w-full rounded-md border-0 py-1.5 pl-16 text-gray-900 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"
+ data-left={left}
+ class="text-right rounded-md rounded-l-none data-[left=true]:text-left w-full py-1.5 pl-3 text-gray-900 placeholder:text-gray-400 sm:text-sm sm:leading-6"
placeholder="0.00" aria-describedby="price-currency"
ref={ref}
name={name}
@@ -371,3 +420,4 @@ export function Amount(
</div>
);
}
+