gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: one form left


From: gnunet
Subject: [taler-wallet-core] branch master updated: one form left
Date: Tue, 16 May 2023 06:23:55 +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 245ab840b one form left
245ab840b is described below

commit 245ab840baf1926ef2c03a8965fce85012887d92
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Tue May 16 01:23:44 2023 -0300

    one form left
---
 packages/exchange-backoffice-ui/src/Dashborad.tsx  |  11 +-
 .../exchange-backoffice-ui/src/forms/902_11e.ts    |   2 +-
 .../exchange-backoffice-ui/src/forms/902_13e.ts    |  24 +-
 .../exchange-backoffice-ui/src/forms/902_15e.ts    | 158 ++++++++++++-
 .../exchange-backoffice-ui/src/forms/902_4e.ts     |   2 +-
 .../exchange-backoffice-ui/src/forms/902_5e.ts     | 246 ++++++++++++++++++++-
 .../exchange-backoffice-ui/src/forms/902_9e.ts     |  99 ++++++++-
 packages/exchange-backoffice-ui/src/forms/index.ts |  26 +++
 .../exchange-backoffice-ui/src/handlers/Group.tsx  |  41 ++++
 .../{InputChoice.tsx => InputChoiceStacked.tsx}    |   0
 .../src/handlers/InputSelectMultiple.tsx           |   8 +-
 .../src/handlers/InputSelectOne.tsx                | 136 ++++++++++++
 .../src/handlers/Separator.tsx                     |  26 +++
 .../exchange-backoffice-ui/src/handlers/forms.ts   |  17 +-
 14 files changed, 750 insertions(+), 46 deletions(-)

diff --git a/packages/exchange-backoffice-ui/src/Dashborad.tsx 
b/packages/exchange-backoffice-ui/src/Dashborad.tsx
index f31160fee..dce41b496 100644
--- a/packages/exchange-backoffice-ui/src/Dashborad.tsx
+++ b/packages/exchange-backoffice-ui/src/Dashborad.tsx
@@ -77,17 +77,17 @@ const navigation = [
     impl: form_902_13e_v1,
   },
   {
-    name: "WIP (902.15e)",
+    name: "Information on life insurance policies (902.15e)",
     icon: DocumentDuplicateIcon,
     impl: form_902_15e_v1,
   },
   {
-    name: "WIP (902.9e)",
+    name: "Declaration of beneficial owner (902.9e)",
     icon: DocumentDuplicateIcon,
     impl: form_902_9e_v1,
   },
   {
-    name: "WIP (902.5e)",
+    name: "Customer profile (902.5e)",
     icon: DocumentDuplicateIcon,
     impl: form_902_5e_v1,
   },
@@ -167,7 +167,7 @@ export function Dashboard({
   children?: ComponentChildren;
 }): VNode {
   const [sidebarOpen, setSidebarOpen] = useState(false);
-  const [selectedForm, setSelectedForm] = useState(3);
+  const [selectedForm, setSelectedForm] = useState(6);
   function changeForm(next: number) {
     setSelectedForm(next);
   }
@@ -177,6 +177,9 @@ export function Dashboard({
     when: {
       t_ms: new Date().getTime(),
     },
+    originOfAssets: {
+      currency: "usd",
+    },
   };
   function showFormOnSidebar(v: any) {
     if (!logRef.current) return;
diff --git a/packages/exchange-backoffice-ui/src/forms/902_11e.ts 
b/packages/exchange-backoffice-ui/src/forms/902_11e.ts
index 49d94736f..0e9a28dce 100644
--- a/packages/exchange-backoffice-ui/src/forms/902_11e.ts
+++ b/packages/exchange-backoffice-ui/src/forms/902_11e.ts
@@ -1,6 +1,6 @@
 import { AbsoluteTime, TranslatedString } from "@gnu-taler/taler-util";
-import { FlexibleForm, languageList } from "./index.js";
 import { FormState } from "../handlers/FormProvider.js";
+import { FlexibleForm } from "./index.js";
 
 export const v1: FlexibleForm<Form902_11e.Form> = {
   versionId: "2023-05-15",
diff --git a/packages/exchange-backoffice-ui/src/forms/902_13e.ts 
b/packages/exchange-backoffice-ui/src/forms/902_13e.ts
index 04dd95bc0..bca96e842 100644
--- a/packages/exchange-backoffice-ui/src/forms/902_13e.ts
+++ b/packages/exchange-backoffice-ui/src/forms/902_13e.ts
@@ -97,10 +97,12 @@ export const v1: FlexibleForm<Form902_13e.Form> = {
                 },
               },
               {
-                type: "text",
+                type: "date",
                 props: {
                   name: "dateOfBirth",
                   label: "Date of birth" as TranslatedString,
+                  pattern: "dd/MM/yyyy",
+                  help: "format 'dd/MM/yyyy'" as TranslatedString,
                 },
               },
               {
@@ -111,11 +113,12 @@ export const v1: FlexibleForm<Form902_13e.Form> = {
                 },
               },
               {
-                type: "text",
+                type: "date",
                 props: {
                   name: "dateOfDeath",
                   label: "Date of death" as TranslatedString,
-                  help: "if deceased" as TranslatedString,
+                  pattern: "dd/MM/yyyy",
+                  help: "if deceased. format 'dd/MM/yyyy'" as TranslatedString,
                 },
               },
               {
@@ -172,10 +175,12 @@ export const v1: FlexibleForm<Form902_13e.Form> = {
                 },
               },
               {
-                type: "text",
+                type: "date",
                 props: {
                   name: "dateOfBirth",
                   label: "Date of birth" as TranslatedString,
+                  pattern: "dd/MM/yyyy",
+                  help: "format 'dd/MM/yyyy'" as TranslatedString,
                 },
               },
               {
@@ -186,11 +191,12 @@ export const v1: FlexibleForm<Form902_13e.Form> = {
                 },
               },
               {
-                type: "text",
+                type: "date",
                 props: {
                   name: "dateOfDeath",
                   label: "Date of death" as TranslatedString,
-                  help: "if deceased" as TranslatedString,
+                  pattern: "dd/MM/yyyy",
+                  help: "if deceased. format 'dd/MM/yyyy'" as TranslatedString,
                 },
               },
             ],
@@ -228,10 +234,12 @@ export const v1: FlexibleForm<Form902_13e.Form> = {
                 },
               },
               {
-                type: "text",
+                type: "date",
                 props: {
                   name: "dateOfBirth",
                   label: "Date of birth" as TranslatedString,
+                  pattern: "dd/MM/yyyy",
+                  help: "format 'dd/MM/yyyy'" as TranslatedString,
                 },
               },
               {
@@ -417,8 +425,8 @@ export const v1: FlexibleForm<Form902_13e.Form> = {
           type: "date",
           props: {
             name: "when",
-            pattern: "dd/MM/yyyy",
             label: "Date" as TranslatedString,
+            pattern: "dd/MM/yyyy",
             help: "format 'dd/MM/yyyy'" as TranslatedString,
           },
         },
diff --git a/packages/exchange-backoffice-ui/src/forms/902_15e.ts 
b/packages/exchange-backoffice-ui/src/forms/902_15e.ts
index 8f927cdc2..07290858e 100644
--- a/packages/exchange-backoffice-ui/src/forms/902_15e.ts
+++ b/packages/exchange-backoffice-ui/src/forms/902_15e.ts
@@ -1,14 +1,13 @@
 import { AbsoluteTime, TranslatedString } from "@gnu-taler/taler-util";
-import { FlexibleForm, languageList } from "./index.js";
 import { FormState } from "../handlers/FormProvider.js";
+import { FlexibleForm } from "./index.js";
 
-export const v1: FlexibleForm<Form902_12e.Form> = {
+export const v1: FlexibleForm<Form902_15e.Form> = {
   versionId: "2023-05-15",
   design: [
     {
-      title: "15" as TranslatedString,
-      description:
-        "for operating legal entities and partnership that are contracting 
partner as well as analogously for operating legal entities and partnership 
that are beneficial owners." as TranslatedString,
+      title:
+        "Information on life insurance policies with separately managed 
accounts/securities accounts" as TranslatedString,
       fields: [
         {
           type: "textArea",
@@ -17,6 +16,123 @@ export const v1: FlexibleForm<Form902_12e.Form> = {
             label: "Contracting partner" as TranslatedString,
           },
         },
+        {
+          type: "text",
+          props: {
+            name: "contractualRelationship",
+            label:
+              "Name or number of the contractual relationship between the 
contracting party and the financial intermediary" as TranslatedString,
+          },
+        },
+        {
+          type: "text",
+          props: {
+            name: "insurancePolicy",
+            label: "Insurance policy" as TranslatedString,
+          },
+        },
+        {
+          type: "separator",
+          props: {
+            label:
+              "The contracting partner confirms in accordance with Art. 41a 
SRO Regulations that it is a licensed and state-supervised insurance company 
and that it has entered into the above-mentioned contractual relationship the 
assets connected to the life insurance policy also mentioned above." as 
TranslatedString,
+          },
+        },
+        {
+          type: "separator",
+          props: {
+            label:
+              "In relation with the above insurance policy, the contracting 
partner gives the following further details" as TranslatedString,
+          },
+        },
+        {
+          type: "group",
+          props: {
+            before: "Policy holder" as TranslatedString,
+            fields: [
+              {
+                type: "text",
+                props: {
+                  name: "holder.fullName",
+                  label:
+                    "Last name(s), first name(s)/entity" as TranslatedString,
+                },
+              },
+              {
+                type: "text",
+                props: {
+                  name: "holder.address",
+                  label:
+                    "Actual address of domicile/registered office (incl. 
country)" as TranslatedString,
+                },
+              },
+              {
+                type: "date",
+                props: {
+                  name: "holder.dateOfBirth",
+                  label: "Date of birth" as TranslatedString,
+                  pattern: "dd/MM/yyyy",
+                  help: "format 'dd/MM/yyyy'" as TranslatedString,
+                },
+              },
+              {
+                type: "text",
+                props: {
+                  name: "holder.nationality",
+                  label: "Nationality" as TranslatedString,
+                },
+              },
+            ],
+          },
+        },
+        {
+          type: "group",
+          props: {
+            before:
+              "Person actually (not in a fiduciary capacity) paying the 
premiums (to be filled in if not identical with point 1 above)" as 
TranslatedString,
+            fields: [
+              {
+                type: "text",
+                props: {
+                  name: "premiumPayer.fullName",
+                  label:
+                    "Last name(s), first name(s)/entity" as TranslatedString,
+                },
+              },
+              {
+                type: "text",
+                props: {
+                  name: "premiumPayer.address",
+                  label:
+                    "Actual address of domicile/registered office (incl. 
country)" as TranslatedString,
+                },
+              },
+              {
+                type: "date",
+                props: {
+                  name: "premiumPayer.dateOfBirth",
+                  label: "Date of birth" as TranslatedString,
+                  pattern: "dd/MM/yyyy",
+                  help: "format 'dd/MM/yyyy'" as TranslatedString,
+                },
+              },
+              {
+                type: "text",
+                props: {
+                  name: "premiumPayer.nationality",
+                  label: "Nationality" as TranslatedString,
+                },
+              },
+            ],
+          },
+        },
+        {
+          type: "separator",
+          props: {
+            label:
+              "The contracting partner hereby undertakes to automatically 
inform the financial intermediary of any changes. The contracting partner 
hereby also declares having been given permission by the above individuals 
and/or entities to transmit their data to the financial intermediary" as 
TranslatedString,
+          },
+        },
         {
           type: "date",
           props: {
@@ -26,12 +142,26 @@ export const v1: FlexibleForm<Form902_12e.Form> = {
             help: "format 'dd/MM/yyyy'" as TranslatedString,
           },
         },
+        {
+          type: "text",
+          props: {
+            name: "signature",
+            label: "Signature" as TranslatedString,
+          },
+        },
+        {
+          type: "separator",
+          props: {
+            label:
+              "It is a criminal offense to deliberately provide false 
information on this form (article 251 of the Swiss Criminal Code, document 
forgery)" as TranslatedString,
+          },
+        },
       ],
     },
   ],
   behavior: function formBehavior(
-    v: Partial<Form902_12e.Form>,
-  ): FormState<Form902_12e.Form> {
+    v: Partial<Form902_15e.Form>,
+  ): FormState<Form902_15e.Form> {
     return {
       when: {
         disabled: true,
@@ -40,9 +170,21 @@ export const v1: FlexibleForm<Form902_12e.Form> = {
   },
 };
 
-namespace Form902_12e {
+namespace Form902_15e {
+  interface Person {
+    fullName: string;
+    address: string;
+    dateOfBirth: AbsoluteTime;
+    nationality: string;
+  }
+
   export interface Form {
     contractingPartner: string;
+    contractualRelationship: string;
+    insurancePolicy: string;
+    holder: Person;
+    premiumsPayer: Person;
     when: AbsoluteTime;
+    signature: string;
   }
 }
diff --git a/packages/exchange-backoffice-ui/src/forms/902_4e.ts 
b/packages/exchange-backoffice-ui/src/forms/902_4e.ts
index 6e8d7f1e2..dd00beccf 100644
--- a/packages/exchange-backoffice-ui/src/forms/902_4e.ts
+++ b/packages/exchange-backoffice-ui/src/forms/902_4e.ts
@@ -1,6 +1,6 @@
 import { AbsoluteTime, TranslatedString } from "@gnu-taler/taler-util";
-import { FlexibleForm, languageList } from "./index.js";
 import { FormState } from "../handlers/FormProvider.js";
+import { FlexibleForm } from "./index.js";
 
 export const v1: FlexibleForm<Form902_12e.Form> = {
   versionId: "2023-05-15",
diff --git a/packages/exchange-backoffice-ui/src/forms/902_5e.ts 
b/packages/exchange-backoffice-ui/src/forms/902_5e.ts
index 20013e727..60bd551d5 100644
--- a/packages/exchange-backoffice-ui/src/forms/902_5e.ts
+++ b/packages/exchange-backoffice-ui/src/forms/902_5e.ts
@@ -1,20 +1,32 @@
-import { AbsoluteTime, TranslatedString } from "@gnu-taler/taler-util";
-import { FlexibleForm, languageList } from "./index.js";
+import {
+  AbsoluteTime,
+  AmountJson,
+  TranslatedString,
+} from "@gnu-taler/taler-util";
 import { FormState } from "../handlers/FormProvider.js";
+import { FlexibleForm, currencyList } from "./index.js";
 
 export const v1: FlexibleForm<Form902_12e.Form> = {
   versionId: "2023-05-15",
   design: [
     {
-      title: "5" as TranslatedString,
+      title: "Customer Profile" as TranslatedString,
       description:
-        "for operating legal entities and partnership that are contracting 
partner as well as analogously for operating legal entities and partnership 
that are beneficial owners." as TranslatedString,
+        "The information below has to refer to the persons from whom the 
assets originate ultimately (e.g. beneficial owner of the assets, 
founder/creator of a trust or foundation). Is the customer an operational legal 
entity or partnership the information may refer to the entity itself (not to 
the controlling person), unless the entity holds the assets in trust for a 
third party." as TranslatedString,
       fields: [
         {
-          type: "textArea",
+          type: "text",
+          props: {
+            name: "customer",
+            label: "Customer" as TranslatedString,
+            help: "Pursuant Identification Form (VQF doc. No. 902.1) numeral 
1" as TranslatedString,
+          },
+        },
+        {
+          type: "text",
           props: {
-            name: "contractingPartner",
-            label: "Contracting partner" as TranslatedString,
+            name: "fullName",
+            label: "Full name" as TranslatedString,
           },
         },
         {
@@ -28,6 +40,194 @@ export const v1: FlexibleForm<Form902_12e.Form> = {
         },
       ],
     },
+    {
+      title: "Business activity" as TranslatedString,
+      fields: [
+        {
+          type: "textArea",
+          props: {
+            label: "Profession, business activities" as TranslatedString,
+            name: "businessActivity",
+            help: "former, current, potentially planned" as TranslatedString,
+          },
+        },
+      ],
+    },
+    {
+      title: "Financial circumstances" as TranslatedString,
+      fields: [
+        {
+          type: "textArea",
+          props: {
+            label: "Income and assets, liabilities" as TranslatedString,
+            name: "financial",
+            help: "estimated" as TranslatedString,
+          },
+        },
+      ],
+    },
+    {
+      title: "Origin of the deposited assets involved" as TranslatedString,
+      fields: [
+        {
+          type: "text",
+          props: {
+            label: "Nature" as TranslatedString,
+            name: "originOfAssets.nature",
+            help: "nature of the involved assets" as TranslatedString,
+          },
+        },
+        {
+          type: "selectOne",
+          props: {
+            name: "originOfAssets.currency",
+            label: "Currency" as TranslatedString,
+            choices: currencyList,
+          },
+        },
+        {
+          type: "integer",
+          props: {
+            label: "Amount" as TranslatedString,
+            name: "originOfAssets.amount",
+          },
+        },
+        {
+          type: "choiceStacked",
+          props: {
+            label: "Category" as TranslatedString,
+            name: "originOfAssets.category",
+            choices: [
+              {
+                label: "Savings" as TranslatedString,
+                value: "savings",
+              },
+              {
+                label: "Own business operations" as TranslatedString,
+                value: "own-business",
+              },
+              {
+                label: "Inheritance" as TranslatedString,
+                value: "inheritance",
+              },
+              {
+                label: "Other, what?" as TranslatedString,
+                value: "other",
+              },
+            ],
+          },
+        },
+        {
+          type: "text",
+          props: {
+            label: "Other category" as TranslatedString,
+            name: "originOfAssets.categoryOther",
+            required: true,
+          },
+        },
+        {
+          type: "textArea",
+          props: {
+            label:
+              "Detailed description of the origins/economical background of 
the assets involved in the business relationship" as TranslatedString,
+            name: "originOfAssets.details",
+          },
+        },
+      ],
+    },
+    {
+      title:
+        "Nature and purpose of the business relationship" as TranslatedString,
+      fields: [
+        {
+          type: "textArea",
+          props: {
+            label: "Purpose of the business relationship" as TranslatedString,
+            name: "nature.purpose",
+            help: "nature of the involved assets" as TranslatedString,
+          },
+        },
+        {
+          type: "textArea",
+          props: {
+            label:
+              "Information on the planned development of the business 
relationship and the assets" as TranslatedString,
+            name: "nature.plan",
+          },
+        },
+        {
+          type: "textArea",
+          props: {
+            label:
+              "Especially in the case of cash or money and asset transfer 
transactions with regular customers: Details on usual business volume, 
Information on the beneficiaries, (Full name, address, bank account)" as 
TranslatedString,
+            name: "nature.cashOrMoneyTransfer",
+          },
+        },
+      ],
+    },
+    {
+      title: "Relationship with third parties" as TranslatedString,
+      fields: [
+        {
+          type: "textArea",
+          props: {
+            label:
+              "Relation of the customer to the beneficial owner involved in 
the business relationship" as TranslatedString,
+            name: "relations.beneficialOwners",
+          },
+        },
+        {
+          type: "textArea",
+          props: {
+            label:
+              "Relation of the customer to the controlling persons involved in 
the business relationship" as TranslatedString,
+            name: "relations.controllingPersons",
+          },
+        },
+        {
+          type: "textArea",
+          props: {
+            label:
+              "Relation of the customer to the authorized signatories involved 
in the business relationship" as TranslatedString,
+            name: "relations.authorizedSignatories",
+          },
+        },
+        {
+          type: "textArea",
+          props: {
+            label:
+              "Relation of the customer to other persons involved in the 
business relationship" as TranslatedString,
+            name: "relations.otherPersons",
+          },
+        },
+        {
+          type: "textArea",
+          props: {
+            label: "Relation to other AMLA-Files" as TranslatedString,
+            name: "relations.withOtherAmlaFiles",
+          },
+        },
+        {
+          type: "textArea",
+          props: {
+            label: "Introducer / agents / references" as TranslatedString,
+            name: "relations.references",
+          },
+        },
+      ],
+    },
+    {
+      title: "Further information" as TranslatedString,
+      fields: [
+        {
+          type: "textArea",
+          props: {
+            label: "Other relevant information" as TranslatedString,
+            name: "furtherInformation",
+          },
+        },
+      ],
+    },
   ],
   behavior: function formBehavior(
     v: Partial<Form902_12e.Form>,
@@ -36,13 +236,43 @@ export const v1: FlexibleForm<Form902_12e.Form> = {
       when: {
         disabled: true,
       },
+      originOfAssets: {
+        categoryOther: {
+          hidden: v.originOfAssets?.category !== "other",
+        },
+      },
     };
   },
 };
 
 namespace Form902_12e {
   export interface Form {
-    contractingPartner: string;
+    customer: string;
+    fullName: string;
     when: AbsoluteTime;
+    businessActivity: string;
+    financial: string;
+    originOfAssets: {
+      nature: string;
+      currency: string;
+      amount: number;
+      category: "savings" | "own-business" | "inheritance" | "other";
+      categoryOther: string;
+      details: string;
+    };
+    nature: {
+      purpose: string;
+      plan: string;
+      cashOrMoneyTransfer: string;
+    };
+    relations: {
+      beneficialOwners: string;
+      controllingPersons: string;
+      authorizedSignatories: string;
+      otherPersons: string;
+      withOtherAmlaFiles: string;
+      references: string;
+    };
+    furtherInformation: string;
   }
 }
diff --git a/packages/exchange-backoffice-ui/src/forms/902_9e.ts 
b/packages/exchange-backoffice-ui/src/forms/902_9e.ts
index d68caba23..053cfaa69 100644
--- a/packages/exchange-backoffice-ui/src/forms/902_9e.ts
+++ b/packages/exchange-backoffice-ui/src/forms/902_9e.ts
@@ -1,14 +1,13 @@
 import { AbsoluteTime, TranslatedString } from "@gnu-taler/taler-util";
-import { FlexibleForm, languageList } from "./index.js";
 import { FormState } from "../handlers/FormProvider.js";
+import { FlexibleForm } from "./index.js";
 
-export const v1: FlexibleForm<Form902_12e.Form> = {
+export const v1: FlexibleForm<Form902_9e.Form> = {
   versionId: "2023-05-15",
   design: [
     {
-      title: "9" as TranslatedString,
-      description:
-        "for operating legal entities and partnership that are contracting 
partner as well as analogously for operating legal entities and partnership 
that are beneficial owners." as TranslatedString,
+      title:
+        "Declaration of identity of the beneficial owner" as TranslatedString,
       fields: [
         {
           type: "textArea",
@@ -26,12 +25,87 @@ export const v1: FlexibleForm<Form902_12e.Form> = {
             help: "format 'dd/MM/yyyy'" as TranslatedString,
           },
         },
+        {
+          type: "separator",
+          props: {
+            label:
+              "The contracting partner hereby declares that the person(s) 
listed below is/are the beneficial owner(s) of the assets involved in the 
business relationship. If the contracting partner is also the sole beneficial 
owner of the assets, the contracting partner's detail must be set out below" as 
TranslatedString,
+          },
+        },
+        {
+          type: "array",
+          props: {
+            label: "Persons" as TranslatedString,
+            labelField: "surname",
+            name: "persons",
+            fields: [
+              {
+                type: "text",
+                props: {
+                  name: "surname",
+                  label: "Surname(s)" as TranslatedString,
+                },
+              },
+              {
+                type: "text",
+                props: {
+                  name: "firstName",
+                  label: "First name(s)" as TranslatedString,
+                },
+              },
+              {
+                type: "date",
+                props: {
+                  name: "dateOfBirth",
+                  label: "Date of birth" as TranslatedString,
+                  pattern: "dd/MM/yyyy",
+                  help: "format 'dd/MM/yyyy'" as TranslatedString,
+                },
+              },
+              {
+                type: "text",
+                props: {
+                  name: "nationality",
+                  label: "Nationality" as TranslatedString,
+                },
+              },
+              {
+                type: "text",
+                props: {
+                  name: "address",
+                  label: "Actual address of domicile" as TranslatedString,
+                },
+              },
+            ],
+          },
+        },
+        {
+          type: "separator",
+          props: {
+            label:
+              "The contracting partner hereby undertakes to inform 
automatically of any changes to the information contained herein" as 
TranslatedString,
+          },
+        },
+        {
+          type: "text",
+          props: {
+            name: "signature",
+            label: "Signature" as TranslatedString,
+          },
+        },
+        {
+          type: "separator",
+          props: {
+            label:
+              "It is a criminal offense to deliberately provide false 
information on this form (article 251 of the Swiss Criminal Code, document 
forgery)" as TranslatedString,
+          },
+        },
       ],
     },
   ],
   behavior: function formBehavior(
-    v: Partial<Form902_12e.Form>,
-  ): FormState<Form902_12e.Form> {
+    v: Partial<Form902_9e.Form>,
+  ): FormState<Form902_9e.Form> {
     return {
       when: {
         disabled: true,
@@ -40,9 +114,18 @@ export const v1: FlexibleForm<Form902_12e.Form> = {
   },
 };
 
-namespace Form902_12e {
+namespace Form902_9e {
+  interface Person {
+    surname: string;
+    firstName: string;
+    dateOfBirth: AbsoluteTime;
+    nationality: string;
+    address: string;
+  }
   export interface Form {
     contractingPartner: string;
+    persons: Person;
     when: AbsoluteTime;
+    signature: string;
   }
 }
diff --git a/packages/exchange-backoffice-ui/src/forms/index.ts 
b/packages/exchange-backoffice-ui/src/forms/index.ts
index 2eb1fba60..c236bbaa3 100644
--- a/packages/exchange-backoffice-ui/src/forms/index.ts
+++ b/packages/exchange-backoffice-ui/src/forms/index.ts
@@ -118,3 +118,29 @@ export const languageList = [
     value: "hau",
   },
 ];
+export const currencyList = [
+  {
+    label: "United States dollar" as TranslatedString,
+    value: "usd",
+  },
+  {
+    label: "Euro" as TranslatedString,
+    value: "eur",
+  },
+  {
+    label: "Swiss franc" as TranslatedString,
+    value: "chf",
+  },
+  {
+    label: "Argentine peso" as TranslatedString,
+    value: "ars",
+  },
+  {
+    label: "Mexican peso" as TranslatedString,
+    value: "mxn",
+  },
+  {
+    label: "Brazilian real" as TranslatedString,
+    value: "brl",
+  },
+];
diff --git a/packages/exchange-backoffice-ui/src/handlers/Group.tsx 
b/packages/exchange-backoffice-ui/src/handlers/Group.tsx
new file mode 100644
index 000000000..04af0647b
--- /dev/null
+++ b/packages/exchange-backoffice-ui/src/handlers/Group.tsx
@@ -0,0 +1,41 @@
+import { TranslatedString } from "@gnu-taler/taler-util";
+import { VNode, h } from "preact";
+import { LabelWithTooltipMaybeRequired } from "./InputLine.js";
+import { RenderAllFieldsByUiConfig, UIFormField } from "./forms.js";
+
+interface Props {
+  before?: TranslatedString;
+  after?: TranslatedString;
+  tooltipBefore?: TranslatedString;
+  tooltipAfter?: TranslatedString;
+  fields: UIFormField[];
+}
+
+export function Group({
+  before,
+  after,
+  tooltipAfter,
+  tooltipBefore,
+  fields,
+}: Props): VNode {
+  return (
+    <div class="sm:col-span-6 p-4 rounded-lg border-r-2 border-2 bg-gray-50">
+      <div class="pb-4">
+        {before && (
+          <LabelWithTooltipMaybeRequired
+            label={before}
+            tooltip={tooltipBefore}
+          />
+        )}
+      </div>
+      <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
+        <RenderAllFieldsByUiConfig fields={fields} />
+      </div>
+      <div class="pt-4">
+        {after && (
+          <LabelWithTooltipMaybeRequired label={after} tooltip={tooltipAfter} 
/>
+        )}
+      </div>
+    </div>
+  );
+}
diff --git a/packages/exchange-backoffice-ui/src/handlers/InputChoice.tsx 
b/packages/exchange-backoffice-ui/src/handlers/InputChoiceStacked.tsx
similarity index 100%
rename from packages/exchange-backoffice-ui/src/handlers/InputChoice.tsx
rename to packages/exchange-backoffice-ui/src/handlers/InputChoiceStacked.tsx
diff --git 
a/packages/exchange-backoffice-ui/src/handlers/InputSelectMultiple.tsx 
b/packages/exchange-backoffice-ui/src/handlers/InputSelectMultiple.tsx
index 05733fe19..dd85453e5 100644
--- a/packages/exchange-backoffice-ui/src/handlers/InputSelectMultiple.tsx
+++ b/packages/exchange-backoffice-ui/src/handlers/InputSelectMultiple.tsx
@@ -1,5 +1,5 @@
 import { Fragment, VNode, h } from "preact";
-import { Choice } from "./InputChoice.js";
+import { Choice } from "./InputChoiceStacked.js";
 import { LabelWithTooltipMaybeRequired, UIFormProps } from "./InputLine.js";
 import { useField } from "./useField.js";
 import { useState } from "preact/hooks";
@@ -8,9 +8,10 @@ export function InputSelectMultiple(
   props: {
     choices: Choice[];
     unique?: boolean;
+    max?: number;
   } & UIFormProps<Array<string>>,
 ): VNode {
-  const { name, label, choices, placeholder, tooltip, required, unique } =
+  const { name, label, choices, placeholder, tooltip, required, unique, max } =
     props;
   const { value, onChange } = useField<{ [s: string]: Array<string> }>(name);
 
@@ -113,6 +114,9 @@ export function InputSelectMultiple(
                     if (unique && list.indexOf(v.value) !== -1) {
                       return;
                     }
+                    if (max !== undefined && list.length >= max) {
+                      return;
+                    }
                     const newValue = [...list];
                     newValue.splice(0, 0, v.value);
                     onChange(newValue);
diff --git a/packages/exchange-backoffice-ui/src/handlers/InputSelectOne.tsx 
b/packages/exchange-backoffice-ui/src/handlers/InputSelectOne.tsx
new file mode 100644
index 000000000..a4ed1ba1c
--- /dev/null
+++ b/packages/exchange-backoffice-ui/src/handlers/InputSelectOne.tsx
@@ -0,0 +1,136 @@
+import { Fragment, VNode, h } from "preact";
+import { Choice } from "./InputChoiceStacked.js";
+import { LabelWithTooltipMaybeRequired, UIFormProps } from "./InputLine.js";
+import { useField } from "./useField.js";
+import { useState } from "preact/hooks";
+
+export function InputSelectOne(
+  props: {
+    choices: Choice[];
+  } & UIFormProps<Array<string>>,
+): VNode {
+  const { name, label, choices, placeholder, tooltip, required } = props;
+  const { value, onChange } = useField<{ [s: string]: string | undefined }>(
+    name,
+  );
+
+  const [filter, setFilter] = useState<string | undefined>(undefined);
+  const regex = new RegExp(`.*${filter}.*`, "i");
+  const choiceMap = choices.reduce((prev, curr) => {
+    return { ...prev, [curr.value]: curr.label };
+  }, {} as Record<string, string>);
+
+  const filteredChoices =
+    filter === undefined
+      ? undefined
+      : choices.filter((v) => {
+          return regex.test(v.label);
+        });
+  return (
+    <div class="sm:col-span-6">
+      <LabelWithTooltipMaybeRequired
+        label={label}
+        required={required}
+        tooltip={tooltip}
+      />
+      {value ? (
+        <span class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-100 
p-1 mr-2 font-medium text-gray-600">
+          {choiceMap[value]}
+          <button
+            type="button"
+            onClick={() => {
+              onChange(undefined);
+            }}
+            class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20"
+          >
+            <span class="sr-only">Remove</span>
+            <svg
+              viewBox="0 0 14 14"
+              class="h-5 w-5 stroke-gray-700/50 group-hover:stroke-gray-700/75"
+            >
+              <path d="M4 4l6 6m0-6l-6 6" />
+            </svg>
+            <span class="absolute -inset-1"></span>
+          </button>
+        </span>
+      ) : (
+        <div class="relative mt-2">
+          <input
+            id="combobox"
+            type="text"
+            value={filter ?? ""}
+            onChange={(e) => {
+              setFilter(e.currentTarget.value);
+            }}
+            placeholder={placeholder}
+            class="w-full rounded-md border-0 bg-white py-1.5 pl-3 pr-12 
text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 
focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+            role="combobox"
+            aria-controls="options"
+            aria-expanded="false"
+          />
+          <button
+            type="button"
+            onClick={() => {
+              setFilter(filter === undefined ? "" : undefined);
+            }}
+            class="absolute inset-y-0 right-0 flex items-center rounded-r-md 
px-2 focus:outline-none"
+          >
+            <svg
+              class="h-5 w-5 text-gray-400"
+              viewBox="0 0 20 20"
+              fill="currentColor"
+              aria-hidden="true"
+            >
+              <path
+                fill-rule="evenodd"
+                d="M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 
4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3zm-3.76 9.2a.75.75 
0 011.06.04l2.7 2.908 2.7-2.908a.75.75 0 111.1 1.02l-3.25 3.5a.75.75 0 01-1.1 
0l-3.25-3.5a.75.75 0 01.04-1.06z"
+                clip-rule="evenodd"
+              />
+            </svg>
+          </button>
+
+          {filteredChoices !== undefined && (
+            <ul
+              class="absolute z-10 mt-1 max-h-60 w-full overflow-auto 
rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 
focus:outline-none sm:text-sm"
+              id="options"
+              role="listbox"
+            >
+              {filteredChoices.map((v, idx) => {
+                return (
+                  <li
+                    class="relative cursor-pointer select-none py-2 pl-3 pr-9 
text-gray-900 hover:text-white hover:bg-indigo-600"
+                    id="option-0"
+                    role="option"
+                    onClick={() => {
+                      setFilter(undefined);
+                      onChange(v.value);
+                    }}
+
+                    // tabindex="-1"
+                  >
+                    {/* <!-- Selected: "font-semibold" --> */}
+                    <span class="block truncate">{v.label}</span>
+
+                    {/* <!--
+          Checkmark, only display for selected option.
+
+          Active: "text-white", Not Active: "text-indigo-600"
+        --> */}
+                  </li>
+                );
+              })}
+
+              {/* <!--
+        Combobox option, manage highlight styles based on 
mouseenter/mouseleave and keyboard navigation.
+
+        Active: "text-white bg-indigo-600", Not Active: "text-gray-900"
+      --> */}
+
+              {/* <!-- More items... --> */}
+            </ul>
+          )}
+        </div>
+      )}
+    </div>
+  );
+}
diff --git a/packages/exchange-backoffice-ui/src/handlers/Separator.tsx 
b/packages/exchange-backoffice-ui/src/handlers/Separator.tsx
new file mode 100644
index 000000000..5fa25c3ca
--- /dev/null
+++ b/packages/exchange-backoffice-ui/src/handlers/Separator.tsx
@@ -0,0 +1,26 @@
+import { VNode, h } from "preact";
+import {
+  InputLine,
+  LabelWithTooltipMaybeRequired,
+  UIFormProps,
+} from "./InputLine.js";
+import { TranslatedString } from "@gnu-taler/taler-util";
+
+interface Props {
+  label: TranslatedString;
+  tooltip?: TranslatedString;
+  help?: TranslatedString;
+}
+
+export function Separator({ label, tooltip, help }: Props): VNode {
+  return (
+    <div class="sm:col-span-6">
+      <LabelWithTooltipMaybeRequired label={label} tooltip={tooltip} />
+      {help && (
+        <p class="mt-2 text-sm text-gray-500" id="email-description">
+          {help}
+        </p>
+      )}
+    </div>
+  );
+}
diff --git a/packages/exchange-backoffice-ui/src/handlers/forms.ts 
b/packages/exchange-backoffice-ui/src/handlers/forms.ts
index b5d1a2b20..418754919 100644
--- a/packages/exchange-backoffice-ui/src/handlers/forms.ts
+++ b/packages/exchange-backoffice-ui/src/handlers/forms.ts
@@ -3,11 +3,14 @@ import { InputText } from "./InputText.js";
 import { InputDate } from "./InputDate.js";
 import { InputInteger } from "./InputInteger.js";
 import { h as create, Fragment, VNode } from "preact";
-import { InputChoiceStacked } from "./InputChoice.js";
+import { InputChoiceStacked } from "./InputChoiceStacked.js";
 import { InputArray } from "./InputArray.js";
 import { InputSelectMultiple } from "./InputSelectMultiple.js";
 import { InputTextArea } from "./InputTextArea.js";
 import { InputFile } from "./InputFile.js";
+import { Separator } from "./Separator.js";
+import { Group } from "./Group.js";
+import { InputSelectOne } from "./InputSelectOne.js";
 
 export type DoubleColumnForm = DoubleColumnFormSection[];
 
@@ -21,9 +24,11 @@ type DoubleColumnFormSection = {
  * Constrain the type with the ui props
  */
 type FieldType = {
-  separator: {};
+  group: Parameters<typeof Group>[0];
+  separator: Parameters<typeof Separator>[0];
   array: Parameters<typeof InputArray>[0];
   file: Parameters<typeof InputFile>[0];
+  selectOne: Parameters<typeof InputSelectOne>[0];
   selectMultiple: Parameters<typeof InputSelectMultiple>[0];
   text: Parameters<typeof InputText>[0];
   textArea: Parameters<typeof InputTextArea>[0];
@@ -36,9 +41,11 @@ type FieldType = {
  * List all the form fields so typescript can type-check the form instance
  */
 export type UIFormField =
+  | { type: "group"; props: FieldType["group"] }
   | { type: "separator"; props: FieldType["separator"] }
   | { type: "array"; props: FieldType["array"] }
   | { type: "file"; props: FieldType["file"] }
+  | { type: "selectOne"; props: FieldType["selectOne"] }
   | { type: "selectMultiple"; props: FieldType["selectMultiple"] }
   | { type: "text"; props: FieldType["text"] }
   | { type: "textArea"; props: FieldType["textArea"] }
@@ -54,14 +61,11 @@ type UIFormFieldMap = {
   [key in keyof FieldType]: FieldComponentFunction<key>;
 };
 
-function Separator(): VNode {
-  return create("div", {});
-}
-
 /**
  * Maps input type with component implementation
  */
 const UIFormConfiguration: UIFormFieldMap = {
+  group: Group,
   separator: Separator,
   array: InputArray,
   text: InputText,
@@ -70,6 +74,7 @@ const UIFormConfiguration: UIFormFieldMap = {
   date: InputDate,
   choiceStacked: InputChoiceStacked,
   integer: InputInteger,
+  selectOne: InputSelectOne,
   selectMultiple: InputSelectMultiple,
 };
 

-- 
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]