From a08ad2c631da0283a5e10189d06977a96665afae Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 9 Apr 2024 11:20:32 -0300 Subject: fix #8638 --- .../paths/instance/templates/create/CreatePage.tsx | 112 +++++++++------ .../paths/instance/templates/update/UpdatePage.tsx | 153 +++++++++++++-------- 2 files changed, 164 insertions(+), 101 deletions(-) (limited to 'packages/merchant-backoffice-ui') diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx index ad36df3cc..90854d820 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx @@ -25,13 +25,13 @@ import { Duration, TalerError, TalerMerchantApi, - TranslatedString + TranslatedString, } from "@gnu-taler/taler-util"; import { useMerchantApiContext, - useTranslationContext + useTranslationContext, } from "@gnu-taler/web-util/browser"; -import { VNode, h } from "preact"; +import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; import { AsyncButton } from "../../../../components/exception/AsyncButton.js"; import { @@ -69,7 +69,7 @@ interface Props { export function CreatePage({ onCreate, onBack }: Props): VNode { const { i18n } = useTranslationContext(); - const { url: backendUrl } = useMerchantApiContext(); + const { url: backendUrl, config } = useMerchantApiContext(); const devices = useInstanceOtpDevices(); const [state, setState] = useState>({ @@ -81,12 +81,12 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { function updateState(up: (s: Partial) => Partial) { setState((old) => { - const newState = up(old) + const newState = up(old); if (!newState.amount_editable) { - newState.currency_editable = false + newState.currency_editable = false; } - return newState - }) + return newState; + }); } const parsedPrice = !state.amount ? undefined : Amounts.parse(state.amount); @@ -98,14 +98,13 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { ? i18n.str`no valid. only characters and numbers` : undefined, description: !state.description ? i18n.str`should not be empty` : undefined, - amount: - !state.amount - ? undefined - : !parsedPrice - ? i18n.str`not valid` - : Amounts.isZero(parsedPrice) - ? i18n.str`must be greater than 0` - : undefined, + amount: !state.amount + ? undefined + : !parsedPrice + ? i18n.str`not valid` + : Amounts.isZero(parsedPrice) + ? i18n.str`must be greater than 0` + : undefined, minimum_age: state.minimum_age && state.minimum_age < 0 ? i18n.str`should be greater that 0` @@ -119,6 +118,8 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { : undefined, }; + const cList = Object.values(config.currencies).map((d) => d.name); + const hasErrors = Object.keys(errors).some( (k) => (errors as Record)[k] !== undefined, ); @@ -133,20 +134,33 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { pay_duration: Duration.toTalerProtocolDuration(state.pay_duration!), amount: state.amount_editable ? undefined : state.amount, summary: state.summary_editable ? undefined : state.summary, + currency: + cList.length > 1 && state.currency_editable + ? undefined + : config.currency, }, editable_defaults: { amount: !state.amount_editable ? undefined : state.amount, summary: !state.summary_editable ? undefined : state.summary, + currency: + cList.length === 1 || !state.currency_editable + ? undefined + : config.currency, }, otp_id: state.otpId!, }); - }; - const deviceList = !devices || devices instanceof TalerError || devices.type === "fail" ? [] : devices.body; - const deviceMap = deviceList.reduce((prev, cur) => { - prev[cur.otp_device_id] = cur.device_description as TranslatedString - return prev - }, {} as Record) + const deviceList = + !devices || devices instanceof TalerError || devices.type === "fail" + ? [] + : devices.body; + const deviceMap = deviceList.reduce( + (prev, cur) => { + prev[cur.otp_device_id] = cur.device_description as TranslatedString; + return prev; + }, + {} as Record, + ); return (
@@ -160,7 +174,9 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { > name="id" - help={new URL(`templates/${state.id ?? ""}`, backendUrl.href).href} + help={ + new URL(`templates/${state.id ?? ""}`, backendUrl.href).href + } label={i18n.str`Identifier`} tooltip={i18n.str`Name of the template in URLs.`} /> @@ -193,13 +209,19 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { label={i18n.str`Amount is editable`} tooltip={i18n.str`Allow the user to select the amount to pay.`} /> - {/* - name="currency_editable" - readonly={!state.amount_editable} - label={i18n.str`Currency is editable`} - tooltip={i18n.str`Allow the user to change currency.`} - /> */} - + {cList.length > 1 && ( + + + name="currency_editable" + readonly={!state.amount_editable} + label={i18n.str`Currency is editable`} + tooltip={i18n.str`Allow the user to change currency.`} + /> + + supported currencies: {cList.join(", ")} + + + )} name="minimum_age" label={i18n.str`Minimum age`} @@ -212,26 +234,34 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { help="" tooltip={i18n.str`How much time has the customer to complete the payment once the order was created.`} /> - {!deviceList.length ? - No OTP device. Add one first - : + {!deviceList.length ? ( + + No OTP device.  + + Add one first + + + ) : ( name="otpId" label={i18n.str`OTP device`} - values={[undefined, ...deviceList.map(e => e.otp_device_id)]} + values={[ + undefined, + ...deviceList.map((e) => e.otp_device_id), + ]} toStr={(v?: string) => { if (!v) { - return i18n.str`No device` + return i18n.str`No device`; } - return deviceMap[v] + return deviceMap[v]; }} tooltip={i18n.str`Use to verify transaction in offline mode.`} /> - } + )}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx index f9e2a3b01..3a32409a0 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx @@ -25,10 +25,13 @@ import { Duration, TalerError, TalerMerchantApi, - TranslatedString + TranslatedString, } from "@gnu-taler/taler-util"; -import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser"; -import { VNode, h } from "preact"; +import { + useMerchantApiContext, + 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 { @@ -45,12 +48,12 @@ import { TextField } from "../../../../components/form/TextField.js"; import { useInstanceOtpDevices } from "../../../../hooks/otp.js"; type Entity = { - description?: string, - otpId?: string | null, - summary?: string, - amount?: AmountString, - minimum_age?: number, - pay_duration?: Duration, + description?: string; + otpId?: string | null; + summary?: string; + amount?: AmountString; + minimum_age?: number; + pay_duration?: Duration; summary_editable?: boolean; amount_editable?: boolean; currency_editable?: boolean; @@ -64,17 +67,22 @@ interface Props { export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { const { i18n } = useTranslationContext(); - const { url: backendUrl } = useMerchantApiContext(); - - + const { url: backendUrl, config } = useMerchantApiContext(); const [state, setState] = useState>({ description: template.template_description, minimum_age: template.template_contract.minimum_age, otpId: template.otp_id, - pay_duration: template.template_contract.pay_duration ? Duration.fromTalerProtocolDuration(template.template_contract.pay_duration) : undefined, - summary: template.editable_defaults?.summary ?? template.template_contract.summary, - amount: template.editable_defaults?.amount ?? template.template_contract.amount as AmountString | undefined, + pay_duration: template.template_contract.pay_duration + ? Duration.fromTalerProtocolDuration( + template.template_contract.pay_duration, + ) + : undefined, + summary: + template.editable_defaults?.summary ?? template.template_contract.summary, + amount: + template.editable_defaults?.amount ?? + (template.template_contract.amount as AmountString | undefined), currency_editable: !!template.editable_defaults?.currency, summary_editable: !!template.editable_defaults?.summary, amount_editable: !!template.editable_defaults?.amount, @@ -82,37 +90,38 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { function updateState(up: (s: Partial) => Partial) { setState((old) => { - const newState = up(old) + const newState = up(old); if (!newState.amount_editable) { - newState.currency_editable = false + newState.currency_editable = false; } - return newState - }) + return newState; + }); } - const devices = useInstanceOtpDevices() - const deviceList = !devices || devices instanceof TalerError || devices.type === "fail" ? [] : devices.body - const deviceMap = deviceList.reduce((prev, cur) => { - prev[cur.otp_device_id] = cur.device_description as TranslatedString - return prev - }, {} as Record) + const devices = useInstanceOtpDevices(); + const deviceList = + !devices || devices instanceof TalerError || devices.type === "fail" + ? [] + : devices.body; + const deviceMap = deviceList.reduce( + (prev, cur) => { + prev[cur.otp_device_id] = cur.device_description as TranslatedString; + return prev; + }, + {} as Record, + ); - const parsedPrice = !state.amount - ? undefined - : Amounts.parse(state.amount); + const parsedPrice = !state.amount ? undefined : Amounts.parse(state.amount); const errors: FormErrors = { - description: !state.description - ? i18n.str`should not be empty` - : undefined, - amount: - !state.amount - ? undefined - : !parsedPrice - ? i18n.str`not valid` - : Amounts.isZero(parsedPrice) - ? i18n.str`must be greater than 0` - : undefined, + description: !state.description ? i18n.str`should not be empty` : undefined, + amount: !state.amount + ? undefined + : !parsedPrice + ? i18n.str`not valid` + : Amounts.isZero(parsedPrice) + ? i18n.str`must be greater than 0` + : undefined, minimum_age: state.minimum_age && state.minimum_age < 0 ? i18n.str`should be greater that 0` @@ -126,6 +135,8 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { : undefined, }; + const cList = Object.values(config.currencies).map((d) => d.name); + const hasErrors = Object.keys(errors).some( (k) => (errors as Record)[k] !== undefined, ); @@ -139,17 +150,23 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { pay_duration: Duration.toTalerProtocolDuration(state.pay_duration!), amount: state.amount_editable ? undefined : state.amount, summary: state.summary_editable ? undefined : state.summary, + currency: + cList.length > 1 && state.currency_editable + ? undefined + : config.currency, }, editable_defaults: { amount: !state.amount_editable ? undefined : state.amount, summary: !state.summary_editable ? undefined : state.summary, + currency: + cList.length === 1 || !state.currency_editable + ? undefined + : config.currency, }, otp_id: state.otpId!, - }) - + }); }; - return (
@@ -176,7 +193,6 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { valueHandler={updateState} errors={errors} > - name="description" label={i18n.str`Description`} @@ -204,12 +220,21 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { label={i18n.str`Amount is editable`} tooltip={i18n.str`Allow the user to select the amount to pay.`} /> - {/* - name="currency_editable" - readonly={!state.amount_editable} - label={i18n.str`Currency is editable`} - tooltip={i18n.str`Allow the user to change currency.`} - /> */} + {cList.length > 1 && ( + + + name="currency_editable" + readonly={!state.amount_editable} + label={i18n.str`Currency is editable`} + tooltip={i18n.str`Allow the user to change currency.`} + /> + + + supported currencies: {cList.join(", ")} + + + + )} name="minimum_age" label={i18n.str`Minimum age`} @@ -222,26 +247,34 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { help="" tooltip={i18n.str`How much time has the customer to complete the payment once the order was created.`} /> - {!deviceList.length ? - No OTP device. Add one first - : + {!deviceList.length ? ( + + No OTP device.  + + Add one first + + + ) : ( name="otpId" label={i18n.str`OTP device`} - values={[undefined, ...deviceList.map(e => e.otp_device_id)]} + values={[ + undefined, + ...deviceList.map((e) => e.otp_device_id), + ]} toStr={(v?: string) => { if (!v) { - return i18n.str`No device` + return i18n.str`No device`; } - return deviceMap[v] + return deviceMap[v]; }} tooltip={i18n.str`Use to verify transaction in offline mode.`} /> - } + )}
-- cgit v1.2.3