/* 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 */ /** * * @author Sebastian Javier Marchano (sebasjm) */ import { AmountString, 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 { Input } from "../form/Input.js"; import { InputCurrency } from "../form/InputCurrency.js"; import { InputImage } from "../form/InputImage.js"; import { InputNumber } from "../form/InputNumber.js"; import { InputStock, Stock } from "../form/InputStock.js"; import { InputTaxes } from "../form/InputTaxes.js"; import { InputWithAddon } from "../form/InputWithAddon.js"; type Entity = TalerMerchantApi.ProductDetail & { product_id: string }; interface Props { onSubscribe: (c?: () => Entity | undefined) => void; initial?: Partial; alreadyExist?: boolean; } export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) { const [value, valueHandler] = useState>({ address: {}, description_i18n: {}, taxes: [], next_restock: { t_s: "never" }, price: ":0" as AmountString, ...initial, stock: !initial || initial.total_stock === -1 ? undefined : { current: initial.total_stock || 0, lost: initial.total_lost || 0, sold: initial.total_sold || 0, address: initial.address, nextRestock: initial.next_restock, }, }); let errors: FormErrors = {}; 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 hasErrors = Object.keys(errors).some( (k) => (errors as Record)[k] !== undefined, ); const submit = useCallback((): Entity | undefined => { const stock = value.stock; if (!stock) { value.total_stock = -1; } else { value.total_stock = stock.current; value.total_lost = stock.lost; value.next_restock = stock.nextRestock instanceof Date ? { t_s: stock.nextRestock.getTime() / 1000 } : stock.nextRestock; value.address = stock.address; } delete value.stock; if (typeof value.minimum_age !== "undefined" && value.minimum_age < 1) { delete value.minimum_age; } return value as TalerMerchantApi.ProductDetail & { product_id: string; }; }, [value]); useEffect(() => { onSubscribe(hasErrors ? undefined : submit); }, [submit, hasErrors]); const { i18n } = useTranslationContext(); const { state } = useSessionContext(); return (
name="product" errors={errors} object={value} valueHandler={valueHandler} > {alreadyExist ? undefined : ( name="product_id" addonBefore={new URL("product/", state.backendUrl.href).href} label={i18n.str`ID`} tooltip={i18n.str`product identification to use in URLs (for internal use only)`} /> )} name="image" label={i18n.str`Image`} tooltip={i18n.str`illustration of the product for customers`} /> name="description" inputType="multiline" label={i18n.str`Description`} tooltip={i18n.str`product description for customers`} /> name="minimum_age" label={i18n.str`Age restriction`} tooltip={i18n.str`is this product restricted for customer below certain age?`} help={i18n.str`minimum age of the buyer`} /> name="unit" label={i18n.str`Unit name`} tooltip={i18n.str`unit describing quantity of product sold (e.g. 2 kilograms, 5 liters, 3 items, 5 meters) for customers`} help={i18n.str`exajmple: kg, items or liters`} /> name="price" label={i18n.str`Price per unit`} tooltip={i18n.str`sale price for customers, including taxes, for above units of the product`} /> name="taxes" label={i18n.str`Taxes`} tooltip={i18n.str`taxes included in the product price, exposed to customers`} />
); }