@decocms/apps 0.23.3 → 0.25.0

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.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/commerce/components/Image.tsx +129 -143
  3. package/commerce/components/JsonLd.tsx +192 -201
  4. package/commerce/components/Picture.tsx +65 -75
  5. package/commerce/sdk/analytics.ts +15 -15
  6. package/commerce/sdk/formatPrice.ts +13 -16
  7. package/commerce/sdk/url.ts +7 -7
  8. package/commerce/sdk/useOffer.ts +46 -57
  9. package/commerce/sdk/useVariantPossibilities.ts +25 -25
  10. package/commerce/types/commerce.ts +868 -875
  11. package/commerce/utils/canonical.ts +5 -8
  12. package/commerce/utils/constants.ts +5 -6
  13. package/commerce/utils/filters.ts +4 -4
  14. package/commerce/utils/productToAnalyticsItem.ts +52 -56
  15. package/commerce/utils/stateByZip.ts +42 -42
  16. package/package.json +24 -4
  17. package/shopify/actions/cart/addItems.ts +24 -25
  18. package/shopify/actions/cart/updateCoupons.ts +19 -20
  19. package/shopify/actions/cart/updateItems.ts +19 -20
  20. package/shopify/actions/user/signIn.ts +25 -30
  21. package/shopify/actions/user/signUp.ts +19 -24
  22. package/shopify/client.ts +24 -24
  23. package/shopify/index.ts +20 -18
  24. package/shopify/init.ts +18 -21
  25. package/shopify/loaders/ProductDetailsPage.ts +16 -20
  26. package/shopify/loaders/ProductList.ts +66 -69
  27. package/shopify/loaders/ProductListingPage.ts +150 -158
  28. package/shopify/loaders/RelatedProducts.ts +24 -27
  29. package/shopify/loaders/cart.ts +53 -52
  30. package/shopify/loaders/shop.ts +22 -27
  31. package/shopify/loaders/user.ts +27 -32
  32. package/shopify/utils/admin/admin.ts +33 -34
  33. package/shopify/utils/admin/queries.ts +2 -2
  34. package/shopify/utils/cart.ts +18 -14
  35. package/shopify/utils/cookies.ts +62 -65
  36. package/shopify/utils/enums.ts +424 -424
  37. package/shopify/utils/graphql.ts +44 -55
  38. package/shopify/utils/storefront/queries.ts +24 -29
  39. package/shopify/utils/storefront/storefront.graphql.gen.ts +55 -55
  40. package/shopify/utils/transform.ts +370 -376
  41. package/shopify/utils/types.ts +118 -118
  42. package/shopify/utils/user.ts +11 -11
  43. package/shopify/utils/utils.ts +135 -140
  44. package/vtex/actions/address.ts +86 -86
  45. package/vtex/actions/auth.ts +14 -27
  46. package/vtex/actions/checkout.ts +36 -49
  47. package/vtex/actions/masterData.ts +10 -27
  48. package/vtex/actions/misc.ts +101 -111
  49. package/vtex/actions/newsletter.ts +48 -52
  50. package/vtex/actions/orders.ts +13 -16
  51. package/vtex/actions/profile.ts +55 -55
  52. package/vtex/actions/session.ts +36 -35
  53. package/vtex/actions/trigger.ts +25 -25
  54. package/vtex/actions/wishlist.ts +51 -53
  55. package/vtex/client.ts +14 -42
  56. package/vtex/hooks/index.ts +4 -4
  57. package/vtex/hooks/useAutocomplete.ts +42 -48
  58. package/vtex/hooks/useCart.ts +153 -165
  59. package/vtex/hooks/useUser.ts +40 -40
  60. package/vtex/hooks/useWishlist.ts +70 -70
  61. package/vtex/inline-loaders/productDetailsPage.ts +1 -3
  62. package/vtex/inline-loaders/productList.ts +121 -127
  63. package/vtex/inline-loaders/productListShelf.ts +159 -0
  64. package/vtex/inline-loaders/productListingPage.ts +10 -34
  65. package/vtex/inline-loaders/relatedProducts.ts +1 -3
  66. package/vtex/inline-loaders/suggestions.ts +36 -39
  67. package/vtex/inline-loaders/workflowProducts.ts +45 -49
  68. package/vtex/invoke.ts +159 -194
  69. package/vtex/loaders/address.ts +49 -54
  70. package/vtex/loaders/brands.ts +19 -26
  71. package/vtex/loaders/cart.ts +24 -21
  72. package/vtex/loaders/catalog.ts +51 -53
  73. package/vtex/loaders/collections.ts +25 -27
  74. package/vtex/loaders/legacy.ts +487 -534
  75. package/vtex/loaders/logistics.ts +33 -37
  76. package/vtex/loaders/navbar.ts +5 -8
  77. package/vtex/loaders/orders.ts +28 -39
  78. package/vtex/loaders/pageType.ts +41 -35
  79. package/vtex/loaders/payment.ts +27 -37
  80. package/vtex/loaders/profile.ts +38 -38
  81. package/vtex/loaders/promotion.ts +5 -8
  82. package/vtex/loaders/search.ts +56 -59
  83. package/vtex/loaders/session.ts +22 -30
  84. package/vtex/loaders/user.ts +39 -41
  85. package/vtex/loaders/wishlist.ts +35 -35
  86. package/vtex/loaders/wishlistProducts.ts +3 -15
  87. package/vtex/loaders/workflow.ts +220 -227
  88. package/vtex/middleware.ts +116 -119
  89. package/vtex/types.ts +201 -201
  90. package/vtex/utils/batch.ts +13 -16
  91. package/vtex/utils/cookies.ts +76 -80
  92. package/vtex/utils/enrichment.ts +62 -42
  93. package/vtex/utils/fetchCache.ts +1 -4
  94. package/vtex/utils/index.ts +6 -6
  95. package/vtex/utils/intelligentSearch.ts +48 -57
  96. package/vtex/utils/legacy.ts +108 -124
  97. package/vtex/utils/pickAndOmit.ts +15 -20
  98. package/vtex/utils/proxy.ts +136 -146
  99. package/vtex/utils/resourceRange.ts +3 -3
  100. package/vtex/utils/segment.ts +100 -111
  101. package/vtex/utils/similars.ts +1 -2
  102. package/vtex/utils/sitemap.ts +91 -91
  103. package/vtex/utils/slugCache.ts +2 -6
  104. package/vtex/utils/slugify.ts +9 -9
  105. package/vtex/utils/transform.ts +1178 -1105
  106. package/vtex/utils/types.ts +1381 -1381
  107. package/vtex/utils/vtexId.ts +44 -47
  108. package/.github/workflows/release.yml +0 -34
  109. package/.releaserc.json +0 -28
  110. package/knip.json +0 -19
  111. package/tsconfig.json +0 -11
@@ -1,180 +1,172 @@
1
1
  import type { ProductListingPage } from "../../commerce/types/commerce";
2
2
  import { getShopifyClient } from "../client";
3
3
  import { ProductsByCollection, SearchProducts } from "../utils/storefront/queries";
4
- import { toFilter, toProduct, type ProductShopify } from "../utils/transform";
4
+ import { type ProductShopify, toFilter, toProduct } from "../utils/transform";
5
5
  import type { Metafield } from "../utils/types";
6
6
  import {
7
- getFiltersByUrl,
8
- searchSortOptions,
9
- searchSortShopify,
10
- sortOptions,
11
- sortShopify,
7
+ getFiltersByUrl,
8
+ searchSortOptions,
9
+ searchSortShopify,
10
+ sortOptions,
11
+ sortShopify,
12
12
  } from "../utils/utils";
13
13
 
14
14
  interface PageInfo {
15
- hasNextPage: boolean;
16
- hasPreviousPage: boolean;
17
- endCursor?: string;
18
- startCursor?: string;
15
+ hasNextPage: boolean;
16
+ hasPreviousPage: boolean;
17
+ endCursor?: string;
18
+ startCursor?: string;
19
19
  }
20
20
 
21
21
  interface FilterNode {
22
- id: string;
23
- label: string;
24
- type: string;
25
- values: Array<{ id: string; label: string; count: number; input: string }>;
22
+ id: string;
23
+ label: string;
24
+ type: string;
25
+ values: Array<{ id: string; label: string; count: number; input: string }>;
26
26
  }
27
27
 
28
28
  interface ProductConnection {
29
- nodes: ProductShopify[];
30
- pageInfo: PageInfo;
31
- filters?: FilterNode[];
29
+ nodes: ProductShopify[];
30
+ pageInfo: PageInfo;
31
+ filters?: FilterNode[];
32
32
  }
33
33
 
34
34
  export interface Props {
35
- query?: string;
36
- collectionName?: string;
37
- count: number;
38
- metafields?: Metafield[];
39
- pageOffset?: number;
40
- page?: number;
41
- startCursor?: string;
42
- endCursor?: string;
43
- pageHref?: string;
35
+ query?: string;
36
+ collectionName?: string;
37
+ count: number;
38
+ metafields?: Metafield[];
39
+ pageOffset?: number;
40
+ page?: number;
41
+ startCursor?: string;
42
+ endCursor?: string;
43
+ pageHref?: string;
44
44
  }
45
45
 
46
46
  export default async function productListingPageLoader(
47
- props: Props,
48
- url?: URL,
47
+ props: Props,
48
+ url?: URL,
49
49
  ): Promise<ProductListingPage | null> {
50
- const pageUrl = url ?? new URL(props.pageHref || "https://localhost");
51
- const client = getShopifyClient();
52
-
53
- const count = props.count ?? 12;
54
- const query = props.query || pageUrl.searchParams.get("q") || "";
55
- const currentPageoffset = props.pageOffset ?? 1;
56
- const pageParam = pageUrl.searchParams.get("page")
57
- ? Number(pageUrl.searchParams.get("page")) - currentPageoffset
58
- : 0;
59
- const page = props.page || pageParam;
60
- const endCursor = props.endCursor || pageUrl.searchParams.get("endCursor") || "";
61
- const startCursor = props.startCursor || pageUrl.searchParams.get("startCursor") || "";
62
- const metafields = props.metafields || [];
63
-
64
- const isSearch = Boolean(query);
65
- let hasNextPage = false;
66
- let hasPreviousPage = false;
67
- let shopifyProducts: ProductConnection | undefined;
68
- let shopifyFilters: FilterNode[] | undefined;
69
- let records: number | undefined;
70
- let collectionTitle: string | undefined;
71
- let collectionDescription: string | undefined;
72
-
73
- const sort = pageUrl.searchParams.get("sort") ?? "";
74
-
75
- if (isSearch) {
76
- const data = await client.query<{
77
- search: ProductConnection & { totalCount?: number; productFilters?: FilterNode[] };
78
- }>(
79
- SearchProducts,
80
- {
81
- ...(!endCursor && { first: count }),
82
- ...(endCursor && { last: count }),
83
- ...(startCursor && { after: startCursor }),
84
- ...(endCursor && { before: endCursor }),
85
- query,
86
- productFilters: getFiltersByUrl(pageUrl),
87
- identifiers: metafields,
88
- ...searchSortShopify[sort],
89
- },
90
- );
91
-
92
- shopifyProducts = data.search;
93
- shopifyFilters = data.search?.productFilters;
94
- records = data.search?.totalCount;
95
- hasNextPage = Boolean(data.search?.pageInfo.hasNextPage);
96
- hasPreviousPage = Boolean(data.search?.pageInfo.hasPreviousPage);
97
- } else {
98
- const pathname = props.collectionName || pageUrl.pathname.split("/")[1];
99
-
100
- const data = await client.query<{
101
- collection?: {
102
- title?: string;
103
- description?: string;
104
- products: ProductConnection;
105
- };
106
- }>(
107
- ProductsByCollection,
108
- {
109
- ...(!endCursor && { first: count }),
110
- ...(endCursor && { last: count }),
111
- ...(startCursor && { after: startCursor }),
112
- ...(endCursor && { before: endCursor }),
113
- identifiers: metafields,
114
- handle: pathname,
115
- filters: getFiltersByUrl(pageUrl),
116
- ...sortShopify[sort],
117
- },
118
- );
119
-
120
- shopifyProducts = data.collection?.products;
121
- shopifyFilters = data.collection?.products?.filters;
122
- hasNextPage = Boolean(data.collection?.products.pageInfo.hasNextPage);
123
- hasPreviousPage = Boolean(data.collection?.products.pageInfo.hasPreviousPage);
124
- collectionTitle = data.collection?.title;
125
- collectionDescription = data.collection?.description;
126
- }
127
-
128
- const products = shopifyProducts?.nodes?.map((p) =>
129
- toProduct(p, p.variants.nodes[0], pageUrl)
130
- );
131
-
132
- const nextPage = new URLSearchParams(pageUrl.searchParams);
133
- const previousPage = new URLSearchParams(pageUrl.searchParams);
134
-
135
- if (hasNextPage) {
136
- nextPage.set("page", (page + currentPageoffset + 1).toString());
137
- nextPage.set("startCursor", shopifyProducts?.pageInfo.endCursor ?? "");
138
- nextPage.delete("endCursor");
139
- }
140
-
141
- if (hasPreviousPage) {
142
- previousPage.set("page", (page + currentPageoffset - 1).toString());
143
- previousPage.set("endCursor", shopifyProducts?.pageInfo.startCursor ?? "");
144
- previousPage.delete("startCursor");
145
- }
146
-
147
- const filters = shopifyFilters?.map((filter) => toFilter(filter, pageUrl));
148
- const currentPage = page + currentPageoffset;
149
-
150
- return {
151
- "@type": "ProductListingPage",
152
- breadcrumb: {
153
- "@type": "BreadcrumbList",
154
- itemListElement: [{
155
- "@type": "ListItem" as const,
156
- name: isSearch ? query : pageUrl.pathname.split("/")[1],
157
- item: isSearch ? pageUrl.href : pageUrl.pathname,
158
- position: 2,
159
- }],
160
- numberOfItems: 1,
161
- },
162
- filters: filters ?? [],
163
- products: products ?? [],
164
- pageInfo: {
165
- nextPage: hasNextPage ? `?${nextPage}` : undefined,
166
- previousPage: hasPreviousPage ? `?${previousPage}` : undefined,
167
- currentPage,
168
- records,
169
- recordPerPage: count,
170
- },
171
- sortOptions: isSearch ? searchSortOptions : sortOptions,
172
- seo: {
173
- title: collectionTitle || "",
174
- description: collectionDescription || "",
175
- canonical: `${pageUrl.origin}${pageUrl.pathname}${
176
- page >= 1 ? `?page=${page}` : ""
177
- }`,
178
- },
179
- };
50
+ const pageUrl = url ?? new URL(props.pageHref || "https://localhost");
51
+ const client = getShopifyClient();
52
+
53
+ const count = props.count ?? 12;
54
+ const query = props.query || pageUrl.searchParams.get("q") || "";
55
+ const currentPageoffset = props.pageOffset ?? 1;
56
+ const pageParam = pageUrl.searchParams.get("page")
57
+ ? Number(pageUrl.searchParams.get("page")) - currentPageoffset
58
+ : 0;
59
+ const page = props.page || pageParam;
60
+ const endCursor = props.endCursor || pageUrl.searchParams.get("endCursor") || "";
61
+ const startCursor = props.startCursor || pageUrl.searchParams.get("startCursor") || "";
62
+ const metafields = props.metafields || [];
63
+
64
+ const isSearch = Boolean(query);
65
+ let hasNextPage = false;
66
+ let hasPreviousPage = false;
67
+ let shopifyProducts: ProductConnection | undefined;
68
+ let shopifyFilters: FilterNode[] | undefined;
69
+ let records: number | undefined;
70
+ let collectionTitle: string | undefined;
71
+ let collectionDescription: string | undefined;
72
+
73
+ const sort = pageUrl.searchParams.get("sort") ?? "";
74
+
75
+ if (isSearch) {
76
+ const data = await client.query<{
77
+ search: ProductConnection & { totalCount?: number; productFilters?: FilterNode[] };
78
+ }>(SearchProducts, {
79
+ ...(!endCursor && { first: count }),
80
+ ...(endCursor && { last: count }),
81
+ ...(startCursor && { after: startCursor }),
82
+ ...(endCursor && { before: endCursor }),
83
+ query,
84
+ productFilters: getFiltersByUrl(pageUrl),
85
+ identifiers: metafields,
86
+ ...searchSortShopify[sort],
87
+ });
88
+
89
+ shopifyProducts = data.search;
90
+ shopifyFilters = data.search?.productFilters;
91
+ records = data.search?.totalCount;
92
+ hasNextPage = Boolean(data.search?.pageInfo.hasNextPage);
93
+ hasPreviousPage = Boolean(data.search?.pageInfo.hasPreviousPage);
94
+ } else {
95
+ const pathname = props.collectionName || pageUrl.pathname.split("/")[1];
96
+
97
+ const data = await client.query<{
98
+ collection?: {
99
+ title?: string;
100
+ description?: string;
101
+ products: ProductConnection;
102
+ };
103
+ }>(ProductsByCollection, {
104
+ ...(!endCursor && { first: count }),
105
+ ...(endCursor && { last: count }),
106
+ ...(startCursor && { after: startCursor }),
107
+ ...(endCursor && { before: endCursor }),
108
+ identifiers: metafields,
109
+ handle: pathname,
110
+ filters: getFiltersByUrl(pageUrl),
111
+ ...sortShopify[sort],
112
+ });
113
+
114
+ shopifyProducts = data.collection?.products;
115
+ shopifyFilters = data.collection?.products?.filters;
116
+ hasNextPage = Boolean(data.collection?.products.pageInfo.hasNextPage);
117
+ hasPreviousPage = Boolean(data.collection?.products.pageInfo.hasPreviousPage);
118
+ collectionTitle = data.collection?.title;
119
+ collectionDescription = data.collection?.description;
120
+ }
121
+
122
+ const products = shopifyProducts?.nodes?.map((p) => toProduct(p, p.variants.nodes[0], pageUrl));
123
+
124
+ const nextPage = new URLSearchParams(pageUrl.searchParams);
125
+ const previousPage = new URLSearchParams(pageUrl.searchParams);
126
+
127
+ if (hasNextPage) {
128
+ nextPage.set("page", (page + currentPageoffset + 1).toString());
129
+ nextPage.set("startCursor", shopifyProducts?.pageInfo.endCursor ?? "");
130
+ nextPage.delete("endCursor");
131
+ }
132
+
133
+ if (hasPreviousPage) {
134
+ previousPage.set("page", (page + currentPageoffset - 1).toString());
135
+ previousPage.set("endCursor", shopifyProducts?.pageInfo.startCursor ?? "");
136
+ previousPage.delete("startCursor");
137
+ }
138
+
139
+ const filters = shopifyFilters?.map((filter) => toFilter(filter, pageUrl));
140
+ const currentPage = page + currentPageoffset;
141
+
142
+ return {
143
+ "@type": "ProductListingPage",
144
+ breadcrumb: {
145
+ "@type": "BreadcrumbList",
146
+ itemListElement: [
147
+ {
148
+ "@type": "ListItem" as const,
149
+ name: isSearch ? query : pageUrl.pathname.split("/")[1],
150
+ item: isSearch ? pageUrl.href : pageUrl.pathname,
151
+ position: 2,
152
+ },
153
+ ],
154
+ numberOfItems: 1,
155
+ },
156
+ filters: filters ?? [],
157
+ products: products ?? [],
158
+ pageInfo: {
159
+ nextPage: hasNextPage ? `?${nextPage}` : undefined,
160
+ previousPage: hasPreviousPage ? `?${previousPage}` : undefined,
161
+ currentPage,
162
+ records,
163
+ recordPerPage: count,
164
+ },
165
+ sortOptions: isSearch ? searchSortOptions : sortOptions,
166
+ seo: {
167
+ title: collectionTitle || "",
168
+ description: collectionDescription || "",
169
+ canonical: `${pageUrl.origin}${pageUrl.pathname}${page >= 1 ? `?page=${page}` : ""}`,
170
+ },
171
+ };
180
172
  }
@@ -1,45 +1,42 @@
1
1
  import type { Product } from "../../commerce/types/commerce";
2
2
  import { getShopifyClient } from "../client";
3
3
  import { GetProduct, ProductRecommendations } from "../utils/storefront/queries";
4
- import { toProduct, type ProductShopify } from "../utils/transform";
4
+ import { type ProductShopify, toProduct } from "../utils/transform";
5
5
  import type { Metafield } from "../utils/types";
6
6
 
7
7
  export interface Props {
8
- slug: string;
9
- count?: number;
10
- metafields?: Metafield[];
8
+ slug: string;
9
+ count?: number;
10
+ metafields?: Metafield[];
11
11
  }
12
12
 
13
13
  export default async function relatedProductsLoader(
14
- props: Props,
15
- url?: URL,
14
+ props: Props,
15
+ url?: URL,
16
16
  ): Promise<Product[] | null> {
17
- const client = getShopifyClient();
18
- const { slug, count = 10, metafields = [] } = props;
17
+ const client = getShopifyClient();
18
+ const { slug, count = 10, metafields = [] } = props;
19
19
 
20
- const splitted = slug?.split("-") ?? [];
21
- const maybeSkuId = Number(splitted[splitted.length - 1]);
22
- const handle = splitted.slice(0, maybeSkuId ? -1 : undefined).join("-");
20
+ const splitted = slug?.split("-") ?? [];
21
+ const maybeSkuId = Number(splitted[splitted.length - 1]);
22
+ const handle = splitted.slice(0, maybeSkuId ? -1 : undefined).join("-");
23
23
 
24
- const productData = await client.query<{ product?: ProductShopify }>(
25
- GetProduct,
26
- { handle, identifiers: metafields },
27
- );
24
+ const productData = await client.query<{ product?: ProductShopify }>(GetProduct, {
25
+ handle,
26
+ identifiers: metafields,
27
+ });
28
28
 
29
- if (!productData?.product) return [];
29
+ if (!productData?.product) return [];
30
30
 
31
- const data = await client.query<{
32
- productRecommendations?: ProductShopify[];
33
- }>(
34
- ProductRecommendations,
35
- { productId: productData.product.id, identifiers: metafields },
36
- );
31
+ const data = await client.query<{
32
+ productRecommendations?: ProductShopify[];
33
+ }>(ProductRecommendations, { productId: productData.product.id, identifiers: metafields });
37
34
 
38
- if (!data?.productRecommendations) return [];
35
+ if (!data?.productRecommendations) return [];
39
36
 
40
- const baseUrl = url ?? new URL("https://localhost");
37
+ const baseUrl = url ?? new URL("https://localhost");
41
38
 
42
- return data.productRecommendations
43
- .map((p) => toProduct(p, p.variants.nodes[0], baseUrl))
44
- .slice(0, count);
39
+ return data.productRecommendations
40
+ .map((p) => toProduct(p, p.variants.nodes[0], baseUrl))
41
+ .slice(0, count);
45
42
  }
@@ -3,71 +3,72 @@ import { getCartCookie, setCartCookie } from "../utils/cart";
3
3
  import { CreateCart, GetCart } from "../utils/storefront/queries";
4
4
 
5
5
  export interface CartLine {
6
- id: string;
7
- quantity: number;
8
- merchandise: {
9
- id: string;
10
- title: string;
11
- image?: { url: string; altText?: string | null } | null;
12
- product: { title: string; handle: string; onlineStoreUrl?: string | null };
13
- price: { amount: string; currencyCode: string };
14
- };
15
- discountAllocations?: Array<{
16
- code?: string;
17
- discountedAmount?: { amount: string; currencyCode: string };
18
- }>;
19
- cost?: {
20
- totalAmount: { amount: string; currencyCode: string };
21
- subtotalAmount: { amount: string; currencyCode: string };
22
- amountPerQuantity?: { amount: string; currencyCode: string };
23
- compareAtAmountPerQuantity?: { amount: string; currencyCode: string } | null;
24
- };
6
+ id: string;
7
+ quantity: number;
8
+ merchandise: {
9
+ id: string;
10
+ title: string;
11
+ image?: { url: string; altText?: string | null } | null;
12
+ product: { title: string; handle: string; onlineStoreUrl?: string | null };
13
+ price: { amount: string; currencyCode: string };
14
+ };
15
+ discountAllocations?: Array<{
16
+ code?: string;
17
+ discountedAmount?: { amount: string; currencyCode: string };
18
+ }>;
19
+ cost?: {
20
+ totalAmount: { amount: string; currencyCode: string };
21
+ subtotalAmount: { amount: string; currencyCode: string };
22
+ amountPerQuantity?: { amount: string; currencyCode: string };
23
+ compareAtAmountPerQuantity?: { amount: string; currencyCode: string } | null;
24
+ };
25
25
  }
26
26
 
27
27
  export interface ShopifyCart {
28
- id: string;
29
- checkoutUrl: string;
30
- totalQuantity: number;
31
- lines: { nodes: CartLine[] };
32
- cost: {
33
- totalTaxAmount?: { amount: string; currencyCode: string };
34
- subtotalAmount: { amount: string; currencyCode: string };
35
- totalAmount: { amount: string; currencyCode: string };
36
- checkoutChargeAmount?: { amount: string; currencyCode: string };
37
- };
38
- discountCodes?: Array<{ applicable: boolean; code: string }>;
39
- discountAllocations?: Array<{
40
- discountedAmount: { amount: string; currencyCode: string };
41
- }>;
28
+ id: string;
29
+ checkoutUrl: string;
30
+ totalQuantity: number;
31
+ lines: { nodes: CartLine[] };
32
+ cost: {
33
+ totalTaxAmount?: { amount: string; currencyCode: string };
34
+ subtotalAmount: { amount: string; currencyCode: string };
35
+ totalAmount: { amount: string; currencyCode: string };
36
+ checkoutChargeAmount?: { amount: string; currencyCode: string };
37
+ };
38
+ discountCodes?: Array<{ applicable: boolean; code: string }>;
39
+ discountAllocations?: Array<{
40
+ discountedAmount: { amount: string; currencyCode: string };
41
+ }>;
42
42
  }
43
43
 
44
44
  export async function getCart(
45
- requestHeaders: Headers,
46
- responseHeaders?: Headers,
45
+ requestHeaders: Headers,
46
+ responseHeaders?: Headers,
47
47
  ): Promise<ShopifyCart | null> {
48
- const client = getShopifyClient();
49
- const maybeCartId = getCartCookie(requestHeaders);
48
+ const client = getShopifyClient();
49
+ const maybeCartId = getCartCookie(requestHeaders);
50
50
 
51
- const cartId = maybeCartId ??
52
- await client.query<{ payload?: { cart?: { id: string } } }>(CreateCart)
53
- .then((data) => data.payload?.cart?.id);
51
+ const cartId =
52
+ maybeCartId ??
53
+ (await client
54
+ .query<{ payload?: { cart?: { id: string } } }>(CreateCart)
55
+ .then((data) => data.payload?.cart?.id));
54
56
 
55
- if (!cartId) throw new Error("Missing cart id");
57
+ if (!cartId) throw new Error("Missing cart id");
56
58
 
57
- const cart = await client.query<{ cart?: ShopifyCart }>(
58
- GetCart,
59
- { id: decodeURIComponent(cartId) },
60
- ).then((data) => data.cart ?? null);
59
+ const cart = await client
60
+ .query<{ cart?: ShopifyCart }>(GetCart, { id: decodeURIComponent(cartId) })
61
+ .then((data) => data.cart ?? null);
61
62
 
62
- if (responseHeaders) {
63
- setCartCookie(responseHeaders, cartId);
64
- }
63
+ if (responseHeaders) {
64
+ setCartCookie(responseHeaders, cartId);
65
+ }
65
66
 
66
- return cart;
67
+ return cart;
67
68
  }
68
69
 
69
70
  export async function createCart(): Promise<string | null> {
70
- const client = getShopifyClient();
71
- const data = await client.query<{ payload?: { cart?: { id: string } } }>(CreateCart);
72
- return data?.payload?.cart?.id ?? null;
71
+ const client = getShopifyClient();
72
+ const data = await client.query<{ payload?: { cart?: { id: string } } }>(CreateCart);
73
+ return data?.payload?.cart?.id ?? null;
73
74
  }
@@ -3,38 +3,33 @@ import { GetShopInfo } from "../utils/storefront/queries";
3
3
  import type { Metafield } from "../utils/types";
4
4
 
5
5
  export interface Shop {
6
- name: string;
7
- description?: string;
8
- privacyPolicy?: { title: string; body: string };
9
- refundPolicy?: { title: string; body: string };
10
- shippingPolicy?: { title: string; body: string };
11
- subscriptionPolicy?: { title: string; body: string };
12
- termsOfService?: { title: string; body: string };
13
- metafields?: Array<{
14
- description?: string | null;
15
- key: string;
16
- namespace: string;
17
- type: string;
18
- value: string;
19
- reference?: { image?: { url: string } } | null;
20
- references?: { edges: Array<{ node: { image?: { url: string } } }> } | null;
21
- } | null>;
6
+ name: string;
7
+ description?: string;
8
+ privacyPolicy?: { title: string; body: string };
9
+ refundPolicy?: { title: string; body: string };
10
+ shippingPolicy?: { title: string; body: string };
11
+ subscriptionPolicy?: { title: string; body: string };
12
+ termsOfService?: { title: string; body: string };
13
+ metafields?: Array<{
14
+ description?: string | null;
15
+ key: string;
16
+ namespace: string;
17
+ type: string;
18
+ value: string;
19
+ reference?: { image?: { url: string } } | null;
20
+ references?: { edges: Array<{ node: { image?: { url: string } } }> } | null;
21
+ } | null>;
22
22
  }
23
23
 
24
24
  export interface Props {
25
- metafields?: Metafield[];
25
+ metafields?: Metafield[];
26
26
  }
27
27
 
28
- export default async function shopLoader(
29
- props?: Props,
30
- ): Promise<Shop> {
31
- const client = getShopifyClient();
32
- const metafields = props?.metafields || [];
28
+ export default async function shopLoader(props?: Props): Promise<Shop> {
29
+ const client = getShopifyClient();
30
+ const metafields = props?.metafields || [];
33
31
 
34
- const data = await client.query<{ shop: Shop }>(
35
- GetShopInfo,
36
- { identifiers: metafields },
37
- );
32
+ const data = await client.query<{ shop: Shop }>(GetShopInfo, { identifiers: metafields });
38
33
 
39
- return data.shop;
34
+ return data.shop;
40
35
  }
@@ -3,42 +3,37 @@ import { FetchCustomerInfo } from "../utils/storefront/queries";
3
3
  import { getUserCookie } from "../utils/user";
4
4
 
5
5
  export interface ShopifyUser {
6
- "@id": string;
7
- email: string;
8
- givenName: string;
9
- familyName: string;
6
+ "@id": string;
7
+ email: string;
8
+ givenName: string;
9
+ familyName: string;
10
10
  }
11
11
 
12
- export default async function userLoader(
13
- requestHeaders: Headers,
14
- ): Promise<ShopifyUser | null> {
15
- const client = getShopifyClient();
16
- const customerAccessToken = getUserCookie(requestHeaders);
12
+ export default async function userLoader(requestHeaders: Headers): Promise<ShopifyUser | null> {
13
+ const client = getShopifyClient();
14
+ const customerAccessToken = getUserCookie(requestHeaders);
17
15
 
18
- if (!customerAccessToken) return null;
16
+ if (!customerAccessToken) return null;
19
17
 
20
- try {
21
- const data = await client.query<{
22
- customer?: {
23
- id: string;
24
- email?: string | null;
25
- firstName?: string | null;
26
- lastName?: string | null;
27
- };
28
- }>(
29
- FetchCustomerInfo,
30
- { customerAccessToken },
31
- );
18
+ try {
19
+ const data = await client.query<{
20
+ customer?: {
21
+ id: string;
22
+ email?: string | null;
23
+ firstName?: string | null;
24
+ lastName?: string | null;
25
+ };
26
+ }>(FetchCustomerInfo, { customerAccessToken });
32
27
 
33
- if (!data.customer) return null;
28
+ if (!data.customer) return null;
34
29
 
35
- return {
36
- "@id": data.customer.id,
37
- email: data.customer.email ?? "",
38
- givenName: data.customer.firstName ?? "",
39
- familyName: data.customer.lastName ?? "",
40
- };
41
- } catch {
42
- return null;
43
- }
30
+ return {
31
+ "@id": data.customer.id,
32
+ email: data.customer.email ?? "",
33
+ givenName: data.customer.firstName ?? "",
34
+ familyName: data.customer.lastName ?? "",
35
+ };
36
+ } catch {
37
+ return null;
38
+ }
44
39
  }