diff options
Diffstat (limited to 'packages/merchant-backoffice-ui/src/paths/instance/products')
-rw-r--r-- | packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx | 62 | ||||
-rw-r--r-- | packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx | 48 |
2 files changed, 72 insertions, 38 deletions
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx index 6bbb89dfa..cbfe1d573 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx @@ -32,6 +32,7 @@ import { import { InputCurrency } from "../../../../components/form/InputCurrency.js"; import { InputNumber } from "../../../../components/form/InputNumber.js"; import { MerchantBackend, WithId } from "../../../../declaration.js"; +import { dateFormatForSettings, useSettings } from "../../../../hooks/useSettings.js"; type Entity = MerchantBackend.Products.ProductDetail & WithId; @@ -122,6 +123,7 @@ function Table({ onDelete, }: TableProps): VNode { const { i18n } = useTranslationContext(); + const [settings] = useSettings(); return ( <div class="table-container"> <table class="table is-fullwidth is-striped is-hoverable is-fullwidth"> @@ -134,7 +136,7 @@ function Table({ <i18n.Translate>Description</i18n.Translate> </th> <th> - <i18n.Translate>Sell</i18n.Translate> + <i18n.Translate>Price per unit</i18n.Translate> </th> <th> <i18n.Translate>Taxes</i18n.Translate> @@ -156,10 +158,10 @@ function Table({ const restStockInfo = !i.next_restock ? "" : i.next_restock.t_s === "never" - ? "never" - : `restock at ${format( + ? "never" + : `restock at ${format( new Date(i.next_restock.t_s * 1000), - "yyyy/MM/dd", + dateFormatForSettings(settings), )}`; let stockInfo: ComponentChildren = ""; if (i.total_stock < 0) { @@ -332,26 +334,35 @@ function FastProductWithInfiniteStockUpdateForm({ /> </FormProvider> - <div class="buttons is-right mt-5"> - <button class="button" onClick={onCancel}> - <i18n.Translate>Cancel</i18n.Translate> - </button> - <span - class="has-tooltip-left" - data-tooltip={i18n.str`update product with new price`} - > - <button - class="button is-info" - onClick={() => - onUpdate({ - ...product, - price: value.price, - }) - } - > - <i18n.Translate>Confirm</i18n.Translate> + <div class="buttons is-expanded"> + + <div class="buttons mt-5"> + + <button class="button " onClick={onCancel}> + <i18n.Translate>Clone</i18n.Translate> </button> - </span> + </div> + <div class="buttons is-right mt-5"> + <button class="button" onClick={onCancel}> + <i18n.Translate>Cancel</i18n.Translate> + </button> + <span + class="has-tooltip-left" + data-tooltip={i18n.str`update product with new price`} + > + <button + class="button is-info" + onClick={() => + onUpdate({ + ...product, + price: value.price, + }) + } + > + <i18n.Translate>Confirm update</i18n.Translate> + </button> + </span> + </div> </div> </Fragment> ); @@ -374,9 +385,8 @@ function FastProductWithManagedStockUpdateForm({ const errors: FormErrors<FastProductUpdate> = { lost: currentStock + value.incoming < value.lost - ? `lost cannot be greater that current + incoming (max ${ - currentStock + value.incoming - })` + ? `lost cannot be greater that current + incoming (max ${currentStock + value.incoming + })` : undefined, }; diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx index 87efd1554..85c50e5ed 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx @@ -36,6 +36,7 @@ import { import { Notification } from "../../../../utils/types.js"; import { CardTable } from "./Table.js"; import { HttpStatusCode } from "@gnu-taler/taler-util"; +import { ConfirmModal, DeleteModal } from "../../../../components/modal/index.js"; interface Props { onUnauthorized: () => VNode; @@ -53,6 +54,8 @@ export default function ProductList({ }: Props): VNode { const result = useInstanceProducts(); const { deleteProduct, updateProduct } = useProductAPI(); + const [deleting, setDeleting] = + useState<MerchantBackend.Products.ProductDetail & WithId | null>(null); const [notif, setNotif] = useState<Notification | undefined>(undefined); const { i18n } = useTranslationContext(); @@ -97,22 +100,43 @@ export default function ProductList({ } onSelect={(product) => onSelect(product.id)} onDelete={(prod: MerchantBackend.Products.ProductDetail & WithId) => - deleteProduct(prod.id) - .then(() => + setDeleting(prod) + } + /> + + {deleting && ( + <ConfirmModal + label={`Delete product`} + description={`Delete the product "${deleting.description}"`} + danger + active + onCancel={() => setDeleting(null)} + onConfirm={async (): Promise<void> => { + try { + await deleteProduct(deleting.id); setNotif({ - message: i18n.str`product delete successfully`, + message: i18n.str`Product "${deleting.description}" (ID: ${deleting.id}) has been deleted`, type: "SUCCESS", - }), - ) - .catch((error) => + }); + } catch (error) { setNotif({ - message: i18n.str`could not delete the product`, + message: i18n.str`Failed to delete product`, type: "ERROR", - description: error.message, - }), - ) - } - /> + description: error instanceof Error ? error.message : undefined, + }); + } + setDeleting(null); + }} + > + <p> + If you delete the product named <b>"{deleting.description}"</b> (ID:{" "} + <b>{deleting.id}</b>), the stock and related information will be lost + </p> + <p class="warning"> + Deleting an product <b>cannot be undone</b>. + </p> + </ConfirmModal> + )} </section> ); } |