Skip to content

Commit 440b28e

Browse files
committed
feat(common): APPEX-202 implement orders page designs
1 parent 63f9dd9 commit 440b28e

File tree

6 files changed

+157
-3
lines changed

6 files changed

+157
-3
lines changed

components/header.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ export const TabRoutes = {
1414
};
1515

1616
const HeaderlessRoutes = [
17+
'/orders/[orderId]',
1718
'/orders/[orderId]/labels',
1819
'/orders/[orderId]/modal',
19-
]
20+
];
2021

2122
const InnerRoutes = [
2223
'/products/[pid]',

lib/hooks.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import useSWR from 'swr';
22
import { useSession } from '../context/session';
3-
import { ErrorProps, ListItem, Order, QueryParams } from '../types';
3+
import { ErrorProps, ListItem, Order, QueryParams, ShippingAndProductsInfo } from '../types';
44

55
async function fetcher(url: string, query: string) {
66
const res = await fetch(`${url}?${query}`);
@@ -75,3 +75,20 @@ export const useOrder = (orderId: number) => {
7575
error,
7676
};
7777
}
78+
79+
export const useShippingAndProductsInfo = (orderId: number) => {
80+
const { context } = useSession();
81+
const params = new URLSearchParams({ context }).toString();
82+
const shouldFetch = context && orderId !== undefined;
83+
84+
// Shipping addresses and products are not included in the order data and need to be fetched separately
85+
const { data, error } = useSWR<ShippingAndProductsInfo, ErrorProps>(
86+
shouldFetch ? [`/api/orders/${orderId}/shipping_products`, params] : null, fetcher
87+
);
88+
89+
return {
90+
order: data,
91+
isLoading: !data && !error,
92+
error,
93+
};
94+
}

pages/api/orders/[orderId]/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default async function orderId(req: NextApiRequest, res: NextApiResponse)
99

1010
try {
1111
const { accessToken, storeHash } = await getSession(req);
12-
const bigcommerce = bigcommerceClient(accessToken, storeHash , 'v2');
12+
const bigcommerce = bigcommerceClient(accessToken, storeHash, 'v2');
1313

1414
switch (method) {
1515
case 'GET': {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { NextApiRequest, NextApiResponse } from 'next';
2+
import { bigcommerceClient, getSession } from '../../../../lib/auth';
3+
4+
export default async function shippingAddressesAndProducts(req: NextApiRequest, res: NextApiResponse) {
5+
const {
6+
query: { orderId },
7+
method,
8+
} = req;
9+
10+
try {
11+
const { accessToken, storeHash } = await getSession(req);
12+
const bigcommerce = bigcommerceClient(accessToken, storeHash, 'v2');
13+
14+
switch (method) {
15+
case 'GET': {
16+
const shipping_addresses = await bigcommerce.get(`/orders/${orderId}/shipping_addresses`);
17+
const products = await bigcommerce.get(`/orders/${orderId}/products`);
18+
19+
res.status(200).json({ shipping_addresses, products });
20+
21+
break;
22+
}
23+
24+
default: {
25+
res.setHeader('Allow', ['GET']);
26+
res.status(405).end(`Method ${method} Not Allowed`);
27+
}
28+
}
29+
30+
} catch (error) {
31+
const { message, response } = error;
32+
res.status(response?.status || 500).json({ message });
33+
}
34+
}

pages/orders/[orderId]/index.tsx

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Button, Flex, H1, Panel, StatefulTable, Text } from '@bigcommerce/big-design';
2+
import { useRouter } from 'next/router';
3+
4+
import ErrorMessage from '../../../components/error';
5+
import Loading from '../../../components/loading';
6+
import { useShippingAndProductsInfo } from '../../../lib/hooks';
7+
import { BillingAddress, OrderProduct, ShippingAndProductsInfo } from '../../../types';
8+
9+
const InternalOrderPage = (order: ShippingAndProductsInfo) => {
10+
const { shipping_addresses = [], products = [] } = order
11+
const items = shipping_addresses.map(address => {
12+
const addressProducts = products.filter(({ order_address_id }) => order_address_id === address.id);
13+
14+
return { address, addressProducts }
15+
});
16+
17+
const Address = (address: BillingAddress) => (
18+
<>
19+
<Text margin='none'>{address.first_name} {address.last_name}</Text>
20+
<Text margin='none'>{address.street_1} {address.street_2}</Text>
21+
<Text margin='none'>{address.city}, {address.state} {address.zip}</Text>
22+
</>
23+
);
24+
25+
const renderOrderProducts = (addressProducts: OrderProduct[]) => (
26+
<>
27+
{addressProducts.map(product => <Text key={product.id}>{product.name}</Text>)}
28+
</>
29+
);
30+
31+
const renderOrderProductsQuantities = (addressProducts: OrderProduct[]) => (
32+
<>
33+
{addressProducts.map(product => <Text key={product.id}>{product.quantity}</Text>)}
34+
</>
35+
);
36+
37+
return (
38+
<>
39+
<Flex justifyContent="space-between" marginBottom="medium">
40+
<H1>Order details</H1>
41+
<Button>Create shipment</Button>
42+
</Flex>
43+
<Panel>
44+
<StatefulTable
45+
columns={[
46+
{ header: 'Ship to', hash: 'address', render: ({ address }) => <Address {...address} /> },
47+
{
48+
header: 'Products',
49+
hash: 'addressProducts',
50+
render: ({ addressProducts }) => renderOrderProducts(addressProducts),
51+
},
52+
{
53+
header: 'Quantity',
54+
hash: 'quantity',
55+
render: ({ addressProducts }) => renderOrderProductsQuantities(addressProducts),
56+
},
57+
]}
58+
items={items}
59+
/>
60+
</Panel>
61+
</>
62+
);
63+
};
64+
65+
const OrderPage = () => {
66+
const router = useRouter();
67+
const { orderId } = router.query;
68+
const { isLoading, order, error }= useShippingAndProductsInfo(parseInt(`${orderId}`, 10));
69+
70+
if (isLoading) return <Loading />;
71+
72+
if (error) return <ErrorMessage error={error} />;
73+
74+
return <InternalOrderPage {...order} />;
75+
};
76+
77+
export default OrderPage;

types/order.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,26 @@ export interface BillingAddress {
1111
country: string;
1212
}
1313

14+
export interface ShippingAddress {
15+
[key: string]: unknown;
16+
first_name: string;
17+
last_name: string;
18+
street_1: string;
19+
street_2: string;
20+
city: string;
21+
state: string;
22+
zip: string;
23+
country: string;
24+
}
25+
26+
export interface OrderProduct {
27+
[key: string]: unknown;
28+
id: number;
29+
name: string;
30+
quantity: number;
31+
order_address_id: number;
32+
}
33+
1434
export interface Order {
1535
// Additional fields exist, type as needed
1636
[key: string]: unknown;
@@ -28,3 +48,8 @@ export interface Order {
2848
total_inc_tax: string;
2949
total_tax: string;
3050
}
51+
52+
export interface ShippingAndProductsInfo {
53+
shipping_addresses: ShippingAddress[];
54+
products: OrderProduct[];
55+
}

0 commit comments

Comments
 (0)