diff options
Diffstat (limited to 'packages/merchant-backoffice-ui/src/paths/admin')
7 files changed, 384 insertions, 234 deletions
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx index cb62b0224..052d61544 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx @@ -15,31 +15,32 @@ */ /** -* -* @author Sebastian Javier Marchano (sebasjm) -*/ + * + * @author Sebastian Javier Marchano (sebasjm) + */ -import { h, VNode, FunctionalComponent } from 'preact'; +import { h, VNode, FunctionalComponent } from "preact"; import { CreatePage as TestedComponent } from "./CreatePage.js"; - export default { - title: 'Pages/Instance/Create', + title: "Pages/Instance/Create", component: TestedComponent, argTypes: { - onCreate: { action: 'onCreate' }, - goBack: { action: 'goBack' }, - } + onCreate: { action: "onCreate" }, + goBack: { action: "goBack" }, + }, }; -function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { - const r = (args: any) => <Component {...args} /> - r.args = props - return r +function createExample<Props>( + Component: FunctionalComponent<Props>, + props: Partial<Props>, +) { + const r = (args: any) => <Component {...args} />; + r.args = props; + return r; } -export const Example = createExample(TestedComponent, { -}); +export const Example = createExample(TestedComponent, {}); // export const Example = (a: any): VNode => <CreatePage {...a} />; // Example.args = { // isLoading: false diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx index 089d4ea80..6fcabb18b 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx @@ -76,7 +76,7 @@ export function CreatePage({ onCreate, onBack, forceId }: Props): VNode { : undefinedIfEmpty( value.payto_uris.map((p) => { return !PAYTO_REGEX.test(p) ? i18n`is not valid` : undefined; - }) + }), ), default_max_deposit_fee: !value.default_max_deposit_fee ? i18n`required` @@ -115,7 +115,7 @@ export function CreatePage({ onCreate, onBack, forceId }: Props): VNode { }; const hasErrors = Object.keys(errors).some( - (k) => (errors as any)[k] !== undefined + (k) => (errors as any)[k] !== undefined, ); const submit = (): Promise<void> => { diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/InstanceCreatedSuccessfully.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/InstanceCreatedSuccessfully.tsx index fde2410e9..c620c6482 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/create/InstanceCreatedSuccessfully.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/create/InstanceCreatedSuccessfully.tsx @@ -14,52 +14,61 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ /** -* -* @author Sebastian Javier Marchano (sebasjm) -*/ + * + * @author Sebastian Javier Marchano (sebasjm) + */ import { h, VNode } from "preact"; import { CreatedSuccessfully } from "../../../components/notifications/CreatedSuccessfully.js"; import { Entity } from "./index.js"; -export function InstanceCreatedSuccessfully({ entity, onConfirm }: { entity: Entity; onConfirm: () => void; }): VNode { - return <CreatedSuccessfully onConfirm={onConfirm}> - <div class="field is-horizontal"> - <div class="field-label is-normal"> - <label class="label">ID</label> - </div> - <div class="field-body is-flex-grow-3"> - <div class="field"> - <p class="control"> - <input class="input" readonly value={entity.id} /> - </p> +export function InstanceCreatedSuccessfully({ + entity, + onConfirm, +}: { + entity: Entity; + onConfirm: () => void; +}): VNode { + return ( + <CreatedSuccessfully onConfirm={onConfirm}> + <div class="field is-horizontal"> + <div class="field-label is-normal"> + <label class="label">ID</label> </div> - </div> - </div> - <div class="field is-horizontal"> - <div class="field-label is-normal"> - <label class="label">Business Name</label> - </div> - <div class="field-body is-flex-grow-3"> - <div class="field"> - <p class="control"> - <input class="input" readonly value={entity.name} /> - </p> + <div class="field-body is-flex-grow-3"> + <div class="field"> + <p class="control"> + <input class="input" readonly value={entity.id} /> + </p> + </div> </div> </div> - </div> - <div class="field is-horizontal"> - <div class="field-label is-normal"> - <label class="label">Access token</label> + <div class="field is-horizontal"> + <div class="field-label is-normal"> + <label class="label">Business Name</label> + </div> + <div class="field-body is-flex-grow-3"> + <div class="field"> + <p class="control"> + <input class="input" readonly value={entity.name} /> + </p> + </div> + </div> </div> - <div class="field-body is-flex-grow-3"> - <div class="field"> - <p class="control"> - {entity.auth.method === 'external' && 'external'} - {entity.auth.method === 'token' && - <input class="input" readonly value={entity.auth.token} />} - </p> + <div class="field is-horizontal"> + <div class="field-label is-normal"> + <label class="label">Access token</label> + </div> + <div class="field-body is-flex-grow-3"> + <div class="field"> + <p class="control"> + {entity.auth.method === "external" && "external"} + {entity.auth.method === "token" && ( + <input class="input" readonly value={entity.auth.token} /> + )} + </p> + </div> </div> </div> - </div> - </CreatedSuccessfully>; + </CreatedSuccessfully> + ); } diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx index 8e83b75ff..ed2f3f068 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx @@ -54,7 +54,7 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode { onBack={onBack} forceId={forceId} onCreate={( - d: MerchantBackend.Instances.InstanceConfigurationMessage + d: MerchantBackend.Instances.InstanceConfigurationMessage, ) => { return createInstance(d) .then(() => { diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx b/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx index 8f2829112..546f34f3a 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx @@ -15,9 +15,9 @@ */ /** -* -* @author Sebastian Javier Marchano (sebasjm) -*/ + * + * @author Sebastian Javier Marchano (sebasjm) + */ import { h, VNode } from "preact"; import { StateUpdater, useEffect, useState } from "preact/hooks"; @@ -34,57 +34,96 @@ interface Props { setInstanceName: (s: string) => void; } -export function CardTable({ instances, onCreate, onUpdate, onPurge, 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[]>([]) + const [rowSelection, rowSelectionHandler] = useState<string[]>([]); useEffect(() => { - if (actionQueue.length > 0 && !selected && actionQueue[0].type == 'DELETE') { - onDelete(actionQueue[0].element) - actionQueueHandler(actionQueue.slice(1)) + if ( + actionQueue.length > 0 && + !selected && + actionQueue[0].type == "DELETE" + ) { + onDelete(actionQueue[0].element); + actionQueueHandler(actionQueue.slice(1)); } - }, [actionQueue, selected, onDelete]) + }, [actionQueue, selected, onDelete]); useEffect(() => { - if (actionQueue.length > 0 && !selected && actionQueue[0].type == 'UPDATE') { - onUpdate(actionQueue[0].element.id) - actionQueueHandler(actionQueue.slice(1)) + if ( + actionQueue.length > 0 && + !selected && + actionQueue[0].type == "UPDATE" + ) { + onUpdate(actionQueue[0].element.id); + actionQueueHandler(actionQueue.slice(1)); } - }, [actionQueue, selected, onUpdate]) - - const i18n = useTranslator() + }, [actionQueue, selected, onUpdate]); - 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>Instances</Translate></p> + const i18n = useTranslator(); - <div class="card-header-icon" aria-label="more options"> + 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>Instances</Translate> + </p> - <button class={rowSelection.length > 0 ? "button is-danger" : "is-hidden"} - type="button" onClick={(): void => actionQueueHandler(buildActions(instances, rowSelection, 'DELETE'))} > - <Translate>Delete</Translate> - </button> - </div> - <div class="card-header-icon" aria-label="more options"> - <span class="has-tooltip-left" data-tooltip={i18n`add new instance`}> - <button class="button is-info" type="button" onClick={onCreate}> - <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" /></span> + <div class="card-header-icon" aria-label="more options"> + <button + class={rowSelection.length > 0 ? "button is-danger" : "is-hidden"} + type="button" + onClick={(): void => + actionQueueHandler( + buildActions(instances, rowSelection, "DELETE"), + ) + } + > + <Translate>Delete</Translate> </button> - </span> - </div> - - </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} onUpdate={onUpdate} setInstanceName={setInstanceName} onDelete={onDelete} rowSelection={rowSelection} rowSelectionHandler={rowSelectionHandler} /> : - <EmptyTable /> - } + </div> + <div class="card-header-icon" aria-label="more options"> + <span class="has-tooltip-left" data-tooltip={i18n`add new instance`}> + <button class="button is-info" type="button" onClick={onCreate}> + <span class="icon is-small"> + <i class="mdi mdi-plus mdi-36px" /> + </span> + </button> + </span> + </div> + </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} + onUpdate={onUpdate} + setInstanceName={setInstanceName} + onDelete={onDelete} + rowSelection={rowSelection} + rowSelectionHandler={rowSelectionHandler} + /> + ) : ( + <EmptyTable /> + )} + </div> </div> </div> </div> - </div> + ); } interface TableProps { rowSelection: string[]; @@ -93,14 +132,23 @@ interface TableProps { onDelete: (id: MerchantBackend.Instances.Instance) => void; onPurge: (id: MerchantBackend.Instances.Instance) => void; rowSelectionHandler: StateUpdater<string[]>; - setInstanceName: (s:string) => 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) + return (prev: T[]): T[] => + prev.indexOf(id) == -1 ? [...prev, id] : prev.filter((e) => e != id); } -function Table({ rowSelection, rowSelectionHandler, setInstanceName, instances, onUpdate, onDelete, onPurge }: 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"> @@ -108,75 +156,127 @@ function Table({ rowSelection, rowSelectionHandler, setInstanceName, instances, <tr> <th class="is-checkbox-cell"> <label class="b-checkbox checkbox"> - <input type="checkbox" checked={rowSelection.length === instances.length} onClick={(): void => rowSelectionHandler(rowSelection.length === instances.length ? [] : instances.map(i => i.id))} /> + <input + type="checkbox" + checked={rowSelection.length === instances.length} + onClick={(): void => + rowSelectionHandler( + rowSelection.length === instances.length + ? [] + : instances.map((i) => i.id), + ) + } + /> <span class="check" /> </label> </th> - <th><Translate>ID</Translate></th> - <th><Translate>Name</Translate></th> + <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"> - <label class="b-checkbox checkbox"> - <input type="checkbox" checked={rowSelection.indexOf(i.id) != -1} onClick={(): void => rowSelectionHandler(toggleSelected(i.id))} /> - <span class="check" /> - </label> - </td> - <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-success jb-modal" type="button" onClick={(): void => onUpdate(i.id)}> - <Translate>Edit</Translate> - </button> - {!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> + {instances.map((i) => { + return ( + <tr key={i.id}> + <td class="is-checkbox-cell"> + <label class="b-checkbox checkbox"> + <input + type="checkbox" + checked={rowSelection.indexOf(i.id) != -1} + onClick={(): void => + rowSelectionHandler(toggleSelected(i.id)) + } + /> + <span class="check" /> + </label> + </td> + <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-success jb-modal" + type="button" + onClick={(): void => onUpdate(i.id)} + > + <Translate>Edit</Translate> + </button> + {!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> + ); })} - </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> + 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'; + type: "DELETE" | "UPDATE"; } function notEmpty<TValue>(value: TValue | null | undefined): value is TValue { return value !== null && value !== undefined; } -function buildActions(instances: MerchantBackend.Instances.Instance[], selected: string[], action: 'DELETE'): Actions[] { - return selected.map(id => instances.find(i => i.id === id)) +function buildActions( + instances: MerchantBackend.Instances.Instance[], + selected: string[], + action: "DELETE", +): Actions[] { + return selected + .map((id) => instances.find((i) => i.id === id)) .filter(notEmpty) - .map(id => ({ element: id, type: action })) + .map((id) => ({ element: id, type: action })); } diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/View.stories.tsx b/packages/merchant-backoffice-ui/src/paths/admin/list/View.stories.tsx index 87d68232a..e0f5d5430 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/list/View.stories.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/list/View.stories.tsx @@ -15,68 +15,76 @@ */ /** -* -* @author Sebastian Javier Marchano (sebasjm) -*/ + * + * @author Sebastian Javier Marchano (sebasjm) + */ -import { h } from 'preact'; +import { h } from "preact"; import { View } from "./View.js"; - export default { - title: 'Pages/Instance/List', + title: "Pages/Instance/List", component: View, argTypes: { - onSelect: { action: 'onSelect' }, + onSelect: { action: "onSelect" }, }, }; export const Empty = (a: any) => <View {...a} />; Empty.args = { - instances: [] -} + instances: [], +}; export const WithDefaultInstance = (a: any) => <View {...a} />; WithDefaultInstance.args = { - instances: [{ - id: 'default', - name: 'the default instance', - merchant_pub: 'abcdef', - payment_targets: [] - }] -} + instances: [ + { + id: "default", + name: "the default instance", + merchant_pub: "abcdef", + payment_targets: [], + }, + ], +}; export const WithFiveInstance = (a: any) => <View {...a} />; WithFiveInstance.args = { - instances: [{ - id: 'first', - name: 'the first instance', - merchant_pub: 'abcdefgh', - payment_targets: ['asd'] - }, { - id: 'second', - name: 'the second instance', - merchant_pub: 'zxczxcz', - payment_targets: ['asd'] - }, { - id: 'third', - name: 'the third instance', - merchant_pub: 'QWEQWEWQE', - payment_targets: ['asd'] - }, { - id: 'other', - name: 'the other instance', - merchant_pub: 'FHJHGJGHJ', - payment_targets: ['asd'] - }, { - id: 'another', - name: 'the another instance', - merchant_pub: 'abcd3423423efgh', - payment_targets: ['asd'] - }, { - id: 'last', - name: 'last instance', - merchant_pub: 'zxcvvbnm', - payment_targets: ['pay-to', 'asd'] - }] -} + instances: [ + { + id: "first", + name: "the first instance", + merchant_pub: "abcdefgh", + payment_targets: ["asd"], + }, + { + id: "second", + name: "the second instance", + merchant_pub: "zxczxcz", + payment_targets: ["asd"], + }, + { + id: "third", + name: "the third instance", + merchant_pub: "QWEQWEWQE", + payment_targets: ["asd"], + }, + { + id: "other", + name: "the other instance", + merchant_pub: "FHJHGJGHJ", + payment_targets: ["asd"], + }, + { + id: "another", + name: "the another instance", + merchant_pub: "abcd3423423efgh", + payment_targets: ["asd"], + }, + { + id: "last", + name: "last instance", + merchant_pub: "zxcvvbnm", + payment_targets: ["pay-to", "asd"], + }, + ], +}; diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/View.tsx b/packages/merchant-backoffice-ui/src/paths/admin/list/View.tsx index 2af9dea71..5180c671c 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/list/View.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/list/View.tsx @@ -15,14 +15,14 @@ */ /** -* -* @author Sebastian Javier Marchano (sebasjm) -*/ + * + * @author Sebastian Javier Marchano (sebasjm) + */ import { h, VNode } from "preact"; import { MerchantBackend } from "../../../declaration.js"; import { CardTable as CardTableActive } from "./TableActive.js"; -import { useState } from 'preact/hooks'; +import { useState } from "preact/hooks"; import { Translate, useTranslator } from "../../../i18n/index.js"; interface Props { @@ -35,46 +35,78 @@ interface Props { setInstanceName: (s: string) => void; } -export function View({ instances, onCreate, onDelete, onPurge, onUpdate, setInstanceName, selected }: Props): VNode { +export function View({ + instances, + onCreate, + onDelete, + onPurge, + onUpdate, + setInstanceName, + selected, +}: Props): VNode { const [show, setShow] = useState<"active" | "deleted" | null>("active"); - const showIsActive = show === 'active' ? "is-active" : '' - const showIsDeleted = show === 'deleted' ? "is-active" : '' - const showAll = show === null ? "is-active" : '' - const i18n = useTranslator() + const showIsActive = show === "active" ? "is-active" : ""; + const showIsDeleted = show === "deleted" ? "is-active" : ""; + const showAll = show === null ? "is-active" : ""; + const i18n = useTranslator(); - const showingInstances = showIsDeleted ? - instances.filter(i => i.deleted) : (showIsActive ? - instances.filter(i => !i.deleted) : - instances) - - return <div id="app"> + const showingInstances = showIsDeleted + ? instances.filter((i) => i.deleted) + : showIsActive + ? instances.filter((i) => !i.deleted) + : instances; - <section class="section is-main-section"> - <div class="columns"> - <div class="column is-two-thirds"> - <div class="tabs" style={{ overflow: 'inherit' }}> - <ul> - <li class={showIsActive}> - <div class="has-tooltip-right" data-tooltip={i18n`Only show active instances`}> - <a onClick={() => setShow("active")}><Translate>Active</Translate></a> - </div> - </li> - <li class={showIsDeleted}> - <div class="has-tooltip-right" data-tooltip={i18n`Only show deleted instances`}> - <a onClick={() => setShow("deleted")}><Translate>Deleted</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> + return ( + <div id="app"> + <section class="section is-main-section"> + <div class="columns"> + <div class="column is-two-thirds"> + <div class="tabs" style={{ overflow: "inherit" }}> + <ul> + <li class={showIsActive}> + <div + class="has-tooltip-right" + data-tooltip={i18n`Only show active instances`} + > + <a onClick={() => setShow("active")}> + <Translate>Active</Translate> + </a> + </div> + </li> + <li class={showIsDeleted}> + <div + class="has-tooltip-right" + data-tooltip={i18n`Only show deleted instances`} + > + <a onClick={() => setShow("deleted")}> + <Translate>Deleted</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> - </div> - <CardTableActive instances={showingInstances} onDelete={onDelete} onPurge={onPurge} setInstanceName={setInstanceName} onUpdate={onUpdate} selected={selected} onCreate={onCreate} /> - </section> - - </div > + <CardTableActive + instances={showingInstances} + onDelete={onDelete} + onPurge={onPurge} + setInstanceName={setInstanceName} + onUpdate={onUpdate} + selected={selected} + onCreate={onCreate} + /> + </section> + </div> + ); } |