gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: payto form


From: gnunet
Subject: [taler-wallet-core] branch master updated: payto form
Date: Sun, 08 Sep 2024 23:10:49 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 19c75d414 payto form
19c75d414 is described below

commit 19c75d414fe8427b4dc72f3021e23cf48017f249
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Sun Sep 8 18:10:26 2024 -0300

    payto form
---
 .../aml-backoffice-ui/src/ExchangeAmlFrame.tsx     |   2 +-
 packages/aml-backoffice-ui/src/pages/Cases.tsx     |   4 +-
 packages/aml-backoffice-ui/src/pages/Search.tsx    | 357 +++++++++++++++++----
 packages/taler-util/src/payto.ts                   |  10 +-
 packages/web-util/src/forms/InputLine.tsx          |   6 +-
 packages/web-util/src/forms/forms.ts               |   2 +-
 6 files changed, 309 insertions(+), 72 deletions(-)

diff --git a/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx 
b/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
index b7741d4c7..a74cd09b9 100644
--- a/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
+++ b/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
@@ -215,7 +215,7 @@ export function ExchangeAmlFrame({
         <div class="flex mx-auto my-4">
           <main
             class="block rounded-lg bg-white px-5 py-6 shadow "
-            style={{ minWidth: 300 }}
+            style={{ minWidth: 600 }}
           >
             {children}
           </main>
diff --git a/packages/aml-backoffice-ui/src/pages/Cases.tsx 
b/packages/aml-backoffice-ui/src/pages/Cases.tsx
index c7191332a..c274cbcb0 100644
--- a/packages/aml-backoffice-ui/src/pages/Cases.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Cases.tsx
@@ -232,7 +232,7 @@ export function Cases() {
 
   return (
     <CasesUI
-      filtered={true}
+      filtered={false}
       records={list.body}
       onFirstPage={list.isFirstPage ? undefined : list.loadFirst}
       onNext={list.isLastPage ? undefined : list.loadNext}
@@ -301,7 +301,7 @@ export function CasesUnderInvestigation() {
 
   return (
     <CasesUI
-      filtered={false}
+      filtered={true}
       records={list.body}
       onFirstPage={list.isFirstPage ? undefined : list.loadFirst}
       onNext={list.isLastPage ? undefined : list.loadNext}
diff --git a/packages/aml-backoffice-ui/src/pages/Search.tsx 
b/packages/aml-backoffice-ui/src/pages/Search.tsx
index 047e56180..bcdca0243 100644
--- a/packages/aml-backoffice-ui/src/pages/Search.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Search.tsx
@@ -13,6 +13,15 @@
  You should have received a copy of the GNU General Public License along with
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
+import {
+  buildPayto,
+  encodeCrock,
+  hashPaytoUri,
+  parsePaytoUri,
+  PaytoUri,
+  stringifyPaytoUri,
+  TranslatedString,
+} from "@gnu-taler/taler-util";
 import {
   convertUiField,
   getConverterById,
@@ -22,7 +31,8 @@ import {
   UIHandlerId,
   useTranslationContext,
 } from "@gnu-taler/web-util/browser";
-import { h } from "preact";
+import { h, VNode } from "preact";
+import { useState } from "preact/hooks";
 import {
   FormErrors,
   FormStatus,
@@ -34,34 +44,16 @@ import {
 import { useOfficer } from "../hooks/officer.js";
 import { undefinedIfEmpty } from "./CreateAccount.js";
 import { HandleAccountNotReady } from "./HandleAccountNotReady.js";
-import { TranslatedString } from "@gnu-taler/taler-util";
-
-interface FormType {
-  paytoType: "generic" | "iban" | "x-taler-bank";
-}
 
 export function Search() {
   const officer = useOfficer();
   const { i18n } = useTranslationContext();
 
+  const [paytoUri, setPayto] = useState<PaytoUri | undefined>(undefined);
+
   const paytoForm = useFormState(
     getShapeFromFields(paytoTypeField(i18n)),
-    { paytoType: "generic" },
-    createFormValidator(i18n),
-  );
-
-  const secondFieldSet =
-    paytoForm.status.status !== "ok"
-      ? []
-      : paytoForm.status.result.paytoType === "iban"
-        ? ibanFields(i18n)
-        : paytoForm.status.result.paytoType === "x-taler-bank"
-          ? talerBankFields(i18n)
-          : genericFields(i18n);
-
-  const secondForm = useFormState(
-    getShapeFromFields(secondFieldSet),
-    {},
+    { paytoType: "iban" },
     createFormValidator(i18n),
   );
 
@@ -95,40 +87,169 @@ export function Search() {
         </div>
       </form>
 
-      <form
-        class="space-y-6"
-        noValidate
-        onSubmit={(e) => {
-          e.preventDefault();
-        }}
-        autoCapitalize="none"
-        autoCorrect="off"
-      >
-        <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-5 md:grid-cols-3">
-          <RenderAllFieldsByUiConfig
-            fields={convertUiField(
-              i18n,
-              secondFieldSet,
-              secondForm.handler,
-              getConverterById,
-            )}
-          />
-        </div>
-      </form>
+      {paytoForm.status.status !== "ok" ? undefined : paytoForm.status.result
+          .paytoType === "x-taler-bank" ? (
+        <XTalerBankForm onSearch={setPayto} />
+      ) : paytoForm.status.result.paytoType === "iban" ? (
+        <IbanForm onSearch={setPayto} />
+      ) : (
+        <GenericForm onSearch={setPayto} />
+      )}
+      <pre>{!paytoUri ? undefined : stringifyPaytoUri(paytoUri)}</pre>
+      <pre>{!paytoUri ? undefined : encodeCrock(hashPaytoUri(paytoUri))}</pre>
     </div>
   );
 }
 
+function XTalerBankForm({
+  onSearch,
+}: {
+  onSearch: (p: PaytoUri | undefined) => void;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  const fields = talerBankFields(i18n);
+  const form = useFormState(
+    getShapeFromFields(fields),
+    {},
+    createTalerBankPaytoValidator(i18n),
+  );
+  const paytoUri =
+    form.status.status === "fail"
+      ? undefined
+      : buildPayto(
+          "x-taler-bank",
+          form.status.result.hostname,
+          form.status.result.account,
+          {
+            "receiver-name": form.status.result.name,
+          },
+        );
+
+  return (
+    <form
+      class="space-y-6"
+      noValidate
+      onSubmit={(e) => {
+        e.preventDefault();
+      }}
+      autoCapitalize="none"
+      autoCorrect="off"
+    >
+      <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-5 md:grid-cols-3">
+        <RenderAllFieldsByUiConfig
+          fields={convertUiField(i18n, fields, form.handler, getConverterById)}
+        />
+      </div>
+      <button
+        disabled={form.status.status === "fail"}
+        class="disabled:bg-gray-100 disabled:text-gray-500 m-4  rounded-md 
w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm 
hover:bg-indigo-700"
+        onClick={() => onSearch(paytoUri)}
+      >
+        Search
+      </button>
+    </form>
+  );
+}
+function IbanForm({
+  onSearch,
+}: {
+  onSearch: (p: PaytoUri | undefined) => void;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  const fields = ibanFields(i18n);
+  const form = useFormState(
+    getShapeFromFields(fields),
+    {},
+    createIbanPaytoValidator(i18n),
+  );
+  const paytoUri =
+    form.status.status === "fail"
+      ? undefined
+      : buildPayto("iban", form.status.result.account, undefined, {
+          "receiver-name": form.status.result.name,
+        });
+
+  return (
+    <form
+      class="space-y-6"
+      noValidate
+      onSubmit={(e) => {
+        e.preventDefault();
+      }}
+      autoCapitalize="none"
+      autoCorrect="off"
+    >
+      <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-5 md:grid-cols-3">
+        <RenderAllFieldsByUiConfig
+          fields={convertUiField(i18n, fields, form.handler, getConverterById)}
+        />
+      </div>
+      <button
+        disabled={form.status.status === "fail"}
+        class="disabled:bg-gray-100 disabled:text-gray-500 m-4  rounded-md 
w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm 
hover:bg-indigo-700"
+        onClick={() => onSearch(paytoUri)}
+      >
+        Search
+      </button>
+    </form>
+  );
+}
+function GenericForm({
+  onSearch,
+}: {
+  onSearch: (p: PaytoUri | undefined) => void;
+}): VNode {
+  const { i18n } = useTranslationContext();
+  const fields = genericFields(i18n);
+  const form = useFormState(
+    getShapeFromFields(fields),
+    {},
+    createGenericPaytoValidator(i18n),
+  );
+  const paytoUri =
+    form.status.status === "fail"
+      ? undefined
+      : parsePaytoUri(form.status.result.payto);
+  return (
+    <form
+      class="space-y-6"
+      noValidate
+      onSubmit={(e) => {
+        e.preventDefault();
+      }}
+      autoCapitalize="none"
+      autoCorrect="off"
+    >
+      <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-5 md:grid-cols-3">
+        <RenderAllFieldsByUiConfig
+          fields={convertUiField(i18n, fields, form.handler, getConverterById)}
+        />
+      </div>
+      <button
+        disabled={form.status.status === "fail"}
+        class="disabled:bg-gray-100 disabled:text-gray-500 m-4  rounded-md 
w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm 
hover:bg-indigo-700"
+        onClick={() => onSearch(paytoUri)}
+      >
+        Search
+      </button>
+    </form>
+  );
+}
+
+interface FormPayto {
+  paytoType: "generic" | "iban" | "x-taler-bank";
+}
+
 function createFormValidator(i18n: InternationalizationAPI) {
   return function check(
-    state: RecursivePartial<FormValues<FormType>>,
-  ): FormStatus<FormType> {
-    const errors = undefinedIfEmpty<FormErrors<FormType>>({
+    state: RecursivePartial<FormValues<FormPayto>>,
+  ): FormStatus<FormPayto> {
+    const errors = undefinedIfEmpty<FormErrors<FormPayto>>({
       paytoType: !state?.paytoType ? i18n.str`required` : undefined,
     });
 
     if (errors === undefined) {
-      const result: FormType = {
+      const result: FormPayto = {
         paytoType: state.paytoType! as any,
       };
       return {
@@ -137,7 +258,7 @@ function createFormValidator(i18n: InternationalizationAPI) 
{
         errors,
       };
     }
-    const result: RecursivePartial<FormType> = {
+    const result: RecursivePartial<FormPayto> = {
       paytoType: state?.paytoType,
     };
     return {
@@ -148,6 +269,119 @@ function createFormValidator(i18n: 
InternationalizationAPI) {
   };
 }
 
+interface PaytoUriGenericForm {
+  payto: string;
+}
+
+function createGenericPaytoValidator(i18n: InternationalizationAPI) {
+  return function check(
+    state: RecursivePartial<FormValues<PaytoUriGenericForm>>,
+  ): FormStatus<PaytoUriGenericForm> {
+    const errors = undefinedIfEmpty<FormErrors<PaytoUriGenericForm>>({
+      payto: !state.payto
+        ? i18n.str`required`
+        : parsePaytoUri(state.payto) === undefined
+          ? i18n.str`invalid`
+          : undefined,
+    });
+
+    if (errors === undefined) {
+      const result: PaytoUriGenericForm = {
+        payto: state.payto! as any,
+      };
+      return {
+        status: "ok",
+        result,
+        errors,
+      };
+    }
+    const result: RecursivePartial<PaytoUriGenericForm> = {
+      // targetType: state.iban
+    };
+    return {
+      status: "fail",
+      result,
+      errors,
+    };
+  };
+}
+
+interface PaytoUriIBANForm {
+  account: string;
+  name: string;
+}
+
+function createIbanPaytoValidator(i18n: InternationalizationAPI) {
+  return function check(
+    state: RecursivePartial<FormValues<PaytoUriIBANForm>>,
+  ): FormStatus<PaytoUriIBANForm> {
+    const errors = undefinedIfEmpty<FormErrors<PaytoUriIBANForm>>({
+      account: !state.account ? i18n.str`required` : undefined,
+      name: !state.name ? i18n.str`required` : undefined,
+    });
+
+    if (errors === undefined) {
+      const result: PaytoUriIBANForm = {
+        account: state.account!,
+        name: state.name!,
+      };
+      return {
+        status: "ok",
+        result,
+        errors,
+      };
+    }
+    const result: RecursivePartial<PaytoUriIBANForm> = {
+      account: state.account,
+      name: state.name,
+    };
+    return {
+      status: "fail",
+      result,
+      errors,
+    };
+  };
+}
+interface PaytoUriTalerBankForm {
+  hostname: string;
+  account: string;
+  name: string;
+}
+function createTalerBankPaytoValidator(i18n: InternationalizationAPI) {
+  return function check(
+    state: RecursivePartial<FormValues<PaytoUriTalerBankForm>>,
+  ): FormStatus<PaytoUriTalerBankForm> {
+    const errors = undefinedIfEmpty<FormErrors<PaytoUriTalerBankForm>>({
+      account: !state.account ? i18n.str`required` : undefined,
+      hostname: !state.hostname ? i18n.str`required` : undefined,
+      name: !state.name ? i18n.str`required` : undefined,
+    });
+
+    if (errors === undefined) {
+      const result: PaytoUriTalerBankForm = {
+        account: state.account!,
+        hostname: state.hostname!,
+        name: state.name!,
+      };
+      return {
+        status: "ok",
+        result,
+        errors,
+      };
+    }
+    const result: RecursivePartial<PaytoUriTalerBankForm> = {
+      account: state.account,
+      hostname: state.hostname,
+      name: state.name,
+    };
+    return {
+      status: "fail",
+      result,
+      errors,
+    };
+  };
+}
+
 const paytoTypeField: (
   i18n: InternationalizationAPI,
 ) => UIFormElementConfig[] = (i18n) => [
@@ -156,10 +390,6 @@ const paytoTypeField: (
     type: "choiceHorizontal",
     required: true,
     choices: [
-      {
-        value: "generic",
-        label: i18n.str`Generic Payto:// URI`,
-      },
       {
         value: "iban",
         label: i18n.str`IBAN`,
@@ -168,18 +398,22 @@ const paytoTypeField: (
         value: "x-taler-bank",
         label: i18n.str`Taler Bank`,
       },
+      {
+        value: "generic",
+        label: i18n.str`Generic Payto:// URI`,
+      },
     ],
-    label: `Account type`,
+    label: i18n.str`Account type`,
   },
 ];
 
 const receiverName: (i18n: InternationalizationAPI) => UIFormElementConfig = (
   i18n,
 ) => ({
-  id: "receiverName" as UIHandlerId,
+  id: "name" as UIHandlerId,
   type: "text",
   required: true,
-  label: `Owner's name`,
+  label: i18n.str`Owner's name`,
   help: i18n.str`It should match the bank account name.`,
   placeholder: i18n.str`John Doe`,
 });
@@ -188,14 +422,13 @@ const genericFields: (
   i18n: InternationalizationAPI,
 ) => UIFormElementConfig[] = (i18n) => [
   {
-    id: "paytoText" as UIHandlerId,
+    id: "payto" as UIHandlerId,
     type: "textArea",
     required: true,
-    label: `Payto URI`,
+    label: i18n.str`Payto URI`,
     help: i18n.str`As defined by RFC 8905`,
     placeholder: i18n.str`payto://`,
   },
-  receiverName(i18n),
 ];
 const ibanFields: (i18n: InternationalizationAPI) => UIFormElementConfig[] = (
   i18n,
@@ -204,10 +437,10 @@ const ibanFields: (i18n: InternationalizationAPI) => 
UIFormElementConfig[] = (
     id: "account" as UIHandlerId,
     type: "text",
     required: true,
-    label: `Account`,
+    label: i18n.str`Account`,
     help: i18n.str`International Bank Account Number`,
     placeholder: i18n.str`DE1231231231`,
-    validator: (value) => validateIBAN(value, i18n),
+    // validator: (value) => validateIBAN(value, i18n),
   },
   receiverName(i18n),
 ];
@@ -219,7 +452,7 @@ const talerBankFields: (
     id: "account" as UIHandlerId,
     type: "text",
     required: true,
-    label: `Bank account`,
+    label: i18n.str`Bank account`,
     help: i18n.str`Bank account id`,
     placeholder: i18n.str`DE123123123`,
   },
@@ -227,10 +460,10 @@ const talerBankFields: (
     id: "hostname" as UIHandlerId,
     type: "text",
     required: true,
-    label: `Hostname`,
-    validator: (value) => validateTalerBank(value, i18n),
+    label: i18n.str`Hostname`,
     help: i18n.str`Without the scheme, may include subpath: bank.com, 
bank.com/path/`,
     placeholder: i18n.str`bank.demo.taler.net`,
+    // validator: (value) => validateTalerBank(value, i18n),
   },
   receiverName(i18n),
 ];
diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts
index 76b5ff0cf..3c28a9ad0 100644
--- a/packages/taler-util/src/payto.ts
+++ b/packages/taler-util/src/payto.ts
@@ -99,21 +99,25 @@ export function buildPayto(
   type: "iban",
   iban: string,
   bic: string | undefined,
+  params?: Record<string, string>,
 ): PaytoUriIBAN;
 export function buildPayto(
   type: "bitcoin",
   address: string,
   reserve: string | undefined,
+  params?: Record<string, string>,
 ): PaytoUriBitcoin;
 export function buildPayto(
   type: "x-taler-bank",
   host: string,
   account: string,
+  params?: Record<string, string>,
 ): PaytoUriTalerBank;
 export function buildPayto(
   type: PaytoType,
   first: string,
   second?: string,
+  params: Record<string, string> = {},
 ): PaytoUriGeneric {
   switch (type) {
     case "bitcoin": {
@@ -123,7 +127,7 @@ export function buildPayto(
         targetType: "bitcoin",
         targetPath: first,
         address: uppercased,
-        params: {},
+        params,
         segwitAddrs: !second ? [] : generateFakeSegwitAddress(second, first),
       };
       return result;
@@ -134,7 +138,7 @@ export function buildPayto(
         isKnown: true,
         targetType: "iban",
         iban: uppercased,
-        params: {},
+        params,
         targetPath: !second ? uppercased : `${second}/${uppercased}`,
       };
       return result;
@@ -146,7 +150,7 @@ export function buildPayto(
         targetType: "x-taler-bank",
         host: first,
         account: second,
-        params: {},
+        params,
         targetPath: `${first}/${second}`,
       };
       return result;
diff --git a/packages/web-util/src/forms/InputLine.tsx 
b/packages/web-util/src/forms/InputLine.tsx
index a89d2e24e..4c0176195 100644
--- a/packages/web-util/src/forms/InputLine.tsx
+++ b/packages/web-util/src/forms/InputLine.tsx
@@ -59,9 +59,9 @@ export function LabelWithTooltipMaybeRequired({
   );
   if (required) {
     return (
-      <div class="flex justify-between">
+      <div class="flex justify-between w-fit">
         {WithTooltip}
-        <span class="text-sm leading-6 text-red-600">*</span>
+        <span class="text-sm leading-6 text-red-600 pl-2">*</span>
       </div>
     );
   }
@@ -121,7 +121,7 @@ function InputWrapper<T extends object, K extends keyof T>({
   children: ComponentChildren;
 } & UIFormProps<T, K>): VNode {
   return (
-    <div class="sm:col-span-6">
+    <div class="sm:col-span-6 ">
       <LabelWithTooltipMaybeRequired
         label={label}
         required={required}
diff --git a/packages/web-util/src/forms/forms.ts 
b/packages/web-util/src/forms/forms.ts
index 3b56081ef..2c789b9a3 100644
--- a/packages/web-util/src/forms/forms.ts
+++ b/packages/web-util/src/forms/forms.ts
@@ -297,7 +297,7 @@ export function convertUiField(
       }
       case "textArea": {
         return {
-          type: "text",
+          type: "textArea",
           properties: {
             ...converBaseFieldsProps(i18n_, config),
             ...converInputFieldsProps(form, config, getConverterById),

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]