commit aafa58dd95ef7785dfb454a45e2c08eb0ed6fdf9 parent cd358984ccc2f1efcd7970a7f63c2ad6e65a6774 Author: Sebastian <sebasjm@gmail.com> Date: Tue, 9 Jul 2024 15:08:39 -0300 removed yup and some i18n strings Diffstat:
16 files changed, 184 insertions(+), 348 deletions(-)
diff --git a/packages/merchant-backoffice-ui/package.json b/packages/merchant-backoffice-ui/package.json @@ -27,8 +27,7 @@ "preact": "10.11.3", "preact-router": "3.2.1", "qrcode-generator": "1.4.4", - "swr": "2.2.2", - "yup": "^0.32.9" + "swr": "2.2.2" }, "devDependencies": { "eslint": "^8.56.0", diff --git a/packages/merchant-backoffice-ui/src/components/form/InputTaxes.tsx b/packages/merchant-backoffice-ui/src/components/form/InputTaxes.tsx @@ -18,57 +18,43 @@ * * @author Sebastian Javier Marchano (sebasjm) */ +import { Amounts, TalerMerchantApi } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { h, VNode } from "preact"; import { useCallback, useState } from "preact/hooks"; -import * as yup from "yup"; -import { TaxSchema as schema } from "../../schemas/index.js"; -import { FormErrors, FormProvider } from "./FormProvider.js"; +import { undefinedIfEmpty } from "../../utils/table.js"; +import { FormProvider } from "./FormProvider.js"; import { Input } from "./Input.js"; import { InputGroup } from "./InputGroup.js"; import { InputProps, useField } from "./useField.js"; -import { TalerMerchantApi } from "@gnu-taler/taler-util"; export interface Props<T> extends InputProps<T> { isValid?: (e: any) => boolean; } type Entity = TalerMerchantApi.Tax; -export function InputTaxes<T>({ - name, - readonly, - label, -}: Props<keyof T>): VNode { +export function InputTaxes<T>({ name, label }: Props<keyof T>): VNode { const { value: taxes, onChange } = useField<T>(name); + const { i18n } = useTranslationContext(); const [value, valueHandler] = useState<Partial<Entity>>({}); - // const [errors, setErrors] = useState<FormErrors<Entity>>({}) - let errors: FormErrors<Entity> = {}; + const errors = undefinedIfEmpty({ + name: !value.name ? i18n.str`required` : undefined, + tax: !value.tax + ? i18n.str`required` + : Amounts.parse(value.tax) === undefined + ? i18n.str`invalid` + : undefined, + }); - try { - schema.validateSync(value, { abortEarly: false }); - } catch (err) { - if (err instanceof yup.ValidationError) { - const yupErrors = err.inner as yup.ValidationError[]; - 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 hasErrors = errors === undefined; const submit = useCallback((): void => { onChange([value as any, ...taxes] as any); valueHandler({}); }, [value]); - const { i18n } = useTranslationContext(); - //FIXME: translating plural singular return ( <InputGroup @@ -76,7 +62,11 @@ export function InputTaxes<T>({ label={label} alternative={ taxes.length > 0 && ( - <p>This product has {taxes.length} applicable taxes configured.</p> + <p> + <i18n.Translate> + This product has {taxes.length} applicable taxes configured. + </i18n.Translate> + </p> ) } > diff --git a/packages/merchant-backoffice-ui/src/components/modal/index.tsx b/packages/merchant-backoffice-ui/src/components/modal/index.tsx @@ -19,14 +19,6 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/browser"; -import { ComponentChildren, Fragment, h, VNode } from "preact"; -import { useState } from "preact/hooks"; -import { DEFAULT_REQUEST_TIMEOUT } from "../../utils/constants.js"; -import { Spinner } from "../exception/loading.js"; -import { FormErrors, FormProvider } from "../form/FormProvider.js"; -import { Input } from "../form/Input.js"; -import { useSessionContext } from "../../context/session.js"; import { AccountLetter, codecForAccountLetter, @@ -34,6 +26,15 @@ import { PaytoUri, stringifyPaytoUri, } from "@gnu-taler/taler-util"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { ComponentChildren, Fragment, h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { useSessionContext } from "../../context/session.js"; +import { DEFAULT_REQUEST_TIMEOUT } from "../../utils/constants.js"; +import { undefinedIfEmpty } from "../../utils/table.js"; +import { Spinner } from "../exception/loading.js"; +import { FormErrors, FormProvider } from "../form/FormProvider.js"; +import { Input } from "../form/Input.js"; interface Props { active?: boolean; @@ -505,7 +506,7 @@ export function UpdateTokenModal({ const { i18n } = useTranslationContext(); const hasInputTheCorrectOldToken = oldToken && oldToken !== form.old_token; - const errors = { + const errors = undefinedIfEmpty({ old_token: hasInputTheCorrectOldToken ? i18n.str`is not the same as the current access token` : undefined, @@ -518,11 +519,9 @@ export function UpdateTokenModal({ form.new_token !== form.repeat_token ? i18n.str`is not the same` : undefined, - }; + }); - const hasErrors = Object.keys(errors).some( - (k) => (errors as any)[k] !== undefined, - ); + const hasErrors = errors === undefined; const { state } = useSessionContext(); diff --git a/packages/merchant-backoffice-ui/src/components/product/NonInventoryProductForm.tsx b/packages/merchant-backoffice-ui/src/components/product/NonInventoryProductForm.tsx @@ -13,19 +13,19 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { AmountString, TalerMerchantApi } from "@gnu-taler/taler-util"; +import { AmountString, Amounts, TalerMerchantApi } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, h, VNode } from "preact"; import { useCallback, useEffect, useState } from "preact/hooks"; import * as yup from "yup"; import { useListener } from "../../hooks/listener.js"; -import { NonInventoryProductSchema as schema } from "../../schemas/index.js"; import { FormErrors, FormProvider } from "../form/FormProvider.js"; import { Input } from "../form/Input.js"; import { InputCurrency } from "../form/InputCurrency.js"; import { InputImage } from "../form/InputImage.js"; import { InputNumber } from "../form/InputNumber.js"; import { InputTaxes } from "../form/InputTaxes.js"; +import { undefinedIfEmpty } from "../../utils/table.js"; type Entity = TalerMerchantApi.Product; @@ -140,38 +140,40 @@ interface NonInventoryProduct { } export function ProductForm({ onSubscribe, initial }: ProductProps): VNode { + const { i18n } = useTranslationContext(); const [value, valueHandler] = useState<Partial<NonInventoryProduct>>({ taxes: [], ...initial, }); - let errors: FormErrors<NonInventoryProduct> = {}; - try { - schema.validateSync(value, { abortEarly: false }); - } catch (err) { - if (err instanceof yup.ValidationError) { - const yupErrors = err.inner as yup.ValidationError[]; - errors = yupErrors.reduce( - (prev, cur) => - !cur.path ? prev : { ...prev, [cur.path]: cur.message }, - {}, - ); - } - } + // let errors: FormErrors<NonInventoryProduct> = {}; + const errors: FormErrors<NonInventoryProduct> | undefined = undefinedIfEmpty({ + quantity: + value.quantity === undefined + ? i18n.str`required` + : typeof value.quantity !== "number" + ? i18n.str`should be a number` + : value.quantity < 1 + ? i18n.str`should be grater than 0` + : undefined, + description: !value.description ? i18n.str`required` : undefined, + unit: !value.description ? i18n.str`required` : undefined, + price: !value.price + ? i18n.str`required` + : Amounts.parse(value.price) === undefined + ? i18n.str`invalid` + : undefined, + }); const submit = useCallback((): Entity | undefined => { return value as TalerMerchantApi.Product; }, [value]); - const hasErrors = Object.keys(errors).some( - (k) => (errors as any)[k] !== undefined, - ); + const hasErrors = errors === undefined; useEffect(() => { onSubscribe(hasErrors ? undefined : submit); }, [submit, hasErrors]); - const { i18n } = useTranslationContext(); - return ( <div> <FormProvider<NonInventoryProduct> diff --git a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx @@ -19,17 +19,13 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { AmountString, TalerMerchantApi } from "@gnu-taler/taler-util"; +import { AmountString, Amounts, TalerMerchantApi } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { h } from "preact"; import { useCallback, useEffect, useState } from "preact/hooks"; -import * as yup from "yup"; import { useSessionContext } from "../../context/session.js"; -import { - ProductCreateSchema as createSchema, - ProductUpdateSchema as updateSchema, -} from "../../schemas/index.js"; -import { FormErrors, FormProvider } from "../form/FormProvider.js"; +import { undefinedIfEmpty } from "../../utils/table.js"; +import { FormProvider } from "../form/FormProvider.js"; import { Input } from "../form/Input.js"; import { InputCurrency } from "../form/InputCurrency.js"; import { InputImage } from "../form/InputImage.js"; @@ -47,6 +43,9 @@ interface Props { } export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) { + const { i18n } = useTranslationContext(); + const { state } = useSessionContext(); + const [value, valueHandler] = useState<Partial<Entity & { stock: Stock }>>({ address: {}, description_i18n: {}, @@ -65,25 +64,30 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) { nextRestock: initial.next_restock, }, }); - let errors: FormErrors<Entity> = {}; - - try { - (alreadyExist ? updateSchema : createSchema).validateSync(value, { - abortEarly: false, - }); - } catch (err) { - if (err instanceof yup.ValidationError) { - const yupErrors = err.inner as yup.ValidationError[]; - errors = yupErrors.reduce( - (prev, cur) => - !cur.path ? prev : { ...prev, [cur.path]: cur.message }, - {}, - ); - } + + const errors = undefinedIfEmpty({ + product_id: !value.product_id ? i18n.str`required` : undefined, + description: !value.description ? i18n.str`required` : undefined, + unit: !value.unit ? i18n.str`required` : undefined, + price: !value.price + ? i18n.str`required` + : Amounts.parse(value.price) === undefined + ? i18n.str`invalid amount` + : undefined, + minimum_age: + value.minimum_age === undefined + ? undefined + : value.minimum_age < 1 + ? i18n.str`should be greater than 0` + : undefined, + }); + + if (alreadyExist && errors) { + // on update, we remove some validations + delete errors.product_id; } - const hasErrors = Object.keys(errors).some( - (k) => (errors as Record<string, unknown>)[k] !== undefined, - ); + + const hasErrors = errors !== undefined; const submit = useCallback((): Entity | undefined => { const stock = value.stock; @@ -114,8 +118,6 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) { onSubscribe(hasErrors ? undefined : submit); }, [submit, hasErrors]); - const { i18n } = useTranslationContext(); - const { state } = useSessionContext(); return ( <div> <FormProvider<Entity> diff --git a/packages/merchant-backoffice-ui/src/components/tokenfamily/TokenFamilyForm.tsx b/packages/merchant-backoffice-ui/src/components/tokenfamily/TokenFamilyForm.tsx @@ -19,19 +19,21 @@ * @author Christian Blättler */ +import { + AbsoluteTime, + Duration, + TalerMerchantApi +} from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { h } from "preact"; import { useCallback, useEffect, useState } from "preact/hooks"; -import * as yup from "yup"; -import { TokenFamilyCreateSchema } from "../../schemas/index.js"; +import { useSessionContext } from "../../context/session.js"; import { FormErrors, FormProvider } from "../form/FormProvider.js"; import { Input } from "../form/Input.js"; -import { InputWithAddon } from "../form/InputWithAddon.js"; import { InputDate } from "../form/InputDate.js"; import { InputDuration } from "../form/InputDuration.js"; import { InputSelector } from "../form/InputSelector.js"; -import { useSessionContext } from "../../context/session.js"; -import { TalerMerchantApi } from "@gnu-taler/taler-util"; +import { InputWithAddon } from "../form/InputWithAddon.js"; type Entity = TalerMerchantApi.TokenFamilyCreateRequest; @@ -43,31 +45,28 @@ interface Props { export function TokenFamilyForm({ onSubscribe }: Props) { const [value, valueHandler] = useState<Partial<Entity>>({ - slug: "", - name: "", - description: "", + slug: undefined, + name: undefined, + description: undefined, description_i18n: {}, kind: TalerMerchantApi.TokenFamilyKind.Discount, - duration: { d_us: "forever" }, - valid_after: { t_s: "never" }, - valid_before: { t_s: "never" }, + duration: Duration.toTalerProtocolDuration(Duration.getForever()), + valid_after: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()), + valid_before: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()), }); - let errors: FormErrors<Entity> = {}; - try { - TokenFamilyCreateSchema.validateSync(value, { - abortEarly: false, - }); - } catch (err) { - if (err instanceof yup.ValidationError) { - const yupErrors = err.inner as yup.ValidationError[]; - errors = yupErrors.reduce( - (prev, cur) => - !cur.path ? prev : { ...prev, [cur.path]: cur.message }, - {}, - ); - } - } + const { i18n } = useTranslationContext(); + + const errors: FormErrors<Entity> = { + slug: !value.slug ? i18n.str`required` : undefined, + name: !value.name ? i18n.str`required` : undefined, + description: !value.description ? i18n.str`required` : undefined, + valid_after: !value.valid_after ? undefined : undefined, + valid_before: !value.valid_before ? i18n.str`required` : undefined, + duration: !value.duration ? i18n.str`required` : undefined, + kind: !value.kind ? i18n.str`required` : undefined, + }; + const hasErrors = Object.keys(errors).some( (k) => (errors as any)[k] !== undefined, ); @@ -82,7 +81,6 @@ export function TokenFamilyForm({ onSubscribe }: Props) { }, [submit, hasErrors]); const { state } = useSessionContext(); - const { i18n } = useTranslationContext(); return ( <div> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx @@ -27,9 +27,7 @@ import { TalerMerchantApi, TalerProtocolDuration, } from "@gnu-taler/taler-util"; -import { - useTranslationContext -} from "@gnu-taler/web-util/browser"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { format, isFuture } from "date-fns"; import { Fragment, VNode, h } from "preact"; import { useEffect, useState } from "preact/hooks"; @@ -340,7 +338,9 @@ export function CreatePage({ const minAgeByProducts = inventoryList.reduce( (cur, prev) => - !prev.product.minimum_age || cur > prev.product.minimum_age ? cur : prev.product.minimum_age, + !prev.product.minimum_age || cur > prev.product.minimum_age + ? cur + : prev.product.minimum_age, 0, ); @@ -396,8 +396,10 @@ export function CreatePage({ alternative={ allProducts.length > 0 && ( <p> - {allProducts.length} products with a total price of{" "} - {totalAsString}. + <i18n.Translate> + {allProducts.length} products with a total price of{" "} + {totalAsString}. + </i18n.Translate> </p> ) } @@ -731,7 +733,7 @@ export function CreatePage({ e.preventDefault(); }} > - add + <i18n.Translate>add</i18n.Translate> </button> </div> </InputGroup> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/List.stories.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/List.stories.tsx @@ -1,28 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2021-2024 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 <http://www.gnu.org/licenses/> - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { FunctionalComponent, h } from "preact"; -import { ListPage as TestedComponent } from "./ListPage.js"; - -export default { - title: "Pages/OtpDevices/List", - component: TestedComponent, -}; diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/ListPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/ListPage.tsx @@ -1,59 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2021-2024 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 <http://www.gnu.org/licenses/> - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { TalerMerchantApi } from "@gnu-taler/taler-util"; -import { h, VNode } from "preact"; -import { CardTable } from "./Table.js"; - -export interface Props { - devices: TalerMerchantApi.OtpDeviceEntry[]; - onLoadMoreBefore?: () => void; - onLoadMoreAfter?: () => void; - onCreate: () => void; - onDelete: (e: TalerMerchantApi.OtpDeviceEntry) => void; - onSelect: (e: TalerMerchantApi.OtpDeviceEntry) => void; -} - -export function ListPage({ - devices, - onCreate, - onDelete, - onSelect, - onLoadMoreBefore, - onLoadMoreAfter, -}: Props): VNode { - - return ( - <section class="section is-main-section"> - <CardTable - devices={devices.map((o) => ({ - ...o, - id: String(o.otp_device_id), - }))} - onCreate={onCreate} - onDelete={onDelete} - onSelect={onSelect} - onLoadMoreBefore={onLoadMoreBefore} - onLoadMoreAfter={onLoadMoreAfter} - /> - </section> - ); -} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx @@ -36,7 +36,7 @@ import { useInstanceOtpDevices } from "../../../../hooks/otp.js"; import { Notification } from "../../../../utils/types.js"; import { LoginPage } from "../../../login/index.js"; import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; -import { ListPage } from "./ListPage.js"; +import { CardTable } from "./Table.js"; interface Props { onCreate: () => void; @@ -72,40 +72,42 @@ export default function ListOtpDevices({ onCreate, onSelect }: Props): VNode { <Fragment> <NotificationCard notification={notif} /> - <ListPage - devices={result.body.otp_devices} - onLoadMoreBefore={undefined} //result.isFirstPage ? undefined : result.loadFirst} - onLoadMoreAfter={undefined} //result.isLastPage ? undefined : result.loadNext} - onCreate={onCreate} - onSelect={(e) => { - onSelect(e.otp_device_id); - }} - onDelete={async (e: TalerMerchantApi.OtpDeviceEntry) => { - return lib.instance - .deleteOtpDevice(state.token, e.otp_device_id) - .then((resp) => { - if (resp.type === "ok") { - setNotif({ - message: i18n.str`device delete successfully`, - type: "SUCCESS", - }); - } else { + <section class="section is-main-section"> + <CardTable + devices={result.body.otp_devices} + onLoadMoreBefore={undefined} //result.isFirstPage ? undefined : result.loadFirst} + onLoadMoreAfter={undefined} //result.isLastPage ? undefined : result.loadNext} + onCreate={onCreate} + onSelect={(e) => { + onSelect(e.otp_device_id); + }} + onDelete={async (e: TalerMerchantApi.OtpDeviceEntry) => { + return lib.instance + .deleteOtpDevice(state.token, e.otp_device_id) + .then((resp) => { + if (resp.type === "ok") { + setNotif({ + message: i18n.str`device delete successfully`, + type: "SUCCESS", + }); + } else { + setNotif({ + message: i18n.str`could not delete the device`, + type: "ERROR", + description: resp.detail.hint, + }); + } + }) + .catch((error) => setNotif({ message: i18n.str`could not delete the device`, type: "ERROR", - description: resp.detail.hint, - }); - } - }) - .catch((error) => - setNotif({ - message: i18n.str`could not delete the device`, - type: "ERROR", - description: error.message, - }), - ); - }} - /> + description: error.message, + }), + ); + }} + /> + </section> </Fragment> ); } diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/create/CreatedSuccessfully.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/create/CreatedSuccessfully.tsx @@ -1,72 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2021-2024 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 <http://www.gnu.org/licenses/> - */ -import { h, VNode } from "preact"; -import { CreatedSuccessfully as Template } from "../../../../components/notifications/CreatedSuccessfully.js"; -import { Entity } from "./index.js"; -import emptyImage from "../../assets/empty.png"; - -interface Props { - entity: Entity; - onConfirm: () => void; - onCreateAnother?: () => void; -} - -export function CreatedSuccessfully({ - entity, - onConfirm, - onCreateAnother, -}: Props): VNode { - return ( - <Template onConfirm={onConfirm} onCreateAnother={onCreateAnother}> - <div class="field is-horizontal"> - <div class="field-label is-normal"> - <label class="label">Image</label> - </div> - <div class="field-body is-flex-grow-3"> - <div class="field"> - <p class="control"> - <img src={entity.image} style={{ width: 200, height: 200 }} /> - </p> - </div> - </div> - </div> - <div class="field is-horizontal"> - <div class="field-label is-normal"> - <label class="label">Description</label> - </div> - <div class="field-body is-flex-grow-3"> - <div class="field"> - <p class="control"> - <textarea class="input" readonly value={entity.description} /> - </p> - </div> - </div> - </div> - <div class="field is-horizontal"> - <div class="field-label is-normal"> - <label class="label">Price</label> - </div> - <div class="field-body is-flex-grow-3"> - <div class="field"> - <p class="control"> - <input class="input" readonly value={entity.price} /> - </p> - </div> - </div> - </div> - </Template> - ); -} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx @@ -150,12 +150,18 @@ export default function ListTemplates({ }} > <p> - If you delete the template{" "} - <b>"{deleting.template_description}"</b> (ID:{" "} - <b>{deleting.template_id}</b>) you may loose information + <i18n.Translate> + If you delete the template{" "} + <b>"{deleting.template_description}"</b> (ID:{" "} + <b>{deleting.template_id}</b>) you may loose information + </i18n.Translate> </p> <p class="warning"> - Deleting an template <b>cannot be undone</b>. + <i18n.Translate>Deleting an template </i18n.Translate> + <b> + <i18n.Translate>cannot be undone</i18n.Translate> + </b> + . </p> </ConfirmModal> )} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/list/index.tsx @@ -147,12 +147,20 @@ export default function TokenFamilyList({ onCreate, onSelect }: Props): VNode { }} > <p> - If you delete the <b>"{deleting.name}"</b> token family - (Slug: <b>{deleting.slug}</b>), all issued tokens will become - invalid. + <i18n.Translate> + If you delete the <b>"{deleting.name}"</b> token family + (Slug: <b>{deleting.slug}</b>), all issued tokens will become + invalid. + </i18n.Translate> </p> <p class="warning"> - Deleting a token family <b>cannot be undone</b>. + <i18n.Translate> + Deleting a token family{" "} + <b> + <i18n.Translate>cannot be undone</i18n.Translate> + </b> + . + </i18n.Translate> </p> </ConfirmModal> )} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/update/UpdatePage.tsx @@ -23,13 +23,11 @@ import { Duration, TalerMerchantApi } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { h } from "preact"; import { useState } from "preact/hooks"; -import * as yup from "yup"; import { AsyncButton } from "../../../../components/exception/AsyncButton.js"; import { FormErrors, FormProvider } from "../../../../components/form/FormProvider.js"; import { Input } from "../../../../components/form/Input.js"; import { InputDate } from "../../../../components/form/InputDate.js"; import { InputDuration } from "../../../../components/form/InputDuration.js"; -import { TokenFamilyUpdateSchema } from "../../../../schemas/index.js"; type Entity = Omit<TalerMerchantApi.TokenFamilyUpdateRequest, "duration"> & { duration: Duration, @@ -52,22 +50,15 @@ function convert(from: TalerMerchantApi.TokenFamilyUpdateRequest) { export function UpdatePage({ onUpdate, onBack, tokenFamily }: Props) { const [value, valueHandler] = useState<Partial<Entity>>(convert(tokenFamily)); - let errors: FormErrors<Entity> = {}; - - try { - TokenFamilyUpdateSchema.validateSync(value, { - abortEarly: false, - }); - } catch (err) { - if (err instanceof yup.ValidationError) { - const yupErrors = err.inner as yup.ValidationError[]; - errors = yupErrors.reduce( - (prev, cur) => - !cur.path ? prev : { ...prev, [cur.path]: cur.message }, - {}, - ); - } - } + const { i18n } = useTranslationContext(); + const errors: FormErrors<Entity> = { + name: !value.name ? i18n.str`required` : undefined, + description: !value.description ? i18n.str`required` : undefined, + valid_after: !value.valid_after ? i18n.str`required` : undefined, + valid_before: !value.valid_before ? i18n.str`required` : undefined, + duration: !value.duration ? i18n.str`required` : undefined, + }; + const hasErrors = Object.keys(errors).some( (k) => (errors as any)[k] !== undefined, ); @@ -84,7 +75,6 @@ export function UpdatePage({ onUpdate, onBack, tokenFamily }: Props) { return onUpdate(result); } - const { i18n } = useTranslationContext(); return ( <div> @@ -95,7 +85,7 @@ export function UpdatePage({ onUpdate, onBack, tokenFamily }: Props) { <div class="level-left"> <div class="level-item"> <span class="is-size-4"> - Token Family: <b>{tokenFamily.name}</b> + <i18n.Translate>Token Family: <b>{tokenFamily.name}</b></i18n.Translate> </span> </div> </div> diff --git a/packages/merchant-backoffice-ui/src/utils/table.ts b/packages/merchant-backoffice-ui/src/utils/table.ts @@ -51,7 +51,7 @@ export function buildActions<T extends WithId>( * @returns */ export function undefinedIfEmpty< - T extends Record<string, unknown> | Array<unknown>, + T extends object | Record<string, unknown> | Array<unknown>, >(obj: T | undefined): T | undefined { if (obj === undefined) return undefined; return Object.values(obj).some((v) => v !== undefined) ? obj : undefined; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml @@ -642,9 +642,6 @@ importers: swr: specifier: 2.2.2 version: 2.2.2(react@18.3.1) - yup: - specifier: ^0.32.9 - version: 0.32.11 devDependencies: '@creativebulma/bulma-tooltip': specifier: ^1.2.0