gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] branch master updated: add creditor name


From: gnunet
Subject: [taler-merchant-backoffice] branch master updated: add creditor name
Date: Sun, 08 Aug 2021 03:00:04 +0200

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

sebasjm pushed a commit to branch master
in repository merchant-backoffice.

The following commit(s) were added to refs/heads/master by this push:
     new a3fd3e8  add creditor name
a3fd3e8 is described below

commit a3fd3e81dc32df7eedff40e1dcb28fa999898b56
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Sat Aug 7 21:59:57 2021 -0300

    add creditor name
---
 .../instance/DefaultInstanceFormFields.tsx         |  11 +-
 packages/frontend/src/components/modal/index.tsx   |  41 +++----
 .../frontend/src/paths/admin/create/CreatePage.tsx |  37 ++++--
 .../frontend/src/paths/admin/list/TableActive.tsx  |  19 +++-
 .../frontend/src/paths/admin/list/TableDeleted.tsx | 125 ---------------------
 packages/frontend/src/paths/admin/list/View.tsx    |  45 ++++++--
 packages/frontend/src/paths/admin/list/index.tsx   |   8 +-
 .../src/paths/instance/update/UpdatePage.tsx       |  37 +++++-
 packages/frontend/src/scss/main.scss               |  11 +-
 9 files changed, 155 insertions(+), 179 deletions(-)

diff --git 
a/packages/frontend/src/components/instance/DefaultInstanceFormFields.tsx 
b/packages/frontend/src/components/instance/DefaultInstanceFormFields.tsx
index 7f68a73..873ee80 100644
--- a/packages/frontend/src/components/instance/DefaultInstanceFormFields.tsx
+++ b/packages/frontend/src/components/instance/DefaultInstanceFormFields.tsx
@@ -37,7 +37,7 @@ export function DefaultInstanceFormFields({ readonlyId, 
showId }: { readonlyId?:
   return <Fragment>
     {showId && <InputWithAddon<Entity> name="id"
       addonBefore={`${backend.url}/instances/`} readonly={readonlyId}
-      label={i18n`Identifier`} 
+      label={i18n`Identifier`}
       tooltip={i18n`Name of the instance in URLs. The 'default' instance is 
special in that it is used to administer other instances.`} />
     }
 
@@ -45,8 +45,13 @@ export function DefaultInstanceFormFields({ readonlyId, 
showId }: { readonlyId?:
       label={i18n`Business name`}
       tooltip={i18n`Legal name of the business represented by this instance.`} 
/>
 
-    <InputPayto<Entity> name="payto_uris"
-      label={i18n`Bank account URI`} 
help="x-taler-bank/bank.taler:5882/blogger" 
+    <Input<Entity> name="creditor_name"
+      label={i18n`Creditor Name`}
+      tooltip={i18n`name of who receive the money`}
+    />
+
+    <InputPayto<Entity> name="payto_uris_base"
+      label={i18n`Bank account URI`} 
help="x-taler-bank/bank.taler:5882/blogger"
       tooltip={i18n`URI specifying bank account for crediting revenue.`} />
 
     <InputCurrency<Entity> name="default_max_deposit_fee"
diff --git a/packages/frontend/src/components/modal/index.tsx 
b/packages/frontend/src/components/modal/index.tsx
index 15157f0..a7edb9e 100644
--- a/packages/frontend/src/components/modal/index.tsx
+++ b/packages/frontend/src/components/modal/index.tsx
@@ -34,17 +34,18 @@ interface Props {
   description?: string;
   onCancel?: () => void;
   onConfirm?: () => void;
+  label?: string;
   children?: ComponentChildren;
   danger?: boolean;
   disabled?: boolean;
 }
 
-export function ConfirmModal({ active, description, onCancel, onConfirm, 
children, danger, disabled }: Props): VNode {
+export function ConfirmModal({ active, description, onCancel, onConfirm, 
children, danger, disabled, label = 'Confirm' }: Props): VNode {
   return <div class={active ? "modal is-active" : "modal"}>
     <div class="modal-background " onClick={onCancel} />
-    <div class="modal-card">
+    <div class="modal-card" style={{maxWidth: 700}}>
       <header class="modal-card-head">
-        {!description ? null : <p class="modal-card-title">{description}</p>}
+        {!description ? null : <p 
class="modal-card-title"><b>{description}</b></p>}
         <button class="delete " aria-label="close" onClick={onCancel} />
       </header>
       <section class="modal-card-body">
@@ -53,7 +54,7 @@ export function ConfirmModal({ active, description, onCancel, 
onConfirm, childre
       <footer class="modal-card-foot">
         <div class="buttons is-right" style={{ width: '100%' }}>
           <button class="button " onClick={onCancel} 
><Translate>Cancel</Translate></button>
-          <button class={danger ? "button is-danger " : "button is-info "} 
disabled={disabled} onClick={onConfirm} ><Translate>Confirm</Translate></button>
+          <button class={danger ? "button is-danger " : "button is-info "} 
disabled={disabled} onClick={onConfirm} ><Translate>{label}</Translate></button>
         </div>
       </footer>
     </div>
@@ -82,16 +83,16 @@ export function ContinueModal({ active, description, 
onCancel, onConfirm, childr
   </div>
 }
 
-export function SimpleModal({onCancel, children}: any):VNode {
+export function SimpleModal({ onCancel, children }: any): VNode {
   return <div class="modal is-active">
-  <div class="modal-background " onClick={onCancel} />
-  <div class="modal-card">
-    <section class="modal-card-body is-main-section">
-      {children}
-    </section>
+    <div class="modal-background " onClick={onCancel} />
+    <div class="modal-card">
+      <section class="modal-card-body is-main-section">
+        {children}
+      </section>
+    </div>
+    <button class="modal-close is-large " aria-label="close" 
onClick={onCancel} />
   </div>
-  <button class="modal-close is-large " aria-label="close" onClick={onCancel} 
/>
-</div>
 }
 
 export function ClearConfirmModal({ description, onCancel, onClear, onConfirm, 
children }: Props & { onClear?: () => void }): VNode {
@@ -124,18 +125,18 @@ interface DeleteModalProps {
 }
 
 export function DeleteModal({ element, onCancel, onConfirm }: 
DeleteModalProps): VNode {
-  return <ConfirmModal description="delete_instance" danger active 
onCancel={onCancel} onConfirm={() => onConfirm(element.id)}>
-    <p>This will deactivate the instance "{element.name}" with id 
<b>{element.id}</b></p>
-    <p>The merchant will not be able to create order or make refunds 
anymore.</p>
-    <p>Please confirm this action</p>
+  return <ConfirmModal label={`Delete instance`} description={`Delete the 
instance "${element.name}"`} danger active onCancel={onCancel} onConfirm={() => 
onConfirm(element.id)}>
+    <p>If you delete the instance named <b>"{element.name}"</b> (ID: 
<b>{element.id}</b>), the merchant will no longer be able to process orders or 
refunds</p>
+    <p>This action deletes the instance private key, but preserves all 
transaction data. You can still access that data after deleting the 
instance.</p>
+    <p class="warning">Deleting an instance <b>cannot be undone</b>.</p>
   </ConfirmModal>
 }
 
 export function PurgeModal({ element, onCancel, onConfirm }: 
DeleteModalProps): VNode {
-  return <ConfirmModal description="delete_instance" danger active 
onCancel={onCancel} onConfirm={() => onConfirm(element.id)}>
-    <p>This will permanently delete instance "{element.name}" with id 
<b>{element.id}</b></p>
-    <p>The information being deleted also include tax records, make sure you 
have backups.</p>
-    <p>Please confirm this action</p>
+  return <ConfirmModal label={`Purge the instance`} description={`Purge the 
instance "${element.name}"`} danger active onCancel={onCancel} onConfirm={() => 
onConfirm(element.id)}>
+    <p>If you purge the instance named <b>"{element.name}"</b> (ID: 
<b>{element.id}</b>), you will also delete all it's transaction data.</p>
+    <p>The instance will disappear from your list, and you will no longer be 
able to access it's data.</p>
+    <p class="warning">Purging an instance <b>cannot be undone</b>.</p>
   </ConfirmModal>
 }
 
diff --git a/packages/frontend/src/paths/admin/create/CreatePage.tsx 
b/packages/frontend/src/paths/admin/create/CreatePage.tsx
index b2e6088..76f02e1 100644
--- a/packages/frontend/src/paths/admin/create/CreatePage.tsx
+++ b/packages/frontend/src/paths/admin/create/CreatePage.tsx
@@ -31,7 +31,12 @@ import { DefaultInstanceFormFields } from 
"../../../components/instance/DefaultI
 import { INSTANCE_ID_REGEX, PAYTO_REGEX } from "../../../utils/constants";
 import { Amounts } from "@gnu-taler/taler-util";
 
-export type Entity = MerchantBackend.Instances.InstanceConfigurationMessage & 
{ auth_token?: string }
+export type Entity = MerchantBackend.Instances.InstanceConfigurationMessage & 
{ 
+  payto_uris_base: string[], // field to construct final payto URI
+  creditor_name: string, // name of the receiver for the payto URI
+  auth_token?: string 
+}
+
 
 interface Props {
   onCreate: (d: Entity) => Promise<void>;
@@ -59,12 +64,23 @@ export function CreatePage({ onCreate, onBack, forceId }: 
Props): VNode {
 
   const i18n = useTranslator()
 
+  if (value.payto_uris && value.payto_uris.length > 0) {
+    const payto = new URL(value.payto_uris[0])
+    value.creditor_name = payto.searchParams.get('receiver-name') || undefined
+    value.payto_uris_base = value.payto_uris.map( p => {
+      const payto = new URL(p)
+      payto.searchParams.delete('receiver-name')
+      return payto.toString()
+    })
+  }
+
   const errors: FormErrors<Entity> = {
-    id: !value.id ? i18n`required` : ( !INSTANCE_ID_REGEX.test(value.id) ? 
i18n`is not valid` : undefined),
+    id: !value.id ? i18n`required` : (!INSTANCE_ID_REGEX.test(value.id) ? 
i18n`is not valid` : undefined),
     name: !value.name ? i18n`required` : undefined,
-    payto_uris:
-      !value.payto_uris || !value.payto_uris.length ? i18n`required` : (
-        undefinedIfEmpty(value.payto_uris.map(p => {
+    creditor_name: !value.creditor_name ? i18n`required` : undefined,
+    payto_uris_base:
+      !value.payto_uris_base || !value.payto_uris_base.length ? i18n`required` 
: (
+        undefinedIfEmpty(value.payto_uris_base.map(p => {
           return !PAYTO_REGEX.test(p) ? i18n`is not valid` : undefined
         }))
       ),
@@ -107,9 +123,16 @@ export function CreatePage({ onCreate, onBack, forceId }: 
Props): VNode {
     const newToken = value.auth_token;
     value.auth_token = undefined;
     value.auth = newToken === null || newToken === undefined ? { method: 
"external" } : { method: "token", token: `secret-token:${newToken}` };
-    if (!value.address) value.address = {} 
-    if (!value.jurisdiction) value.jurisdiction = {} 
+    if (!value.address) value.address = {}
+    if (!value.jurisdiction) value.jurisdiction = {}
     // remove above use conversion
+    const receiverName = value.creditor_name!
+    value.payto_uris = value.payto_uris_base?.map(p => {
+      const payto = new URL(p)
+      payto.searchParams.set('receiver-name', receiverName)
+      return payto.toString()
+    }) || []
+    value.payto_uris_base = undefined
     // schema.validateSync(value, { abortEarly: false })
     return onCreate(value as Entity);
   }
diff --git a/packages/frontend/src/paths/admin/list/TableActive.tsx 
b/packages/frontend/src/paths/admin/list/TableActive.tsx
index d4e586b..9286589 100644
--- a/packages/frontend/src/paths/admin/list/TableActive.tsx
+++ b/packages/frontend/src/paths/admin/list/TableActive.tsx
@@ -28,12 +28,13 @@ interface Props {
   instances: MerchantBackend.Instances.Instance[];
   onUpdate: (id: string) => void;
   onDelete: (id: MerchantBackend.Instances.Instance) => void;
+  onPurge: (id: MerchantBackend.Instances.Instance) => void;
   onCreate: () => void;
   selected?: boolean;
   setInstanceName: (s: string) => void;
 }
 
-export function CardTable({ instances, onCreate, onUpdate, setInstanceName, 
onDelete, selected }: Props): VNode {
+export function CardTable({ instances, onCreate, onUpdate, onPurge, 
setInstanceName, onDelete, selected }: Props): VNode {
   const [actionQueue, actionQueueHandler] = useState<Actions[]>([]);
   const [rowSelection, rowSelectionHandler] = useState<string[]>([])
 
@@ -77,7 +78,7 @@ export function CardTable({ instances, onCreate, onUpdate, 
setInstanceName, onDe
       <div class="b-table has-pagination">
         <div class="table-wrapper has-mobile-cards">
           {instances.length > 0 ?
-            <Table instances={instances} onUpdate={onUpdate} 
setInstanceName={setInstanceName} onDelete={onDelete} 
rowSelection={rowSelection} rowSelectionHandler={rowSelectionHandler} /> :
+            <Table instances={instances} onPurge={onPurge} onUpdate={onUpdate} 
setInstanceName={setInstanceName} onDelete={onDelete} 
rowSelection={rowSelection} rowSelectionHandler={rowSelectionHandler} /> :
             <EmptyTable />
           }
         </div>
@@ -90,6 +91,7 @@ interface TableProps {
   instances: MerchantBackend.Instances.Instance[];
   onUpdate: (id: string) => void;
   onDelete: (id: MerchantBackend.Instances.Instance) => void;
+  onPurge: (id: MerchantBackend.Instances.Instance) => void;
   rowSelectionHandler: StateUpdater<string[]>;
   setInstanceName: (s:string) => void;
 }
@@ -98,7 +100,7 @@ function toggleSelected<T>(id: T): (prev: T[]) => T[] {
   return (prev: T[]): T[] => prev.indexOf(id) == -1 ? [...prev, id] : 
prev.filter(e => e != id)
 }
 
-function Table({ rowSelection, rowSelectionHandler, setInstanceName, 
instances, onUpdate, onDelete }: TableProps): VNode {
+function Table({ rowSelection, rowSelectionHandler, setInstanceName, 
instances, onUpdate, onDelete, onPurge }: TableProps): VNode {
   return (
     <div class="table-container">
       <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
@@ -133,9 +135,16 @@ function Table({ rowSelection, rowSelectionHandler, 
setInstanceName, instances,
                   <button class="button is-small is-success jb-modal" 
type="button" onClick={(): void => onUpdate(i.id)}>
                     <Translate>Edit</Translate>
                   </button>
-                  <button class="button is-small is-danger jb-modal" 
type="button" onClick={(): void => onDelete(i)}>
-                    <Translate>Disable</Translate>
+                  {!i.deleted &&
+                  <button class="button is-small is-danger jb-modal 
is-outlined" type="button" onClick={(): void => onDelete(i)}>
+                    <Translate>Delete</Translate>
                   </button>
+                  }
+                  {i.deleted &&
+                  <button class="button is-small is-danger jb-modal" 
type="button" onClick={(): void => onPurge(i)}>
+                    <Translate>Purge</Translate>
+                  </button>
+                  }
                 </div>
               </td>
             </tr>
diff --git a/packages/frontend/src/paths/admin/list/TableDeleted.tsx 
b/packages/frontend/src/paths/admin/list/TableDeleted.tsx
deleted file mode 100644
index 1726877..0000000
--- a/packages/frontend/src/paths/admin/list/TableDeleted.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- 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/>
- */
-
-/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { h, VNode } from "preact";
-import { StateUpdater, useEffect, useState } from "preact/hooks";
-import { MerchantBackend } from "../../../declaration";
-import { Translate, useTranslator } from "../../../i18n";
-
-interface Props {
-  instances: MerchantBackend.Instances.Instance[];
-  onPurge: (id: MerchantBackend.Instances.Instance) => void;
-  setInstanceName: (s: string) => void;
-}
-
-export function CardTable({ instances, onPurge, setInstanceName }: Props): 
VNode {
-
-  const i18n = useTranslator()
-
-  return <div class="card has-table">
-    <header class="card-header">
-      <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-desktop-mac" /></span><Translate>Disabled instances</Translate></p>
-
-    </header>
-    <div class="card-content">
-      <div class="b-table has-pagination">
-        <div class="table-wrapper has-mobile-cards">
-          {instances.length > 0 ?
-            <Table instances={instances} onPurge={onPurge} 
setInstanceName={setInstanceName} /> :
-            <EmptyTable />
-          }
-        </div>
-      </div>
-    </div>
-  </div>
-}
-interface TableProps {
-  instances: MerchantBackend.Instances.Instance[];
-  onPurge: (id: MerchantBackend.Instances.Instance) => void;
-  setInstanceName: (s: string) => void;
-}
-
-function toggleSelected<T>(id: T): (prev: T[]) => T[] {
-  return (prev: T[]): T[] => prev.indexOf(id) == -1 ? [...prev, id] : 
prev.filter(e => e != id)
-}
-
-function Table({ instances, onPurge, setInstanceName }: TableProps): VNode {
-  return (
-    <div class="table-container">
-      <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
-        <thead>
-          <tr>
-            <th class="is-checkbox-cell" />
-            <th><Translate>ID</Translate></th>
-            <th><Translate>Name</Translate></th>
-            <th />
-          </tr>
-        </thead>
-        <tbody>
-          {instances.map(i => {
-            return <tr key={i.id}>
-              <td class="is-checkbox-cell" />
-              <td><a href={`#/orders?instance=${i.id}`} onClick={(e) => {
-                setInstanceName(i.id);
-              }}>{i.id}</a></td>
-              <td >{i.name}</td>
-              <td class="is-actions-cell right-sticky">
-                <div class="buttons is-right">
-                  <button class="button is-small is-danger jb-modal" 
type="button" onClick={(): void => onPurge(i)}>
-                    <Translate>Delete</Translate>
-                  </button>
-                </div>
-              </td>
-            </tr>
-          })}
-
-        </tbody>
-      </table>
-    </div>
-  )
-}
-
-function EmptyTable(): VNode {
-  return <div class="content has-text-grey has-text-centered">
-    <p>
-      <span class="icon is-large"><i class="mdi mdi-emoticon-sad mdi-48px" 
/></span>
-    </p>
-    <p><Translate>There is no instances yet, add more pressing the + 
sign</Translate></p>
-  </div>
-}
-
-
-interface Actions {
-  element: MerchantBackend.Instances.Instance;
-  type: 'DELETE' | 'UPDATE';
-}
-
-function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
-  return value !== null && value !== undefined;
-}
-
-function buildActions(intances: MerchantBackend.Instances.Instance[], 
selected: string[], action: 'DELETE'): Actions[] {
-  return selected.map(id => intances.find(i => i.id === id))
-    .filter(notEmpty)
-    .map(id => ({ element: id, type: action }))
-}
-
-
diff --git a/packages/frontend/src/paths/admin/list/View.tsx 
b/packages/frontend/src/paths/admin/list/View.tsx
index d7f31ec..8febcff 100644
--- a/packages/frontend/src/paths/admin/list/View.tsx
+++ b/packages/frontend/src/paths/admin/list/View.tsx
@@ -22,7 +22,8 @@
 import { h, VNode } from "preact";
 import { MerchantBackend } from "../../../declaration";
 import { CardTable as CardTableActive } from './TableActive';
-import { CardTable as CardTableDeleted } from './TableDeleted';
+import { useState } from 'preact/hooks';
+import { Translate, useTranslator } from "../../../i18n";
 
 interface Props {
   instances: MerchantBackend.Instances.Instance[];
@@ -35,17 +36,45 @@ interface Props {
 }
 
 export function View({ instances, onCreate, onDelete, onPurge, onUpdate, 
setInstanceName, selected }: Props): VNode {
-  const deletedInstances = instances.filter(i => i.deleted);
+  const [show, setShow] = useState<"enabled" | "disabled" | null>("enabled");
+  const showIsEnabled = show === 'enabled' ? "is-active" : ''
+  const showIsDisabled = show === 'disabled' ? "is-active" : ''
+  const showAll = show === null ? "is-active" : ''
+  const i18n = useTranslator()
 
+  const showingInstances = showIsDisabled ? 
+    instances.filter(i => i.deleted) : (showIsEnabled ?
+      instances.filter(i => !i.deleted) :
+      instances)
+  
   return <div id="app">
 
     <section class="section is-main-section">
-      <CardTableActive instances={instances.filter(i => !i.deleted)} 
onDelete={onDelete} setInstanceName={setInstanceName} onUpdate={onUpdate} 
selected={selected} onCreate={onCreate} />
+      <div class="columns">
+        <div class="column is-two-thirds">
+          <div class="tabs" style={{ overflow: 'inherit' }}>
+            <ul>
+              <li class={showIsEnabled}>
+                <div class="has-tooltip-right" data-tooltip={i18n`only show 
enabled instances`}>
+                  <a onClick={() => 
setShow("enabled")}><Translate>Enable</Translate></a>
+                </div>
+              </li>
+              <li class={showIsDisabled}>
+                <div class="has-tooltip-right" data-tooltip={i18n`only show 
disabled instances`}>
+                  <a onClick={() => 
setShow("disabled")}><Translate>Disable</Translate></a>
+                </div>
+              </li>
+              <li class={showAll}>
+                <div class="has-tooltip-right" data-tooltip={i18n`show all 
instances`}>
+                  <a onClick={() => 
setShow(null)}><Translate>All</Translate></a>
+                </div>
+              </li>
+            </ul>
+          </div>
+        </div>
+      </div>
+      <CardTableActive instances={showingInstances} onDelete={onDelete} 
onPurge={onPurge} setInstanceName={setInstanceName} onUpdate={onUpdate} 
selected={selected} onCreate={onCreate} />
     </section>
 
-    {deletedInstances.length > 0 && <section class="section is-main-section">
-      <CardTableDeleted instances={deletedInstances} onPurge={onPurge} 
setInstanceName={setInstanceName} />
-    </section>}
-
   </div >
-}
\ No newline at end of file
+}
diff --git a/packages/frontend/src/paths/admin/list/index.tsx 
b/packages/frontend/src/paths/admin/list/index.tsx
index 8dd5eef..2dd9c2b 100644
--- a/packages/frontend/src/paths/admin/list/index.tsx
+++ b/packages/frontend/src/paths/admin/list/index.tsx
@@ -73,12 +73,12 @@ export default function Instances({ onUnauthorized, 
onLoadError, onNotFound, onC
           await deleteInstance(deleting.id)
           // pushNotification({ message: 'delete_success', type: 'SUCCESS' })
           setNotif({
-            message: i18n`Instance disable`,
+            message: i18n`Instance "${deleting.name}" (ID: ${deleting.id}) has 
been deleted`,
             type: 'SUCCESS'
           })
         } catch (error) {
           setNotif({
-            message: i18n`Failed to disable instance`,
+            message: i18n`Failed to delete instance`,
             type: "ERROR",
             description: error.message
           })
@@ -94,12 +94,12 @@ export default function Instances({ onUnauthorized, 
onLoadError, onNotFound, onC
         try {
           await purgeInstance(purging.id)
           setNotif({
-            message: i18n`Instance deleted`,
+            message: i18n`Instance "${purging.name}" (ID: ${purging.id}) has 
been disabled`,
             type: 'SUCCESS'
           })
         } catch (error) {
           setNotif({
-            message: i18n`Failed to delete instance`,
+            message: i18n`Failed to purge instance`,
             type: "ERROR",
             description: error.message
           })
diff --git a/packages/frontend/src/paths/instance/update/UpdatePage.tsx 
b/packages/frontend/src/paths/instance/update/UpdatePage.tsx
index 6e7b9eb..4a965b6 100644
--- a/packages/frontend/src/paths/instance/update/UpdatePage.tsx
+++ b/packages/frontend/src/paths/instance/update/UpdatePage.tsx
@@ -34,7 +34,12 @@ import { PAYTO_REGEX } from "../../../utils/constants";
 import { Amounts } from "@gnu-taler/taler-util";
 
 
-type Entity = MerchantBackend.Instances.InstanceReconfigurationMessage & { 
auth_token?: string }
+type Entity = MerchantBackend.Instances.InstanceReconfigurationMessage & { 
+  payto_uris_base: string[], // field to construct final payto URI
+  creditor_name: string, // name of the receiver for the payto URI
+  auth_token?: string 
+}
+
 //MerchantBackend.Instances.InstanceAuthConfigurationMessage
 interface Props {
   onUpdate: (d: Entity) => void;
@@ -51,8 +56,19 @@ function convert(from: 
MerchantBackend.Instances.QueryInstancesResponse): Entity
     default_wire_fee_amortization: 1,
     default_pay_delay: { d_ms: 1000 * 60 * 60 }, //one hour
     default_wire_transfer_delay: { d_ms: 1000 * 60 * 60 * 2 }, //two hours
+    creditor_name: '',
+    payto_uris_base: new Array<string>()
+  }
+  if (payto_uris && payto_uris.length > 0) {
+    const payto = new URL(payto_uris[0])
+    defaults.creditor_name = payto.searchParams.get('receiver-name') || ''
+    defaults.payto_uris_base = payto_uris.map( p => {
+      const payto = new URL(p)
+      payto.searchParams.delete('receiver-name')
+      return payto.toString()
+    })
   }
-  return { ...defaults, ...rest, payto_uris };
+  return { ...defaults, ...rest, payto_uris: [] };
 }
 
 function getTokenValuePart(t?: string): string | undefined {
@@ -87,9 +103,10 @@ export function UpdatePage({ onUpdate, onChangeAuth, 
selected, onBack }: Props):
 
   const errors: FormErrors<Entity> = {
     name: !value.name ? i18n`required` : undefined,
-    payto_uris:
-      !value.payto_uris || !value.payto_uris.length ? i18n`required` : (
-        undefinedIfEmpty(value.payto_uris.map(p => {
+    creditor_name: !value.creditor_name ? i18n`required` : undefined,
+    payto_uris_base:
+      !value.payto_uris_base || !value.payto_uris_base.length ? i18n`required` 
: (
+        undefinedIfEmpty(value.payto_uris_base.map(p => {
           return !PAYTO_REGEX.test(p) ? i18n`is not valid` : undefined
         }))
       ),
@@ -124,9 +141,17 @@ export function UpdatePage({ onUpdate, onChangeAuth, 
selected, onBack }: Props):
         undefined
     }),
   };
-  
+
   const hasErrors = Object.keys(errors).some(k => (errors as any)[k] !== 
undefined)
   const submit = async (): Promise<void> => {
+    const receiverName = value.creditor_name!
+    value.payto_uris = value.payto_uris_base?.map(p => {
+      const payto = new URL(p)
+      payto.searchParams.set('receiver-name', receiverName)
+      return payto.toString()
+    }) || []
+    value.payto_uris_base = undefined
+
     await onUpdate(schema.cast(value));
     await onBack()
     return Promise.resolve()
diff --git a/packages/frontend/src/scss/main.scss 
b/packages/frontend/src/scss/main.scss
index d59a1db..f9ae0ef 100644
--- a/packages/frontend/src/scss/main.scss
+++ b/packages/frontend/src/scss/main.scss
@@ -178,4 +178,13 @@ span[data-tooltip] {
 
 div[data-tooltip]::before {
   position: absolute;
-}
\ No newline at end of file
+}
+
+.modal-card-body > p {
+  padding: 1em;
+}
+
+.modal-card-body > p.warning {
+  background-color: #fffbdd;
+  border: solid 1px #f2e9bf;
+}

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