diff options
Diffstat (limited to 'packages/frontend/src/paths/instance/orders')
8 files changed, 159 insertions, 114 deletions
diff --git a/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx b/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx index 1b47564..ae32dac 100644 --- a/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx +++ b/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx @@ -257,7 +257,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { with a total price of {totalPriceProducts} </p> } tooltip={i18n`Add products without inventory management to the order.`}> - <NonInventoryProductFrom value={editingProduct} onAddProduct={(p) => { + <NonInventoryProductFrom productToEdit={editingProduct} onAddProduct={(p) => { setEditingProduct(undefined) return addNewProduct(p) }} /> diff --git a/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx b/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx index 6cf48f8..b97b39a 100644 --- a/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx +++ b/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx @@ -39,12 +39,14 @@ export function InventoryProductForm({ currentProducts, onAddProduct }: Props): const i18n = useTranslator() + const productWithInfiniteStock = state.product && state.product.total_stock === -1 + const submit = (): void => { if (!state.product) { setErrors({ product: i18n`You must enter a valid product identifier.` }); return; } - if (state.product.total_stock === -1) { + if (productWithInfiniteStock) { onAddProduct(state.product, 1) } else { if (!state.quantity || state.quantity <= 0) { @@ -73,9 +75,9 @@ export function InventoryProductForm({ currentProducts, onAddProduct }: Props): return <FormProvider<Form> errors={errors} object={state} valueHandler={setState}> <InputSearchProduct selected={state.product} onChange={(p) => setState(v => ({ ...v, product: p }))} /> - <InputNumber<Form> name="quantity" label={i18n`Quantity`} tooltip={i18n`how many products will be added`} /> + { state.product && !productWithInfiniteStock && <InputNumber<Form> name="quantity" label={i18n`Quantity`} tooltip={i18n`how many products will be added`} /> } <div class="buttons is-right mt-5"> - <button class="button is-success" onClick={submit}><Translate>Add</Translate></button> + <button class="button is-success" disabled={!state.product} onClick={submit}><Translate>Add</Translate></button> </div> </FormProvider> } diff --git a/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx b/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx index 967f1cb..756ec23 100644 --- a/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx +++ b/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx @@ -28,22 +28,22 @@ import { NonInventoryProductSchema as schema } from '../../../../schemas'; import * as yup from 'yup'; -import { useTranslator } from "../../../../i18n"; +import { Translate, useTranslator } from "../../../../i18n"; type Entity = MerchantBackend.Product interface Props { onAddProduct: (p: Entity) => Promise<void>; - value?: Entity; + productToEdit?: Entity; } -export function NonInventoryProductFrom({ value, onAddProduct }: Props): VNode { +export function NonInventoryProductFrom({ productToEdit, onAddProduct }: Props): VNode { const [showCreateProduct, setShowCreateProduct] = useState(false) - const editing = !!value + const isEditing = !!productToEdit useEffect(() => { - setShowCreateProduct(editing) - }, [editing]) + setShowCreateProduct(isEditing) + }, [isEditing]) const [submitForm, addFormSubmitter] = useListener<Partial<MerchantBackend.Product> | undefined>((result) => { if (result) { @@ -62,10 +62,12 @@ export function NonInventoryProductFrom({ value, onAddProduct }: Props): VNode { return <Fragment> <div class="buttons"> - <button class="button is-success" onClick={() => setShowCreateProduct(true)} >add new product</button> + <button class="button is-success" onClick={() => setShowCreateProduct(true)} ><Translate>add new product</Translate></button> </div> - {showCreateProduct && <ConfirmModal active onCancel={() => setShowCreateProduct(false)} onConfirm={submitForm}> - <ProductForm initial={value} onSubscribe={addFormSubmitter} /> + {showCreateProduct && <ConfirmModal active + description="alskdj alsk jdalksjd laksjd lkasjd" + onCancel={() => setShowCreateProduct(false)} onConfirm={submitForm}> + <ProductForm initial={productToEdit} onSubscribe={addFormSubmitter} /> </ConfirmModal>} </Fragment> } diff --git a/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx b/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx index db0be90..14c5d68 100644 --- a/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx +++ b/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx @@ -17,6 +17,7 @@ import { h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { CreatedSuccessfully } from "../../../../components/notifications/CreatedSuccessfully"; import { useOrderAPI } from "../../../../hooks/order"; +import { Translate } from "../../../../i18n"; import { Entity } from "./index"; interface Props { @@ -38,7 +39,7 @@ export function OrderCreatedSuccessfully({ entity, onConfirm, onCreateAnother }: return <CreatedSuccessfully onConfirm={onConfirm} onCreateAnother={onCreateAnother}> <div class="field is-horizontal"> <div class="field-label is-normal"> - <label class="label">Amount</label> + <label class="label"><Translate>Amount</Translate></label> </div> <div class="field-body is-flex-grow-3"> <div class="field"> @@ -50,7 +51,7 @@ export function OrderCreatedSuccessfully({ entity, onConfirm, onCreateAnother }: </div> <div class="field is-horizontal"> <div class="field-label is-normal"> - <label class="label">Summary</label> + <label class="label"><Translate>Summary</Translate></label> </div> <div class="field-body is-flex-grow-3"> <div class="field"> @@ -62,7 +63,7 @@ export function OrderCreatedSuccessfully({ entity, onConfirm, onCreateAnother }: </div> <div class="field is-horizontal"> <div class="field-label is-normal"> - <label class="label">Order ID</label> + <label class="label"><Translate>Order ID</Translate></label> </div> <div class="field-body is-flex-grow-3"> <div class="field"> @@ -74,7 +75,7 @@ export function OrderCreatedSuccessfully({ entity, onConfirm, onCreateAnother }: </div> <div class="field is-horizontal"> <div class="field-label is-normal"> - <label class="label">Payment URL</label> + <label class="label"><Translate>Payment URL</Translate></label> </div> <div class="field-body is-flex-grow-3"> <div class="field"> diff --git a/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx b/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx index be05b43..9f148b6 100644 --- a/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx +++ b/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx @@ -19,6 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { AmountJson, Amounts } from "@gnu-taler/taler-util"; import { format } from "date-fns"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; @@ -29,7 +30,7 @@ import { InputDate } from "../../../../components/form/InputDate"; import { InputDuration } from "../../../../components/form/InputDuration"; import { InputGroup } from "../../../../components/form/InputGroup"; import { InputLocation } from "../../../../components/form/InputLocation"; -import { NotificationCard } from "../../../../components/menu"; +import { TextField } from "../../../../components/form/TextField"; import { ProductList } from "../../../../components/product/ProductList"; import { MerchantBackend } from "../../../../declaration"; import { Translate, useTranslator } from "../../../../i18n"; @@ -52,6 +53,35 @@ type Unpaid = MerchantBackend.Orders.CheckPaymentUnpaidResponse type Claimed = MerchantBackend.Orders.CheckPaymentClaimedResponse +function ContractTerms({ value }: { value: CT }) { + const i18n = useTranslator() + + return <InputGroup name="contract_terms" label={i18n`Contract Terms`}> + <FormProvider<CT> object={value} valueHandler={null} > + <Input<CT> readonly name="summary" label={i18n`Summary`} tooltip={i18n`human-readable description of the whole purchase`} /> + <InputCurrency<CT> readonly name="amount" label={i18n`Amount`} tooltip={i18n`total price for the transaction`} /> + {value.fulfillment_url && + <Input<CT> readonly name="fulfillment_url" label={i18n`Fulfillment URL`} tooltip={i18n`URL for this purchase`} /> + } + <Input<CT> readonly name="max_fee" label={i18n`Max fee`} tooltip={i18n`maximum total deposit fee accepted by the merchant for this contract`} /> + <Input<CT> readonly name="max_wire_fee" label={i18n`Max wire fee`} tooltip={i18n`maximum wire fee accepted by the merchant`} /> + <Input<CT> readonly name="wire_fee_amortization" label={i18n`Wire fee amortization`} tooltip={i18n`over how many customer transactions does the merchant expect to amortize wire fees on average`} /> + <InputDate<CT> readonly name="timestamp" label={i18n`Created at`} tooltip={i18n`time when this contract was generated`} /> + <InputDate<CT> readonly name="refund_deadline" label={i18n`Refund deadline`} tooltip={i18n`after this deadline has passed no refunds will be accepted`} /> + <InputDate<CT> readonly name="pay_deadline" label={i18n`Payment deadline`} tooltip={i18n`after this deadline, the merchant won't accept payments for the contract`} /> + <InputDate<CT> readonly name="wire_transfer_deadline" label={i18n`Wire transfer deadline`} tooltip={i18n`transfer deadline for the exchange`} /> + <InputDate<CT> readonly name="delivery_date" label={i18n`Delivery date`} tooltip={i18n`time indicating when the order should be delivered`} /> + {value.delivery_date && + <InputGroup name="delivery_location" label={i18n`Location`} tooltip={i18n`where the order will be delivered`} > + <InputLocation name="payments.delivery_location" /> + </InputGroup> + } + <InputDuration<CT> readonly name="auto_refund" label={i18n`Auto-refund delay`} tooltip={i18n`how long the wallet should try to get an automatic refund for the purchase`} /> + <Input<CT> readonly name="extra" label={i18n`Extra info`} tooltip={i18n`extra data that is only interpreted by the merchant frontend`} /> + </FormProvider> + </InputGroup> +} + function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders.CheckPaymentClaimedResponse }) { const events: Event[] = [] events.push({ @@ -126,11 +156,8 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders. whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', - // maxWidth: '100%', }}> - {/* <a href={order.order_status_url} rel="nofollow" target="new">{order.order_status_url}</a> */} - <p><Translate>pay at</Translate>: <b>missing value, there is no order_status_url</b></p> - <p><Translate>created at</Translate>: {format(new Date(order.contract_terms.timestamp.t_ms), 'yyyy-MM-dd HH:mm:ss')}</p> + <p><b><Translate>claimed at</Translate>:</b> {format(new Date(order.contract_terms.timestamp.t_ms), 'yyyy-MM-dd HH:mm:ss')}</p> </div> </div> </div> @@ -155,18 +182,12 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders. </div> </section> - {order.contract_terms.products.length > 0 && - <section class="section"> - <div class="columns"> - <div class="column is-12" > - <div class="title"><Translate>Product list</Translate></div> - <ProductList list={order.contract_terms.products} /> - </div> - <div class="column" /> - </div> - </section> - } + {order.contract_terms.products.length ? <Fragment> + <div class="title"><Translate>Product list</Translate></div> + <ProductList list={order.contract_terms.products} /> + </Fragment> : undefined} + {value.contract_terms && <ContractTerms value={value.contract_terms} />} </div> <div class="column" /> </div> @@ -207,19 +228,43 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. type: 'refund', }) }) - order.wire_details.forEach(e => { - events.push({ - when: new Date(e.execution_time.t_ms), - description: `wired`, - type: 'wired', - }) - }) - if (order.contract_terms.wire_transfer_deadline.t_ms !== 'never' && - order.contract_terms.wire_transfer_deadline.t_ms < new Date().getTime()) events.push({ - when: new Date(order.contract_terms.wire_transfer_deadline.t_ms - 1000 * 10), - description: `wired (faked)`, - type: 'wired', - }) + if (order.wire_details && order.wire_details.length) { + if (order.wire_details.length > 1) { + let last: MerchantBackend.Orders.TransactionWireTransfer | null = null + let first: MerchantBackend.Orders.TransactionWireTransfer | null = null + let total: AmountJson | null = null + + order.wire_details.forEach(w => { + if (last === null || last.execution_time.t_ms < w.execution_time.t_ms) { + last = w + } + if (first === null || first.execution_time.t_ms > w.execution_time.t_ms) { + first = w + } + total = total === null ? Amounts.parseOrThrow(w.amount) : Amounts.add(total, Amounts.parseOrThrow(w.amount)).amount + }) + events.push({ + when: new Date(last!.execution_time.t_ms), + description: `wired ${Amounts.stringify(total!)}`, + type: 'wired-range', + }) + events.push({ + when: new Date(first!.execution_time.t_ms), + description: `wire transfer started...`, + type: 'wired-range', + }) + } else { + order.wire_details.forEach(e => { + events.push({ + when: new Date(e.execution_time.t_ms), + description: `wired ${e.amount}`, + type: 'wired', + }) + }) + + } + + } const [value, valueHandler] = useState<Partial<Paid>>(order) @@ -261,10 +306,9 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. <div class="level-item"> <h1 class="title"> <div class="buttons"> - {refundable && <button class="button is-danger" onClick={() => onRefund(id)}><Translate>refund</Translate></button>} - <button class="button is-info" onClick={() => { - if (order.contract_terms.fulfillment_url) copyToClipboard(order.contract_terms.fulfillment_url) - }}><Translate>copy url</Translate></button> + <span class="has-tooltip-left" data-tooltip={refundable ? i18n`refund order`: i18n`not refundable`}> + <button class="button is-danger" disabled={!refundable} onClick={() => onRefund(id)}><Translate>refund</Translate></button> + </span> </div> </h1> </div> @@ -301,53 +345,23 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. <InputCurrency<Paid> name="deposit_total" readonly label={i18n`Deposit total`} /> {order.refunded && <InputCurrency<Paid> name="refund_amount" readonly label={i18n`Refunded amount`} />} <Input<Paid> name="order_status" readonly label={i18n`Order status`} /> - {order.order_status_url && <Input<Paid> name="order_status_url" readonly label={i18n`Status URL`} />} + <TextField<Paid> name="order_status_url" label={i18n`Status URL`} > + <a target="_blank" href={order.order_status_url}> + {order.order_status_url} + </a> + </TextField> </FormProvider> </div> </div> </section> - {value.contract_terms && <section class="section"> - <div class="columns"> - <div class="column is-12" > - <div class="title"><Translate>Contract Terms</Translate></div> - <FormProvider<CT> object={value.contract_terms} valueHandler={null} > - <Input<CT> readonly name="summary" label={i18n`Summary`} tooltip={i18n`human-readable description of the whole purchase`} /> - <InputCurrency<CT> readonly name="amount" label={i18n`Amount`} tooltip={i18n`total price for the transaction`} /> - {value.contract_terms.fulfillment_url && - <Input<CT> readonly name="fulfillment_url" label={i18n`Fulfillment URL`} tooltip={i18n`URL for this purchase`} /> - } - <Input<CT> readonly name="max_fee" label={i18n`Max fee`} tooltip={i18n`maximum total deposit fee accepted by the merchant for this contract`} /> - <Input<CT> readonly name="max_wire_fee" label={i18n`Max wire fee`} tooltip={i18n`maximum wire fee accepted by the merchant`} /> - <Input<CT> readonly name="wire_fee_amortization" label={i18n`Wire fee amortization`} tooltip={i18n`over how many customer transactions does the merchant expect to amortize wire fees on average`} /> - <InputDate<CT> readonly name="timestamp" label={i18n`Created at`} tooltip={i18n`time when this contract was generated`} /> - <InputDate<CT> readonly name="refund_deadline" label={i18n`Refund deadline`} tooltip={i18n`after this deadline has passed no refunds will be accepted`} /> - <InputDate<CT> readonly name="pay_deadline" label={i18n`Payment deadline`} tooltip={i18n`after this deadline, the merchant won't accept payments for the contract`} /> - <InputDate<CT> readonly name="wire_transfer_deadline" label={i18n`Wire transfer deadline`} tooltip={i18n`transfer deadline for the exchange`} /> - <InputDate<CT> readonly name="delivery_date" label={i18n`Delivery date`} tooltip={i18n`time indicating when the order should be delivered`} /> - {value.contract_terms.delivery_date && - <InputGroup name="delivery_location" label={i18n`Location`} tooltip={i18n`where the order will be delivered`} > - <InputLocation name="payments.delivery_location" /> - </InputGroup> - } - <InputDuration<CT> readonly name="auto_refund" label={i18n`Auto-refund delay`} tooltip={i18n`how long the wallet should try to get an automatic refund for the purchase`} /> - <Input<CT> readonly name="extra" label={i18n`Extra info`} tooltip={i18n`extra data that is only interpreted by the merchant frontend`} /> - </FormProvider> - </div> - <div class="column" /> - </div> - </section>} - {order.contract_terms.products.length ? <section class="section"> - <div class="columns"> - <div class="column is-12" > - <div class="title"><Translate>Product list</Translate></div> - <ProductList list={order.contract_terms.products} /> - </div> - <div class="column" /> - </div> - </section> : undefined} + {order.contract_terms.products.length ? <Fragment> + <div class="title"><Translate>Product list</Translate></div> + <ProductList list={order.contract_terms.products} /> + </Fragment> : undefined} + {value.contract_terms && <ContractTerms value={value.contract_terms} />} </div> <div class="column" /> </div> @@ -380,10 +394,9 @@ function UnpaidPage({ id, order }: { id: string; order: MerchantBackend.Orders.C whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', - // maxWidth: '100%', }}> - <p><Translate>pay at</Translate>: <a href={order.order_status_url} rel="nofollow" target="new">{order.order_status_url}</a></p> - <p><Translate>created at</Translate>: <b>missing value, there is no contract term yet</b></p> + <p><b><Translate>pay at</Translate>:</b> <a href={order.order_status_url} rel="nofollow" target="new">{order.order_status_url}</a></p> + <p><b><Translate>created at</Translate>:</b> {format(new Date(order.creation_time.t_ms), 'yyyy-MM-dd HH:mm:ss')}</p> </div> </div> </div> @@ -394,8 +407,10 @@ function UnpaidPage({ id, order }: { id: string; order: MerchantBackend.Orders.C <section class="section is-main-section"> <div class="columns"> <div class="column" /> - <div class="column is-6"> + <div class="column is-four-fifths"> <FormProvider<Unpaid> object={value} valueHandler={valueHandler} > + <Input<Unpaid> readonly name="summary" label={i18n`Summary`} tooltip={i18n`human-readable description of the whole purchase`} /> + <InputCurrency<Unpaid> readonly name="total_amount" label={i18n`Amount`} tooltip={i18n`total price for the transaction`} /> <Input<Unpaid> name="order_status" readonly label={i18n`Order status`} /> <Input<Unpaid> name="order_status_url" readonly label={i18n`Order status URL`} /> <Input<Unpaid> name="taler_pay_uri" readonly label={i18n`Payment URI`} /> @@ -432,7 +447,7 @@ export function DetailPage({ id, selected, onRefund, onBack }: Props): VNode { />} <div class="columns"> <div class="column" /> - <div class="column is-two-thirds"> + <div class="column is-four-fifths"> <div class="buttons is-right mt-5"> <button class="button" onClick={onBack}><Translate>Back</Translate></button> </div> diff --git a/packages/frontend/src/paths/instance/orders/details/Timeline.tsx b/packages/frontend/src/paths/instance/orders/details/Timeline.tsx index d4f17c4..16adbcb 100644 --- a/packages/frontend/src/paths/instance/orders/details/Timeline.tsx +++ b/packages/frontend/src/paths/instance/orders/details/Timeline.tsx @@ -47,7 +47,7 @@ export function Timeline({ events:e }: Props) { } }) return <div class="timeline"> - {events.map((e,i) => { + {state.map((e,i) => { return <div key={i} class="timeline-item"> {(() => { switch (e.type) { @@ -55,6 +55,7 @@ export function Timeline({ events:e }: Props) { case "delivery": return <div class="timeline-marker is-icon "><i class="mdi mdi-delivery" /></div> case "start": return <div class="timeline-marker is-icon is-success"><i class="mdi mdi-flag " /></div> case "wired": return <div class="timeline-marker is-icon is-success"><i class="mdi mdi-cash" /></div> + case "wired-range": return <div class="timeline-marker is-icon is-success"><i class="mdi mdi-cash" /></div> case "refund": return <div class="timeline-marker is-icon is-danger"><i class="mdi mdi-cash" /></div> case "now": return <div class="timeline-marker is-icon is-info"><i class="mdi mdi-clock" /></div> } @@ -71,5 +72,5 @@ export function Timeline({ events:e }: Props) { export interface Event { when: Date; description: string; - type: 'start' | 'refund' | 'wired' | 'deadline' | 'delivery' | 'now' + type: 'start' | 'refund' | 'wired' | 'wired-range' |'deadline' | 'delivery' | 'now' } diff --git a/packages/frontend/src/paths/instance/orders/list/Table.tsx b/packages/frontend/src/paths/instance/orders/list/Table.tsx index 4057ca2..41c7293 100644 --- a/packages/frontend/src/paths/instance/orders/list/Table.tsx +++ b/packages/frontend/src/paths/instance/orders/list/Table.tsx @@ -31,7 +31,7 @@ import { ConfirmModal } from "../../../../components/modal"; import { MerchantBackend, WithId } from "../../../../declaration"; import { useOrderDetails } from "../../../../hooks/order"; import { Translate, useTranslator } from "../../../../i18n"; -import { AuthorizeTipSchema, RefundSchema as RefundSchema } from "../../../../schemas"; +import { RefundSchema as RefundSchema } from "../../../../schemas"; import { mergeRefunds, subtractPrices, sumPrices } from "../../../../utils/amount"; import { AMOUNT_ZERO_REGEX } from "../../../../utils/constants"; @@ -54,6 +54,7 @@ export function CardTable({ instances, onCreate, onRefund, onCopyURL, onSelect, const [showRefund, setShowRefund] = useState<string | undefined>(undefined) + const i18n = useTranslator() return <div class="card has-table"> <header class="card-header"> @@ -62,9 +63,11 @@ export function CardTable({ instances, onCreate, onRefund, onCopyURL, onSelect, <div class="card-header-icon" aria-label="more options" /> <div class="card-header-icon" aria-label="more options"> + <span class="has-tooltip-left" data-tooltip={i18n`add new order`}> <button class="button is-info" type="button" onClick={onCreate}> <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" /></span> </button> + </span> </div> </header> @@ -114,7 +117,7 @@ function Table({ instances, onSelect, onRefund, onCopyURL, onLoadMoreAfter, onLo <tr> <th style={{ minWidth: 100 }}><Translate>Date</Translate></th> <th style={{ minWidth: 100 }}><Translate>Amount</Translate></th> - <th style={{ minWidth: 500 }}><Translate>Summary</Translate></th> + <th style={{ minWidth: 400 }}><Translate>Summary</Translate></th> <th style={{ minWidth: 50 }} /> </tr> </thead> diff --git a/packages/frontend/src/paths/instance/orders/list/index.tsx b/packages/frontend/src/paths/instance/orders/list/index.tsx index c85db0b..8bfe23d 100644 --- a/packages/frontend/src/paths/instance/orders/list/index.tsx +++ b/packages/frontend/src/paths/instance/orders/list/index.tsx @@ -41,7 +41,7 @@ interface Props { export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNotFound }: Props): VNode { - const [filter, setFilter] = useState<InstanceOrderFilter>({ }) + const [filter, setFilter] = useState<InstanceOrderFilter>({}) const [pickDate, setPickDate] = useState(false) const setNewDate = (date: Date) => setFilter(prev => ({ ...prev, date })) @@ -66,7 +66,7 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo async function testIfOrderExistAndSelect() { if (!orderId) { - setErrorOrderId('Enter an order id') + setErrorOrderId(i18n`Enter an order id`) return; } try { @@ -74,11 +74,12 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo onSelect(orderId) setErrorOrderId(undefined) } catch { - setErrorOrderId('order not found') + setErrorOrderId(i18n`order not found`) } } const i18n = useTranslator() + const dateTooltip = i18n`jump to order closer to a given date` return <section class="section is-main-section"> <NotificationCard notification={notif} /> @@ -91,11 +92,11 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo <input class={errorOrderId ? "input is-danger" : "input"} type="text" value={orderId} onChange={e => setOrderId(e.currentTarget.value)} placeholder={i18n`order id`} /> {errorOrderId && <p class="help is-danger">{errorOrderId}</p>} </div> - <div class="control"> - <a class="button" onClick={testIfOrderExistAndSelect}> + <span class="has-tooltip-bottom" data-tooltip={i18n`view order details`}> + <button class="button" onClick={testIfOrderExistAndSelect}> <span class="icon"><i class="mdi mdi-arrow-right" /></span> - </a> - </div> + </button> + </span> </div> </div> </div> @@ -104,10 +105,26 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo <div class="column"> <div class="tabs"> <ul> - <li class={isAllActive}><a onClick={() => setFilter({})}><Translate>All</Translate></a></li> - <li class={isPaidActive}><a onClick={() => setFilter({ paid: 'yes' })}><Translate>Paid</Translate></a></li> - <li class={isRefundedActive}><a onClick={() => setFilter({ refunded: 'yes' })}><Translate>Refunded</Translate></a></li> - <li class={isNotWiredActive}><a onClick={() => setFilter({ wired: 'no' })}><Translate>Not wired</Translate></a></li> + <li class={isAllActive}> + <div class="has-tooltip-right" data-tooltip={i18n`remove all filters`}> + <a onClick={() => setFilter({})}><Translate>All</Translate></a> + </div> + </li> + <li class={isPaidActive}> + <div class="has-tooltip-right" data-tooltip={i18n`filter paid orders`}> + <a onClick={() => setFilter({ paid: 'yes' })}><Translate>Paid</Translate></a> + </div> + </li> + <li class={isRefundedActive}> + <div class="has-tooltip-right" data-tooltip={i18n`filter refunded orders`}> + <a onClick={() => setFilter({ refunded: 'yes' })}><Translate>Refunded</Translate></a> + </div> + </li> + <li class={isNotWiredActive}> + <div class="has-tooltip-left" data-tooltip={i18n`filter not yet wired orders`}> + <a onClick={() => setFilter({ wired: 'no' })}><Translate>Not wired</Translate></a> + </div> + </li> </ul> </div> </div> @@ -120,12 +137,16 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo </a> </div>} <div class="control"> - <input class="input" type="text" readonly value={!filter.date ? '' : format(filter.date, 'yyyy/MM/dd')} placeholder={i18n`date (YYYY/MM/DD)`} /> + <span class="has-tooltip-top" data-tooltip={dateTooltip}> + <input class="input" type="text" readonly value={!filter.date ? '' : format(filter.date, 'yyyy/MM/dd')} placeholder={i18n`date (YYYY/MM/DD)`} onClick={() => { setPickDate(true) }} /> + </span> </div> <div class="control"> - <a class="button" onClick={() => { setPickDate(true) }}> - <span class="icon"><i class="mdi mdi-calendar" /></span> - </a> + <span class="has-tooltip-left" data-tooltip={dateTooltip}> + <a class="button" onClick={() => { setPickDate(true) }}> + <span class="icon"><i class="mdi mdi-calendar" /></span> + </a> + </span> </div> </div> </div> |