From 7a201c3b885c5d23bf0fd0f3da32379a49b30c38 Mon Sep 17 00:00:00 2001 From: Nic Eigel Date: Sun, 14 Jan 2024 15:18:12 +0100 Subject: adding auditor-backoffice-ui --- .../instance/templates/create/Create.stories.tsx | 28 +++ .../paths/instance/templates/create/CreatePage.tsx | 259 +++++++++++++++++++++ .../src/paths/instance/templates/create/index.tsx | 61 +++++ .../paths/instance/templates/list/List.stories.tsx | 28 +++ .../src/paths/instance/templates/list/ListPage.tsx | 68 ++++++ .../src/paths/instance/templates/list/Table.tsx | 235 +++++++++++++++++++ .../src/paths/instance/templates/list/index.tsx | 152 ++++++++++++ .../src/paths/instance/templates/qr/Qr.stories.tsx | 27 +++ .../src/paths/instance/templates/qr/QrPage.tsx | 172 ++++++++++++++ .../src/paths/instance/templates/qr/index.tsx | 80 +++++++ .../instance/templates/update/Update.stories.tsx | 32 +++ .../paths/instance/templates/update/UpdatePage.tsx | 254 ++++++++++++++++++++ .../src/paths/instance/templates/update/index.tsx | 99 ++++++++ .../paths/instance/templates/use/Use.stories.tsx | 27 +++ .../src/paths/instance/templates/use/UsePage.tsx | 143 ++++++++++++ .../src/paths/instance/templates/use/index.tsx | 101 ++++++++ 16 files changed, 1766 insertions(+) create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/create/Create.stories.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/create/index.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/list/List.stories.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/list/ListPage.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/list/Table.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/list/index.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/qr/Qr.stories.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/qr/index.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/update/Update.stories.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/update/index.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/use/Use.stories.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx create mode 100644 packages/auditor-backoffice-ui/src/paths/instance/templates/use/index.tsx (limited to 'packages/auditor-backoffice-ui/src/paths/instance/templates') diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/create/Create.stories.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/create/Create.stories.tsx new file mode 100644 index 000000000..c9d17ea3b --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/create/Create.stories.tsx @@ -0,0 +1,28 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { h, VNode, FunctionalComponent } from "preact"; +import { CreatePage as TestedComponent } from "./CreatePage.js"; + +export default { + title: "Pages/Templates/Create", + component: TestedComponent, +}; diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx new file mode 100644 index 000000000..947f3572c --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx @@ -0,0 +1,259 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { + Amounts, + MerchantTemplateContractDetails, +} from "@gnu-taler/taler-util"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Fragment, VNode, h } from "preact"; +import { useState } from "preact/hooks"; +import { AsyncButton } from "../../../../components/exception/AsyncButton.js"; +import { + FormErrors, + FormProvider, +} from "../../../../components/form/FormProvider.js"; +import { Input } from "../../../../components/form/Input.js"; +import { InputCurrency } from "../../../../components/form/InputCurrency.js"; +import { InputDuration } from "../../../../components/form/InputDuration.js"; +import { InputNumber } from "../../../../components/form/InputNumber.js"; +import { InputSearchOnList } from "../../../../components/form/InputSearchOnList.js"; +import { InputWithAddon } from "../../../../components/form/InputWithAddon.js"; +import { useBackendContext } from "../../../../context/backend.js"; +import { MerchantBackend } from "../../../../declaration.js"; +import { useInstanceOtpDevices } from "../../../../hooks/otp.js"; +import { undefinedIfEmpty } from "../../../../utils/table.js"; +import { InputTab } from "../../../../components/form/InputTab.js"; + +enum Steps { + BOTH_FIXED, + FIXED_PRICE, + FIXED_SUMMARY, + NON_FIXED, +} + +type Entity = MerchantBackend.Template.TemplateAddDetails & { type: Steps }; + +interface Props { + onCreate: (d: Entity) => Promise; + onBack?: () => void; +} + +export function CreatePage({ onCreate, onBack }: Props): VNode { + const { i18n } = useTranslationContext(); + const { url: backendURL } = useBackendContext() + const devices = useInstanceOtpDevices() + + const [state, setState] = useState>({ + template_contract: { + minimum_age: 0, + pay_duration: { + d_us: 1000 * 1000 * 60 * 30, //30 min + }, + }, + type: Steps.NON_FIXED, + }); + + const parsedPrice = !state.template_contract?.amount + ? undefined + : Amounts.parse(state.template_contract?.amount); + + const errors: FormErrors = { + template_id: !state.template_id + ? i18n.str`should not be empty` + : !/[a-zA-Z0-9]*/.test(state.template_id) + ? i18n.str`no valid. only characters and numbers` + : undefined, + template_description: !state.template_description + ? i18n.str`should not be empty` + : undefined, + template_contract: !state.template_contract + ? undefined + : undefinedIfEmpty({ + amount: !(state.type === Steps.FIXED_PRICE || state.type === Steps.BOTH_FIXED) + ? undefined + : !state.template_contract?.amount + ? i18n.str`required` + : !parsedPrice + ? i18n.str`not valid` + : Amounts.isZero(parsedPrice) + ? i18n.str`must be greater than 0` + : undefined, + summary: !(state.type === Steps.FIXED_SUMMARY || state.type === Steps.BOTH_FIXED) + ? undefined + : !state.template_contract?.summary + ? i18n.str`required` + : undefined, + minimum_age: + state.template_contract.minimum_age < 0 + ? i18n.str`should be greater that 0` + : undefined, + pay_duration: !state.template_contract.pay_duration + ? i18n.str`can't be empty` + : state.template_contract.pay_duration.d_us === "forever" + ? undefined + : state.template_contract.pay_duration.d_us < 1000 * 1000 //less than one second + ? i18n.str`to short` + : undefined, + } as Partial), + }; + + const hasErrors = Object.keys(errors).some( + (k) => (errors as any)[k] !== undefined, + ); + + const submitForm = () => { + if (hasErrors) return Promise.reject(); + if (state.template_contract) { + if (state.type === Steps.NON_FIXED) { + delete state.template_contract.amount; + delete state.template_contract.summary; + } else if (state.type === Steps.FIXED_SUMMARY) { + delete state.template_contract.amount; + } else if (state.type === Steps.FIXED_PRICE) { + delete state.template_contract.summary; + } + } + delete state.type + return onCreate(state as any); + }; + + const deviceList = !devices.ok ? [] : devices.data.otp_devices + + return ( +
+
+
+
+
+ + + name="template_id" + help={`${backendURL}/templates/${state.template_id ?? ""}`} + label={i18n.str`Identifier`} + tooltip={i18n.str`Name of the template in URLs.`} + /> + + name="template_description" + label={i18n.str`Description`} + help="" + tooltip={i18n.str`Describe what this template stands for`} + /> + { + switch (state.type) { + case Steps.NON_FIXED: return i18n.str`User will be able to input price and summary before payment.` + case Steps.FIXED_PRICE: return i18n.str`User will be able to add a summary before payment.` + case Steps.FIXED_SUMMARY: return i18n.str`User will be able to set the price before payment.` + case Steps.BOTH_FIXED: return i18n.str`User will not be able to change the price or the summary.` + } + })()} + tooltip={i18n.str`Define what the user be allowed to modify`} + values={[ + Steps.NON_FIXED, + Steps.FIXED_PRICE, + Steps.FIXED_SUMMARY, + Steps.BOTH_FIXED, + ]} + toStr={(v: Steps): string => { + switch (v) { + case Steps.NON_FIXED: return i18n.str`Simple` + case Steps.FIXED_PRICE: return i18n.str`With price` + case Steps.FIXED_SUMMARY: return i18n.str`With summary` + case Steps.BOTH_FIXED: return i18n.str`With price and summary` + } + }} + /> + {state.type === Steps.BOTH_FIXED || state.type === Steps.FIXED_SUMMARY ? + + : undefined} + {state.type === Steps.BOTH_FIXED || state.type === Steps.FIXED_PRICE ? + + : undefined} + + + + name="otp_id" + label={i18n.str`OTP device`} + readonly + tooltip={i18n.str`Use to verify transaction in offline mode.`} + /> + setState((v) => ({ ...v, otp_id: p?.id }))} + list={deviceList.map(e => ({ + description: e.device_description, + id: e.otp_device_id + }))} + /> + + + +
+ {onBack && ( + + )} + + Confirm + +
+
+
+
+
+
+ ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/create/index.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/create/index.tsx new file mode 100644 index 000000000..a29ee53b6 --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/create/index.tsx @@ -0,0 +1,61 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Fragment, h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { NotificationCard } from "../../../../components/menu/index.js"; +import { MerchantBackend } from "../../../../declaration.js"; +import { useTemplateAPI } from "../../../../hooks/templates.js"; +import { Notification } from "../../../../utils/types.js"; +import { CreatePage } from "./CreatePage.js"; + +export type Entity = MerchantBackend.Transfers.TransferInformation; +interface Props { + onBack?: () => void; + onConfirm: () => void; +} + +export default function CreateTransfer({ onConfirm, onBack }: Props): VNode { + const { createTemplate } = useTemplateAPI(); + const [notif, setNotif] = useState(undefined); + const { i18n } = useTranslationContext(); + + return ( + <> + + { + return createTemplate(request) + .then(() => onConfirm()) + .catch((error) => { + setNotif({ + message: i18n.str`could not inform template`, + type: "ERROR", + description: error.message, + }); + }); + }} + /> + + ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/list/List.stories.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/list/List.stories.tsx new file mode 100644 index 000000000..702e9ba4a --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/list/List.stories.tsx @@ -0,0 +1,28 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { FunctionalComponent, h } from "preact"; +import { ListPage as TestedComponent } from "./ListPage.js"; + +export default { + title: "Pages/Templates/List", + component: TestedComponent, +}; diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/list/ListPage.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/list/ListPage.tsx new file mode 100644 index 000000000..bf6062c34 --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/list/ListPage.tsx @@ -0,0 +1,68 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { h, VNode } from "preact"; +import { MerchantBackend } from "../../../../declaration.js"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { CardTable } from "./Table.js"; + +export interface Props { + templates: MerchantBackend.Template.TemplateEntry[]; + onLoadMoreBefore?: () => void; + onLoadMoreAfter?: () => void; + onCreate: () => void; + onDelete: (e: MerchantBackend.Template.TemplateEntry) => void; + onSelect: (e: MerchantBackend.Template.TemplateEntry) => void; + onNewOrder: (e: MerchantBackend.Template.TemplateEntry) => void; + onQR: (e: MerchantBackend.Template.TemplateEntry) => void; +} + +export function ListPage({ + templates, + onCreate, + onDelete, + onSelect, + onNewOrder, + onQR, + onLoadMoreBefore, + onLoadMoreAfter, +}: Props): VNode { + const form = { payto_uri: "" }; + + const { i18n } = useTranslationContext(); + return ( + ({ + ...o, + id: String(o.template_id), + }))} + onQR={onQR} + onCreate={onCreate} + onDelete={onDelete} + onSelect={onSelect} + onNewOrder={onNewOrder} + onLoadMoreBefore={onLoadMoreBefore} + hasMoreBefore={!onLoadMoreBefore} + onLoadMoreAfter={onLoadMoreAfter} + hasMoreAfter={!onLoadMoreAfter} + /> + ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/list/Table.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/list/Table.tsx new file mode 100644 index 000000000..9fdf4ead9 --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/list/Table.tsx @@ -0,0 +1,235 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { h, VNode } from "preact"; +import { StateUpdater, useState } from "preact/hooks"; +import { MerchantBackend } from "../../../../declaration.js"; + +type Entity = MerchantBackend.Template.TemplateEntry; + +interface Props { + templates: Entity[]; + onDelete: (e: Entity) => void; + onSelect: (e: Entity) => void; + onNewOrder: (e: Entity) => void; + onQR: (e: Entity) => void; + onCreate: () => void; + onLoadMoreBefore?: () => void; + hasMoreBefore?: boolean; + hasMoreAfter?: boolean; + onLoadMoreAfter?: () => void; +} + +export function CardTable({ + templates, + onCreate, + onDelete, + onSelect, + onQR, + onNewOrder, + onLoadMoreAfter, + onLoadMoreBefore, + hasMoreAfter, + hasMoreBefore, +}: Props): VNode { + const [rowSelection, rowSelectionHandler] = useState([]); + + const { i18n } = useTranslationContext(); + + return ( +
+
+

+ + + + Templates +

+
+ + + +
+
+
+
+
+ {templates.length > 0 ? ( + + ) : ( + + )} + + + + + ); +} +interface TableProps { + rowSelection: string[]; + instances: Entity[]; + onDelete: (e: Entity) => void; + onNewOrder: (e: Entity) => void; + onQR: (e: Entity) => void; + onSelect: (e: Entity) => void; + rowSelectionHandler: StateUpdater; + onLoadMoreBefore?: () => void; + hasMoreBefore?: boolean; + hasMoreAfter?: boolean; + onLoadMoreAfter?: () => void; +} + +function toggleSelected(id: T): (prev: T[]) => T[] { + return (prev: T[]): T[] => + prev.indexOf(id) == -1 ? [...prev, id] : prev.filter((e) => e != id); +} + +function Table({ + instances, + onLoadMoreAfter, + onDelete, + onNewOrder, + onQR, + onSelect, + onLoadMoreBefore, + hasMoreAfter, + hasMoreBefore, +}: TableProps): VNode { + const { i18n } = useTranslationContext(); + return ( +
+ {hasMoreBefore && ( + + )} +
+ + + + + + + + {instances.map((i) => { + return ( + + + + + + ); + })} + +
+ ID + + Description + +
onSelect(i)} + style={{ cursor: "pointer" }} + > + {i.template_id} + onSelect(i)} + style={{ cursor: "pointer" }} + > + {i.template_description} + +
+ + + +
+
+ {hasMoreAfter && ( + + )} +
+ ); +} + +function EmptyTable(): VNode { + const { i18n } = useTranslationContext(); + return ( +
+

+ + + +

+

+ + There is no templates yet, add more pressing the + sign + +

+
+ ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/list/index.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/list/index.tsx new file mode 100644 index 000000000..b9767442f --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/list/index.tsx @@ -0,0 +1,152 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { + ErrorType, + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; +import { Fragment, h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { Loading } from "../../../../components/exception/loading.js"; +import { NotificationCard } from "../../../../components/menu/index.js"; +import { MerchantBackend } from "../../../../declaration.js"; +import { + useInstanceTemplates, + useTemplateAPI, +} from "../../../../hooks/templates.js"; +import { Notification } from "../../../../utils/types.js"; +import { ListPage } from "./ListPage.js"; +import { HttpStatusCode, TranslatedString } from "@gnu-taler/taler-util"; +import { ConfirmModal } from "../../../../components/modal/index.js"; +import { JumpToElementById } from "../../../../components/form/JumpToElementById.js"; + +interface Props { + onUnauthorized: () => VNode; + onLoadError: (error: HttpError) => VNode; + onNotFound: () => VNode; + onCreate: () => void; + onSelect: (id: string) => void; + onNewOrder: (id: string) => void; + onQR: (id: string) => void; +} + +export default function ListTemplates({ + onUnauthorized, + onLoadError, + onCreate, + onQR, + onSelect, + onNewOrder, + onNotFound, +}: Props): VNode { + const [position, setPosition] = useState(undefined); + const { i18n } = useTranslationContext(); + const [notif, setNotif] = useState(undefined); + const { deleteTemplate, testTemplateExist } = useTemplateAPI(); + const result = useInstanceTemplates({ position }, (id) => setPosition(id)); + const [deleting, setDeleting] = + useState(null); + + if (result.loading) return ; + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } + + return ( +
+ + + + + { + onSelect(e.template_id); + }} + onNewOrder={(e) => { + onNewOrder(e.template_id); + }} + onQR={(e) => { + onQR(e.template_id); + }} + onDelete={(e: MerchantBackend.Template.TemplateEntry) => { + setDeleting(e) + } + } + /> + + {deleting && ( + setDeleting(null)} + onConfirm={async (): Promise => { + try { + await deleteTemplate(deleting.template_id); + setNotif({ + message: i18n.str`Template "${deleting.template_description}" (ID: ${deleting.template_id}) has been deleted`, + type: "SUCCESS", + }); + } catch (error) { + setNotif({ + message: i18n.str`Failed to delete template`, + type: "ERROR", + description: error instanceof Error ? error.message : undefined, + }); + } + setDeleting(null); + }} + > +

+ If you delete the template "{deleting.template_description}" (ID:{" "} + {deleting.template_id}) you may loose information +

+

+ Deleting an template cannot be undone. +

+
+ )} +
+ ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/qr/Qr.stories.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/qr/Qr.stories.tsx new file mode 100644 index 000000000..eb853c8ff --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/qr/Qr.stories.tsx @@ -0,0 +1,27 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { QrPage as TestedComponent } from "./QrPage.js"; + +export default { + title: "Pages/Templates/QR", + component: TestedComponent, +}; diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx new file mode 100644 index 000000000..5140aae3a --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx @@ -0,0 +1,172 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { stringifyPayTemplateUri } from "@gnu-taler/taler-util"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { VNode, h } from "preact"; +import { useState } from "preact/hooks"; +import { QR } from "../../../../components/exception/QR.js"; +import { + FormErrors, + FormProvider, +} from "../../../../components/form/FormProvider.js"; +import { Input } from "../../../../components/form/Input.js"; +import { InputCurrency } from "../../../../components/form/InputCurrency.js"; +import { useBackendContext } from "../../../../context/backend.js"; +import { useConfigContext } from "../../../../context/config.js"; +import { useInstanceContext } from "../../../../context/instance.js"; +import { MerchantBackend } from "../../../../declaration.js"; + +type Entity = MerchantBackend.Template.UsingTemplateDetails; + +interface Props { + contract: MerchantBackend.Template.TemplateContractDetails; + id: string; + onBack?: () => void; +} + +export function QrPage({ contract, id: templateId, onBack }: Props): VNode { + const { i18n } = useTranslationContext(); + const { url: backendURL } = useBackendContext() + const { id: instanceId } = useInstanceContext(); + const config = useConfigContext(); + + const [state, setState] = useState>({ + amount: contract.amount, + summary: contract.summary, + }); + + const errors: FormErrors = {}; + + const fixedAmount = !!contract.amount; + const fixedSummary = !!contract.summary; + + const templateParams: Record = {} + if (!fixedAmount) { + if (state.amount) { + templateParams.amount = state.amount + } else { + templateParams.amount = config.currency + } + } + + if (!fixedSummary) { + templateParams.summary = state.summary ?? "" + } + + const merchantBaseUrl = new URL(backendURL).href; + + const payTemplateUri = stringifyPayTemplateUri({ + merchantBaseUrl, + templateId, + templateParams + }) + + const issuer = encodeURIComponent( + `${new URL(backendURL).host}/${instanceId}`, + ); + + return ( +
+
+
+
+
+

+ + Here you can specify a default value for fields that are not + fixed. Default values can be edited by the customer before the + payment. + +

+ +

+ + + name="amount" + label={ + fixedAmount + ? i18n.str`Fixed amount` + : i18n.str`Default amount` + } + readonly={fixedAmount} + tooltip={i18n.str`Amount of the order`} + /> + + name="summary" + inputType="multiline" + readonly={fixedSummary} + label={ + fixedSummary + ? i18n.str`Fixed summary` + : i18n.str`Default summary` + } + tooltip={i18n.str`Title of the order to be shown to the customer`} + /> + + +
+ {onBack && ( + + )} + +
+
+
+
+
+
+ +
+          {payTemplateUri}
+        
+
+
+ ); +} + +function saveAsPDF(name: string): void { + const printWindow = window.open("", "", "height=400,width=800"); + if (!printWindow) return; + const divContents = document.getElementById("printThis"); + if (!divContents) return; + printWindow.document.write( + `Order template for ${name} "); + printWindow.document.close(); + printWindow.document.body.appendChild(divContents.cloneNode(true)); + printWindow.addEventListener("load", () => { + printWindow.print(); + printWindow.close(); + }); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/qr/index.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/qr/index.tsx new file mode 100644 index 000000000..7db7478f7 --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/qr/index.tsx @@ -0,0 +1,80 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { + ErrorType, + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; +import { Fragment, h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { Loading } from "../../../../components/exception/loading.js"; +import { NotificationCard } from "../../../../components/menu/index.js"; +import { MerchantBackend } from "../../../../declaration.js"; +import { + useTemplateAPI, + useTemplateDetails, +} from "../../../../hooks/templates.js"; +import { Notification } from "../../../../utils/types.js"; +import { QrPage } from "./QrPage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; + +export type Entity = MerchantBackend.Transfers.TransferInformation; +interface Props { + onBack?: () => void; + onUnauthorized: () => VNode; + onNotFound: () => VNode; + onLoadError: (e: HttpError) => VNode; + tid: string; +} + +export default function TemplateQrPage({ + tid, + onBack, + onLoadError, + onNotFound, + onUnauthorized, +}: Props): VNode { + const result = useTemplateDetails(tid); + const [notif, setNotif] = useState(undefined); + + if (result.loading) return ; + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } + + return ( + <> + + + + ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/update/Update.stories.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/update/Update.stories.tsx new file mode 100644 index 000000000..8d07cb31f --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/update/Update.stories.tsx @@ -0,0 +1,32 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { h, VNode, FunctionalComponent } from "preact"; +import { UpdatePage as TestedComponent } from "./UpdatePage.js"; + +export default { + title: "Pages/Templates/Update", + component: TestedComponent, + argTypes: { + onUpdate: { action: "onUpdate" }, + onBack: { action: "onBack" }, + }, +}; diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx new file mode 100644 index 000000000..b578d4664 --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx @@ -0,0 +1,254 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { + Amounts, + MerchantTemplateContractDetails, +} from "@gnu-taler/taler-util"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Fragment, VNode, h } from "preact"; +import { useState } from "preact/hooks"; +import { AsyncButton } from "../../../../components/exception/AsyncButton.js"; +import { + FormErrors, + FormProvider, +} from "../../../../components/form/FormProvider.js"; +import { Input } from "../../../../components/form/Input.js"; +import { InputCurrency } from "../../../../components/form/InputCurrency.js"; +import { InputDuration } from "../../../../components/form/InputDuration.js"; +import { InputNumber } from "../../../../components/form/InputNumber.js"; +import { InputWithAddon } from "../../../../components/form/InputWithAddon.js"; +import { useBackendContext } from "../../../../context/backend.js"; +import { MerchantBackend, WithId } from "../../../../declaration.js"; +import { undefinedIfEmpty } from "../../../../utils/table.js"; +import { InputTab } from "../../../../components/form/InputTab.js"; + +enum Steps { + BOTH_FIXED, + FIXED_PRICE, + FIXED_SUMMARY, + NON_FIXED, +} + +type Entity = MerchantBackend.Template.TemplatePatchDetails & WithId; + +interface Props { + onUpdate: (d: Entity) => Promise; + onBack?: () => void; + template: Entity; +} + +export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { + const { i18n } = useTranslationContext(); + const { url: backendURL } = useBackendContext() + + const intialStep = + template.template_contract?.amount === undefined && template.template_contract?.summary === undefined + ? Steps.NON_FIXED + : template.template_contract?.summary === undefined + ? Steps.FIXED_PRICE + : template.template_contract?.amount === undefined + ? Steps.FIXED_SUMMARY + : Steps.BOTH_FIXED; + + const [state, setState] = useState>({ ...template, type: intialStep }); + + const parsedPrice = !state.template_contract?.amount + ? undefined + : Amounts.parse(state.template_contract?.amount); + + const errors: FormErrors = { + template_description: !state.template_description + ? i18n.str`should not be empty` + : undefined, + template_contract: !state.template_contract + ? undefined + : undefinedIfEmpty({ + amount: !(state.type === Steps.FIXED_PRICE || state.type === Steps.BOTH_FIXED) + ? undefined + : !state.template_contract?.amount + ? i18n.str`required` + : !parsedPrice + ? i18n.str`not valid` + : Amounts.isZero(parsedPrice) + ? i18n.str`must be greater than 0` + : undefined, + summary: !(state.type === Steps.FIXED_SUMMARY || state.type === Steps.BOTH_FIXED) + ? undefined + : !state.template_contract?.summary + ? i18n.str`required` + : undefined, + minimum_age: + state.template_contract.minimum_age < 0 + ? i18n.str`should be greater that 0` + : undefined, + pay_duration: !state.template_contract.pay_duration + ? i18n.str`can't be empty` + : state.template_contract.pay_duration.d_us === "forever" + ? undefined + : state.template_contract.pay_duration.d_us < 1000 * 1000 // less than one second + ? i18n.str`to short` + : undefined, + } as Partial), + }; + + const hasErrors = Object.keys(errors).some( + (k) => (errors as any)[k] !== undefined, + ); + + const submitForm = () => { + if (hasErrors) return Promise.reject(); + if (state.template_contract) { + if (state.type === Steps.NON_FIXED) { + delete state.template_contract.amount; + delete state.template_contract.summary; + } else if (state.type === Steps.FIXED_SUMMARY) { + delete state.template_contract.amount; + } else if (state.type === Steps.FIXED_PRICE) { + delete state.template_contract.summary; + } + } + delete state.type + return onUpdate(state as any); + }; + + + return ( +
+
+
+
+
+
+
+ + {backendURL}/templates/{template.id} + +
+
+
+
+
+
+ +
+
+
+ + + name="id" + addonBefore={`templates/`} + readonly + label={i18n.str`Identifier`} + tooltip={i18n.str`Name of the template in URLs.`} + /> + + + name="template_description" + label={i18n.str`Description`} + help="" + tooltip={i18n.str`Describe what this template stands for`} + /> + { + switch (state.type) { + case Steps.NON_FIXED: return i18n.str`User will be able to input price and summary before payment.` + case Steps.FIXED_PRICE: return i18n.str`User will be able to add a summary before payment.` + case Steps.FIXED_SUMMARY: return i18n.str`User will be able to set the price before payment.` + case Steps.BOTH_FIXED: return i18n.str`User will not be able to change the price or the summary.` + } + })()} + tooltip={i18n.str`Define what the user be allowed to modify`} + values={[ + Steps.NON_FIXED, + Steps.FIXED_PRICE, + Steps.FIXED_SUMMARY, + Steps.BOTH_FIXED, + ]} + toStr={(v: Steps): string => { + switch (v) { + case Steps.NON_FIXED: return i18n.str`Simple` + case Steps.FIXED_PRICE: return i18n.str`With price` + case Steps.FIXED_SUMMARY: return i18n.str`With summary` + case Steps.BOTH_FIXED: return i18n.str`With price and summary` + } + }} + /> + {state.type === Steps.BOTH_FIXED || state.type === Steps.FIXED_SUMMARY ? + + : undefined} + {state.type === Steps.BOTH_FIXED || state.type === Steps.FIXED_PRICE ? + + : undefined} + + + + +
+ {onBack && ( + + )} + + Confirm + +
+
+
+
+
+
+ ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/update/index.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/update/index.tsx new file mode 100644 index 000000000..3adca45db --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/update/index.tsx @@ -0,0 +1,99 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { + ErrorType, + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; +import { Fragment, h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { Loading } from "../../../../components/exception/loading.js"; +import { NotificationCard } from "../../../../components/menu/index.js"; +import { MerchantBackend, WithId } from "../../../../declaration.js"; +import { + useTemplateAPI, + useTemplateDetails, +} from "../../../../hooks/templates.js"; +import { Notification } from "../../../../utils/types.js"; +import { UpdatePage } from "./UpdatePage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; + +export type Entity = MerchantBackend.Template.TemplatePatchDetails & WithId; + +interface Props { + onBack?: () => void; + onConfirm: () => void; + onUnauthorized: () => VNode; + onNotFound: () => VNode; + onLoadError: (e: HttpError) => VNode; + tid: string; +} +export default function UpdateTemplate({ + tid, + onConfirm, + onBack, + onUnauthorized, + onNotFound, + onLoadError, +}: Props): VNode { + const { updateTemplate } = useTemplateAPI(); + const result = useTemplateDetails(tid); + const [notif, setNotif] = useState(undefined); + + const { i18n } = useTranslationContext(); + + if (result.loading) return ; + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } + + return ( + + + { + return updateTemplate(tid, data) + .then(onConfirm) + .catch((error) => { + setNotif({ + message: i18n.str`could not update template`, + type: "ERROR", + description: error.message, + }); + }); + }} + /> + + ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/use/Use.stories.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/use/Use.stories.tsx new file mode 100644 index 000000000..13576d94d --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/use/Use.stories.tsx @@ -0,0 +1,27 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { UsePage as TestedComponent } from "./UsePage.js"; + +export default { + title: "Pages/Templates/Create", + component: TestedComponent, +}; diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx new file mode 100644 index 000000000..983804d3e --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx @@ -0,0 +1,143 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { AsyncButton } from "../../../../components/exception/AsyncButton.js"; +import { + FormErrors, + FormProvider, +} from "../../../../components/form/FormProvider.js"; +import { Input } from "../../../../components/form/Input.js"; +import { InputCurrency } from "../../../../components/form/InputCurrency.js"; +import { MerchantBackend } from "../../../../declaration.js"; + +type Entity = MerchantBackend.Template.UsingTemplateDetails; + +interface Props { + id: string; + template: MerchantBackend.Template.TemplateDetails; + onCreateOrder: (d: Entity) => Promise; + onBack?: () => void; +} + +export function UsePage({ id, template, onCreateOrder, onBack }: Props): VNode { + const { i18n } = useTranslationContext(); + + const [state, setState] = useState>({ + amount: template.template_contract.amount, + summary: template.template_contract.summary, + }); + + const errors: FormErrors = { + amount: + !template.template_contract.amount && !state.amount + ? i18n.str`Amount is required` + : undefined, + summary: + !template.template_contract.summary && !state.summary + ? i18n.str`Order summary is required` + : undefined, + }; + + const hasErrors = Object.keys(errors).some( + (k) => (errors as any)[k] !== undefined, + ); + + const submitForm = () => { + if (hasErrors) return Promise.reject(); + if (template.template_contract.amount) { + delete state.amount; + } + if (template.template_contract.summary) { + delete state.summary; + } + return onCreateOrder(state as any); + }; + + return ( +
+
+
+
+
+
+
+ + New order for template:{" "} + {id} + +
+
+
+
+
+
+
+
+
+
+ + + name="amount" + label={i18n.str`Amount`} + readonly={!!template.template_contract.amount} + tooltip={i18n.str`Amount of the order`} + /> + + name="summary" + inputType="multiline" + label={i18n.str`Order summary`} + readonly={!!template.template_contract.summary} + tooltip={i18n.str`Title of the order to be shown to the customer`} + /> + + +
+ {onBack && ( + + )} + + Confirm + +
+
+
+
+
+
+ ); +} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/templates/use/index.tsx b/packages/auditor-backoffice-ui/src/paths/instance/templates/use/index.tsx new file mode 100644 index 000000000..ed1242ef5 --- /dev/null +++ b/packages/auditor-backoffice-ui/src/paths/instance/templates/use/index.tsx @@ -0,0 +1,101 @@ +/* + This file is part of GNU Taler + (C) 2021-2023 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { + ErrorType, + HttpError, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; +import { Fragment, h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { Loading } from "../../../../components/exception/loading.js"; +import { NotificationCard } from "../../../../components/menu/index.js"; +import { MerchantBackend } from "../../../../declaration.js"; +import { + useTemplateAPI, + useTemplateDetails, +} from "../../../../hooks/templates.js"; +import { Notification } from "../../../../utils/types.js"; +import { UsePage } from "./UsePage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; + +export type Entity = MerchantBackend.Transfers.TransferInformation; +interface Props { + onBack?: () => void; + onOrderCreated: (id: string) => void; + onUnauthorized: () => VNode; + onNotFound: () => VNode; + onLoadError: (e: HttpError) => VNode; + tid: string; +} + +export default function TemplateUsePage({ + tid, + onOrderCreated, + onBack, + onLoadError, + onNotFound, + onUnauthorized, +}: Props): VNode { + const { createOrderFromTemplate } = useTemplateAPI(); + const result = useTemplateDetails(tid); + const [notif, setNotif] = useState(undefined); + const { i18n } = useTranslationContext(); + + if (result.loading) return ; + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } + + return ( + <> + + { + return createOrderFromTemplate(tid, request) + .then((res) => onOrderCreated(res.data.order_id)) + .catch((error) => { + setNotif({ + message: i18n.str`could not create order from template`, + type: "ERROR", + description: error.message, + }); + }); + }} + /> + + ); +} -- cgit v1.2.3