diff options
Diffstat (limited to 'packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx')
-rw-r--r-- | packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx | 218 |
1 files changed, 118 insertions, 100 deletions
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 d27f6a022..b07582252 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 @@ -23,11 +23,12 @@ import { AmountString, Amounts, Duration, - MerchantTemplateContractDetails, assertUnreachable, } from "@gnu-taler/taler-util"; -import { useTranslationContext } from "@gnu-taler/web-util/browser"; -import { Fragment, VNode, h } from "preact"; +import { + useTranslationContext +} from "@gnu-taler/web-util/browser"; +import { VNode, h } from "preact"; import { useState } from "preact/hooks"; import { AsyncButton } from "../../../../components/exception/AsyncButton.js"; import { @@ -39,12 +40,11 @@ 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 { InputTab } from "../../../../components/form/InputTab.js"; import { InputWithAddon } from "../../../../components/form/InputWithAddon.js"; -import { useBackendContext } from "../../../../context/backend.js"; +import { useSessionContext } from "../../../../context/session.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, @@ -55,14 +55,14 @@ enum Steps { // type Entity = MerchantBackend.Template.TemplateAddDetails & { type: Steps }; type Entity = { - id?: string, - description?: string, - otpId?: string, - summary?: string, - amount?: AmountString, - minimum_age?: number, - pay_duration?: Duration, - type: Steps, + id?: string; + description?: string; + otpId?: string; + summary?: string; + amount?: AmountString; + minimum_age?: number; + pay_duration?: Duration; + type: Steps; }; interface Props { @@ -72,8 +72,10 @@ interface Props { export function CreatePage({ onCreate, onBack }: Props): VNode { const { i18n } = useTranslationContext(); - const { url: backendURL } = useBackendContext() - const devices = useInstanceOtpDevices() + const { + state: { backendUrl }, + } = useSessionContext(); + const devices = useInstanceOtpDevices(); const [state, setState] = useState<Partial<Entity>>({ minimum_age: 0, @@ -83,9 +85,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { type: Steps.NON_FIXED, }); - const parsedPrice = !state.amount - ? undefined - : Amounts.parse(state.amount); + const parsedPrice = !state.amount ? undefined : Amounts.parse(state.amount); const errors: FormErrors<Entity> = { id: !state.id @@ -93,10 +93,10 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { : !/[a-zA-Z0-9]*/.test(state.id) ? i18n.str`no valid. only characters and numbers` : undefined, - description: !state.description - ? i18n.str`should not be empty` - : undefined, - amount: !(state.type === Steps.FIXED_PRICE || state.type === Steps.BOTH_FIXED) + description: !state.description ? i18n.str`should not be empty` : undefined, + amount: !( + state.type === Steps.FIXED_PRICE || state.type === Steps.BOTH_FIXED + ) ? undefined : !state.amount ? i18n.str`required` @@ -105,7 +105,9 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { : Amounts.isZero(parsedPrice) ? i18n.str`must be greater than 0` : undefined, - summary: !(state.type === Steps.FIXED_SUMMARY || state.type === Steps.BOTH_FIXED) + summary: !( + state.type === Steps.FIXED_SUMMARY || state.type === Steps.BOTH_FIXED + ) ? undefined : !state.summary ? i18n.str`required` @@ -130,55 +132,60 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { const submitForm = () => { if (hasErrors || state.type === undefined) return Promise.reject(); switch (state.type) { - case Steps.FIXED_PRICE: return onCreate({ - template_id: state.id!, - template_description: state.description!, - template_contract: { - minimum_age: state.minimum_age!, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration!), - amount: state.amount!, - // summary: state.summary, - }, - otp_id: state.otpId! - }) - case Steps.FIXED_SUMMARY: return onCreate({ - template_id: state.id!, - template_description: state.description!, - template_contract: { - minimum_age: state.minimum_age!, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration!), - // amount: state.amount!, - summary: state.summary, - }, - otp_id: state.otpId!, - }) - case Steps.NON_FIXED: return onCreate({ - template_id: state.id!, - template_description: state.description!, - template_contract: { - minimum_age: state.minimum_age!, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration!), - // amount: state.amount!, - // summary: state.summary, - }, - otp_id: state.otpId!, - }) - case Steps.BOTH_FIXED: return onCreate({ - template_id: state.id!, - template_description: state.description!, - template_contract: { - minimum_age: state.minimum_age!, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration!), - amount: state.amount!, - summary: state.summary, - }, - otp_id: state.otpId!, - }) - default: assertUnreachable(state.type) + case Steps.FIXED_PRICE: + return onCreate({ + template_id: state.id!, + template_description: state.description!, + template_contract: { + minimum_age: state.minimum_age!, + pay_duration: Duration.toTalerProtocolDuration(state.pay_duration!), + amount: state.amount!, + // summary: state.summary, + }, + otp_id: state.otpId!, + }); + case Steps.FIXED_SUMMARY: + return onCreate({ + template_id: state.id!, + template_description: state.description!, + template_contract: { + minimum_age: state.minimum_age!, + pay_duration: Duration.toTalerProtocolDuration(state.pay_duration!), + // amount: state.amount!, + summary: state.summary, + }, + otp_id: state.otpId!, + }); + case Steps.NON_FIXED: + return onCreate({ + template_id: state.id!, + template_description: state.description!, + template_contract: { + minimum_age: state.minimum_age!, + pay_duration: Duration.toTalerProtocolDuration(state.pay_duration!), + // amount: state.amount!, + // summary: state.summary, + }, + otp_id: state.otpId!, + }); + case Steps.BOTH_FIXED: + return onCreate({ + template_id: state.id!, + template_description: state.description!, + template_contract: { + minimum_age: state.minimum_age!, + pay_duration: Duration.toTalerProtocolDuration(state.pay_duration!), + amount: state.amount!, + summary: state.summary, + }, + otp_id: state.otpId!, + }); + default: + assertUnreachable(state.type); // return onCreate(state); - }; - } - const deviceList = !devices.ok ? [] : devices.data.otp_devices + } + }; + const deviceList = !devices.ok ? [] : devices.data.otp_devices; return ( <div> @@ -193,7 +200,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { > <InputWithAddon<Entity> name="id" - help={`${backendURL}/templates/${state.id ?? ""}`} + help={new URL(`templates/${state.id ?? ""}`, backendUrl).href} label={i18n.str`Identifier`} tooltip={i18n.str`Name of the template in URLs.`} /> @@ -207,12 +214,16 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { name="type" label={i18n.str`Type`} help={(() => { - if (state.type === undefined) return "" + if (state.type === undefined) return ""; 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.` + 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`} @@ -224,28 +235,34 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { ]} 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` + 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 ? + {state.type === Steps.BOTH_FIXED || + state.type === Steps.FIXED_SUMMARY ? ( <Input<Entity> name="summary" inputType="multiline" label={i18n.str`Fixed summary`} tooltip={i18n.str`If specified, this template will create order with the same summary`} /> - : undefined} - {state.type === Steps.BOTH_FIXED || state.type === Steps.FIXED_PRICE ? + ) : undefined} + {state.type === Steps.BOTH_FIXED || + state.type === Steps.FIXED_PRICE ? ( <InputCurrency<Entity> name="amount" label={i18n.str`Fixed price`} tooltip={i18n.str`If specified, this template will create order with the same price`} /> - : undefined} + ) : undefined} <InputNumber<Entity> name="minimum_age" label={i18n.str`Minimum age`} @@ -262,28 +279,29 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { name="otpId" label={i18n.str`OTP device`} readonly - side={<button - class="button is-danger" - data-tooltip={i18n.str`without otp device`} - onClick={(): void => { - setState((v) => ({ ...v, otpId: undefined })); - }} - > - <span> - <i18n.Translate>remove</i18n.Translate> - </span> - </button>} + side={ + <button + class="button is-danger" + data-tooltip={i18n.str`without otp device`} + onClick={(): void => { + setState((v) => ({ ...v, otpId: undefined })); + }} + > + <span> + <i18n.Translate>remove</i18n.Translate> + </span> + </button> + } tooltip={i18n.str`Use to verify transaction in offline mode.`} /> <InputSearchOnList label={i18n.str`Search device`} onChange={(p) => setState((v) => ({ ...v, otpId: p?.id }))} - list={deviceList.map(e => ({ + list={deviceList.map((e) => ({ description: e.device_description, - id: e.otp_device_id + id: e.otp_device_id, }))} /> - </FormProvider> <div class="buttons is-right mt-5"> |