@decocms/apps 0.23.3 → 0.24.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.
- package/LICENSE +21 -0
- package/commerce/components/Image.tsx +129 -143
- package/commerce/components/JsonLd.tsx +192 -201
- package/commerce/components/Picture.tsx +65 -75
- package/commerce/sdk/analytics.ts +15 -15
- package/commerce/sdk/formatPrice.ts +13 -16
- package/commerce/sdk/url.ts +7 -7
- package/commerce/sdk/useOffer.ts +46 -57
- package/commerce/sdk/useVariantPossibilities.ts +25 -25
- package/commerce/types/commerce.ts +868 -875
- package/commerce/utils/canonical.ts +5 -8
- package/commerce/utils/constants.ts +5 -6
- package/commerce/utils/filters.ts +4 -4
- package/commerce/utils/productToAnalyticsItem.ts +52 -56
- package/commerce/utils/stateByZip.ts +42 -42
- package/package.json +23 -4
- package/shopify/actions/cart/addItems.ts +24 -25
- package/shopify/actions/cart/updateCoupons.ts +19 -20
- package/shopify/actions/cart/updateItems.ts +19 -20
- package/shopify/actions/user/signIn.ts +25 -30
- package/shopify/actions/user/signUp.ts +19 -24
- package/shopify/client.ts +24 -24
- package/shopify/index.ts +20 -18
- package/shopify/init.ts +18 -21
- package/shopify/loaders/ProductDetailsPage.ts +16 -20
- package/shopify/loaders/ProductList.ts +66 -69
- package/shopify/loaders/ProductListingPage.ts +150 -158
- package/shopify/loaders/RelatedProducts.ts +24 -27
- package/shopify/loaders/cart.ts +53 -52
- package/shopify/loaders/shop.ts +22 -27
- package/shopify/loaders/user.ts +27 -32
- package/shopify/utils/admin/admin.ts +33 -34
- package/shopify/utils/admin/queries.ts +2 -2
- package/shopify/utils/cart.ts +18 -14
- package/shopify/utils/cookies.ts +62 -65
- package/shopify/utils/enums.ts +424 -424
- package/shopify/utils/graphql.ts +44 -55
- package/shopify/utils/storefront/queries.ts +24 -29
- package/shopify/utils/storefront/storefront.graphql.gen.ts +55 -55
- package/shopify/utils/transform.ts +370 -376
- package/shopify/utils/types.ts +118 -118
- package/shopify/utils/user.ts +11 -11
- package/shopify/utils/utils.ts +135 -140
- package/vtex/actions/address.ts +86 -86
- package/vtex/actions/auth.ts +14 -27
- package/vtex/actions/checkout.ts +36 -49
- package/vtex/actions/masterData.ts +10 -27
- package/vtex/actions/misc.ts +101 -111
- package/vtex/actions/newsletter.ts +48 -52
- package/vtex/actions/orders.ts +13 -16
- package/vtex/actions/profile.ts +55 -55
- package/vtex/actions/session.ts +36 -35
- package/vtex/actions/trigger.ts +25 -25
- package/vtex/actions/wishlist.ts +51 -53
- package/vtex/client.ts +14 -42
- package/vtex/hooks/index.ts +4 -4
- package/vtex/hooks/useAutocomplete.ts +42 -48
- package/vtex/hooks/useCart.ts +153 -165
- package/vtex/hooks/useUser.ts +40 -40
- package/vtex/hooks/useWishlist.ts +70 -70
- package/vtex/inline-loaders/productDetailsPage.ts +1 -3
- package/vtex/inline-loaders/productList.ts +121 -127
- package/vtex/inline-loaders/productListingPage.ts +10 -34
- package/vtex/inline-loaders/relatedProducts.ts +1 -3
- package/vtex/inline-loaders/suggestions.ts +36 -39
- package/vtex/inline-loaders/workflowProducts.ts +45 -49
- package/vtex/invoke.ts +159 -194
- package/vtex/loaders/address.ts +49 -54
- package/vtex/loaders/brands.ts +19 -26
- package/vtex/loaders/cart.ts +24 -21
- package/vtex/loaders/catalog.ts +51 -53
- package/vtex/loaders/collections.ts +25 -27
- package/vtex/loaders/legacy.ts +487 -534
- package/vtex/loaders/logistics.ts +33 -37
- package/vtex/loaders/navbar.ts +5 -8
- package/vtex/loaders/orders.ts +28 -39
- package/vtex/loaders/pageType.ts +41 -35
- package/vtex/loaders/payment.ts +27 -37
- package/vtex/loaders/profile.ts +38 -38
- package/vtex/loaders/promotion.ts +5 -8
- package/vtex/loaders/search.ts +56 -59
- package/vtex/loaders/session.ts +22 -30
- package/vtex/loaders/user.ts +39 -41
- package/vtex/loaders/wishlist.ts +35 -35
- package/vtex/loaders/wishlistProducts.ts +3 -15
- package/vtex/loaders/workflow.ts +220 -227
- package/vtex/middleware.ts +116 -119
- package/vtex/types.ts +201 -201
- package/vtex/utils/batch.ts +13 -16
- package/vtex/utils/cookies.ts +76 -80
- package/vtex/utils/enrichment.ts +62 -42
- package/vtex/utils/fetchCache.ts +1 -4
- package/vtex/utils/index.ts +6 -6
- package/vtex/utils/intelligentSearch.ts +48 -57
- package/vtex/utils/legacy.ts +108 -124
- package/vtex/utils/pickAndOmit.ts +15 -20
- package/vtex/utils/proxy.ts +136 -146
- package/vtex/utils/resourceRange.ts +3 -3
- package/vtex/utils/segment.ts +100 -111
- package/vtex/utils/similars.ts +1 -2
- package/vtex/utils/sitemap.ts +91 -91
- package/vtex/utils/slugCache.ts +2 -6
- package/vtex/utils/slugify.ts +9 -9
- package/vtex/utils/transform.ts +1012 -1105
- package/vtex/utils/types.ts +1381 -1381
- package/vtex/utils/vtexId.ts +44 -47
- package/.github/workflows/release.yml +0 -34
- package/.releaserc.json +0 -28
- package/knip.json +0 -19
- package/tsconfig.json +0 -11
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import { BreadcrumbList } from "../types/commerce";
|
|
1
|
+
import type { BreadcrumbList } from "../types/commerce";
|
|
2
2
|
|
|
3
|
-
export const canonicalFromBreadcrumblist = (
|
|
4
|
-
|
|
5
|
-
)
|
|
6
|
-
const items = b?.itemListElement ?? [];
|
|
7
|
-
if (!Array.isArray(items) || items.length === 0) return undefined;
|
|
3
|
+
export const canonicalFromBreadcrumblist = (b?: BreadcrumbList) => {
|
|
4
|
+
const items = b?.itemListElement ?? [];
|
|
5
|
+
if (!Array.isArray(items) || items.length === 0) return undefined;
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
.item;
|
|
7
|
+
return items.reduce((acc, curr) => (acc.position < curr.position ? curr : acc)).item;
|
|
11
8
|
};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { ImageObject } from "../types/commerce";
|
|
1
|
+
import type { ImageObject } from "../types/commerce";
|
|
2
2
|
|
|
3
3
|
export const DEFAULT_IMAGE: ImageObject = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"https://ozksgdmyrqcxcwhnbepg.supabase.co/storage/v1/object/public/assets/1818/ff6bb37e-0eab-40e1-a454-86856efc278e",
|
|
4
|
+
"@type": "ImageObject",
|
|
5
|
+
encodingFormat: "image",
|
|
6
|
+
alternateName: "Default Image Placeholder",
|
|
7
|
+
url: "https://ozksgdmyrqcxcwhnbepg.supabase.co/storage/v1/object/public/assets/1818/ff6bb37e-0eab-40e1-a454-86856efc278e",
|
|
9
8
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export const parseRange = (price: string) => {
|
|
2
|
-
|
|
2
|
+
const splitted = price.split(":");
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const from = Number(splitted?.[0]);
|
|
5
|
+
const to = Number(splitted?.[1]);
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
return Number.isNaN(from) || Number.isNaN(to) ? null : { from, to };
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
export const formatRange = (from: number, to: number) => `${from}:${to}`;
|
|
@@ -1,67 +1,63 @@
|
|
|
1
1
|
import type { AnalyticsItem, BreadcrumbList, Product } from "../types/commerce";
|
|
2
2
|
|
|
3
3
|
export const mapCategoriesToAnalyticsCategories = (
|
|
4
|
-
|
|
4
|
+
categories: string[],
|
|
5
5
|
): Record<`item_category${number | ""}`, string> => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
return categories.slice(0, 5).reduce(
|
|
7
|
+
(result, category, index) => {
|
|
8
|
+
result[`item_category${index === 0 ? "" : index + 1}`] = category;
|
|
9
|
+
return result;
|
|
10
|
+
},
|
|
11
|
+
{} as Record<`item_category${number | ""}`, string>,
|
|
12
|
+
);
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
export const mapProductCategoryToAnalyticsCategories = (category: string) => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
return category.split(">").reduce(
|
|
17
|
+
(result, category, index) => {
|
|
18
|
+
result[`item_category${index === 0 ? "" : index + 1}`] = category.trim();
|
|
19
|
+
return result;
|
|
20
|
+
},
|
|
21
|
+
{} as Record<`item_category${number | ""}`, string>,
|
|
22
|
+
);
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
export const mapProductToAnalyticsItem = (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
.filter(Boolean) ??
|
|
49
|
-
[],
|
|
50
|
-
)
|
|
51
|
-
: mapProductCategoryToAnalyticsCategories(product.category ?? "");
|
|
25
|
+
export const mapProductToAnalyticsItem = ({
|
|
26
|
+
product,
|
|
27
|
+
breadcrumbList,
|
|
28
|
+
price,
|
|
29
|
+
listPrice,
|
|
30
|
+
index = 0,
|
|
31
|
+
quantity = 1,
|
|
32
|
+
coupon = "",
|
|
33
|
+
}: {
|
|
34
|
+
product: Product;
|
|
35
|
+
breadcrumbList?: BreadcrumbList;
|
|
36
|
+
price?: number;
|
|
37
|
+
listPrice?: number;
|
|
38
|
+
index?: number;
|
|
39
|
+
quantity?: number;
|
|
40
|
+
coupon?: string;
|
|
41
|
+
}): AnalyticsItem => {
|
|
42
|
+
const { name, productID, inProductGroupWithID, isVariantOf, url } = product;
|
|
43
|
+
const categories = breadcrumbList?.itemListElement
|
|
44
|
+
? mapCategoriesToAnalyticsCategories(
|
|
45
|
+
breadcrumbList?.itemListElement.map(({ name: _name }) => _name ?? "").filter(Boolean) ?? [],
|
|
46
|
+
)
|
|
47
|
+
: mapProductCategoryToAnalyticsCategories(product.category ?? "");
|
|
52
48
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
49
|
+
return {
|
|
50
|
+
item_id: productID,
|
|
51
|
+
item_group_id: inProductGroupWithID,
|
|
52
|
+
quantity,
|
|
53
|
+
coupon,
|
|
54
|
+
price,
|
|
55
|
+
index,
|
|
56
|
+
discount: Number((price && listPrice ? listPrice - price : 0).toFixed(2)),
|
|
57
|
+
item_name: isVariantOf?.name ?? name ?? "",
|
|
58
|
+
item_variant: name,
|
|
59
|
+
item_brand: product.brand?.name ?? "",
|
|
60
|
+
item_url: url,
|
|
61
|
+
...categories,
|
|
62
|
+
};
|
|
67
63
|
};
|
|
@@ -1,50 +1,50 @@
|
|
|
1
1
|
const getStateFromZip = (cep: string) => {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
// Remove non-numeric characters
|
|
3
|
+
cep = cep.replace(/\D/g, "");
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
5
|
+
// zip range by: https://buscacepinter.correios.com.br/app/faixa_cep_uf_localidade/index.php
|
|
6
|
+
const zipRange = [
|
|
7
|
+
{ state: "AC", startRange: 69900000, endRange: 69999999 },
|
|
8
|
+
{ state: "AL", startRange: 57000000, endRange: 57999999 },
|
|
9
|
+
{ state: "AM", startRange: 69000000, endRange: 69299999 },
|
|
10
|
+
{ state: "AM", startRange: 69400000, endRange: 69899999 },
|
|
11
|
+
{ state: "AP", startRange: 68900000, endRange: 68999999 },
|
|
12
|
+
{ state: "BA", startRange: 40000000, endRange: 48999999 },
|
|
13
|
+
{ state: "CE", startRange: 60000000, endRange: 63999999 },
|
|
14
|
+
{ state: "DF", startRange: 70000000, endRange: 72799999 },
|
|
15
|
+
{ state: "DF", startRange: 73000000, endRange: 73699999 },
|
|
16
|
+
{ state: "ES", startRange: 29000000, endRange: 29999999 },
|
|
17
|
+
{ state: "GO", startRange: 72800000, endRange: 72999999 },
|
|
18
|
+
{ state: "GO", startRange: 73700000, endRange: 76799999 },
|
|
19
|
+
{ state: "MA", startRange: 65000000, endRange: 65999999 },
|
|
20
|
+
{ state: "MG", startRange: 30000000, endRange: 39999999 },
|
|
21
|
+
{ state: "MS", startRange: 79000000, endRange: 79999999 },
|
|
22
|
+
{ state: "MT", startRange: 78000000, endRange: 78899999 },
|
|
23
|
+
{ state: "PA", startRange: 66000000, endRange: 68899999 },
|
|
24
|
+
{ state: "PB", startRange: 58000000, endRange: 58999999 },
|
|
25
|
+
{ state: "PE", startRange: 50000000, endRange: 56999999 },
|
|
26
|
+
{ state: "PI", startRange: 64000000, endRange: 64999999 },
|
|
27
|
+
{ state: "PR", startRange: 80000000, endRange: 87999999 },
|
|
28
|
+
{ state: "RJ", startRange: 20000000, endRange: 28999999 },
|
|
29
|
+
{ state: "RN", startRange: 59000000, endRange: 59999999 },
|
|
30
|
+
{ state: "RO", startRange: 76800000, endRange: 76999999 },
|
|
31
|
+
{ state: "RR", startRange: 69300000, endRange: 69399999 },
|
|
32
|
+
{ state: "RS", startRange: 90000000, endRange: 99999999 },
|
|
33
|
+
{ state: "SC", startRange: 88000000, endRange: 89999999 },
|
|
34
|
+
{ state: "SE", startRange: 49000000, endRange: 49999999 },
|
|
35
|
+
{ state: "SP", startRange: 1000000, endRange: 19999999 },
|
|
36
|
+
{ state: "TO", startRange: 77000000, endRange: 77999999 },
|
|
37
|
+
];
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
const zipCode = parseInt(cep, 10);
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
for (const range of zipRange) {
|
|
42
|
+
if (zipCode >= range.startRange && zipCode <= range.endRange) {
|
|
43
|
+
return range.state;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
return "";
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
export default getStateFromZip;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/apps",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Deco commerce apps for TanStack Start - Shopify, VTEX, commerce types, analytics utils",
|
|
6
6
|
"exports": {
|
|
@@ -42,7 +42,13 @@
|
|
|
42
42
|
"typecheck": "tsc --noEmit",
|
|
43
43
|
"lint:unused": "knip",
|
|
44
44
|
"lint:unused:fix": "knip --fix",
|
|
45
|
-
"
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"test:watch": "vitest",
|
|
47
|
+
"test:coverage": "vitest run --coverage",
|
|
48
|
+
"lint": "biome check .",
|
|
49
|
+
"lint:fix": "biome check --write .",
|
|
50
|
+
"format": "biome format --write .",
|
|
51
|
+
"check": "tsc --noEmit && biome check . && knip"
|
|
46
52
|
},
|
|
47
53
|
"keywords": [
|
|
48
54
|
"deco",
|
|
@@ -57,6 +63,15 @@
|
|
|
57
63
|
"type": "git",
|
|
58
64
|
"url": "https://github.com/decocms/apps-start.git"
|
|
59
65
|
},
|
|
66
|
+
"files": [
|
|
67
|
+
"commerce/",
|
|
68
|
+
"shopify/",
|
|
69
|
+
"vtex/",
|
|
70
|
+
"!**/__tests__/"
|
|
71
|
+
],
|
|
72
|
+
"engines": {
|
|
73
|
+
"node": ">=18"
|
|
74
|
+
},
|
|
60
75
|
"publishConfig": {
|
|
61
76
|
"registry": "https://registry.npmjs.org",
|
|
62
77
|
"access": "public"
|
|
@@ -68,13 +83,17 @@
|
|
|
68
83
|
"react-dom": ">=18"
|
|
69
84
|
},
|
|
70
85
|
"devDependencies": {
|
|
71
|
-
"@
|
|
86
|
+
"@biomejs/biome": "^2.4.7",
|
|
87
|
+
"@decocms/start": "^0.29.3",
|
|
72
88
|
"@semantic-release/exec": "^7.1.0",
|
|
73
89
|
"@semantic-release/git": "^10.0.1",
|
|
74
90
|
"@tanstack/react-query": "^5.90.21",
|
|
75
91
|
"@types/react": "^19.0.0",
|
|
92
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
76
93
|
"knip": "^5.86.0",
|
|
77
94
|
"react": "^19.0.0",
|
|
78
|
-
"
|
|
95
|
+
"react-dom": "^19.0.0",
|
|
96
|
+
"typescript": "^5.9.3",
|
|
97
|
+
"vitest": "^4.1.0"
|
|
79
98
|
}
|
|
80
99
|
}
|
|
@@ -1,37 +1,36 @@
|
|
|
1
1
|
import { getShopifyClient } from "../../client";
|
|
2
|
+
import type { ShopifyCart } from "../../loaders/cart";
|
|
2
3
|
import { getCartCookie, setCartCookie } from "../../utils/cart";
|
|
3
4
|
import { AddItemToCart } from "../../utils/storefront/queries";
|
|
4
|
-
import type { ShopifyCart } from "../../loaders/cart";
|
|
5
5
|
|
|
6
6
|
export interface AddItemProps {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
lines: {
|
|
8
|
+
merchandiseId: string;
|
|
9
|
+
attributes?: Array<{ key: string; value: string }>;
|
|
10
|
+
quantity?: number;
|
|
11
|
+
sellingPlanId?: string;
|
|
12
|
+
};
|
|
13
|
+
requestHeaders: Headers;
|
|
14
|
+
responseHeaders?: Headers;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export default async function addItems(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
export default async function addItems({
|
|
18
|
+
lines,
|
|
19
|
+
requestHeaders,
|
|
20
|
+
responseHeaders,
|
|
21
|
+
}: AddItemProps): Promise<ShopifyCart | null> {
|
|
22
|
+
const client = getShopifyClient();
|
|
23
|
+
const cartId = getCartCookie(requestHeaders);
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
if (!cartId) throw new Error("Missing cart cookie");
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
AddItemToCart,
|
|
29
|
-
{ cartId, lines },
|
|
30
|
-
);
|
|
27
|
+
const data = await client.query<{
|
|
28
|
+
payload?: { cart?: ShopifyCart };
|
|
29
|
+
}>(AddItemToCart, { cartId, lines });
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
if (responseHeaders) {
|
|
32
|
+
setCartCookie(responseHeaders, cartId);
|
|
33
|
+
}
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
return data.payload?.cart ?? null;
|
|
37
36
|
}
|
|
@@ -1,32 +1,31 @@
|
|
|
1
1
|
import { getShopifyClient } from "../../client";
|
|
2
|
+
import type { ShopifyCart } from "../../loaders/cart";
|
|
2
3
|
import { getCartCookie, setCartCookie } from "../../utils/cart";
|
|
3
4
|
import { AddCoupon } from "../../utils/storefront/queries";
|
|
4
|
-
import type { ShopifyCart } from "../../loaders/cart";
|
|
5
5
|
|
|
6
6
|
export interface UpdateCouponsProps {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
discountCodes: string[];
|
|
8
|
+
requestHeaders: Headers;
|
|
9
|
+
responseHeaders?: Headers;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export default async function updateCoupons(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
export default async function updateCoupons({
|
|
13
|
+
discountCodes,
|
|
14
|
+
requestHeaders,
|
|
15
|
+
responseHeaders,
|
|
16
|
+
}: UpdateCouponsProps): Promise<ShopifyCart | null> {
|
|
17
|
+
const client = getShopifyClient();
|
|
18
|
+
const cartId = getCartCookie(requestHeaders);
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
if (!cartId) throw new Error("Missing cart cookie");
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
AddCoupon,
|
|
24
|
-
{ cartId, discountCodes },
|
|
25
|
-
);
|
|
22
|
+
const data = await client.query<{
|
|
23
|
+
payload?: { cart?: ShopifyCart };
|
|
24
|
+
}>(AddCoupon, { cartId, discountCodes });
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
if (responseHeaders) {
|
|
27
|
+
setCartCookie(responseHeaders, cartId);
|
|
28
|
+
}
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
return data.payload?.cart ?? null;
|
|
32
31
|
}
|
|
@@ -1,32 +1,31 @@
|
|
|
1
1
|
import { getShopifyClient } from "../../client";
|
|
2
|
+
import type { ShopifyCart } from "../../loaders/cart";
|
|
2
3
|
import { getCartCookie, setCartCookie } from "../../utils/cart";
|
|
3
4
|
import { UpdateItems } from "../../utils/storefront/queries";
|
|
4
|
-
import type { ShopifyCart } from "../../loaders/cart";
|
|
5
5
|
|
|
6
6
|
export interface UpdateItemsProps {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
lines: Array<{ id: string; quantity: number }>;
|
|
8
|
+
requestHeaders: Headers;
|
|
9
|
+
responseHeaders?: Headers;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export default async function updateItems(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
export default async function updateItems({
|
|
13
|
+
lines,
|
|
14
|
+
requestHeaders,
|
|
15
|
+
responseHeaders,
|
|
16
|
+
}: UpdateItemsProps): Promise<ShopifyCart | null> {
|
|
17
|
+
const client = getShopifyClient();
|
|
18
|
+
const cartId = getCartCookie(requestHeaders);
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
if (!cartId) throw new Error("Missing cart cookie");
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
UpdateItems,
|
|
24
|
-
{ cartId, lines },
|
|
25
|
-
);
|
|
22
|
+
const data = await client.query<{
|
|
23
|
+
payload?: { cart?: ShopifyCart };
|
|
24
|
+
}>(UpdateItems, { cartId, lines });
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
if (responseHeaders) {
|
|
27
|
+
setCartCookie(responseHeaders, cartId);
|
|
28
|
+
}
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
return data.payload?.cart ?? null;
|
|
32
31
|
}
|
|
@@ -3,43 +3,38 @@ import { SignInWithEmailAndPassword } from "../../utils/storefront/queries";
|
|
|
3
3
|
import { getUserCookie, setUserCookie } from "../../utils/user";
|
|
4
4
|
|
|
5
5
|
export interface SignInProps {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
email: string;
|
|
7
|
+
password: string;
|
|
8
|
+
requestHeaders: Headers;
|
|
9
|
+
responseHeaders?: Headers;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export interface SignInResult {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
customerAccessTokenCreate: {
|
|
14
|
+
customerAccessToken?: { accessToken: string; expiresAt: string } | null;
|
|
15
|
+
customerUserErrors?: Array<{ code?: string; message: string }>;
|
|
16
|
+
};
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export default async function signIn(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const client = getShopifyClient();
|
|
23
|
-
const { email, password, requestHeaders, responseHeaders } = props;
|
|
19
|
+
export default async function signIn(props: SignInProps): Promise<SignInResult | null> {
|
|
20
|
+
const client = getShopifyClient();
|
|
21
|
+
const { email, password, requestHeaders, responseHeaders } = props;
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
const existingToken = getUserCookie(requestHeaders);
|
|
24
|
+
if (existingToken) return null;
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
SignInWithEmailAndPassword,
|
|
31
|
-
{ email, password },
|
|
32
|
-
);
|
|
26
|
+
try {
|
|
27
|
+
const data = await client.query<SignInResult>(SignInWithEmailAndPassword, { email, password });
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
if (data.customerAccessTokenCreate.customerAccessToken && responseHeaders) {
|
|
30
|
+
setUserCookie(
|
|
31
|
+
responseHeaders,
|
|
32
|
+
data.customerAccessTokenCreate.customerAccessToken.accessToken,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
return data;
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
45
40
|
}
|
|
@@ -2,35 +2,30 @@ import { getShopifyClient } from "../../client";
|
|
|
2
2
|
import { RegisterAccount } from "../../utils/storefront/queries";
|
|
3
3
|
|
|
4
4
|
export interface SignUpProps {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
email: string;
|
|
6
|
+
password: string;
|
|
7
|
+
firstName?: string;
|
|
8
|
+
lastName?: string;
|
|
9
|
+
acceptsMarketing?: boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export interface SignUpResult {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
customerCreate: {
|
|
14
|
+
customer?: { id: string } | null;
|
|
15
|
+
customerUserErrors?: Array<{ code?: string; message: string }>;
|
|
16
|
+
};
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export default async function signUp(
|
|
20
|
-
|
|
21
|
-
): Promise<SignUpResult> {
|
|
22
|
-
const client = getShopifyClient();
|
|
19
|
+
export default async function signUp(props: SignUpProps): Promise<SignUpResult> {
|
|
20
|
+
const client = getShopifyClient();
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
acceptsMarketing: props.acceptsMarketing,
|
|
32
|
-
},
|
|
33
|
-
);
|
|
22
|
+
const data = await client.query<SignUpResult>(RegisterAccount, {
|
|
23
|
+
email: props.email,
|
|
24
|
+
password: props.password,
|
|
25
|
+
firstName: props.firstName,
|
|
26
|
+
lastName: props.lastName,
|
|
27
|
+
acceptsMarketing: props.acceptsMarketing,
|
|
28
|
+
});
|
|
34
29
|
|
|
35
|
-
|
|
30
|
+
return data;
|
|
36
31
|
}
|