commit dd03dc5877bbeca17efb4dc5007f62a7dd90eb16
parent 2444fb8a6d3160fe2ed639207a7856f026913fd4
Author: Sebastian <sebasjm@gmail.com>
Date: Wed, 14 Apr 2021 14:27:22 -0300
product list into the order detail
Diffstat:
5 files changed, 127 insertions(+), 101 deletions(-)
diff --git a/packages/frontend/src/components/product/ProductList.tsx b/packages/frontend/src/components/product/ProductList.tsx
@@ -0,0 +1,49 @@
+import { h } from "preact"
+import { MerchantBackend } from "../../declaration"
+import { multiplyPrice } from "../../utils/amount"
+
+interface Props {
+ list: MerchantBackend.Product[],
+ actions?: {
+ name: string;
+ handler: (d: MerchantBackend.Product, index: number) => void;
+ }[]
+}
+export function ProductList({ list, actions = [] }: Props) {
+ return <div class="table-container">
+ <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
+ <thead>
+ <tr>
+ <th>image</th>
+ <th>description</th>
+ <th>quantity</th>
+ <th>unit price</th>
+ <th>total price</th>
+ <th />
+ </tr>
+ </thead>
+ <tbody>
+ {list.map((entry, index) => {
+ return <tr>
+ <td>image</td>
+ <td >{entry.description}</td>
+ <td >
+ {entry.quantity} {entry.unit}
+ </td>
+ <td >{entry.price}</td>
+ <td >{multiplyPrice(entry.price, entry.quantity)}</td>
+ <td class="is-actions-cell right-sticky">
+ {actions.map(a => {
+ <div class="buttons is-right">
+ <button class="button is-small is-danger jb-modal" type="button" onClick={() => a.handler(entry, index)}>
+ {a.name}
+ </button>
+ </div>
+ })}
+ </td>
+ </tr>
+ })}
+ </tbody>
+ </table>
+ </div>
+}
diff --git a/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx b/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx
@@ -36,6 +36,7 @@ import { InputDate } from "../../../../components/form/InputDate";
import { useInstanceDetails } from "../../../../hooks/instance";
import { add } from "date-fns";
import { multiplyPrice, rate, subtractPrices, sumPrices } from "../../../../utils/amount";
+import { ProductList } from "../../../../components/product/ProductList";
interface Props {
onCreate: (d: MerchantBackend.Orders.PostOrderRequest) => void;
@@ -52,11 +53,12 @@ function with_defaults(): Entity {
};
}
+interface ProductAndQuantity {
+ product: MerchantBackend.Products.ProductDetail & WithId,
+ quantity: number;
+}
export interface ProductMap {
- [id: string]: {
- product: MerchantBackend.Products.ProductDetail & WithId,
- quantity: number;
- }
+ [id: string]: ProductAndQuantity;
}
interface Pricing {
@@ -82,7 +84,7 @@ interface Entity {
products: MerchantBackend.Product[],
pricing: Pricing;
payments: Payments;
- extra:string;
+ extra: string;
}
export function CreatePage({ onCreate, onBack }: Props): VNode {
@@ -103,12 +105,12 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
summary: order.pricing.summary,
products: productList,
extra: value.extra,
- pay_deadline: value.payments.pay_deadline ? { t_ms: value.payments.pay_deadline.getTime()*1000 } : undefined,
- wire_transfer_deadline: value.payments.pay_deadline ? { t_ms: value.payments.pay_deadline.getTime()*1000 } : undefined,
- refund_deadline: value.payments.refund_deadline ? { t_ms: value.payments.refund_deadline.getTime()*1000 } : undefined,
+ pay_deadline: value.payments.pay_deadline ? { t_ms: value.payments.pay_deadline.getTime() * 1000 } : undefined,
+ wire_transfer_deadline: value.payments.pay_deadline ? { t_ms: value.payments.pay_deadline.getTime() * 1000 } : undefined,
+ refund_deadline: value.payments.refund_deadline ? { t_ms: value.payments.refund_deadline.getTime() * 1000 } : undefined,
max_fee: value.payments.max_fee,
max_wire_fee: value.payments.max_wire_fee,
- delivery_date: value.payments.delivery_date ? { t_ms: value.payments.delivery_date.getTime()*1000 } : undefined,
+ delivery_date: value.payments.delivery_date ? { t_ms: value.payments.delivery_date.getTime() * 1000 } : undefined,
delivery_location: value.payments.delivery_location,
},
inventory_products: inventoryList.map(p => ({
@@ -116,6 +118,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
quantity: p.quantity
})),
}
+
onCreate(request);
} catch (err) {
const errors = err.inner as yup.ValidationError[]
@@ -185,6 +188,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
const discountOrRise = rate(value.pricing.order_price, totalPrice)
+
useEffect(() => {
valueHandler(v => {
return ({
@@ -201,7 +205,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
useEffect(() => {
if (details_response.ok) {
valueHandler(v => {
- const defaultPayDeadline = !details_response.data.default_pay_delay || details_response.data.default_pay_delay.d_ms === "forever" ? undefined : add(new Date(), {seconds: details_response.data.default_pay_delay.d_ms/1000})
+ const defaultPayDeadline = !details_response.data.default_pay_delay || details_response.data.default_pay_delay.d_ms === "forever" ? undefined : add(new Date(), { seconds: details_response.data.default_pay_delay.d_ms / 1000 })
return ({
...v, payments: {
...v.payments,
@@ -235,41 +239,13 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
onAddProduct={addProductToTheInventoryList}
/>
- {inventoryList.length > 0 && <div class="table-container">
- <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
- <thead>
- <tr>
- <th>image</th>
- <th>description</th>
- <th>quantity</th>
- <th>unit price</th>
- <th>total price</th>
- <th />
- </tr>
- </thead>
- <tbody>
- {inventoryList.map((entry, index) => {
- return <tr>
- <td>image</td>
- <td >{entry.product.description}</td>
- <td >
- {entry.quantity} {entry.product.unit}
- </td>
- <td >{entry.product.price}</td>
- <td >{multiplyPrice(entry.product.price, entry.quantity)}</td>
- <td class="is-actions-cell right-sticky">
- <div class="buttons is-right">
- <button class="button is-small is-danger jb-modal" type="button" onClick={(): void => removeProductFromTheInventoryList(entry.product.id)}>
- Remove
- </button>
- </div>
- </td>
- </tr>
- })}
-
- </tbody>
- </table>
- </div>}
+ {inventoryList.length > 0 &&
+ <ProductList list={inventoryList.map(asProduct)}
+ actions={[{
+ name: 'Remove', handler: (e) => removeProductFromTheInventoryList(e.product_id!)
+ }]}
+ />
+ }
</InputGroup>
<InputGroup name="products" alternative={
@@ -283,46 +259,22 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
setEditingProduct(undefined)
addNewProduct(p)
}} />
- {productList.length > 0 && <div class="table-container">
- <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
- <thead>
- <tr>
- <th>image</th>
- <th>description</th>
- <th>quantity</th>
- <th>unit price</th>
- <th>total price</th>
- <th />
- </tr>
- </thead>
- <tbody>
- {productList.map((entry, index) => {
- return <tr>
- <td>image</td>
- <td >{entry.description}</td>
- <td >
- {entry.quantity} {entry.unit}
- </td>
- <td >{entry.price}</td>
- <td >{multiplyPrice(entry.price, entry.quantity)}</td>
- <td class="is-actions-cell right-sticky">
- <div class="buttons is-right">
- <button class="button is-small is-success jb-modal" type="button" onClick={(): void => {
- removeFromNewProduct(index)
- setEditingProduct(entry)
- }}>
- Edit
- </button>
- <button class="button is-small is-danger jb-modal" type="button" onClick={(): void => removeFromNewProduct(index)}>
- Remove
- </button>
- </div>
- </td>
- </tr>
- })}
- </tbody>
- </table>
- </div>}
+
+ {productList.length > 0 &&
+ <ProductList list={productList}
+ actions={[{
+ name: 'Update', handler: (e, index) => {
+ removeFromNewProduct(index);
+ setEditingProduct(e);
+ }
+ }, {
+ name: 'Remove', handler: (e, index) => {
+ removeFromNewProduct(index);
+ }
+ }]}
+ />
+
+ }
</InputGroup>
<FormProvider<Entity> errors={errors} object={value} valueHandler={valueHandler as any}>
@@ -343,14 +295,13 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
<Input name="pricing.summary" inputType="multiline" />
-
<InputGroup name="payments">
<InputDate name="payments.auto_refund_deadline" />
<InputDate name="payments.refund_deadline" />
<InputDate name="payments.pay_deadline" />
<InputDate name="payments.delivery_date" />
- { value.payments.delivery_date && <InputGroup name="payments.delivery_location" >
+ {value.payments.delivery_date && <InputGroup name="payments.delivery_location" >
<Input name="payments.delivery_location.country" />
<Input name="payments.delivery_location.address_lines" inputType="multiline"
toStr={(v: string[] | undefined) => !v ? '' : v.join('\n')}
@@ -364,13 +315,14 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
<Input name="payments.delivery_location.town" />
<Input name="payments.delivery_location.district" />
<Input name="payments.delivery_location.country_subdivision" />
- </InputGroup> }
+ </InputGroup>}
<InputCurrency name="payments.max_fee" currency={config.currency} />
<InputCurrency name="payments.max_wire_fee" currency={config.currency} />
<Input name="payments.wire_fee_amortization" />
<Input name="payments.fullfilment_url" />
</InputGroup>
+
<InputGroup name="extra">
<Input name="extra" inputType="multiline" />
</InputGroup>
@@ -389,4 +341,14 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
</div>
}
-
+function asProduct(p: ProductAndQuantity) {
+ 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
+ })
+}
+\ No newline at end of file
diff --git a/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx b/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx
@@ -32,6 +32,7 @@ import { format } from "date-fns";
import { Event, Timeline } from "./Timeline";
import { RefundModal } from "../list/Table";
import { mergeRefunds } from "../../../../utils/amount";
+import { ProductList } from "../../../../components/product/ProductList";
type Entity = MerchantBackend.Orders.MerchantOrderStatusResponse;
interface Props {
@@ -162,14 +163,9 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders.
<section class="section">
<div class="columns">
- <div class="column is-2" />
- <div class="column is-8" >
- <div class="title">Payment details</div>
- <FormProvider<Claimed> errors={errors} object={value} valueHandler={valueHandler} >
- <Input name="contract_terms.summary" readonly inputType="multiline" />
- <InputCurrency name="contract_terms.amount" readonly currency={config.currency} />
- <Input<Claimed> name="order_status" readonly />
- </FormProvider>
+ <div class="column is-12" >
+ <div class="title">Product list</div>
+ <ProductList list={order.contract_terms.products} />
</div>
<div class="column" />
</div>
@@ -324,6 +320,16 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend.
</div>
</section>
+ {order.contract_terms.products.length ? <section class="section">
+ <div class="columns">
+ <div class="column is-12" >
+ <div class="title">Product list</div>
+ <ProductList list={order.contract_terms.products} />
+ </div>
+ <div class="column" />
+ </div>
+ </section> :undefined }
+
</div>
<div class="column" />
</div>
diff --git a/packages/frontend/src/paths/instance/products/list/index.tsx b/packages/frontend/src/paths/instance/products/list/index.tsx
@@ -20,11 +20,9 @@
*/
import { h, VNode } from 'preact';
-import { create } from 'yup/lib/Reference';
-import { HttpError, HttpResponseServerError, RequestInfo } from '../../../../hooks/backend';
+import { HttpError } from '../../../../hooks/backend';
import { useProductAPI } from "../../../../hooks/product";
import { CardTable } from './Table';
-import logo from '../../../../assets/logo.jpeg';
import { useConfigContext } from '../../../../context/backend';
import { MerchantBackend, WithId } from '../../../../declaration';
import { Loading } from '../../../../components/exception/loading';
@@ -92,7 +90,16 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo
}))
}
onSelect={(product) => onSelect(product.id)}
- onDelete={(prod: (MerchantBackend.Products.ProductDetail & WithId)) => deleteProduct(prod.id)}
+ onDelete={(prod: (MerchantBackend.Products.ProductDetail & WithId)) => deleteProduct(prod.id)
+ .then(() => setNotif({
+ message: 'product delete successfully',
+ type: "SUCCESS"
+ })).catch((error) => setNotif({
+ message: 'could not delete the product',
+ type: "ERROR",
+ description: error.message
+ }))
+ }
/>
</section>
}
\ No newline at end of file
diff --git a/packages/frontend/src/utils/amount.ts b/packages/frontend/src/utils/amount.ts
@@ -57,6 +57,7 @@ export const rate = (one?: string, two?: string) => {
const intOne = parseInt(valueOne, 10)
const intTwo = parseInt(valueTwo, 10)
if (!intTwo) return intOne
+ if (!intOne) return 0
return intOne / intTwo
}