@shopify/cli 3.85.3 → 3.85.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/hydrogen/bundle/analyzer.html +155 -148
- package/dist/assets/hydrogen/starter/CHANGELOG.md +125 -49
- package/dist/assets/hydrogen/starter/app/components/AddToCartButton.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/CartLineItem.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/CartMain.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/CartSummary.tsx +62 -29
- package/dist/assets/hydrogen/starter/app/components/Header.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/PageLayout.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/ProductForm.tsx +2 -2
- package/dist/assets/hydrogen/starter/app/components/SearchForm.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/components/SearchFormPredictive.tsx +8 -3
- package/dist/assets/hydrogen/starter/app/components/SearchResults.tsx +3 -11
- package/dist/assets/hydrogen/starter/app/components/SearchResultsPredictive.tsx +2 -6
- package/dist/assets/hydrogen/starter/app/entry.client.tsx +10 -2
- package/dist/assets/hydrogen/starter/app/entry.server.tsx +5 -3
- package/dist/assets/hydrogen/starter/app/graphql/customer-account/CustomerAddressMutations.ts +7 -4
- package/dist/assets/hydrogen/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +1 -1
- package/dist/assets/hydrogen/starter/app/graphql/customer-account/CustomerOrderQuery.ts +4 -1
- package/dist/assets/hydrogen/starter/app/graphql/customer-account/CustomerOrdersQuery.ts +10 -5
- package/dist/assets/hydrogen/starter/app/graphql/customer-account/CustomerUpdateMutation.ts +3 -2
- package/dist/assets/hydrogen/starter/app/lib/context.ts +34 -17
- package/dist/assets/hydrogen/starter/app/lib/fragments.ts +1 -0
- package/dist/assets/hydrogen/starter/app/lib/orderFilters.ts +90 -0
- package/dist/assets/hydrogen/starter/app/lib/redirect.ts +1 -1
- package/dist/assets/hydrogen/starter/app/lib/session.ts +1 -1
- package/dist/assets/hydrogen/starter/app/lib/variants.ts +1 -1
- package/dist/assets/hydrogen/starter/app/root.tsx +23 -18
- package/dist/assets/hydrogen/starter/app/routes/$.tsx +2 -2
- package/dist/assets/hydrogen/starter/app/routes/[robots.txt].tsx +2 -2
- package/dist/assets/hydrogen/starter/app/routes/[sitemap.xml].tsx +2 -3
- package/dist/assets/hydrogen/starter/app/routes/_index.tsx +12 -8
- package/dist/assets/hydrogen/starter/app/routes/account.$.tsx +4 -3
- package/dist/assets/hydrogen/starter/app/routes/account._index.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/account.addresses.tsx +15 -11
- package/dist/assets/hydrogen/starter/app/routes/account.orders.$id.tsx +47 -22
- package/dist/assets/hydrogen/starter/app/routes/account.orders._index.tsx +152 -23
- package/dist/assets/hydrogen/starter/app/routes/account.profile.tsx +11 -8
- package/dist/assets/hydrogen/starter/app/routes/account.tsx +16 -4
- package/dist/assets/hydrogen/starter/app/routes/account_.authorize.tsx +2 -2
- package/dist/assets/hydrogen/starter/app/routes/account_.login.tsx +5 -3
- package/dist/assets/hydrogen/starter/app/routes/account_.logout.tsx +3 -2
- package/dist/assets/hydrogen/starter/app/routes/api.$version.[graphql.json].tsx +2 -2
- package/dist/assets/hydrogen/starter/app/routes/blogs.$blogHandle.$articleHandle.tsx +6 -10
- package/dist/assets/hydrogen/starter/app/routes/blogs.$blogHandle._index.tsx +10 -7
- package/dist/assets/hydrogen/starter/app/routes/blogs._index.tsx +13 -7
- package/dist/assets/hydrogen/starter/app/routes/cart.$lines.tsx +3 -2
- package/dist/assets/hydrogen/starter/app/routes/cart.tsx +13 -9
- package/dist/assets/hydrogen/starter/app/routes/collections.$handle.tsx +8 -11
- package/dist/assets/hydrogen/starter/app/routes/collections._index.tsx +6 -6
- package/dist/assets/hydrogen/starter/app/routes/collections.all.tsx +10 -7
- package/dist/assets/hydrogen/starter/app/routes/discount.$code.tsx +3 -2
- package/dist/assets/hydrogen/starter/app/routes/pages.$handle.tsx +8 -6
- package/dist/assets/hydrogen/starter/app/routes/policies.$handle.tsx +7 -4
- package/dist/assets/hydrogen/starter/app/routes/policies._index.tsx +19 -13
- package/dist/assets/hydrogen/starter/app/routes/products.$handle.tsx +9 -6
- package/dist/assets/hydrogen/starter/app/routes/search.tsx +14 -14
- package/dist/assets/hydrogen/starter/app/routes/sitemap.$type.$page[.xml].tsx +2 -3
- package/dist/assets/hydrogen/starter/app/routes.ts +1 -1
- package/dist/assets/hydrogen/starter/app/styles/app.css +53 -1
- package/dist/assets/hydrogen/starter/customer-accountapi.generated.d.ts +47 -13
- package/dist/assets/hydrogen/starter/env.d.ts +1 -39
- package/dist/assets/hydrogen/starter/eslint.config.js +35 -52
- package/dist/assets/hydrogen/starter/package.json +14 -15
- package/dist/assets/hydrogen/starter/react-router.config.ts +9 -3
- package/dist/assets/hydrogen/starter/server.ts +7 -7
- package/dist/assets/hydrogen/starter/storefrontapi.generated.d.ts +1 -1
- package/dist/assets/hydrogen/starter/tsconfig.json +17 -13
- package/dist/assets/hydrogen/starter/vite.config.ts +3 -0
- package/dist/assets/hydrogen/virtual-routes/components/RequestDetails.jsx +13 -20
- package/dist/assets/hydrogen/virtual-routes/routes/[.]well-known.appspecific.com[.]chrome[.]devtools[.]json.jsx +37 -0
- package/dist/{chokidar-TTCYG5AA.js → chokidar-HTKREZL3.js} +482 -7
- package/dist/{chunk-RPU6TIF2.js → chunk-3ULYQTX3.js} +7 -7
- package/dist/{chunk-IHXRXBUN.js → chunk-AVSSZ6MY.js} +6 -6
- package/dist/{chunk-I4ATBX6D.js → chunk-CHLX44DR.js} +4 -4
- package/dist/{chunk-UW4ASA6Y.js → chunk-CQSO2B3C.js} +2 -2
- package/dist/{chunk-OQKAZQIC.js → chunk-DHW4GI57.js} +5 -5
- package/dist/{chunk-HTTZVPR6.js → chunk-FGSQR4VQ.js} +3 -3
- package/dist/{chunk-3XWYM7QS.js → chunk-FMD2ETAR.js} +3 -3
- package/dist/{chunk-FGEKMLLA.js → chunk-FRHZJBJZ.js} +5 -5
- package/dist/{chunk-Y4H4HMEZ.js → chunk-G2I4CD5D.js} +2 -2
- package/dist/{chunk-HS2O5IHL.js → chunk-GG2ELY5O.js} +2 -3
- package/dist/{chunk-F7TU455C.js → chunk-GQ63RYWN.js} +2 -2
- package/dist/{chunk-VVUZFYUK.js → chunk-IAX3IWUQ.js} +4 -4
- package/dist/{chunk-EWEA4LRT.js → chunk-J6T7KVRL.js} +2 -2
- package/dist/{chunk-GRVHLYQS.js → chunk-JF6DQIJR.js} +3 -3
- package/dist/{chunk-JAUHWNMJ.js → chunk-MDDWB46W.js} +5 -5
- package/dist/{chunk-QHKSKL4E.js → chunk-MR763CPY.js} +3 -3
- package/dist/{chunk-6A6GDV25.js → chunk-MUZ7NPCX.js} +4 -4
- package/dist/{chunk-NLFRHIZY.js → chunk-NMGJYSTC.js} +5 -5
- package/dist/{chunk-D5DJSKHK.js → chunk-NTCXWD2Q.js} +111 -112
- package/dist/{chunk-HBANZKAF.js → chunk-O2O5GRI6.js} +3 -3
- package/dist/{chunk-CAONVM2S.js → chunk-ODJ7LSLO.js} +3 -3
- package/dist/{chunk-5RNGA7FX.js → chunk-P46WMXBU.js} +5 -5
- package/dist/{chunk-LJXXOFEJ.js → chunk-PFBQBDNU.js} +2 -2
- package/dist/{chunk-OURS5IQY.js → chunk-PZUWEJO3.js} +3 -3
- package/dist/{chunk-VR6Z7LKU.js → chunk-R6BNSDGA.js} +3 -3
- package/dist/{chunk-AMWSD3HH.js → chunk-RAZVOMJW.js} +3 -3
- package/dist/{chunk-C45MKMJT.js → chunk-RZPYG7LO.js} +28 -25
- package/dist/{chunk-EDXQ22O4.js → chunk-SMBX232U.js} +6 -6
- package/dist/{chunk-QP2MOS2Y.js → chunk-TE4CUUT4.js} +2 -2
- package/dist/{chunk-V5ONTA7N.js → chunk-TXX6R3WL.js} +2 -2
- package/dist/{chunk-L54PNQGV.js → chunk-TYHJPUOR.js} +2 -2
- package/dist/{chunk-XJBIASMX.js → chunk-UF2X5VHR.js} +3 -3
- package/dist/{chunk-ZHKIKKU7.js → chunk-UQT7B7DM.js} +3 -3
- package/dist/{chunk-6RJ7HBOQ.js → chunk-VVDGGMKJ.js} +3 -3
- package/dist/cli/commands/auth/login.js +10 -10
- package/dist/cli/commands/auth/login.test.js +11 -11
- package/dist/cli/commands/auth/logout.js +10 -10
- package/dist/cli/commands/auth/logout.test.js +11 -11
- package/dist/cli/commands/cache/clear.js +10 -10
- package/dist/cli/commands/debug/command-flags.js +10 -10
- package/dist/cli/commands/docs/generate.js +10 -10
- package/dist/cli/commands/docs/generate.test.js +10 -10
- package/dist/cli/commands/help.js +10 -10
- package/dist/cli/commands/kitchen-sink/async.js +11 -11
- package/dist/cli/commands/kitchen-sink/async.test.js +11 -11
- package/dist/cli/commands/kitchen-sink/index.js +13 -13
- package/dist/cli/commands/kitchen-sink/index.test.js +13 -13
- package/dist/cli/commands/kitchen-sink/prompts.js +11 -11
- package/dist/cli/commands/kitchen-sink/prompts.test.js +11 -11
- package/dist/cli/commands/kitchen-sink/static.js +11 -11
- package/dist/cli/commands/kitchen-sink/static.test.js +11 -11
- package/dist/cli/commands/notifications/generate.js +11 -11
- package/dist/cli/commands/notifications/list.js +11 -11
- package/dist/cli/commands/search.js +11 -11
- package/dist/cli/commands/upgrade.js +11 -11
- package/dist/cli/commands/version.js +11 -11
- package/dist/cli/commands/version.test.js +11 -11
- package/dist/cli/services/commands/notifications.js +6 -6
- package/dist/cli/services/commands/search.js +2 -2
- package/dist/cli/services/commands/search.test.js +2 -2
- package/dist/cli/services/commands/version.js +3 -3
- package/dist/cli/services/commands/version.test.js +4 -4
- package/dist/cli/services/kitchen-sink/async.js +2 -2
- package/dist/cli/services/kitchen-sink/prompts.js +2 -2
- package/dist/cli/services/kitchen-sink/static.js +2 -2
- package/dist/cli/services/upgrade.js +3 -3
- package/dist/cli/services/upgrade.test.js +4 -4
- package/dist/{custom-oclif-loader-YDKLB47A.js → custom-oclif-loader-X7GLA66E.js} +2 -2
- package/dist/{error-handler-BYZU2C5C.js → error-handler-QOTWDLMF.js} +8 -8
- package/dist/hooks/postrun.js +6 -6
- package/dist/hooks/prerun.js +7 -7
- package/dist/index.js +1800 -3480
- package/dist/{local-XLJD5WYP.js → local-FS3UI7PE.js} +2 -2
- package/dist/{morph-5D7H6MU2.js → morph-D4BXY376.js} +9 -9
- package/dist/{node-package-manager-I7AWSWJ4.js → node-package-manager-TX3WZQGI.js} +3 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/{ui-2AJAFJYY.js → ui-PUN5STUM.js} +2 -2
- package/dist/{workerd-4DJKRJUB.js → workerd-GJFM5MYN.js} +12 -12
- package/oclif.manifest.json +11 -56
- package/package.json +8 -8
- package/dist/chokidar-XUA2BN3J.js +0 -1120
- package/dist/chunk-F7J5CUMZ.js +0 -497
|
@@ -1,25 +1,30 @@
|
|
|
1
|
-
import {redirect,
|
|
2
|
-
import
|
|
3
|
-
import {Money, Image
|
|
4
|
-
import type {
|
|
1
|
+
import {redirect, useLoaderData} from 'react-router';
|
|
2
|
+
import type {Route} from './+types/account.orders.$id';
|
|
3
|
+
import {Money, Image} from '@shopify/hydrogen';
|
|
4
|
+
import type {
|
|
5
|
+
OrderLineItemFullFragment,
|
|
6
|
+
OrderQuery,
|
|
7
|
+
} from 'customer-accountapi.generated';
|
|
5
8
|
import {CUSTOMER_ORDER_QUERY} from '~/graphql/customer-account/CustomerOrderQuery';
|
|
6
9
|
|
|
7
|
-
export const meta: MetaFunction
|
|
10
|
+
export const meta: Route.MetaFunction = ({data}) => {
|
|
8
11
|
return [{title: `Order ${data?.order?.name}`}];
|
|
9
12
|
};
|
|
10
13
|
|
|
11
|
-
export async function loader({params, context}:
|
|
14
|
+
export async function loader({params, context}: Route.LoaderArgs) {
|
|
15
|
+
const {customerAccount} = context;
|
|
12
16
|
if (!params.id) {
|
|
13
17
|
return redirect('/account/orders');
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
const orderId = atob(params.id);
|
|
17
|
-
const {data, errors}
|
|
18
|
-
CUSTOMER_ORDER_QUERY,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const {data, errors}: {data: OrderQuery; errors?: Array<{message: string}>} =
|
|
22
|
+
await customerAccount.query(CUSTOMER_ORDER_QUERY, {
|
|
23
|
+
variables: {
|
|
24
|
+
orderId,
|
|
25
|
+
language: customerAccount.i18n.language,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
23
28
|
|
|
24
29
|
if (errors?.length || !data?.order) {
|
|
25
30
|
throw new Error('Order not found');
|
|
@@ -27,20 +32,37 @@ export async function loader({params, context}: LoaderFunctionArgs) {
|
|
|
27
32
|
|
|
28
33
|
const {order} = data;
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
const
|
|
35
|
+
// Extract line items directly from nodes array
|
|
36
|
+
const lineItems = order.lineItems.nodes;
|
|
37
|
+
|
|
38
|
+
// Extract discount applications directly from nodes array
|
|
39
|
+
const discountApplications = order.discountApplications.nodes;
|
|
32
40
|
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
// Get fulfillment status from first fulfillment node
|
|
42
|
+
const fulfillmentStatus = order.fulfillments.nodes[0]?.status ?? 'N/A';
|
|
35
43
|
|
|
44
|
+
// Get first discount value with proper type checking
|
|
36
45
|
const firstDiscount = discountApplications[0]?.value;
|
|
37
46
|
|
|
47
|
+
// Type guard for MoneyV2 discount
|
|
38
48
|
const discountValue =
|
|
39
|
-
firstDiscount?.__typename === 'MoneyV2'
|
|
49
|
+
firstDiscount?.__typename === 'MoneyV2'
|
|
50
|
+
? (firstDiscount as Extract<
|
|
51
|
+
typeof firstDiscount,
|
|
52
|
+
{__typename: 'MoneyV2'}
|
|
53
|
+
>)
|
|
54
|
+
: null;
|
|
40
55
|
|
|
56
|
+
// Type guard for percentage discount
|
|
41
57
|
const discountPercentage =
|
|
42
|
-
firstDiscount?.__typename === 'PricingPercentageValue'
|
|
43
|
-
|
|
58
|
+
firstDiscount?.__typename === 'PricingPercentageValue'
|
|
59
|
+
? (
|
|
60
|
+
firstDiscount as Extract<
|
|
61
|
+
typeof firstDiscount,
|
|
62
|
+
{__typename: 'PricingPercentageValue'}
|
|
63
|
+
>
|
|
64
|
+
).percentage
|
|
65
|
+
: null;
|
|
44
66
|
|
|
45
67
|
return {
|
|
46
68
|
order,
|
|
@@ -60,9 +82,12 @@ export default function OrderRoute() {
|
|
|
60
82
|
fulfillmentStatus,
|
|
61
83
|
} = useLoaderData<typeof loader>();
|
|
62
84
|
return (
|
|
63
|
-
|
|
85
|
+
<div className="account-order">
|
|
64
86
|
<h2>Order {order.name}</h2>
|
|
65
87
|
<p>Placed on {new Date(order.processedAt!).toDateString()}</p>
|
|
88
|
+
{order.confirmationNumber && (
|
|
89
|
+
<p>Confirmation: {order.confirmationNumber}</p>
|
|
90
|
+
)}
|
|
66
91
|
<br />
|
|
67
92
|
<div>
|
|
68
93
|
<table>
|
|
@@ -77,7 +102,7 @@ export default function OrderRoute() {
|
|
|
77
102
|
<tbody>
|
|
78
103
|
{lineItems.map((lineItem, lineItemIndex) => (
|
|
79
104
|
// eslint-disable-next-line react/no-array-index-key
|
|
80
|
-
|
|
105
|
+
<OrderLineRow key={lineItemIndex} lineItem={lineItem} />
|
|
81
106
|
))}
|
|
82
107
|
</tbody>
|
|
83
108
|
<tfoot>
|
|
@@ -165,7 +190,7 @@ export default function OrderRoute() {
|
|
|
165
190
|
View Order Status →
|
|
166
191
|
</a>
|
|
167
192
|
</p>
|
|
168
|
-
</div>
|
|
193
|
+
</div>
|
|
169
194
|
);
|
|
170
195
|
}
|
|
171
196
|
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Link,
|
|
3
|
+
useLoaderData,
|
|
4
|
+
useNavigation,
|
|
5
|
+
useSearchParams,
|
|
6
|
+
} from 'react-router';
|
|
7
|
+
import type {Route} from './+types/account.orders._index';
|
|
8
|
+
import {useRef} from 'react';
|
|
2
9
|
import {
|
|
3
10
|
Money,
|
|
4
11
|
getPaginationVariables,
|
|
5
12
|
flattenConnection,
|
|
6
13
|
} from '@shopify/hydrogen';
|
|
7
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
buildOrderSearchQuery,
|
|
16
|
+
parseOrderFilters,
|
|
17
|
+
ORDER_FILTER_FIELDS,
|
|
18
|
+
type OrderFilterParams,
|
|
19
|
+
} from '~/lib/orderFilters';
|
|
8
20
|
import {CUSTOMER_ORDERS_QUERY} from '~/graphql/customer-account/CustomerOrdersQuery';
|
|
9
21
|
import type {
|
|
10
22
|
CustomerOrdersFragment,
|
|
@@ -12,67 +24,181 @@ import type {
|
|
|
12
24
|
} from 'customer-accountapi.generated';
|
|
13
25
|
import {PaginatedResourceSection} from '~/components/PaginatedResourceSection';
|
|
14
26
|
|
|
15
|
-
|
|
27
|
+
type OrdersLoaderData = {
|
|
28
|
+
customer: CustomerOrdersFragment;
|
|
29
|
+
filters: OrderFilterParams;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const meta: Route.MetaFunction = () => {
|
|
16
33
|
return [{title: 'Orders'}];
|
|
17
34
|
};
|
|
18
35
|
|
|
19
|
-
export async function loader({request, context}:
|
|
36
|
+
export async function loader({request, context}: Route.LoaderArgs) {
|
|
37
|
+
const {customerAccount} = context;
|
|
20
38
|
const paginationVariables = getPaginationVariables(request, {
|
|
21
39
|
pageBy: 20,
|
|
22
40
|
});
|
|
23
41
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
42
|
+
const url = new URL(request.url);
|
|
43
|
+
const filters = parseOrderFilters(url.searchParams);
|
|
44
|
+
const query = buildOrderSearchQuery(filters);
|
|
45
|
+
|
|
46
|
+
const {data, errors} = await customerAccount.query(CUSTOMER_ORDERS_QUERY, {
|
|
47
|
+
variables: {
|
|
48
|
+
...paginationVariables,
|
|
49
|
+
query,
|
|
50
|
+
language: customerAccount.i18n.language,
|
|
30
51
|
},
|
|
31
|
-
);
|
|
52
|
+
});
|
|
32
53
|
|
|
33
54
|
if (errors?.length || !data?.customer) {
|
|
34
55
|
throw Error('Customer orders not found');
|
|
35
56
|
}
|
|
36
57
|
|
|
37
|
-
return {customer: data.customer};
|
|
58
|
+
return {customer: data.customer, filters};
|
|
38
59
|
}
|
|
39
60
|
|
|
40
61
|
export default function Orders() {
|
|
41
|
-
const {customer} = useLoaderData<
|
|
62
|
+
const {customer, filters} = useLoaderData<OrdersLoaderData>();
|
|
42
63
|
const {orders} = customer;
|
|
64
|
+
|
|
43
65
|
return (
|
|
44
66
|
<div className="orders">
|
|
45
|
-
|
|
67
|
+
<OrderSearchForm currentFilters={filters} />
|
|
68
|
+
<OrdersTable orders={orders} filters={filters} />
|
|
46
69
|
</div>
|
|
47
70
|
);
|
|
48
71
|
}
|
|
49
72
|
|
|
50
|
-
function OrdersTable({
|
|
73
|
+
function OrdersTable({
|
|
74
|
+
orders,
|
|
75
|
+
filters,
|
|
76
|
+
}: {
|
|
77
|
+
orders: CustomerOrdersFragment['orders'];
|
|
78
|
+
filters: OrderFilterParams;
|
|
79
|
+
}) {
|
|
80
|
+
const hasFilters = !!(filters.name || filters.confirmationNumber);
|
|
81
|
+
|
|
51
82
|
return (
|
|
52
|
-
<div className="acccount-orders">
|
|
83
|
+
<div className="acccount-orders" aria-live="polite">
|
|
53
84
|
{orders?.nodes.length ? (
|
|
54
85
|
<PaginatedResourceSection connection={orders}>
|
|
55
86
|
{({node: order}) => <OrderItem key={order.id} order={order} />}
|
|
56
87
|
</PaginatedResourceSection>
|
|
57
88
|
) : (
|
|
58
|
-
<EmptyOrders />
|
|
89
|
+
<EmptyOrders hasFilters={hasFilters} />
|
|
59
90
|
)}
|
|
60
91
|
</div>
|
|
61
92
|
);
|
|
62
93
|
}
|
|
63
94
|
|
|
64
|
-
function EmptyOrders() {
|
|
95
|
+
function EmptyOrders({hasFilters = false}: {hasFilters?: boolean}) {
|
|
65
96
|
return (
|
|
66
97
|
<div>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
98
|
+
{hasFilters ? (
|
|
99
|
+
<>
|
|
100
|
+
<p>No orders found matching your search.</p>
|
|
101
|
+
<br />
|
|
102
|
+
<p>
|
|
103
|
+
<Link to="/account/orders">Clear filters →</Link>
|
|
104
|
+
</p>
|
|
105
|
+
</>
|
|
106
|
+
) : (
|
|
107
|
+
<>
|
|
108
|
+
<p>You haven't placed any orders yet.</p>
|
|
109
|
+
<br />
|
|
110
|
+
<p>
|
|
111
|
+
<Link to="/collections">Start Shopping →</Link>
|
|
112
|
+
</p>
|
|
113
|
+
</>
|
|
114
|
+
)}
|
|
72
115
|
</div>
|
|
73
116
|
);
|
|
74
117
|
}
|
|
75
118
|
|
|
119
|
+
function OrderSearchForm({
|
|
120
|
+
currentFilters,
|
|
121
|
+
}: {
|
|
122
|
+
currentFilters: OrderFilterParams;
|
|
123
|
+
}) {
|
|
124
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
125
|
+
const navigation = useNavigation();
|
|
126
|
+
const isSearching =
|
|
127
|
+
navigation.state !== 'idle' &&
|
|
128
|
+
navigation.location?.pathname?.includes('orders');
|
|
129
|
+
const formRef = useRef<HTMLFormElement>(null);
|
|
130
|
+
|
|
131
|
+
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
const formData = new FormData(event.currentTarget);
|
|
134
|
+
const params = new URLSearchParams();
|
|
135
|
+
|
|
136
|
+
const name = formData.get(ORDER_FILTER_FIELDS.NAME)?.toString().trim();
|
|
137
|
+
const confirmationNumber = formData
|
|
138
|
+
.get(ORDER_FILTER_FIELDS.CONFIRMATION_NUMBER)
|
|
139
|
+
?.toString()
|
|
140
|
+
.trim();
|
|
141
|
+
|
|
142
|
+
if (name) params.set(ORDER_FILTER_FIELDS.NAME, name);
|
|
143
|
+
if (confirmationNumber)
|
|
144
|
+
params.set(ORDER_FILTER_FIELDS.CONFIRMATION_NUMBER, confirmationNumber);
|
|
145
|
+
|
|
146
|
+
setSearchParams(params);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const hasFilters = currentFilters.name || currentFilters.confirmationNumber;
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<form
|
|
153
|
+
ref={formRef}
|
|
154
|
+
onSubmit={handleSubmit}
|
|
155
|
+
className="order-search-form"
|
|
156
|
+
aria-label="Search orders"
|
|
157
|
+
>
|
|
158
|
+
<fieldset className="order-search-fieldset">
|
|
159
|
+
<legend className="order-search-legend">Filter Orders</legend>
|
|
160
|
+
|
|
161
|
+
<div className="order-search-inputs">
|
|
162
|
+
<input
|
|
163
|
+
type="search"
|
|
164
|
+
name={ORDER_FILTER_FIELDS.NAME}
|
|
165
|
+
placeholder="Order #"
|
|
166
|
+
aria-label="Order number"
|
|
167
|
+
defaultValue={currentFilters.name || ''}
|
|
168
|
+
className="order-search-input"
|
|
169
|
+
/>
|
|
170
|
+
<input
|
|
171
|
+
type="search"
|
|
172
|
+
name={ORDER_FILTER_FIELDS.CONFIRMATION_NUMBER}
|
|
173
|
+
placeholder="Confirmation #"
|
|
174
|
+
aria-label="Confirmation number"
|
|
175
|
+
defaultValue={currentFilters.confirmationNumber || ''}
|
|
176
|
+
className="order-search-input"
|
|
177
|
+
/>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<div className="order-search-buttons">
|
|
181
|
+
<button type="submit" disabled={isSearching}>
|
|
182
|
+
{isSearching ? 'Searching' : 'Search'}
|
|
183
|
+
</button>
|
|
184
|
+
{hasFilters && (
|
|
185
|
+
<button
|
|
186
|
+
type="button"
|
|
187
|
+
disabled={isSearching}
|
|
188
|
+
onClick={() => {
|
|
189
|
+
setSearchParams(new URLSearchParams());
|
|
190
|
+
formRef.current?.reset();
|
|
191
|
+
}}
|
|
192
|
+
>
|
|
193
|
+
Clear
|
|
194
|
+
</button>
|
|
195
|
+
)}
|
|
196
|
+
</div>
|
|
197
|
+
</fieldset>
|
|
198
|
+
</form>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
76
202
|
function OrderItem({order}: {order: OrderItemFragment}) {
|
|
77
203
|
const fulfillmentStatus = flattenConnection(order.fulfillments)[0]?.status;
|
|
78
204
|
return (
|
|
@@ -82,6 +208,9 @@ function OrderItem({order}: {order: OrderItemFragment}) {
|
|
|
82
208
|
<strong>#{order.number}</strong>
|
|
83
209
|
</Link>
|
|
84
210
|
<p>{new Date(order.processedAt).toDateString()}</p>
|
|
211
|
+
{order.confirmationNumber && (
|
|
212
|
+
<p>Confirmation: {order.confirmationNumber}</p>
|
|
213
|
+
)}
|
|
85
214
|
<p>{order.financialStatus}</p>
|
|
86
215
|
{fulfillmentStatus && <p>{fulfillmentStatus}</p>}
|
|
87
216
|
<Money data={order.totalPrice} />
|
|
@@ -3,27 +3,29 @@ import type {CustomerUpdateInput} from '@shopify/hydrogen/customer-account-api-t
|
|
|
3
3
|
import {CUSTOMER_UPDATE_MUTATION} from '~/graphql/customer-account/CustomerUpdateMutation';
|
|
4
4
|
import {
|
|
5
5
|
data,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
Form,
|
|
7
|
+
useActionData,
|
|
8
|
+
useNavigation,
|
|
9
|
+
useOutletContext,
|
|
10
|
+
} from 'react-router';
|
|
11
|
+
import type {Route} from './+types/account.profile';
|
|
10
12
|
|
|
11
13
|
export type ActionResponse = {
|
|
12
14
|
error: string | null;
|
|
13
15
|
customer: CustomerFragment | null;
|
|
14
16
|
};
|
|
15
17
|
|
|
16
|
-
export const meta: MetaFunction = () => {
|
|
18
|
+
export const meta: Route.MetaFunction = () => {
|
|
17
19
|
return [{title: 'Profile'}];
|
|
18
20
|
};
|
|
19
21
|
|
|
20
|
-
export async function loader({context}:
|
|
21
|
-
|
|
22
|
+
export async function loader({context}: Route.LoaderArgs) {
|
|
23
|
+
context.customerAccount.handleAuthStatus();
|
|
22
24
|
|
|
23
25
|
return {};
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
export async function action({request, context}:
|
|
28
|
+
export async function action({request, context}: Route.ActionArgs) {
|
|
27
29
|
const {customerAccount} = context;
|
|
28
30
|
|
|
29
31
|
if (request.method !== 'PUT') {
|
|
@@ -50,6 +52,7 @@ export async function action({request, context}: ActionFunctionArgs) {
|
|
|
50
52
|
{
|
|
51
53
|
variables: {
|
|
52
54
|
customer,
|
|
55
|
+
language: customerAccount.i18n.language,
|
|
53
56
|
},
|
|
54
57
|
},
|
|
55
58
|
);
|
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
data as remixData,
|
|
3
|
+
Form,
|
|
4
|
+
NavLink,
|
|
5
|
+
Outlet,
|
|
6
|
+
useLoaderData,
|
|
7
|
+
} from 'react-router';
|
|
8
|
+
import type {Route} from './+types/account';
|
|
3
9
|
import {CUSTOMER_DETAILS_QUERY} from '~/graphql/customer-account/CustomerDetailsQuery';
|
|
4
10
|
|
|
5
11
|
export function shouldRevalidate() {
|
|
6
12
|
return true;
|
|
7
13
|
}
|
|
8
14
|
|
|
9
|
-
export async function loader({context}:
|
|
10
|
-
const {
|
|
15
|
+
export async function loader({context}: Route.LoaderArgs) {
|
|
16
|
+
const {customerAccount} = context;
|
|
17
|
+
const {data, errors} = await customerAccount.query(
|
|
11
18
|
CUSTOMER_DETAILS_QUERY,
|
|
19
|
+
{
|
|
20
|
+
variables: {
|
|
21
|
+
language: customerAccount.i18n.language,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
12
24
|
);
|
|
13
25
|
|
|
14
26
|
if (errors?.length || !data?.customer) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {Route} from './+types/account_.authorize';
|
|
2
2
|
|
|
3
|
-
export async function loader({context}:
|
|
3
|
+
export async function loader({context}: Route.LoaderArgs) {
|
|
4
4
|
return context.customerAccount.authorize();
|
|
5
5
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {Route} from './+types/account_.login';
|
|
2
2
|
|
|
3
|
-
export async function loader({request, context}:
|
|
4
|
-
return context.customerAccount.login(
|
|
3
|
+
export async function loader({request, context}: Route.LoaderArgs) {
|
|
4
|
+
return context.customerAccount.login({
|
|
5
|
+
countryCode: context.storefront.i18n.country,
|
|
6
|
+
});
|
|
5
7
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {redirect
|
|
1
|
+
import {redirect} from 'react-router';
|
|
2
|
+
import type {Route} from './+types/account_.logout';
|
|
2
3
|
|
|
3
4
|
// if we don't implement this, /account/logout will get caught by account.$.tsx to do login
|
|
4
5
|
export async function loader() {
|
|
5
6
|
return redirect('/');
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
export async function action({context}:
|
|
9
|
+
export async function action({context}: Route.ActionArgs) {
|
|
9
10
|
return context.customerAccount.logout();
|
|
10
11
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type {Route} from './+types/api.$version.[graphql.json]';
|
|
2
2
|
|
|
3
|
-
export async function action({params, context, request}:
|
|
3
|
+
export async function action({params, context, request}: Route.ActionArgs) {
|
|
4
4
|
const response = await fetch(
|
|
5
5
|
`https://${context.env.PUBLIC_CHECKOUT_DOMAIN}/api/${params.version}/graphql.json`,
|
|
6
6
|
{
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import {useLoaderData} from 'react-router';
|
|
2
|
+
import type {Route} from './+types/blogs.$blogHandle.$articleHandle';
|
|
3
3
|
import {Image} from '@shopify/hydrogen';
|
|
4
4
|
import {redirectIfHandleIsLocalized} from '~/lib/redirect';
|
|
5
5
|
|
|
6
|
-
export const meta: MetaFunction
|
|
6
|
+
export const meta: Route.MetaFunction = ({data}) => {
|
|
7
7
|
return [{title: `Hydrogen | ${data?.article.title ?? ''} article`}];
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
export async function loader(args:
|
|
10
|
+
export async function loader(args: Route.LoaderArgs) {
|
|
11
11
|
// Start fetching non-critical data without blocking time to first byte
|
|
12
12
|
const deferredData = loadDeferredData(args);
|
|
13
13
|
|
|
@@ -21,11 +21,7 @@ export async function loader(args: LoaderFunctionArgs) {
|
|
|
21
21
|
* Load data necessary for rendering content above the fold. This is the critical data
|
|
22
22
|
* needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
|
|
23
23
|
*/
|
|
24
|
-
async function loadCriticalData({
|
|
25
|
-
context,
|
|
26
|
-
request,
|
|
27
|
-
params,
|
|
28
|
-
}: LoaderFunctionArgs) {
|
|
24
|
+
async function loadCriticalData({context, request, params}: Route.LoaderArgs) {
|
|
29
25
|
const {blogHandle, articleHandle} = params;
|
|
30
26
|
|
|
31
27
|
if (!articleHandle || !blogHandle) {
|
|
@@ -65,7 +61,7 @@ async function loadCriticalData({
|
|
|
65
61
|
* fetched after the initial page load. If it's unavailable, the page should still 200.
|
|
66
62
|
* Make sure to not throw any errors here, as it will cause the page to 500.
|
|
67
63
|
*/
|
|
68
|
-
function loadDeferredData({context}:
|
|
64
|
+
function loadDeferredData({context}: Route.LoaderArgs) {
|
|
69
65
|
return {};
|
|
70
66
|
}
|
|
71
67
|
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
Link,
|
|
3
|
+
useLoaderData,
|
|
4
|
+
} from 'react-router';
|
|
5
|
+
import type {Route} from './+types/blogs.$blogHandle._index';
|
|
3
6
|
import {Image, getPaginationVariables} from '@shopify/hydrogen';
|
|
4
7
|
import type {ArticleItemFragment} from 'storefrontapi.generated';
|
|
5
8
|
import {PaginatedResourceSection} from '~/components/PaginatedResourceSection';
|
|
6
9
|
import {redirectIfHandleIsLocalized} from '~/lib/redirect';
|
|
7
10
|
|
|
8
|
-
export const meta: MetaFunction
|
|
11
|
+
export const meta: Route.MetaFunction = ({data}) => {
|
|
9
12
|
return [{title: `Hydrogen | ${data?.blog.title ?? ''} blog`}];
|
|
10
13
|
};
|
|
11
14
|
|
|
12
|
-
export async function loader(args:
|
|
15
|
+
export async function loader(args: Route.LoaderArgs) {
|
|
13
16
|
// Start fetching non-critical data without blocking time to first byte
|
|
14
17
|
const deferredData = loadDeferredData(args);
|
|
15
18
|
|
|
@@ -27,7 +30,7 @@ async function loadCriticalData({
|
|
|
27
30
|
context,
|
|
28
31
|
request,
|
|
29
32
|
params,
|
|
30
|
-
}:
|
|
33
|
+
}: Route.LoaderArgs) {
|
|
31
34
|
const paginationVariables = getPaginationVariables(request, {
|
|
32
35
|
pageBy: 4,
|
|
33
36
|
});
|
|
@@ -60,7 +63,7 @@ async function loadCriticalData({
|
|
|
60
63
|
* fetched after the initial page load. If it's unavailable, the page should still 200.
|
|
61
64
|
* Make sure to not throw any errors here, as it will cause the page to 500.
|
|
62
65
|
*/
|
|
63
|
-
function loadDeferredData({context}:
|
|
66
|
+
function loadDeferredData({context}: Route.LoaderArgs) {
|
|
64
67
|
return {};
|
|
65
68
|
}
|
|
66
69
|
|
|
@@ -72,7 +75,7 @@ export default function Blog() {
|
|
|
72
75
|
<div className="blog">
|
|
73
76
|
<h1>{blog.title}</h1>
|
|
74
77
|
<div className="blog-grid">
|
|
75
|
-
<PaginatedResourceSection connection={articles}>
|
|
78
|
+
<PaginatedResourceSection<ArticleItemFragment> connection={articles}>
|
|
76
79
|
{({node: article, index}) => (
|
|
77
80
|
<ArticleItem
|
|
78
81
|
article={article}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
Link,
|
|
3
|
+
useLoaderData,
|
|
4
|
+
} from 'react-router';
|
|
5
|
+
import type {Route} from './+types/blogs._index';
|
|
3
6
|
import {getPaginationVariables} from '@shopify/hydrogen';
|
|
4
7
|
import {PaginatedResourceSection} from '~/components/PaginatedResourceSection';
|
|
8
|
+
import type {BlogsQuery} from 'storefrontapi.generated';
|
|
5
9
|
|
|
6
|
-
|
|
10
|
+
type BlogNode = BlogsQuery['blogs']['nodes'][0];
|
|
11
|
+
|
|
12
|
+
export const meta: Route.MetaFunction = () => {
|
|
7
13
|
return [{title: `Hydrogen | Blogs`}];
|
|
8
14
|
};
|
|
9
15
|
|
|
10
|
-
export async function loader(args:
|
|
16
|
+
export async function loader(args: Route.LoaderArgs) {
|
|
11
17
|
// Start fetching non-critical data without blocking time to first byte
|
|
12
18
|
const deferredData = loadDeferredData(args);
|
|
13
19
|
|
|
@@ -21,7 +27,7 @@ export async function loader(args: LoaderFunctionArgs) {
|
|
|
21
27
|
* Load data necessary for rendering content above the fold. This is the critical data
|
|
22
28
|
* needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
|
|
23
29
|
*/
|
|
24
|
-
async function loadCriticalData({context, request}:
|
|
30
|
+
async function loadCriticalData({context, request}: Route.LoaderArgs) {
|
|
25
31
|
const paginationVariables = getPaginationVariables(request, {
|
|
26
32
|
pageBy: 10,
|
|
27
33
|
});
|
|
@@ -43,7 +49,7 @@ async function loadCriticalData({context, request}: LoaderFunctionArgs) {
|
|
|
43
49
|
* fetched after the initial page load. If it's unavailable, the page should still 200.
|
|
44
50
|
* Make sure to not throw any errors here, as it will cause the page to 500.
|
|
45
51
|
*/
|
|
46
|
-
function loadDeferredData({context}:
|
|
52
|
+
function loadDeferredData({context}: Route.LoaderArgs) {
|
|
47
53
|
return {};
|
|
48
54
|
}
|
|
49
55
|
|
|
@@ -54,7 +60,7 @@ export default function Blogs() {
|
|
|
54
60
|
<div className="blogs">
|
|
55
61
|
<h1>Blogs</h1>
|
|
56
62
|
<div className="blogs-grid">
|
|
57
|
-
<PaginatedResourceSection connection={blogs}>
|
|
63
|
+
<PaginatedResourceSection<BlogNode> connection={blogs}>
|
|
58
64
|
{({node: blog}) => (
|
|
59
65
|
<Link
|
|
60
66
|
className="blog"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {redirect
|
|
1
|
+
import {redirect} from 'react-router';
|
|
2
|
+
import type {Route} from './+types/cart.$lines';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Automatically creates a new cart based on the URL and redirects straight to checkout.
|
|
@@ -18,7 +19,7 @@ import {redirect, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
|
|
|
18
19
|
*
|
|
19
20
|
* ```
|
|
20
21
|
*/
|
|
21
|
-
export async function loader({request, context, params}:
|
|
22
|
+
export async function loader({request, context, params}: Route.LoaderArgs) {
|
|
22
23
|
const {cart} = context;
|
|
23
24
|
const {lines} = params;
|
|
24
25
|
if (!lines) return redirect('/cart');
|