From 75ff04672c011cf4c47b8f07d327adbf59323396 Mon Sep 17 00:00:00 2001 From: Nic Eigel Date: Mon, 24 Jun 2024 09:16:33 +0200 Subject: fixing merge-error --- .../instance/orders/create/Create.stories.tsx | 71 --- .../paths/instance/orders/create/CreatePage.tsx | 705 --------------------- .../orders/create/OrderCreatedSuccessfully.tsx | 114 ---- .../src/paths/instance/orders/create/index.tsx | 114 ---- 4 files changed, 1004 deletions(-) delete mode 100644 packages/auditor-backoffice-ui/src/paths/instance/orders/create/Create.stories.tsx delete mode 100644 packages/auditor-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx delete mode 100644 packages/auditor-backoffice-ui/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx delete mode 100644 packages/auditor-backoffice-ui/src/paths/instance/orders/create/index.tsx (limited to 'packages/auditor-backoffice-ui/src/paths/instance/orders/create') diff --git a/packages/auditor-backoffice-ui/src/paths/instance/orders/create/Create.stories.tsx b/packages/auditor-backoffice-ui/src/paths/instance/orders/create/Create.stories.tsx deleted file mode 100644 index fc814b68f..000000000 --- a/packages/auditor-backoffice-ui/src/paths/instance/orders/create/Create.stories.tsx +++ /dev/null @@ -1,71 +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 - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { h, VNode, FunctionalComponent } from "preact"; -import { CreatePage as TestedComponent } from "./CreatePage.js"; - -export default { - title: "Pages/Order/Create", - component: TestedComponent, - argTypes: { - onCreate: { action: "onCreate" }, - goBack: { action: "goBack" }, - }, -}; - -function createExample( - Component: FunctionalComponent, - props: Partial, -) { - const r = (args: any) => ; - r.args = props; - return r; -} - -export const Example = createExample(TestedComponent, { - instanceConfig: { - default_pay_delay: { - d_us: 1000 * 1000 * 60 * 60, //one hour - }, - default_wire_transfer_delay: { - d_us: 1000 * 1000 * 60 * 60, //one hour - }, - use_stefan: true, - }, - instanceInventory: [ - { - id: "t-shirt-1", - description: "a m size t-shirt", - price: "TESTKUDOS:1", - total_stock: -1, - }, - { - id: "t-shirt-2", - price: "TESTKUDOS:1", - description: "a xl size t-shirt", - } as any, - { - id: "t-shirt-3", - price: "TESTKUDOS:1", - description: "a s size t-shirt", - } as any, - ], -}); diff --git a/packages/auditor-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx b/packages/auditor-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx deleted file mode 100644 index 92271f52f..000000000 --- a/packages/auditor-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx +++ /dev/null @@ -1,705 +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 - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { AbsoluteTime, Amounts, Duration, TalerProtocolDuration } from "@gnu-taler/taler-util"; -import { useTranslationContext } from "@gnu-taler/web-util/browser"; -import { format, isFuture } from "date-fns"; -import { ComponentChildren, Fragment, VNode, h } from "preact"; -import { useEffect, useState } from "preact/hooks"; -import { - FormErrors, - FormProvider, -} from "../../../../components/form/FormProvider.js"; -import { Input } from "../../../../components/form/Input.js"; -import { InputCurrency } from "../../../../components/form/InputCurrency.js"; -import { InputDate } from "../../../../components/form/InputDate.js"; -import { InputDuration } from "../../../../components/form/InputDuration.js"; -import { InputGroup } from "../../../../components/form/InputGroup.js"; -import { InputLocation } from "../../../../components/form/InputLocation.js"; -import { InputNumber } from "../../../../components/form/InputNumber.js"; -import { InputToggle } from "../../../../components/form/InputToggle.js"; -import { InventoryProductForm } from "../../../../components/product/InventoryProductForm.js"; -import { NonInventoryProductFrom } from "../../../../components/product/NonInventoryProductForm.js"; -import { ProductList } from "../../../../components/product/ProductList.js"; -import { useConfigContext } from "../../../../context/config.js"; -import { MerchantBackend, WithId } from "../../../../declaration.js"; -import { useSettings } from "../../../../hooks/useSettings.js"; -import { OrderCreateSchema as schema } from "../../../../schemas/index.js"; -import { rate } from "../../../../utils/amount.js"; -import { undefinedIfEmpty } from "../../../../utils/table.js"; - -interface Props { - onCreate: (d: MerchantBackend.Orders.PostOrderRequest) => void; - onBack?: () => void; - instanceConfig: InstanceConfig; - instanceInventory: (MerchantBackend.Products.ProductDetail & WithId)[]; -} -interface InstanceConfig { - use_stefan: boolean; - default_pay_delay: TalerProtocolDuration; - default_wire_transfer_delay: TalerProtocolDuration; -} - -function with_defaults(config: InstanceConfig, currency: string): Partial { - const defaultPayDeadline = Duration.fromTalerProtocolDuration(config.default_pay_delay); - const defaultWireDeadline = Duration.fromTalerProtocolDuration(config.default_wire_transfer_delay); - - return { - inventoryProducts: {}, - products: [], - pricing: {}, - payments: { - max_fee: undefined, - createToken: true, - pay_deadline: (defaultPayDeadline), - refund_deadline: (defaultPayDeadline), - wire_transfer_deadline: (defaultWireDeadline), - }, - shipping: {}, - extra: {}, - }; -} - -interface ProductAndQuantity { - product: MerchantBackend.Products.ProductDetail & WithId; - quantity: number; -} -export interface ProductMap { - [id: string]: ProductAndQuantity; -} - -interface Pricing { - products_price: string; - order_price: string; - summary: string; -} -interface Shipping { - delivery_date?: Date; - delivery_location?: MerchantBackend.Location; - fullfilment_url?: string; -} -interface Payments { - refund_deadline: Duration; - pay_deadline: Duration; - wire_transfer_deadline: Duration; - auto_refund_deadline: Duration; - max_fee?: string; - createToken: boolean; - minimum_age?: number; -} -interface Entity { - inventoryProducts: ProductMap; - products: MerchantBackend.Product[]; - pricing: Partial; - payments: Partial; - shipping: Partial; - extra: Record; -} - -const stringIsValidJSON = (value: string) => { - try { - JSON.parse(value.trim()); - return true; - } catch { - return false; - } -}; - -export function CreatePage({ - onCreate, - onBack, - instanceConfig, - instanceInventory, -}: Props): VNode { - const config = useConfigContext(); - const instance_default = with_defaults(instanceConfig, config.currency) - const [value, valueHandler] = useState(instance_default); - const zero = Amounts.zeroOfCurrency(config.currency); - const [settings, updateSettings] = useSettings() - const inventoryList = Object.values(value.inventoryProducts || {}); - const productList = Object.values(value.products || {}); - - const { i18n } = useTranslationContext(); - - const parsedPrice = !value.pricing?.order_price - ? undefined - : Amounts.parse(value.pricing.order_price); - - const errors: FormErrors = { - pricing: undefinedIfEmpty({ - summary: !value.pricing?.summary ? i18n.str`required` : undefined, - order_price: !value.pricing?.order_price - ? i18n.str`required` - : !parsedPrice - ? i18n.str`not valid` - : Amounts.isZero(parsedPrice) - ? i18n.str`must be greater than 0` - : undefined, - }), - payments: undefinedIfEmpty({ - refund_deadline: !value.payments?.refund_deadline - ? undefined - : value.payments.pay_deadline && - Duration.cmp(value.payments.refund_deadline, value.payments.pay_deadline) === -1 - ? i18n.str`refund deadline cannot be before pay deadline` - : value.payments.wire_transfer_deadline && - Duration.cmp( - value.payments.wire_transfer_deadline, - value.payments.refund_deadline, - ) === -1 - ? i18n.str`wire transfer deadline cannot be before refund deadline` - : undefined, - pay_deadline: !value.payments?.pay_deadline - ? i18n.str`required` - : value.payments.wire_transfer_deadline && - Duration.cmp( - value.payments.wire_transfer_deadline, - value.payments.pay_deadline, - ) === -1 - ? i18n.str`wire transfer deadline cannot be before pay deadline` - : undefined, - wire_transfer_deadline: !value.payments?.wire_transfer_deadline - ? i18n.str`required` - : undefined, - auto_refund_deadline: !value.payments?.auto_refund_deadline - ? undefined - : !value.payments?.refund_deadline - ? i18n.str`should have a refund deadline` - : Duration.cmp( - value.payments.refund_deadline, - value.payments.auto_refund_deadline, - ) == -1 - ? i18n.str`auto refund cannot be after refund deadline` - : undefined, - - }), - shipping: undefinedIfEmpty({ - delivery_date: !value.shipping?.delivery_date - ? undefined - : !isFuture(value.shipping.delivery_date) - ? i18n.str`should be in the future` - : undefined, - }), - }; - const hasErrors = Object.keys(errors).some( - (k) => (errors as any)[k] !== undefined, - ); - - const submit = (): void => { - const order = value as any; //schema.cast(value); - if (!value.payments) return; - if (!value.shipping) return; - - const request: MerchantBackend.Orders.PostOrderRequest = { - order: { - amount: order.pricing.order_price, - summary: order.pricing.summary, - products: productList, - extra: undefinedIfEmpty(value.extra), - pay_deadline: !value.payments.pay_deadline ? - i18n.str`required` : - AbsoluteTime.toProtocolTimestamp(AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.pay_deadline)) - ,// : undefined, - wire_transfer_deadline: value.payments.wire_transfer_deadline - ? AbsoluteTime.toProtocolTimestamp(AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.wire_transfer_deadline)) - : undefined, - refund_deadline: value.payments.refund_deadline - ? AbsoluteTime.toProtocolTimestamp(AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.refund_deadline)) - : undefined, - auto_refund: value.payments.auto_refund_deadline - ? Duration.toTalerProtocolDuration(value.payments.auto_refund_deadline) - : undefined, - max_fee: value.payments.max_fee as string, - - delivery_date: value.shipping.delivery_date - ? { t_s: value.shipping.delivery_date.getTime() / 1000 } - : undefined, - delivery_location: value.shipping.delivery_location, - fulfillment_url: value.shipping.fullfilment_url, - minimum_age: value.payments.minimum_age, - }, - inventory_products: inventoryList.map((p) => ({ - product_id: p.product.id, - quantity: p.quantity, - })), - create_token: value.payments.createToken, - }; - - onCreate(request); - }; - - const addProductToTheInventoryList = ( - product: MerchantBackend.Products.ProductDetail & WithId, - quantity: number, - ) => { - valueHandler((v) => { - const inventoryProducts = { ...v.inventoryProducts }; - inventoryProducts[product.id] = { product, quantity }; - return { ...v, inventoryProducts }; - }); - }; - - const removeProductFromTheInventoryList = (id: string) => { - valueHandler((v) => { - const inventoryProducts = { ...v.inventoryProducts }; - delete inventoryProducts[id]; - return { ...v, inventoryProducts }; - }); - }; - - const addNewProduct = async (product: MerchantBackend.Product) => { - return valueHandler((v) => { - const products = v.products ? [...v.products, product] : []; - return { ...v, products }; - }); - }; - - const removeFromNewProduct = (index: number) => { - valueHandler((v) => { - const products = v.products ? [...v.products] : []; - products.splice(index, 1); - return { ...v, products }; - }); - }; - - const [editingProduct, setEditingProduct] = useState< - MerchantBackend.Product | undefined - >(undefined); - - const totalPriceInventory = inventoryList.reduce((prev, cur) => { - const p = Amounts.parseOrThrow(cur.product.price); - return Amounts.add(prev, Amounts.mult(p, cur.quantity).amount).amount; - }, zero); - - const totalPriceProducts = productList.reduce((prev, cur) => { - if (!cur.price) return zero; - const p = Amounts.parseOrThrow(cur.price); - return Amounts.add(prev, Amounts.mult(p, cur.quantity).amount).amount; - }, zero); - - const hasProducts = inventoryList.length > 0 || productList.length > 0; - const totalPrice = Amounts.add(totalPriceInventory, totalPriceProducts); - - const totalAsString = Amounts.stringify(totalPrice.amount); - const allProducts = productList.concat(inventoryList.map(asProduct)); - - const [newField, setNewField] = useState("") - - useEffect(() => { - valueHandler((v) => { - return { - ...v, - pricing: { - ...v.pricing, - products_price: hasProducts ? totalAsString : undefined, - order_price: hasProducts ? totalAsString : undefined, - }, - }; - }); - }, [hasProducts, totalAsString]); - - const discountOrRise = rate( - parsedPrice ?? Amounts.zeroOfCurrency(config.currency), - totalPrice.amount, - ); - - const minAgeByProducts = allProducts.reduce( - (cur, prev) => - !prev.minimum_age || cur > prev.minimum_age ? cur : prev.minimum_age, - 0, - ); - - // if there is no default pay deadline - const noDefault_payDeadline = !instance_default.payments || !instance_default.payments.pay_deadline - // and there is no default wire deadline - const noDefault_wireDeadline = !instance_default.payments || !instance_default.payments.wire_transfer_deadline - // user required to set the taler options - const requiresSomeTalerOptions = noDefault_payDeadline || noDefault_wireDeadline - - - return ( -
- -
-
-
    -
  • { - updateSettings({ - ...settings, - advanceOrderMode: false - }) - }}> - - Simple - -
  • -
  • { - updateSettings({ - ...settings, - advanceOrderMode: true - }) - }}> - - Advanced - -
  • -
-
-
-
-
- {/* // FIXME: translating plural singular */} - 0 && ( -

- {allProducts.length} products with a total price of{" "} - {totalAsString}. -

- ) - } - tooltip={i18n.str`Manage list of products in the order.`} - > - - - {settings.advanceOrderMode && - { - setEditingProduct(undefined); - return addNewProduct(p); - }} - /> - } - - {allProducts.length > 0 && ( - { - if (e.product_id) { - removeProductFromTheInventoryList(e.product_id); - } else { - removeFromNewProduct(index); - setEditingProduct(e); - } - }, - }, - ]} - /> - )} -
- - - errors={errors} - object={value} - valueHandler={valueHandler as any} - > - {hasProducts ? ( - - - 0 && - (discountOrRise < 1 - ? `discount of %${Math.round( - (1 - discountOrRise) * 100, - )}` - : `rise of %${Math.round((discountOrRise - 1) * 100)}`) - } - tooltip={i18n.str`Amount to be paid by the customer`} - /> - - ) : ( - - )} - - - - {settings.advanceOrderMode && - - - {value.shipping?.delivery_date && ( - - - - )} - - - } - - {(settings.advanceOrderMode || requiresSomeTalerOptions) && - - {(settings.advanceOrderMode || noDefault_payDeadline) && } - withForever - withoutClear - tooltip={i18n.str`Time for the customer to pay for the offer before it expires. Inventory products will be reserved until this deadline. Time start to run after the order is created.`} - side={ - - - - } - />} - {settings.advanceOrderMode && } - withForever - withoutClear - tooltip={i18n.str`Time while the order can be refunded by the merchant. Time starts after the order is created.`} - side={ - - - - } - />} - {(settings.advanceOrderMode || noDefault_wireDeadline) && } - withoutClear - withForever - tooltip={i18n.str`Time for the exchange to make the wire transfer. Time starts after the order is created.`} - side={ - - - - } - />} - {settings.advanceOrderMode && } - tooltip={i18n.str`Time until which the wallet will automatically check for refunds without user interaction.`} - withForever - />} - - {settings.advanceOrderMode && } - {settings.advanceOrderMode && } - {settings.advanceOrderMode && 0 - ? i18n.str`Min age defined by the producs is ${minAgeByProducts}` - : i18n.str`No product with age restriction in this order` - } - />} - - } - - {settings.advanceOrderMode && - - {Object.keys(value.extra ?? {}).map((key) => { - - return { - if (value.extra && value.extra[key] !== undefined) { - console.log(value.extra) - delete value.extra[key] - } - valueHandler({ - ...value, - }) - }}>remove - } - /> - })} -
-
- -
-
-
-

- setNewField(e.currentTarget.value)} /> -

-
-
- -
-
- } - - -
- {onBack && ( - - )} - -
-
-
-
-
-
- ); -} - -function asProduct(p: ProductAndQuantity): MerchantBackend.Product { - return { - product_id: p.product.id, - image: p.product.image, - price: p.product.price, - unit: p.product.unit, - quantity: p.quantity, - description: p.product.description, - taxes: p.product.taxes, - minimum_age: p.product.minimum_age, - }; -} - - -function DeadlineHelp({ duration }: { duration?: Duration }): VNode { - const { i18n } = useTranslationContext(); - const [now, setNow] = useState(AbsoluteTime.now()) - useEffect(() => { - const iid = setInterval(() => { - setNow(AbsoluteTime.now()) - }, 60 * 1000) - return () => { - clearInterval(iid) - } - }) - if (!duration) return Disabled - const when = AbsoluteTime.addDuration(now, duration) - if (when.t_ms === "never") return No deadline - return Deadline at {format(when.t_ms, "dd/MM/yy HH:mm")} -} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx b/packages/auditor-backoffice-ui/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx deleted file mode 100644 index 3f7b20f52..000000000 --- a/packages/auditor-backoffice-ui/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx +++ /dev/null @@ -1,114 +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 - */ -import { useTranslationContext } from "@gnu-taler/web-util/browser"; -import { h, VNode } from "preact"; -import { useEffect, useState } from "preact/hooks"; -import { CreatedSuccessfully } from "../../../../components/notifications/CreatedSuccessfully.js"; -import { useOrderAPI } from "../../../../hooks/order.js"; -import { Entity } from "./index.js"; - -interface Props { - entity: Entity; - onConfirm: () => void; - onCreateAnother?: () => void; -} - -export function OrderCreatedSuccessfully({ - entity, - onConfirm, - onCreateAnother, -}: Props): VNode { - const { getPaymentURL } = useOrderAPI(); - const [url, setURL] = useState(undefined); - const { i18n } = useTranslationContext(); - useEffect(() => { - getPaymentURL(entity.response.order_id).then((response) => { - setURL(response.data); - }); - }, [getPaymentURL, entity.response.order_id]); - - return ( - -
-
- -
-
-
-

- -

-
-
-
-
-
- -
-
-
-

- -

-
-
-
-
-
- -
-
-
-

- -

-
-
-
-
-
- -
-
-
-

- -

-
-
-
-
- ); -} diff --git a/packages/auditor-backoffice-ui/src/paths/instance/orders/create/index.tsx b/packages/auditor-backoffice-ui/src/paths/instance/orders/create/index.tsx deleted file mode 100644 index d2a8619ce..000000000 --- a/packages/auditor-backoffice-ui/src/paths/instance/orders/create/index.tsx +++ /dev/null @@ -1,114 +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 - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { ErrorType, HttpError } from "@gnu-taler/web-util/browser"; -import { Fragment, h, VNode } from "preact"; -import { useState } from "preact/hooks"; -import { Loading } from "../../../../components/exception/loading.js"; -import { NotificationCard } from "../../../../components/menu/index.js"; -import { MerchantBackend } from "../../../../declaration.js"; -import { useInstanceDetails } from "../../../../hooks/instance.js"; -import { useOrderAPI } from "../../../../hooks/order.js"; -import { useInstanceProducts } from "../../../../hooks/product.js"; -import { Notification } from "../../../../utils/types.js"; -import { CreatePage } from "./CreatePage.js"; -import { HttpStatusCode } from "@gnu-taler/taler-util"; - -export type Entity = { - request: MerchantBackend.Orders.PostOrderRequest; - response: MerchantBackend.Orders.PostOrderResponse; -}; -interface Props { - onBack?: () => void; - onConfirm: (id: string) => void; - onUnauthorized: () => VNode; - onNotFound: () => VNode; - onLoadError: (error: HttpError) => VNode; -} -export default function OrderCreate({ - onConfirm, - onBack, - onLoadError, - onNotFound, - onUnauthorized, -}: Props): VNode { - const { createOrder } = useOrderAPI(); - const [notif, setNotif] = useState(undefined); - - const detailsResult = useInstanceDetails(); - const inventoryResult = useInstanceProducts(); - - if (detailsResult.loading) return ; - if (inventoryResult.loading) return ; - - if (!detailsResult.ok) { - if ( - detailsResult.type === ErrorType.CLIENT && - detailsResult.status === HttpStatusCode.Unauthorized - ) - return onUnauthorized(); - if ( - detailsResult.type === ErrorType.CLIENT && - detailsResult.status === HttpStatusCode.NotFound - ) - return onNotFound(); - return onLoadError(detailsResult); - } - - if (!inventoryResult.ok) { - if ( - inventoryResult.type === ErrorType.CLIENT && - inventoryResult.status === HttpStatusCode.Unauthorized - ) - return onUnauthorized(); - if ( - inventoryResult.type === ErrorType.CLIENT && - inventoryResult.status === HttpStatusCode.NotFound - ) - return onNotFound(); - return onLoadError(inventoryResult); - } - - return ( - - - - { - createOrder(request) - .then((r) => { - return onConfirm(r.data.order_id) - }) - .catch((error) => { - setNotif({ - message: "could not create order", - type: "ERROR", - description: error.message, - }); - }); - }} - instanceConfig={detailsResult.data} - instanceInventory={inventoryResult.data} - /> - - ); -} -- cgit v1.2.3