summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2021-08-07 21:59:57 -0300
committerSebastian <sebasjm@gmail.com>2021-08-07 21:59:57 -0300
commita3fd3e81dc32df7eedff40e1dcb28fa999898b56 (patch)
tree859c6c657c7138106f69ec36c1d5a25690dbe65a /packages
parent6f892448822638bcd5bea33083d311e83352b552 (diff)
downloadmerchant-backoffice-a3fd3e81dc32df7eedff40e1dcb28fa999898b56.tar.gz
merchant-backoffice-a3fd3e81dc32df7eedff40e1dcb28fa999898b56.tar.bz2
merchant-backoffice-a3fd3e81dc32df7eedff40e1dcb28fa999898b56.zip
add creditor name
Diffstat (limited to 'packages')
-rw-r--r--packages/frontend/src/components/instance/DefaultInstanceFormFields.tsx11
-rw-r--r--packages/frontend/src/components/modal/index.tsx41
-rw-r--r--packages/frontend/src/paths/admin/create/CreatePage.tsx37
-rw-r--r--packages/frontend/src/paths/admin/list/TableActive.tsx19
-rw-r--r--packages/frontend/src/paths/admin/list/TableDeleted.tsx125
-rw-r--r--packages/frontend/src/paths/admin/list/View.tsx45
-rw-r--r--packages/frontend/src/paths/admin/list/index.tsx8
-rw-r--r--packages/frontend/src/paths/instance/update/UpdatePage.tsx37
-rw-r--r--packages/frontend/src/scss/main.scss11
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;
+}