From e1d86816a7c07cb8ca2d54676d5cdbbe513f2ba7 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 4 Sep 2023 14:17:55 -0300 Subject: backoffcie new version, lot of changes --- .../paths/instance/reserves/create/CreatePage.tsx | 14 +-- .../reserves/create/CreatedSuccessfully.tsx | 22 ++-- .../src/paths/instance/reserves/create/index.tsx | 8 +- .../paths/instance/reserves/details/DetailPage.tsx | 36 +++--- .../instance/reserves/details/Details.stories.tsx | 6 +- .../paths/instance/reserves/details/RewardInfo.tsx | 88 +++++++++++++++ .../paths/instance/reserves/details/TipInfo.tsx | 87 --------------- .../instance/reserves/list/AutorizeRewardModal.tsx | 124 +++++++++++++++++++++ .../instance/reserves/list/AutorizeTipModal.tsx | 124 --------------------- .../instance/reserves/list/CreatedSuccessfully.tsx | 18 +-- .../paths/instance/reserves/list/List.stories.tsx | 6 - .../src/paths/instance/reserves/list/Table.tsx | 39 ++++--- .../src/paths/instance/reserves/list/index.tsx | 82 ++++++++++---- 13 files changed, 348 insertions(+), 306 deletions(-) create mode 100644 packages/merchant-backoffice-ui/src/paths/instance/reserves/details/RewardInfo.tsx delete mode 100644 packages/merchant-backoffice-ui/src/paths/instance/reserves/details/TipInfo.tsx create mode 100644 packages/merchant-backoffice-ui/src/paths/instance/reserves/list/AutorizeRewardModal.tsx delete mode 100644 packages/merchant-backoffice-ui/src/paths/instance/reserves/list/AutorizeTipModal.tsx (limited to 'packages/merchant-backoffice-ui/src/paths/instance/reserves') diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx index fccb20121..2201e75a5 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx @@ -36,7 +36,7 @@ import { URL_REGEX, } from "../../../../utils/constants.js"; -type Entity = MerchantBackend.Tips.ReserveCreateRequest; +type Entity = MerchantBackend.Rewards.ReserveCreateRequest; interface Props { onCreate: (d: Entity) => Promise; @@ -80,15 +80,15 @@ function ViewStep({ initial_balance: !reserve.initial_balance ? "cannot be empty" : !(parseInt(reserve.initial_balance.split(":")[1], 10) > 0) - ? i18n.str`it should be greater than 0` - : undefined, + ? i18n.str`it should be greater than 0` + : undefined, exchange_url: !reserve.exchange_url ? i18n.str`cannot be empty` : !URL_REGEX.test(reserve.exchange_url) - ? i18n.str`must be a valid URL` - : !exchangeQueryError - ? undefined - : exchangeQueryError, + ? i18n.str`must be a valid URL` + : !exchangeQueryError + ? undefined + : exchangeQueryError, }; const hasErrors = Object.keys(errors).some( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatedSuccessfully.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatedSuccessfully.tsx index 94fcdaff7..1d512c843 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatedSuccessfully.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatedSuccessfully.tsx @@ -22,8 +22,8 @@ import { CreatedSuccessfully as Template } from "../../../../components/notifica import { MerchantBackend, WireAccount } from "../../../../declaration.js"; type Entity = { - request: MerchantBackend.Tips.ReserveCreateRequest; - response: MerchantBackend.Tips.ReserveCreateConfirmation; + request: MerchantBackend.Rewards.ReserveCreateRequest; + response: MerchantBackend.Rewards.ReserveCreateConfirmation; }; interface Props { @@ -98,15 +98,15 @@ export function ShowAccountsOfReserveAsQRWithLink({ const accountsInfo = !accounts ? [] : accounts - .map((acc) => { - const p = parsePaytoUri(acc.payto_uri); - if (p) { - p.params["message"] = message; - p.params["amount"] = amount; - } - return p; - }) - .filter(isNotUndefined); + .map((acc) => { + const p = parsePaytoUri(acc.payto_uri); + if (p) { + p.params["message"] = message; + p.params["amount"] = amount; + } + return p; + }) + .filter(isNotUndefined); const links = accountsInfo.map((a) => stringifyPaytoUri(a)); diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/index.tsx index 8a4fe1565..4bbaf1459 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/index.tsx @@ -39,9 +39,9 @@ export default function CreateReserve({ onBack, onConfirm }: Props): VNode { const [createdOk, setCreatedOk] = useState< | { - request: MerchantBackend.Tips.ReserveCreateRequest; - response: MerchantBackend.Tips.ReserveCreateConfirmation; - } + request: MerchantBackend.Rewards.ReserveCreateRequest; + response: MerchantBackend.Rewards.ReserveCreateConfirmation; + } | undefined >(undefined); @@ -54,7 +54,7 @@ export default function CreateReserve({ onBack, onConfirm }: Props): VNode { { + onCreate={(request: MerchantBackend.Rewards.ReserveCreateRequest) => { return createReserve(request) .then((r) => setCreatedOk({ request, response: r.data })) .catch((error) => { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/DetailPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/DetailPage.tsx index b0173b5d3..d8840eeac 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/DetailPage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/DetailPage.tsx @@ -36,11 +36,12 @@ import { InputDate } from "../../../../components/form/InputDate.js"; import { TextField } from "../../../../components/form/TextField.js"; import { SimpleModal } from "../../../../components/modal/index.js"; import { MerchantBackend } from "../../../../declaration.js"; -import { useTipDetails } from "../../../../hooks/reserves.js"; -import { TipInfo } from "./TipInfo.js"; +import { useRewardDetails } from "../../../../hooks/reserves.js"; +import { RewardInfo } from "./RewardInfo.js"; import { ShowAccountsOfReserveAsQRWithLink } from "../create/CreatedSuccessfully.js"; +import { datetimeFormatForSettings, useSettings } from "../../../../hooks/useSettings.js"; -type Entity = MerchantBackend.Tips.ReserveDetail; +type Entity = MerchantBackend.Rewards.ReserveDetail; type CT = MerchantBackend.ContractTerms; interface Props { @@ -116,14 +117,14 @@ export function DetailPage({ id, selected, onBack }: Props): VNode { - Tips + Rewards

- {selected.tips && selected.tips.length > 0 ? ( - + {selected.rewards && selected.rewards.length > 0 ? ( +
) : ( )} @@ -163,7 +164,7 @@ function EmptyTable(): VNode {

- No tips has been authorized from this reserve + No reward has been authorized from this reserve

@@ -171,10 +172,10 @@ function EmptyTable(): VNode { } interface TableProps { - tips: MerchantBackend.Tips.TipStatusEntry[]; + rewards: MerchantBackend.Rewards.RewardStatusEntry[]; } -function Table({ tips }: TableProps): VNode { +function Table({ rewards }: TableProps): VNode { const { i18n } = useTranslationContext(); return (
@@ -196,8 +197,8 @@ function Table({ tips }: TableProps): VNode {
- {tips.map((t, i) => { - return ; + {rewards.map((t, i) => { + return ; })}
@@ -205,15 +206,16 @@ function Table({ tips }: TableProps): VNode { ); } -function TipRow({ +function RewardRow({ id, entry, }: { id: string; - entry: MerchantBackend.Tips.TipStatusEntry; + entry: MerchantBackend.Rewards.RewardStatusEntry; }) { const [selected, setSelected] = useState(false); - const result = useTipDetails(id); + const result = useRewardDetails(id); + const [settings] = useSettings(); if (result.loading) { return ( @@ -242,11 +244,11 @@ function TipRow({ {selected && ( setSelected(false)} > - + )} @@ -256,7 +258,7 @@ function TipRow({ {info.expiration.t_s === "never" ? "never" - : format(info.expiration.t_s * 1000, "yyyy/MM/dd HH:mm:ss")} + : format(info.expiration.t_s * 1000, datetimeFormatForSettings(settings))} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/Details.stories.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/Details.stories.tsx index 2592e2c6e..41c715f20 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/Details.stories.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/Details.stories.tsx @@ -92,7 +92,7 @@ export const NotYetFunded = createExample(TestedComponent, { }, }); -export const FundedWithEmptyTips = createExample(TestedComponent, { +export const FundedWithEmptyRewards = createExample(TestedComponent, { id: "THISISTHERESERVEID", selected: { active: true, @@ -115,10 +115,10 @@ export const FundedWithEmptyTips = createExample(TestedComponent, { }, ], exchange_url: "http://exchange.taler/", - tips: [ + rewards: [ { reason: "asdasd", - tip_id: "123", + reward_id: "123", total_amount: "TESTKUDOS:1", }, ], diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/RewardInfo.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/RewardInfo.tsx new file mode 100644 index 000000000..57a051ed7 --- /dev/null +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/RewardInfo.tsx @@ -0,0 +1,88 @@ +/* + 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 + */ +import { format } from "date-fns"; +import { Fragment, h, VNode } from "preact"; +import { useBackendContext } from "../../../../context/backend.js"; +import { MerchantBackend } from "../../../../declaration.js"; +import { datetimeFormatForSettings, useSettings } from "../../../../hooks/useSettings.js"; +import { stringifyRewardUri } from "@gnu-taler/taler-util"; + +type Entity = MerchantBackend.Rewards.RewardDetails; + +interface Props { + id: string; + entity: Entity; + amount: string; +} + +export function RewardInfo({ id: merchantRewardId, amount, entity }: Props): VNode { + const { url: merchantBaseUrl } = useBackendContext(); + const [settings] = useSettings(); + const rewardURL = stringifyRewardUri({ merchantBaseUrl, merchantRewardId }) + return ( + +
+
+ +
+
+
+

+ +

+
+
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+
+

+ +

+
+
+
+
+ ); +} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/TipInfo.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/TipInfo.tsx deleted file mode 100644 index 360d39aba..000000000 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/TipInfo.tsx +++ /dev/null @@ -1,87 +0,0 @@ -/* - 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 - */ -import { format } from "date-fns"; -import { Fragment, h, VNode } from "preact"; -import { useBackendContext } from "../../../../context/backend.js"; -import { MerchantBackend } from "../../../../declaration.js"; - -type Entity = MerchantBackend.Tips.TipDetails; - -interface Props { - id: string; - entity: Entity; - amount: string; -} - -export function TipInfo({ id, amount, entity }: Props): VNode { - const { url } = useBackendContext(); - const tipHost = url.replace(/.*:\/\//, ""); // remove protocol part - const proto = url.startsWith("http://") ? "taler+http" : "taler"; - const tipURL = `${proto}://tip/${tipHost}/${id}`; - return ( - -
-
- -
-
-
-

- -

-
-
-
-
-
- -
-
- -
-
-
-
- -
-
-
-

- -

-
-
-
-
- ); -} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/AutorizeRewardModal.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/AutorizeRewardModal.tsx new file mode 100644 index 000000000..e205ee621 --- /dev/null +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/AutorizeRewardModal.tsx @@ -0,0 +1,124 @@ +/* + 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 * as yup from "yup"; +import { + FormErrors, + FormProvider, +} from "../../../../components/form/FormProvider.js"; +import { Input } from "../../../../components/form/Input.js"; +import { InputCurrency } from "../../../../components/form/InputCurrency.js"; +import { + ConfirmModal, + ContinueModal, +} from "../../../../components/modal/index.js"; +import { MerchantBackend } from "../../../../declaration.js"; +import { AuthorizeRewardSchema } from "../../../../schemas/index.js"; +import { CreatedSuccessfully } from "./CreatedSuccessfully.js"; + +interface AuthorizeRewardModalProps { + onCancel: () => void; + onConfirm: (value: MerchantBackend.Rewards.RewardCreateRequest) => void; + rewardAuthorized?: { + response: MerchantBackend.Rewards.RewardCreateConfirmation; + request: MerchantBackend.Rewards.RewardCreateRequest; + }; +} + +export function AuthorizeRewardModal({ + onCancel, + onConfirm, + rewardAuthorized, +}: AuthorizeRewardModalProps): VNode { + // const result = useOrderDetails(id) + type State = MerchantBackend.Rewards.RewardCreateRequest; + const [form, setValue] = useState>({}); + const { i18n } = useTranslationContext(); + + // const [errors, setErrors] = useState>({}) + let errors: FormErrors = {}; + try { + AuthorizeRewardSchema.validateSync(form, { abortEarly: false }); + } catch (err) { + if (err instanceof yup.ValidationError) { + const yupErrors = err.inner as any[]; + errors = yupErrors.reduce( + (prev, cur) => + !cur.path ? prev : { ...prev, [cur.path]: cur.message }, + {}, + ); + } + } + const hasErrors = Object.keys(errors).some( + (k) => (errors as any)[k] !== undefined, + ); + + const validateAndConfirm = () => { + onConfirm(form as State); + }; + if (rewardAuthorized) { + return ( + + + + ); + } + + return ( + + + errors={errors} + object={form} + valueHandler={setValue} + > + + name="amount" + label={i18n.str`Amount`} + tooltip={i18n.str`amount of reward`} + /> + + name="justification" + label={i18n.str`Justification`} + inputType="multiline" + tooltip={i18n.str`reason for the reward`} + /> + + name="next_url" + label={i18n.str`URL after reward`} + tooltip={i18n.str`URL to visit after reward payment`} + /> + + + ); +} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/AutorizeTipModal.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/AutorizeTipModal.tsx deleted file mode 100644 index 1882f50d3..000000000 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/AutorizeTipModal.tsx +++ /dev/null @@ -1,124 +0,0 @@ -/* - 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 * as yup from "yup"; -import { - FormErrors, - FormProvider, -} from "../../../../components/form/FormProvider.js"; -import { Input } from "../../../../components/form/Input.js"; -import { InputCurrency } from "../../../../components/form/InputCurrency.js"; -import { - ConfirmModal, - ContinueModal, -} from "../../../../components/modal/index.js"; -import { MerchantBackend } from "../../../../declaration.js"; -import { AuthorizeTipSchema } from "../../../../schemas/index.js"; -import { CreatedSuccessfully } from "./CreatedSuccessfully.js"; - -interface AuthorizeTipModalProps { - onCancel: () => void; - onConfirm: (value: MerchantBackend.Tips.TipCreateRequest) => void; - tipAuthorized?: { - response: MerchantBackend.Tips.TipCreateConfirmation; - request: MerchantBackend.Tips.TipCreateRequest; - }; -} - -export function AuthorizeTipModal({ - onCancel, - onConfirm, - tipAuthorized, -}: AuthorizeTipModalProps): VNode { - // const result = useOrderDetails(id) - type State = MerchantBackend.Tips.TipCreateRequest; - const [form, setValue] = useState>({}); - const { i18n } = useTranslationContext(); - - // const [errors, setErrors] = useState>({}) - let errors: FormErrors = {}; - try { - AuthorizeTipSchema.validateSync(form, { abortEarly: false }); - } catch (err) { - if (err instanceof yup.ValidationError) { - const yupErrors = err.inner as any[]; - errors = yupErrors.reduce( - (prev, cur) => - !cur.path ? prev : { ...prev, [cur.path]: cur.message }, - {}, - ); - } - } - const hasErrors = Object.keys(errors).some( - (k) => (errors as any)[k] !== undefined, - ); - - const validateAndConfirm = () => { - onConfirm(form as State); - }; - if (tipAuthorized) { - return ( - - - - ); - } - - return ( - - - errors={errors} - object={form} - valueHandler={setValue} - > - - name="amount" - label={i18n.str`Amount`} - tooltip={i18n.str`amount of tip`} - /> - - name="justification" - label={i18n.str`Justification`} - inputType="multiline" - tooltip={i18n.str`reason for the tip`} - /> - - name="next_url" - label={i18n.str`URL after tip`} - tooltip={i18n.str`URL to visit after tip payment`} - /> - - - ); -} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/CreatedSuccessfully.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/CreatedSuccessfully.tsx index 643651b52..b78236bc7 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/CreatedSuccessfully.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/CreatedSuccessfully.tsx @@ -17,12 +17,13 @@ import { format } from "date-fns"; import { Fragment, h, VNode } from "preact"; import { CreatedSuccessfully as Template } from "../../../../components/notifications/CreatedSuccessfully.js"; import { MerchantBackend } from "../../../../declaration.js"; +import { datetimeFormatForSettings, useSettings } from "../../../../hooks/useSettings.js"; -type Entity = MerchantBackend.Tips.TipCreateConfirmation; +type Entity = MerchantBackend.Rewards.RewardCreateConfirmation; interface Props { entity: Entity; - request: MerchantBackend.Tips.TipCreateRequest; + request: MerchantBackend.Rewards.RewardCreateRequest; onConfirm: () => void; onCreateAnother?: () => void; } @@ -33,6 +34,7 @@ export function CreatedSuccessfully({ onConfirm, onCreateAnother, }: Props): VNode { + const [settings] = useSettings(); return (
@@ -66,7 +68,7 @@ export function CreatedSuccessfully({

- +

@@ -82,13 +84,13 @@ export function CreatedSuccessfully({ class="input" readonly value={ - !entity.tip_expiration || - entity.tip_expiration.t_s === "never" + !entity.reward_expiration || + entity.reward_expiration.t_s === "never" ? "never" : format( - entity.tip_expiration.t_s * 1000, - "yyyy/MM/dd HH:mm:ss", - ) + entity.reward_expiration.t_s * 1000, + datetimeFormatForSettings(settings), + ) } />

diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/List.stories.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/List.stories.tsx index fe305f4fd..b070bbde3 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/List.stories.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/List.stories.tsx @@ -25,12 +25,6 @@ import { CardTable as TestedComponent } from "./Table.js"; export default { title: "Pages/Reserve/List", component: TestedComponent, - argTypes: { - onCreate: { action: "onCreate" }, - onDelete: { action: "onDelete" }, - onNewTip: { action: "onNewTip" }, - onSelect: { action: "onSelect" }, - }, }; function createExample( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/Table.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/Table.tsx index 1f229d7cb..795e7ec82 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/Table.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/Table.tsx @@ -23,12 +23,13 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { format } from "date-fns"; import { Fragment, h, VNode } from "preact"; import { MerchantBackend, WithId } from "../../../../declaration.js"; +import { datetimeFormatForSettings, useSettings } from "../../../../hooks/useSettings.js"; -type Entity = MerchantBackend.Tips.ReserveStatusEntry & WithId; +type Entity = MerchantBackend.Rewards.ReserveStatusEntry & WithId; interface Props { instances: Entity[]; - onNewTip: (id: Entity) => void; + onNewReward: (id: Entity) => void; onSelect: (id: Entity) => void; onDelete: (id: Entity) => void; onCreate: () => void; @@ -38,7 +39,7 @@ export function CardTable({ instances, onCreate, onSelect, - onNewTip, + onNewReward, onDelete, }: Props): VNode { const [withoutFunds, withFunds] = instances.reduce((prev, current) => { @@ -70,7 +71,7 @@ export function CardTable({
@@ -108,7 +109,7 @@ export function CardTable({ {withFunds.length > 0 ? ( @@ -124,13 +125,14 @@ export function CardTable({ } interface TableProps { instances: Entity[]; - onNewTip: (id: Entity) => void; + onNewReward: (id: Entity) => void; onDelete: (id: Entity) => void; onSelect: (id: Entity) => void; } -function Table({ instances, onNewTip, onSelect, onDelete }: TableProps): VNode { +function Table({ instances, onNewReward, onSelect, onDelete }: TableProps): VNode { const { i18n } = useTranslationContext(); + const [settings] = useSettings(); return (
@@ -164,7 +166,7 @@ function Table({ instances, onNewTip, onSelect, onDelete }: TableProps): VNode { > {i.creation_time.t_s === "never" ? "never" - : format(i.creation_time.t_s * 1000, "yyyy/MM/dd HH:mm:ss")} + : format(i.creation_time.t_s * 1000, datetimeFormatForSettings(settings))} @@ -249,6 +251,7 @@ function TableWithoutFund({ onDelete, }: TableProps): VNode { const { i18n } = useTranslationContext(); + const [settings] = useSettings(); return (
onSelect(i)} @@ -173,9 +175,9 @@ function Table({ instances, onNewTip, onSelect, onDelete }: TableProps): VNode { {i.expiration_time.t_s === "never" ? "never" : format( - i.expiration_time.t_s * 1000, - "yyyy/MM/dd HH:mm:ss", - )} + i.expiration_time.t_s * 1000, + datetimeFormatForSettings(settings), + )} onSelect(i)} @@ -207,11 +209,11 @@ function Table({ instances, onNewTip, onSelect, onDelete }: TableProps): VNode {
@@ -276,7 +279,7 @@ function TableWithoutFund({ > {i.creation_time.t_s === "never" ? "never" - : format(i.creation_time.t_s * 1000, "yyyy/MM/dd HH:mm:ss")} + : format(i.creation_time.t_s * 1000, datetimeFormatForSettings(settings))}
onSelect(i)} @@ -285,9 +288,9 @@ function TableWithoutFund({ {i.expiration_time.t_s === "never" ? "never" : format( - i.expiration_time.t_s * 1000, - "yyyy/MM/dd HH:mm:ss", - )} + i.expiration_time.t_s * 1000, + datetimeFormatForSettings(settings), + )} onSelect(i)} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx index 14387c2a9..b26ff0000 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx @@ -34,9 +34,10 @@ import { useReservesAPI, } from "../../../../hooks/reserves.js"; import { Notification } from "../../../../utils/types.js"; -import { AuthorizeTipModal } from "./AutorizeTipModal.js"; +import { AuthorizeRewardModal } from "./AutorizeRewardModal.js"; import { CardTable } from "./Table.js"; import { HttpStatusCode } from "@gnu-taler/taler-util"; +import { ConfirmModal } from "../../../../components/modal/index.js"; interface Props { onUnauthorized: () => VNode; @@ -46,12 +47,12 @@ interface Props { onCreate: () => void; } -interface TipConfirmation { - response: MerchantBackend.Tips.TipCreateConfirmation; - request: MerchantBackend.Tips.TipCreateRequest; +interface RewardConfirmation { + response: MerchantBackend.Rewards.RewardCreateConfirmation; + request: MerchantBackend.Rewards.RewardCreateRequest; } -export default function ListTips({ +export default function ListRewards({ onUnauthorized, onLoadError, onNotFound, @@ -59,14 +60,16 @@ export default function ListTips({ onCreate, }: Props): VNode { const result = useInstanceReserves(); - const { deleteReserve, authorizeTipReserve } = useReservesAPI(); + const { deleteReserve, authorizeRewardReserve } = useReservesAPI(); const [notif, setNotif] = useState(undefined); const { i18n } = useTranslationContext(); - const [reserveForTip, setReserveForTip] = useState( + const [reserveForReward, setReserveForReward] = useState( undefined, ); - const [tipAuthorized, setTipAuthorized] = useState< - TipConfirmation | undefined + const [deleting, setDeleting] = + useState(null); + const [rewardAuthorized, setRewardAuthorized] = useState< + RewardConfirmation | undefined >(undefined); if (result.loading) return ; @@ -88,30 +91,30 @@ export default function ListTips({
- {reserveForTip && ( - { - setReserveForTip(undefined); - setTipAuthorized(undefined); + setReserveForReward(undefined); + setRewardAuthorized(undefined); }} - tipAuthorized={tipAuthorized} + rewardAuthorized={rewardAuthorized} onConfirm={async (request) => { try { - const response = await authorizeTipReserve( - reserveForTip, + const response = await authorizeRewardReserve( + reserveForReward, request, ); - setTipAuthorized({ + setRewardAuthorized({ request, response: response.data, }); } catch (error) { setNotif({ - message: i18n.str`could not create the tip`, + message: i18n.str`could not create the reward`, type: "ERROR", description: error instanceof Error ? error.message : undefined, }); - setReserveForTip(undefined); + setReserveForReward(undefined); } }} /> @@ -122,10 +125,47 @@ export default function ListTips({ .filter((r) => r.active) .map((o) => ({ ...o, id: o.reserve_pub }))} onCreate={onCreate} - onDelete={(reserve) => deleteReserve(reserve.reserve_pub)} + onDelete={(reserve) => { + setDeleting(reserve) + }} onSelect={(reserve) => onSelect(reserve.id)} - onNewTip={(reserve) => setReserveForTip(reserve.id)} + onNewReward={(reserve) => setReserveForReward(reserve.id)} /> + + {deleting && ( + setDeleting(null)} + onConfirm={async (): Promise => { + try { + await deleteReserve(deleting.reserve_pub); + setNotif({ + message: i18n.str`Reserve for "${deleting.merchant_initial_amount}" (ID: ${deleting.reserve_pub}) has been deleted`, + type: "SUCCESS", + }); + } catch (error) { + setNotif({ + message: i18n.str`Failed to delete reserve`, + type: "ERROR", + description: error instanceof Error ? error.message : undefined, + }); + } + setDeleting(null); + }} + > +

+ If you delete the reserve for "{deleting.merchant_initial_amount}" you won't be able to create more rewards.
+ Reserve ID: {deleting.reserve_pub} +

+

+ Deleting an template cannot be undone. +

+
+ )} +
); } -- cgit v1.2.3