From 7b5afb41336fe4557fe8872236122dea398d2cf8 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 9 Apr 2024 10:58:23 -0300 Subject: fix #8638 --- .../src/components/form/InputToggle.tsx | 2 +- .../paths/instance/templates/create/CreatePage.tsx | 249 ++++++++------------- .../src/paths/instance/templates/qr/QrPage.tsx | 77 +++---- .../paths/instance/templates/update/UpdatePage.tsx | 234 ++++++++----------- .../src/paths/instance/templates/use/UsePage.tsx | 11 +- .../merchant-backoffice-ui/src/scss/toggle.scss | 20 +- 6 files changed, 243 insertions(+), 350 deletions(-) (limited to 'packages/merchant-backoffice-ui') diff --git a/packages/merchant-backoffice-ui/src/components/form/InputToggle.tsx b/packages/merchant-backoffice-ui/src/components/form/InputToggle.tsx index 89b815b4b..8c935f33b 100644 --- a/packages/merchant-backoffice-ui/src/components/form/InputToggle.tsx +++ b/packages/merchant-backoffice-ui/src/components/form/InputToggle.tsx @@ -79,7 +79,7 @@ export function InputToggle({ disabled={readonly} onChange={onCheckboxClick} /> -
+
{help}

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 2ba637f44..ad36df3cc 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,7 +25,7 @@ import { Duration, TalerError, TalerMerchantApi, - assertUnreachable, + TranslatedString } from "@gnu-taler/taler-util"; import { useMerchantApiContext, @@ -42,18 +42,12 @@ 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 { InputTab } from "../../../../components/form/InputTab.js"; +import { InputSelector } from "../../../../components/form/InputSelector.js"; +import { InputToggle } from "../../../../components/form/InputToggle.js"; import { InputWithAddon } from "../../../../components/form/InputWithAddon.js"; +import { TextField } from "../../../../components/form/TextField.js"; import { useInstanceOtpDevices } from "../../../../hooks/otp.js"; -enum Steps { - BOTH_FIXED, - FIXED_PRICE, - FIXED_SUMMARY, - NON_FIXED, -} - // type Entity = TalerMerchantApi.TemplateAddDetails & { type: Steps }; type Entity = { id?: string; @@ -63,7 +57,9 @@ type Entity = { amount?: AmountString; minimum_age?: number; pay_duration?: Duration; - type: Steps; + summary_editable?: boolean; + amount_editable?: boolean; + currency_editable?: boolean; }; interface Props { @@ -81,9 +77,18 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { pay_duration: { d_ms: 1000 * 60 * 30, //30 min }, - type: Steps.NON_FIXED, }); + function updateState(up: (s: Partial) => Partial) { + setState((old) => { + const newState = up(old) + if (!newState.amount_editable) { + newState.currency_editable = false + } + return newState + }) + } + const parsedPrice = !state.amount ? undefined : Amounts.parse(state.amount); const errors: FormErrors = { @@ -93,24 +98,14 @@ 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.type === Steps.FIXED_PRICE || state.type === Steps.BOTH_FIXED - ) - ? undefined - : !state.amount - ? i18n.str`required` + amount: + !state.amount + ? undefined : !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.summary - ? i18n.str`required` - : undefined, minimum_age: state.minimum_age && state.minimum_age < 0 ? i18n.str`should be greater that 0` @@ -125,67 +120,33 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { }; const hasErrors = Object.keys(errors).some( - (k) => (errors as Record)[k] !== undefined, + (k) => (errors as Record)[k] !== undefined, ); 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); - // return onCreate(state); - } + if (hasErrors) return Promise.reject(); + 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_editable ? undefined : state.amount, + summary: state.summary_editable ? undefined : state.summary, + }, + editable_defaults: { + amount: !state.amount_editable ? undefined : state.amount, + summary: !state.summary_editable ? undefined : state.summary, + }, + 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) return (
@@ -194,7 +155,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
@@ -209,59 +170,36 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { help="" tooltip={i18n.str`Describe what this template stands for`} /> - - name="type" - label={i18n.str`Type`} - help={(() => { - 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.`; - } - })()} - 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`; - } - }} + + + name="summary" + inputType="multiline" + label={i18n.str`Summary`} + tooltip={i18n.str`If specified, this template will create order with the same summary`} /> - {state.type === Steps.BOTH_FIXED || - state.type === Steps.FIXED_SUMMARY ? ( - - 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 ? ( - - name="amount" - label={i18n.str`Fixed price`} - tooltip={i18n.str`If specified, this template will create order with the same price`} - /> - ) : undefined} + + name="summary_editable" + label={i18n.str`Summary is editable`} + tooltip={i18n.str`Allow the user to change the summary.`} + /> + + + name="amount" + label={i18n.str`Amount`} + tooltip={i18n.str`If specified, this template will create order with the same price`} + /> + + name="amount_editable" + 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.`} + /> */} + name="minimum_age" label={i18n.str`Minimum age`} @@ -274,33 +212,26 @@ 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 ? { - setState((v) => ({ ...v, otpId: undefined })); - }} - > - - remove - - - } - tooltip={i18n.str`Use to verify transaction in offline mode.`} - /> - setState((v) => ({ ...v, otpId: p?.id }))} - list={deviceList.map((e) => ({ - description: e.device_description, - id: e.otp_device_id, - }))} - /> + tooltip={i18n.str`Use to verify transaction while offline.`} + > + No OTP device. Add one first + : + + name="otpId" + label={i18n.str`OTP device`} + values={[undefined, ...deviceList.map(e => e.otp_device_id)]} + toStr={(v?: string) => { + if (!v) { + return i18n.str`No device` + } + return deviceMap[v] + }} + tooltip={i18n.str`Use to verify transaction in offline mode.`} + /> + }
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx index 0749f45d3..cd6b8b45c 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx @@ -46,79 +46,78 @@ export function QrPage({ contract, id: templateId, onBack }: Props): VNode { const { i18n } = useTranslationContext(); const { config, url: backendUrl } = useMerchantApiContext(); - const [state, setState] = useState>({ - amount: contract.amount, - summary: contract.summary, - }); + // const [state, setState] = useState>({ + // amount: contract.amount, + // summary: contract.summary, + // }); - const errors: FormErrors = {}; + // const errors: FormErrors = {}; - const fixedAmount = !!contract.amount; - const fixedSummary = !!contract.summary; + // 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; - } - } + // const templateParams: Record = {}; + // if (!fixedAmount) { + // if (state.amount) { + // templateParams.amount = state.amount; + // } else { + // templateParams.amount = config.currency; + // } + // } - if (!fixedSummary) { - templateParams.summary = state.summary ?? ""; - } + // if (!fixedSummary) { + // templateParams.summary = state.summary ?? ""; + // } const merchantBaseUrl = backendUrl.href; const payTemplateUri = stringifyPayTemplateUri({ merchantBaseUrl, templateId, - templateParams, + templateParams: {}, }); return (
+
+ +
+          {payTemplateUri}
+        
+
+
-

+ {/*

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} + label={i18n.str`Amount`} + readonly tooltip={i18n.str`Amount of the order`} /> name="summary" inputType="multiline" - readonly={fixedSummary} - label={ - fixedSummary - ? i18n.str`Fixed summary` - : i18n.str`Default summary` - } + readonly + label={i18n.str`Summary`} tooltip={i18n.str`Title of the order to be shown to the customer`} /> - + */}
{onBack && ( @@ -137,12 +136,6 @@ export function QrPage({ contract, id: templateId, onBack }: Props): VNode {
-
- -
-          {payTemplateUri}
-        
-
); } @@ -160,6 +153,6 @@ function saveAsPDF(name: string): void { printWindow.document.body.appendChild(divContents.cloneNode(true)); printWindow.addEventListener("load", () => { printWindow.print(); - printWindow.close(); + // printWindow.close(); }); } 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 b99549825..f9e2a3b01 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,7 +25,7 @@ import { Duration, TalerError, TalerMerchantApi, - assertUnreachable + TranslatedString } from "@gnu-taler/taler-util"; import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser"; import { VNode, h } from "preact"; @@ -39,17 +39,11 @@ 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 { InputTab } from "../../../../components/form/InputTab.js"; +import { InputSelector } from "../../../../components/form/InputSelector.js"; +import { InputToggle } from "../../../../components/form/InputToggle.js"; +import { TextField } from "../../../../components/form/TextField.js"; import { useInstanceOtpDevices } from "../../../../hooks/otp.js"; -enum Steps { - BOTH_FIXED, - FIXED_PRICE, - FIXED_SUMMARY, - NON_FIXED, -} - type Entity = { description?: string, otpId?: string | null, @@ -57,6 +51,9 @@ type Entity = { amount?: AmountString, minimum_age?: number, pay_duration?: Duration, + summary_editable?: boolean; + amount_editable?: boolean; + currency_editable?: boolean; }; interface Props { @@ -70,26 +67,35 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { const { url: backendUrl } = useMerchantApiContext(); - 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>({ - amount: template.template_contract.amount as AmountString | undefined, + 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.template_contract.summary, - type: intialStep, + 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, }); + + function updateState(up: (s: Partial) => Partial) { + setState((old) => { + const newState = up(old) + if (!newState.amount_editable) { + newState.currency_editable = false + } + 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 parsedPrice = !state.amount ? undefined @@ -99,20 +105,14 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { 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` + amount: + !state.amount + ? undefined : !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.summary - ? i18n.str`required` - : undefined, minimum_age: state.minimum_age && state.minimum_age < 0 ? i18n.str`should be greater that 0` @@ -127,54 +127,26 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { }; const hasErrors = Object.keys(errors).some( - (k) => (errors as Record)[k] !== undefined, + (k) => (errors as Record)[k] !== undefined, ); const submitForm = () => { - if (hasErrors || state.type === undefined) return Promise.reject(); - switch (state.type) { - case Steps.FIXED_PRICE: return onUpdate({ - 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 onUpdate({ - 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 onUpdate({ - 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 onUpdate({ - 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) - } + if (hasErrors) return Promise.reject(); + return onUpdate({ + template_description: state.description!, + template_contract: { + minimum_age: state.minimum_age!, + pay_duration: Duration.toTalerProtocolDuration(state.pay_duration!), + amount: state.amount_editable ? undefined : state.amount, + summary: state.summary_editable ? undefined : state.summary, + }, + editable_defaults: { + amount: !state.amount_editable ? undefined : state.amount, + summary: !state.summary_editable ? undefined : state.summary, + }, + otp_id: state.otpId!, + }) + }; @@ -187,7 +159,7 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
- {new URL(`templates/${template.id}`,backendUrl.href).href} + {new URL(`templates/${template.id}`, backendUrl.href).href}
@@ -201,7 +173,7 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
@@ -211,48 +183,33 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode { 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` - } - }} + + name="summary" + inputType="multiline" + label={i18n.str`Summary`} + tooltip={i18n.str`If specified, this template will create order with the same summary`} /> - {state.type === Steps.BOTH_FIXED || state.type === Steps.FIXED_SUMMARY ? - - 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 ? - - name="amount" - label={i18n.str`Fixed price`} - tooltip={i18n.str`If specified, this template will create order with the same price`} - /> - : undefined} + + name="summary_editable" + label={i18n.str`Summary is editable`} + tooltip={i18n.str`Allow the user to change the summary.`} + /> + + name="amount" + label={i18n.str`Amount`} + tooltip={i18n.str`If specified, this template will create order with the same price`} + /> + + name="amount_editable" + 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.`} + /> */} name="minimum_age" label={i18n.str`Minimum age`} @@ -265,31 +222,26 @@ 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 ? { - setState((v) => ({ ...v, otpId: null })); + tooltip={i18n.str`Use to verify transaction while offline.`} + > + No OTP device. Add one first + : + + name="otpId" + label={i18n.str`OTP device`} + values={[undefined, ...deviceList.map(e => e.otp_device_id)]} + toStr={(v?: string) => { + if (!v) { + return i18n.str`No device` + } + return deviceMap[v] }} - > - - remove - - } - tooltip={i18n.str`Use to verify transaction in offline mode.`} - /> - setState((v) => ({ ...v, otpId: p?.id }))} - list={deviceList.map(e => ({ - description: e.device_description, - id: e.otp_device_id - }))} - /> + tooltip={i18n.str`Use to verify transaction in offline mode.`} + /> + }
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx index 58e63cc8e..360c9d373 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx @@ -31,7 +31,7 @@ import { import { Input } from "../../../../components/form/Input.js"; import { InputCurrency } from "../../../../components/form/InputCurrency.js"; -type Entity = TalerMerchantApi.UsingTemplateDetails; +type Entity = TalerMerchantApi.TemplateContractDetails; interface Props { id: string; @@ -44,17 +44,18 @@ 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, + currency: template.editable_defaults?.currency ?? template.template_contract.currency, + amount: template.editable_defaults?.amount ?? template.template_contract.amount, + summary: template.editable_defaults?.summary ?? template.template_contract.summary, }); const errors: FormErrors = { amount: - !template.template_contract.amount && !state.amount + !state.amount ? i18n.str`Amount is required` : undefined, summary: - !template.template_contract.summary && !state.summary + !state.summary ? i18n.str`Order summary is required` : undefined, }; diff --git a/packages/merchant-backoffice-ui/src/scss/toggle.scss b/packages/merchant-backoffice-ui/src/scss/toggle.scss index 24636da2f..6c7346eb3 100644 --- a/packages/merchant-backoffice-ui/src/scss/toggle.scss +++ b/packages/merchant-backoffice-ui/src/scss/toggle.scss @@ -4,6 +4,7 @@ $green: #56c080; cursor: pointer; display: inline-block; } + .toggle-switch { display: inline-block; background: #ccc; @@ -13,10 +14,12 @@ $green: #56c080; position: relative; vertical-align: middle; transition: background 0.25s; + &:before, &:after { content: ""; } + &:before { display: block; background: linear-gradient(to bottom, #fff 0%, #eee 100%); @@ -29,23 +32,36 @@ $green: #56c080; left: 4px; transition: left 0.25s; } + .toggle:hover &:before { background: linear-gradient(to bottom, #fff 0%, #fff 100%); box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5); } - .toggle-checkbox:checked + & { + + &.disabled:before { + background: linear-gradient(to bottom, #ccc 0%, #bbb 100%); + } + + .toggle:hover &.disabled:before { + background: linear-gradient(to bottom, #ccc 0%, #bbb 100%); + } + + .toggle-checkbox:checked+& { background: $green; + &:before { left: 30px; } } } + .toggle-checkbox { position: absolute; visibility: hidden; } + .toggle-label { margin-left: 5px; position: relative; top: 2px; -} +} \ No newline at end of file -- cgit v1.2.3