aboutsummaryrefslogtreecommitdiff
path: root/packages/merchant-backoffice-ui/src/paths/instance/orders/list
diff options
context:
space:
mode:
Diffstat (limited to 'packages/merchant-backoffice-ui/src/paths/instance/orders/list')
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/list/List.stories.tsx2
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx256
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx10
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx258
4 files changed, 321 insertions, 205 deletions
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/List.stories.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/List.stories.tsx
index 8cddd7fd6..156c577f4 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/List.stories.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/List.stories.tsx
@@ -43,7 +43,7 @@ export default {
function createExample<Props>(
Component: FunctionalComponent<Props>,
- props: Partial<Props>
+ props: Partial<Props>,
) {
const r = (args: any) => <Component {...args} />;
r.args = props;
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx
index 60be23c21..bca90e352 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx
@@ -15,33 +15,33 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { format } from 'date-fns';
-import { h, VNode } from 'preact';
-import { useState } from 'preact/hooks';
+import { format } from "date-fns";
+import { h, VNode } from "preact";
+import { useState } from "preact/hooks";
import { DatePicker } from "../../../../components/picker/DatePicker.js";
import { MerchantBackend, WithId } from "../../../../declaration.js";
-import { Translate, useTranslator } from '../../../../i18n/index.js';
+import { Translate, useTranslator } from "../../../../i18n/index.js";
import { CardTable } from "./Table.js";
export interface ListPageProps {
- errorOrderId: string | undefined,
+ errorOrderId: string | undefined;
- onShowAll: () => void,
- onShowPaid: () => void,
- onShowRefunded: () => void,
- onShowNotWired: () => void,
+ onShowAll: () => void;
+ onShowPaid: () => void;
+ onShowRefunded: () => void;
+ onShowNotWired: () => void;
onCopyURL: (id: string) => void;
- isAllActive: string,
- isPaidActive: string,
- isRefundedActive: string,
- isNotWiredActive: string,
+ isAllActive: string;
+ isPaidActive: string;
+ isRefundedActive: string;
+ isNotWiredActive: string;
- jumpToDate?: Date,
- onSelectDate: (date?: Date) => void,
+ jumpToDate?: Date;
+ onSelectDate: (date?: Date) => void;
orders: (MerchantBackend.Orders.OrderHistoryEntry & WithId)[];
onLoadMoreBefore?: () => void;
@@ -55,92 +55,168 @@ export interface ListPageProps {
onCreate: () => void;
}
-export function ListPage({ orders, errorOrderId, isAllActive, onSelectOrder, onRefundOrder, onSearchOrderById, jumpToDate, onCopyURL, onShowAll, onShowPaid, onShowRefunded, onShowNotWired, onSelectDate, isPaidActive, isRefundedActive, isNotWiredActive, onCreate }: ListPageProps): VNode {
+export function ListPage({
+ orders,
+ errorOrderId,
+ isAllActive,
+ onSelectOrder,
+ onRefundOrder,
+ onSearchOrderById,
+ jumpToDate,
+ onCopyURL,
+ onShowAll,
+ onShowPaid,
+ onShowRefunded,
+ onShowNotWired,
+ onSelectDate,
+ isPaidActive,
+ isRefundedActive,
+ isNotWiredActive,
+ onCreate,
+}: ListPageProps): VNode {
const i18n = useTranslator();
const dateTooltip = i18n`select date to show nearby orders`;
const [pickDate, setPickDate] = useState(false);
- const [orderId, setOrderId] = useState<string>('');
-
- return <section class="section is-main-section">
+ const [orderId, setOrderId] = useState<string>("");
- <div class="level">
- <div class="level-left">
- <div class="level-item">
- <div class="field has-addons">
- <div class="control">
- <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>}
+ return (
+ <section class="section is-main-section">
+ <div class="level">
+ <div class="level-left">
+ <div class="level-item">
+ <div class="field has-addons">
+ <div class="control">
+ <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>
+ <span
+ class="has-tooltip-bottom"
+ data-tooltip={i18n`jump to order with the given order ID`}
+ >
+ <button
+ class="button"
+ onClick={(e) => onSearchOrderById(orderId)}
+ >
+ <span class="icon">
+ <i class="mdi mdi-arrow-right" />
+ </span>
+ </button>
+ </span>
</div>
- <span class="has-tooltip-bottom" data-tooltip={i18n`jump to order with the given order ID`}>
- <button class="button" onClick={(e) => onSearchOrderById(orderId)}>
- <span class="icon"><i class="mdi mdi-arrow-right" /></span>
- </button>
- </span>
</div>
</div>
</div>
- </div>
- <div class="columns">
- <div class="column is-two-thirds">
- <div class="tabs" style={{overflow:'inherit'}}>
- <ul>
- <li class={isAllActive}>
- <div class="has-tooltip-right" data-tooltip={i18n`remove all filters`}>
- <a onClick={onShowAll}><Translate>All</Translate></a>
- </div>
- </li>
- <li class={isPaidActive}>
- <div class="has-tooltip-right" data-tooltip={i18n`only show paid orders`}>
- <a onClick={onShowPaid}><Translate>Paid</Translate></a>
- </div>
- </li>
- <li class={isRefundedActive}>
- <div class="has-tooltip-right" data-tooltip={i18n`only show orders with refunds`}>
- <a onClick={onShowRefunded}><Translate>Refunded</Translate></a>
+ <div class="columns">
+ <div class="column is-two-thirds">
+ <div class="tabs" style={{ overflow: "inherit" }}>
+ <ul>
+ <li class={isAllActive}>
+ <div
+ class="has-tooltip-right"
+ data-tooltip={i18n`remove all filters`}
+ >
+ <a onClick={onShowAll}>
+ <Translate>All</Translate>
+ </a>
+ </div>
+ </li>
+ <li class={isPaidActive}>
+ <div
+ class="has-tooltip-right"
+ data-tooltip={i18n`only show paid orders`}
+ >
+ <a onClick={onShowPaid}>
+ <Translate>Paid</Translate>
+ </a>
+ </div>
+ </li>
+ <li class={isRefundedActive}>
+ <div
+ class="has-tooltip-right"
+ data-tooltip={i18n`only show orders with refunds`}
+ >
+ <a onClick={onShowRefunded}>
+ <Translate>Refunded</Translate>
+ </a>
+ </div>
+ </li>
+ <li class={isNotWiredActive}>
+ <div
+ class="has-tooltip-left"
+ data-tooltip={i18n`only show orders where customers paid, but wire payments from payment provider are still pending`}
+ >
+ <a onClick={onShowNotWired}>
+ <Translate>Not wired</Translate>
+ </a>
+ </div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ <div class="column ">
+ <div class="buttons is-right">
+ <div class="field has-addons">
+ {jumpToDate && (
+ <div class="control">
+ <a class="button" onClick={() => onSelectDate(undefined)}>
+ <span class="icon" data-tooltip={i18n`clear date filter`}>
+ <i class="mdi mdi-close" />
+ </span>
+ </a>
+ </div>
+ )}
+ <div class="control">
+ <span class="has-tooltip-top" data-tooltip={dateTooltip}>
+ <input
+ class="input"
+ type="text"
+ readonly
+ value={!jumpToDate ? "" : format(jumpToDate, "yyyy/MM/dd")}
+ placeholder={i18n`date (YYYY/MM/DD)`}
+ onClick={() => {
+ setPickDate(true);
+ }}
+ />
+ </span>
</div>
- </li>
- <li class={isNotWiredActive}>
- <div class="has-tooltip-left" data-tooltip={i18n`only show orders where customers paid, but wire payments from payment provider are still pending`}>
- <a onClick={onShowNotWired}><Translate>Not wired</Translate></a>
+ <div class="control">
+ <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>
- </li>
- </ul>
- </div>
- </div>
- <div class="column ">
- <div class="buttons is-right">
- <div class="field has-addons">
- {jumpToDate && <div class="control">
- <a class="button" onClick={() => onSelectDate(undefined)}>
- <span class="icon" data-tooltip={i18n`clear date filter`}><i class="mdi mdi-close" /></span>
- </a>
- </div>}
- <div class="control">
- <span class="has-tooltip-top" data-tooltip={dateTooltip}>
- <input class="input" type="text" readonly value={!jumpToDate ? '' : format(jumpToDate, 'yyyy/MM/dd')} placeholder={i18n`date (YYYY/MM/DD)`} onClick={() => { setPickDate(true); }} />
- </span>
- </div>
- <div class="control">
- <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>
</div>
- </div>
- <DatePicker
- opened={pickDate}
- closeFunction={() => setPickDate(false)}
- dateReceiver={onSelectDate} />
+ <DatePicker
+ opened={pickDate}
+ closeFunction={() => setPickDate(false)}
+ dateReceiver={onSelectDate}
+ />
- <CardTable orders={orders}
- onCreate={onCreate}
- onCopyURL={onCopyURL}
- onSelect={onSelectOrder}
- onRefund={onRefundOrder} />
- </section>;
+ <CardTable
+ orders={orders}
+ onCreate={onCreate}
+ onCopyURL={onCopyURL}
+ onSelect={onSelectOrder}
+ onRefund={onRefundOrder}
+ />
+ </section>
+ );
}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx
index 924d09682..a1ec8d291 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx
@@ -173,7 +173,7 @@ function Table({
? "never"
: format(
new Date(i.timestamp.t_s * 1000),
- "yyyy/MM/dd HH:mm:ss"
+ "yyyy/MM/dd HH:mm:ss",
)}
</td>
<td
@@ -268,7 +268,7 @@ export function RefundModal({
.map((r) => r.amount)
.reduce(
(p, c) => Amounts.add(p, Amounts.parseOrThrow(c)).amount,
- Amounts.zeroOfCurrency(config.currency)
+ Amounts.zeroOfCurrency(config.currency),
);
const orderPrice =
order.order_status === "paid"
@@ -298,7 +298,7 @@ export function RefundModal({
: undefined,
};
const hasErrors = Object.keys(errors).some(
- (k) => (errors as any)[k] !== undefined
+ (k) => (errors as any)[k] !== undefined,
);
const validateAndConfirm = () => {
@@ -306,7 +306,7 @@ export function RefundModal({
if (!form.refund) return;
onConfirm({
refund: Amounts.stringify(
- Amounts.add(Amounts.parse(form.refund)!, totalRefunded).amount
+ Amounts.add(Amounts.parse(form.refund)!, totalRefunded).amount,
),
reason:
form.description === undefined
@@ -358,7 +358,7 @@ export function RefundModal({
? "never"
: format(
new Date(r.timestamp.t_s * 1000),
- "yyyy-MM-dd HH:mm:ss"
+ "yyyy-MM-dd HH:mm:ss",
)}
</td>
<td>{r.amount}</td>
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
index a033e7b3a..b5fe7611c 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
@@ -15,18 +15,23 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { h, VNode, Fragment } from 'preact';
-import { useState } from 'preact/hooks';
+import { h, VNode, Fragment } from "preact";
+import { useState } from "preact/hooks";
import { Loading } from "../../../../components/exception/loading.js";
import { NotificationCard } from "../../../../components/menu/index.js";
import { MerchantBackend, WithId } from "../../../../declaration.js";
import { HttpError } from "../../../../hooks/backend.js";
-import { InstanceOrderFilter, useInstanceOrders, useOrderAPI, useOrderDetails } from "../../../../hooks/order.js";
-import { useTranslator } from '../../../../i18n/index.js';
+import {
+ InstanceOrderFilter,
+ useInstanceOrders,
+ useOrderAPI,
+ useOrderDetails,
+} from "../../../../hooks/order.js";
+import { useTranslator } from "../../../../i18n/index.js";
import { Notification } from "../../../../utils/types.js";
import { RefundModal } from "./Table.js";
import { ListPage } from "./ListPage.js";
@@ -39,107 +44,133 @@ interface Props {
onCreate: () => void;
}
-export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNotFound }: Props): VNode {
- const [filter, setFilter] = useState<InstanceOrderFilter>({})
- const [orderToBeRefunded, setOrderToBeRefunded] = useState<MerchantBackend.Orders.OrderHistoryEntry | undefined>(undefined)
-
- const setNewDate = (date?: Date) => setFilter(prev => ({ ...prev, date }))
-
- const result = useInstanceOrders(filter, setNewDate)
- const { refundOrder, getPaymentURL } = useOrderAPI()
-
- const [notif, setNotif] = useState<Notification | undefined>(undefined)
-
- if (result.clientError && result.isUnauthorized) return onUnauthorized()
- if (result.clientError && result.isNotfound) return onNotFound()
- if (result.loading) return <Loading />
- if (!result.ok) return onLoadError(result)
-
- const isPaidActive = filter.paid === 'yes' ? "is-active" : ''
- const isRefundedActive = filter.refunded === 'yes' ? "is-active" : ''
- const isNotWiredActive = filter.wired === 'no' ? "is-active" : ''
- const isAllActive = filter.paid === undefined && filter.refunded === undefined && filter.wired === undefined ? 'is-active' : ''
-
- const i18n = useTranslator()
- const [errorOrderId, setErrorOrderId] = useState<string | undefined>(undefined)
+export default function ({
+ onUnauthorized,
+ onLoadError,
+ onCreate,
+ onSelect,
+ onNotFound,
+}: Props): VNode {
+ const [filter, setFilter] = useState<InstanceOrderFilter>({});
+ const [orderToBeRefunded, setOrderToBeRefunded] = useState<
+ MerchantBackend.Orders.OrderHistoryEntry | undefined
+ >(undefined);
+
+ const setNewDate = (date?: Date) => setFilter((prev) => ({ ...prev, date }));
+
+ const result = useInstanceOrders(filter, setNewDate);
+ const { refundOrder, getPaymentURL } = useOrderAPI();
+
+ const [notif, setNotif] = useState<Notification | undefined>(undefined);
+
+ if (result.clientError && result.isUnauthorized) return onUnauthorized();
+ if (result.clientError && result.isNotfound) return onNotFound();
+ if (result.loading) return <Loading />;
+ if (!result.ok) return onLoadError(result);
+
+ const isPaidActive = filter.paid === "yes" ? "is-active" : "";
+ const isRefundedActive = filter.refunded === "yes" ? "is-active" : "";
+ const isNotWiredActive = filter.wired === "no" ? "is-active" : "";
+ const isAllActive =
+ filter.paid === undefined &&
+ filter.refunded === undefined &&
+ filter.wired === undefined
+ ? "is-active"
+ : "";
+
+ const i18n = useTranslator();
+ const [errorOrderId, setErrorOrderId] = useState<string | undefined>(
+ undefined,
+ );
async function testIfOrderExistAndSelect(orderId: string) {
if (!orderId) {
- setErrorOrderId(i18n`Enter an order id`)
+ setErrorOrderId(i18n`Enter an order id`);
return;
}
try {
- await getPaymentURL(orderId)
- onSelect(orderId)
- setErrorOrderId(undefined)
+ await getPaymentURL(orderId);
+ onSelect(orderId);
+ setErrorOrderId(undefined);
} catch {
- setErrorOrderId(i18n`order not found`)
+ setErrorOrderId(i18n`order not found`);
}
}
- return <Fragment>
- <NotificationCard notification={notif} />
-
- <ListPage
- orders={result.data.orders.map(o => ({ ...o, id: o.order_id }))}
- onLoadMoreBefore={result.loadMorePrev} hasMoreBefore={!result.isReachingStart}
- onLoadMoreAfter={result.loadMore} hasMoreAfter={!result.isReachingEnd}
-
- onSelectOrder={(order) => onSelect(order.id)}
- onRefundOrder={(value) => setOrderToBeRefunded(value)}
-
- errorOrderId={errorOrderId}
- isAllActive={isAllActive}
- isNotWiredActive={isNotWiredActive}
- isPaidActive={isPaidActive}
- isRefundedActive={isRefundedActive}
- jumpToDate={filter.date}
- onCopyURL={(id) => getPaymentURL(id).then((resp) => copyToClipboard(resp.data))}
-
- onCreate={onCreate}
- onSearchOrderById={testIfOrderExistAndSelect}
- onSelectDate={setNewDate}
- onShowAll={() => setFilter({})}
- onShowPaid={() => setFilter({ paid: 'yes' })}
- onShowRefunded={() => setFilter({ refunded: 'yes' })}
- onShowNotWired={() => setFilter({ wired: 'no' })}
-
- />
-
- {orderToBeRefunded && <RefundModalForTable
- id={orderToBeRefunded.order_id}
- onCancel={() => setOrderToBeRefunded(undefined)}
- onConfirm={(value) => refundOrder(orderToBeRefunded.order_id, value)
- .then(() => setNotif({
- message: i18n`refund created successfully`,
- type: "SUCCESS"
- }))
- .catch((error) => setNotif({
- message: i18n`could not create the refund`,
- type: "ERROR",
- description: error.message
- }))
- .then(() => setOrderToBeRefunded(undefined))}
- onLoadError={(error) => {
- setNotif({
- message: i18n`could not create the refund`,
- type: "ERROR",
- description: error.message
- });
- setOrderToBeRefunded(undefined);
- return <div />;
- }}
- onUnauthorized={onUnauthorized}
- onNotFound={() => {
- setNotif({
- message: i18n`could not get the order to refund`,
- type: "ERROR",
- // description: error.message
- });
- setOrderToBeRefunded(undefined);
- return <div />;
- }} />}
- </Fragment>
+ return (
+ <Fragment>
+ <NotificationCard notification={notif} />
+
+ <ListPage
+ orders={result.data.orders.map((o) => ({ ...o, id: o.order_id }))}
+ onLoadMoreBefore={result.loadMorePrev}
+ hasMoreBefore={!result.isReachingStart}
+ onLoadMoreAfter={result.loadMore}
+ hasMoreAfter={!result.isReachingEnd}
+ onSelectOrder={(order) => onSelect(order.id)}
+ onRefundOrder={(value) => setOrderToBeRefunded(value)}
+ errorOrderId={errorOrderId}
+ isAllActive={isAllActive}
+ isNotWiredActive={isNotWiredActive}
+ isPaidActive={isPaidActive}
+ isRefundedActive={isRefundedActive}
+ jumpToDate={filter.date}
+ onCopyURL={(id) =>
+ getPaymentURL(id).then((resp) => copyToClipboard(resp.data))
+ }
+ onCreate={onCreate}
+ onSearchOrderById={testIfOrderExistAndSelect}
+ onSelectDate={setNewDate}
+ onShowAll={() => setFilter({})}
+ onShowPaid={() => setFilter({ paid: "yes" })}
+ onShowRefunded={() => setFilter({ refunded: "yes" })}
+ onShowNotWired={() => setFilter({ wired: "no" })}
+ />
+
+ {orderToBeRefunded && (
+ <RefundModalForTable
+ id={orderToBeRefunded.order_id}
+ onCancel={() => setOrderToBeRefunded(undefined)}
+ onConfirm={(value) =>
+ refundOrder(orderToBeRefunded.order_id, value)
+ .then(() =>
+ setNotif({
+ message: i18n`refund created successfully`,
+ type: "SUCCESS",
+ }),
+ )
+ .catch((error) =>
+ setNotif({
+ message: i18n`could not create the refund`,
+ type: "ERROR",
+ description: error.message,
+ }),
+ )
+ .then(() => setOrderToBeRefunded(undefined))
+ }
+ onLoadError={(error) => {
+ setNotif({
+ message: i18n`could not create the refund`,
+ type: "ERROR",
+ description: error.message,
+ });
+ setOrderToBeRefunded(undefined);
+ return <div />;
+ }}
+ onUnauthorized={onUnauthorized}
+ onNotFound={() => {
+ setNotif({
+ message: i18n`could not get the order to refund`,
+ type: "ERROR",
+ // description: error.message
+ });
+ setOrderToBeRefunded(undefined);
+ return <div />;
+ }}
+ />
+ )}
+ </Fragment>
+ );
}
interface RefundProps {
@@ -151,21 +182,30 @@ interface RefundProps {
onConfirm: (m: MerchantBackend.Orders.RefundRequest) => void;
}
-function RefundModalForTable({ id, onUnauthorized, onLoadError, onNotFound, onConfirm, onCancel }: RefundProps) {
+function RefundModalForTable({
+ id,
+ onUnauthorized,
+ onLoadError,
+ onNotFound,
+ onConfirm,
+ onCancel,
+}: RefundProps) {
const result = useOrderDetails(id);
- if (result.clientError && result.isUnauthorized) return onUnauthorized()
- if (result.clientError && result.isNotfound) return onNotFound()
- if (result.loading) return <Loading />
- if (!result.ok) return onLoadError(result)
+ if (result.clientError && result.isUnauthorized) return onUnauthorized();
+ if (result.clientError && result.isNotfound) return onNotFound();
+ if (result.loading) return <Loading />;
+ if (!result.ok) return onLoadError(result);
- return <RefundModal
- order={result.data}
- onCancel={onCancel}
- onConfirm={onConfirm}
- />
+ return (
+ <RefundModal
+ order={result.data}
+ onCancel={onCancel}
+ onConfirm={onConfirm}
+ />
+ );
}
async function copyToClipboard(text: string) {
- return navigator.clipboard.writeText(text)
+ return navigator.clipboard.writeText(text);
}