@pradip1995/commerce-core 1.0.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/README.md +15 -0
- package/package.json +70 -0
- package/src/analytics/ga4-ecommerce.ts +96 -0
- package/src/config.ts +36 -0
- package/src/constants.tsx +84 -0
- package/src/context/modal-context.tsx +40 -0
- package/src/context/wishlist-context.tsx +96 -0
- package/src/data/cart/abandoned.ts +111 -0
- package/src/data/cart/buyNow.ts +184 -0
- package/src/data/cart/checkout.ts +487 -0
- package/src/data/cart/index.ts +7 -0
- package/src/data/cart/mutations.ts +189 -0
- package/src/data/cart/promotions.ts +121 -0
- package/src/data/cart/region.ts +66 -0
- package/src/data/cart/retrieve.ts +162 -0
- package/src/data/categories.ts +90 -0
- package/src/data/collections.ts +109 -0
- package/src/data/contact.ts +143 -0
- package/src/data/cookies.ts +170 -0
- package/src/data/customer-registration.ts +365 -0
- package/src/data/customer.ts +638 -0
- package/src/data/dynamic-config.ts +420 -0
- package/src/data/fulfillment.ts +95 -0
- package/src/data/guest.ts +357 -0
- package/src/data/locale-actions.ts +74 -0
- package/src/data/locales.ts +28 -0
- package/src/data/newsletter.ts +41 -0
- package/src/data/notifications.ts +22 -0
- package/src/data/onboarding.ts +9 -0
- package/src/data/orders.ts +500 -0
- package/src/data/payment-details.ts +68 -0
- package/src/data/payment.ts +32 -0
- package/src/data/products.ts +424 -0
- package/src/data/regions.ts +64 -0
- package/src/data/returns.ts +305 -0
- package/src/data/reviews.ts +279 -0
- package/src/data/swaps.ts +154 -0
- package/src/data/variants.ts +38 -0
- package/src/data/wishlist.ts +292 -0
- package/src/domain/cart/abandoned-carts.ts +49 -0
- package/src/domain/cart/buy-now.ts +15 -0
- package/src/domain/cart/checkout.ts +25 -0
- package/src/domain/cart/index.ts +8 -0
- package/src/domain/cart/metadata.ts +21 -0
- package/src/domain/cart/payment.ts +21 -0
- package/src/domain/cart/phone.ts +17 -0
- package/src/domain/cart/reorder.ts +19 -0
- package/src/domain/cart/validation.ts +43 -0
- package/src/domain/product/pricing.ts +49 -0
- package/src/domain/product/variant-selection.ts +193 -0
- package/src/firebase.ts +48 -0
- package/src/hooks/index.ts +8 -0
- package/src/hooks/use-add-to-cart.ts +63 -0
- package/src/hooks/use-cart.ts +132 -0
- package/src/hooks/use-checkout.ts +62 -0
- package/src/hooks/use-in-view.tsx +29 -0
- package/src/hooks/use-product-actions.ts +190 -0
- package/src/hooks/use-product-reviews.ts +18 -0
- package/src/hooks/use-product-variant.ts +142 -0
- package/src/hooks/use-server-action.ts +30 -0
- package/src/hooks/use-toggle-state.tsx +46 -0
- package/src/hooks/use-wishlist.ts +3 -0
- package/src/theme/inline-vars.ts +12 -0
- package/src/types/account.ts +21 -0
- package/src/types/cart.ts +13 -0
- package/src/types/home.ts +52 -0
- package/src/types/layout.ts +29 -0
- package/src/types/product-card.ts +17 -0
- package/src/util/compare-addresses.ts +28 -0
- package/src/util/env.ts +3 -0
- package/src/util/get-locale-header.ts +8 -0
- package/src/util/get-percentage-diff.ts +6 -0
- package/src/util/get-product-price.ts +78 -0
- package/src/util/google-oauth.ts +28 -0
- package/src/util/isEmpty.ts +11 -0
- package/src/util/medusa-error.ts +18 -0
- package/src/util/money.ts +26 -0
- package/src/util/order-status.tsx +179 -0
- package/src/util/product.ts +431 -0
- package/src/util/repeat.ts +5 -0
- package/src/util/returns.ts +71 -0
- package/src/util/sort-products.ts +48 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use server"
|
|
2
|
+
|
|
3
|
+
import { sdk } from "@core/config"
|
|
4
|
+
import medusaError from "@core/util/medusa-error"
|
|
5
|
+
import { HttpTypes } from "@medusajs/types"
|
|
6
|
+
import { revalidateTag, revalidatePath } from "next/cache"
|
|
7
|
+
import { redirect } from "next/navigation"
|
|
8
|
+
import { headers as getRequestHeaders } from "next/headers"
|
|
9
|
+
import {
|
|
10
|
+
getAuthHeaders,
|
|
11
|
+
getCacheOptions,
|
|
12
|
+
getCacheTag,
|
|
13
|
+
getCartId,
|
|
14
|
+
removeCartId,
|
|
15
|
+
setCartId,
|
|
16
|
+
getHoldCartId,
|
|
17
|
+
setHoldCartId,
|
|
18
|
+
removeHoldCartId,
|
|
19
|
+
setBuyNowCartId,
|
|
20
|
+
removeBuyNowCartId,
|
|
21
|
+
} from "../cookies"
|
|
22
|
+
import { getRegion } from "../regions"
|
|
23
|
+
import { getLocale } from "@core/data/locale-actions"
|
|
24
|
+
import { retrieveCustomer, transferCart } from "@core/data/customer"
|
|
25
|
+
import { cache } from "react"
|
|
26
|
+
import {
|
|
27
|
+
createBuyNowMetadata,
|
|
28
|
+
filterOutCurrentCart,
|
|
29
|
+
getBuyNowCheckoutUrl,
|
|
30
|
+
getPostOrderCookieAction,
|
|
31
|
+
getResumeAbandonedCheckoutUrl,
|
|
32
|
+
isEphemeralCart,
|
|
33
|
+
normalizePhoneForRazorpay,
|
|
34
|
+
partitionAbandonedCarts,
|
|
35
|
+
shouldCheckEphemeralCartMetadata,
|
|
36
|
+
shouldSkipToPayment,
|
|
37
|
+
validateAddToCartInput,
|
|
38
|
+
validateCartId,
|
|
39
|
+
validateLineItemDeleteInput,
|
|
40
|
+
validateLineItemUpdateInput,
|
|
41
|
+
validateRazorpayPreflight,
|
|
42
|
+
} from "@core/domain/cart"
|
|
43
|
+
import { getOrSetCart } from "./retrieve"
|
|
44
|
+
|
|
45
|
+
export async function updateCart(data: HttpTypes.StoreUpdateCart) {
|
|
46
|
+
const cartId = await getCartId()
|
|
47
|
+
|
|
48
|
+
if (!cartId) {
|
|
49
|
+
throw new Error("No existing cart found, please create one before updating")
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const headers = {
|
|
53
|
+
...(await getAuthHeaders()),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return sdk.store.cart
|
|
57
|
+
.update(cartId, data, {}, headers)
|
|
58
|
+
.then(async ({ cart }: { cart: HttpTypes.StoreCart }) => {
|
|
59
|
+
const cartCacheTag = await getCacheTag("carts")
|
|
60
|
+
revalidateTag(cartCacheTag)
|
|
61
|
+
|
|
62
|
+
const fulfillmentCacheTag = await getCacheTag("fulfillment")
|
|
63
|
+
revalidateTag(fulfillmentCacheTag)
|
|
64
|
+
|
|
65
|
+
return cart
|
|
66
|
+
})
|
|
67
|
+
.catch(medusaError)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function addToCart({
|
|
71
|
+
variantId,
|
|
72
|
+
quantity,
|
|
73
|
+
countryCode,
|
|
74
|
+
}: {
|
|
75
|
+
variantId: string
|
|
76
|
+
quantity: number
|
|
77
|
+
countryCode: string
|
|
78
|
+
}) {
|
|
79
|
+
validateAddToCartInput({ variantId, quantity })
|
|
80
|
+
|
|
81
|
+
const cart = await getOrSetCart(countryCode)
|
|
82
|
+
|
|
83
|
+
if (!cart) {
|
|
84
|
+
throw new Error("Error retrieving or creating cart")
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const headers = {
|
|
88
|
+
...(await getAuthHeaders()),
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
await sdk.store.cart
|
|
92
|
+
.createLineItem(
|
|
93
|
+
cart.id,
|
|
94
|
+
{
|
|
95
|
+
variant_id: variantId,
|
|
96
|
+
quantity,
|
|
97
|
+
},
|
|
98
|
+
{},
|
|
99
|
+
headers
|
|
100
|
+
)
|
|
101
|
+
.then(async () => {
|
|
102
|
+
const cartCacheTag = await getCacheTag("carts")
|
|
103
|
+
revalidateTag(cartCacheTag)
|
|
104
|
+
|
|
105
|
+
const fulfillmentCacheTag = await getCacheTag("fulfillment")
|
|
106
|
+
revalidateTag(fulfillmentCacheTag)
|
|
107
|
+
})
|
|
108
|
+
.catch(medusaError)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export async function updateLineItem({
|
|
112
|
+
lineId,
|
|
113
|
+
quantity,
|
|
114
|
+
}: {
|
|
115
|
+
lineId: string
|
|
116
|
+
quantity: number
|
|
117
|
+
}) {
|
|
118
|
+
validateLineItemUpdateInput({ lineId, quantity })
|
|
119
|
+
|
|
120
|
+
const cartId = await getCartId()
|
|
121
|
+
validateCartId(cartId)
|
|
122
|
+
|
|
123
|
+
const headers = {
|
|
124
|
+
...(await getAuthHeaders()),
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
await sdk.store.cart
|
|
128
|
+
.updateLineItem(cartId!, lineId, { quantity }, {}, headers)
|
|
129
|
+
.then(async () => {
|
|
130
|
+
const cartCacheTag = await getCacheTag("carts")
|
|
131
|
+
revalidateTag(cartCacheTag)
|
|
132
|
+
|
|
133
|
+
const fulfillmentCacheTag = await getCacheTag("fulfillment")
|
|
134
|
+
revalidateTag(fulfillmentCacheTag)
|
|
135
|
+
})
|
|
136
|
+
.catch(medusaError)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function deleteLineItem(lineId: string) {
|
|
140
|
+
validateLineItemDeleteInput(lineId)
|
|
141
|
+
|
|
142
|
+
const cartId = await getCartId()
|
|
143
|
+
validateCartId(cartId)
|
|
144
|
+
|
|
145
|
+
const headers = {
|
|
146
|
+
...(await getAuthHeaders()),
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
await sdk.store.cart
|
|
150
|
+
.deleteLineItem(cartId!, lineId, {}, headers)
|
|
151
|
+
.then(async () => {
|
|
152
|
+
const cartCacheTag = await getCacheTag("carts")
|
|
153
|
+
revalidateTag(cartCacheTag)
|
|
154
|
+
|
|
155
|
+
const fulfillmentCacheTag = await getCacheTag("fulfillment")
|
|
156
|
+
revalidateTag(fulfillmentCacheTag)
|
|
157
|
+
})
|
|
158
|
+
.catch(medusaError)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export async function updateLineItemVariant({
|
|
162
|
+
lineId,
|
|
163
|
+
variantId,
|
|
164
|
+
quantity,
|
|
165
|
+
countryCode,
|
|
166
|
+
}: {
|
|
167
|
+
lineId: string
|
|
168
|
+
variantId: string
|
|
169
|
+
quantity: number
|
|
170
|
+
countryCode: string
|
|
171
|
+
}) {
|
|
172
|
+
if (!lineId) {
|
|
173
|
+
throw new Error("Missing lineItem ID when updating variant")
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!variantId) {
|
|
177
|
+
throw new Error("Missing variant ID when updating variant")
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Delete the old line item
|
|
181
|
+
await deleteLineItem(lineId)
|
|
182
|
+
|
|
183
|
+
// Add new line item with the new variant
|
|
184
|
+
await addToCart({
|
|
185
|
+
variantId,
|
|
186
|
+
quantity,
|
|
187
|
+
countryCode,
|
|
188
|
+
})
|
|
189
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use server"
|
|
2
|
+
|
|
3
|
+
import { sdk } from "@core/config"
|
|
4
|
+
import medusaError from "@core/util/medusa-error"
|
|
5
|
+
import { HttpTypes } from "@medusajs/types"
|
|
6
|
+
import { revalidateTag, revalidatePath } from "next/cache"
|
|
7
|
+
import { redirect } from "next/navigation"
|
|
8
|
+
import { headers as getRequestHeaders } from "next/headers"
|
|
9
|
+
import {
|
|
10
|
+
getAuthHeaders,
|
|
11
|
+
getCacheOptions,
|
|
12
|
+
getCacheTag,
|
|
13
|
+
getCartId,
|
|
14
|
+
removeCartId,
|
|
15
|
+
setCartId,
|
|
16
|
+
getHoldCartId,
|
|
17
|
+
setHoldCartId,
|
|
18
|
+
removeHoldCartId,
|
|
19
|
+
setBuyNowCartId,
|
|
20
|
+
removeBuyNowCartId,
|
|
21
|
+
} from "../cookies"
|
|
22
|
+
import { getRegion } from "../regions"
|
|
23
|
+
import { getLocale } from "@core/data/locale-actions"
|
|
24
|
+
import { retrieveCustomer, transferCart } from "@core/data/customer"
|
|
25
|
+
import { cache } from "react"
|
|
26
|
+
import {
|
|
27
|
+
createBuyNowMetadata,
|
|
28
|
+
filterOutCurrentCart,
|
|
29
|
+
getBuyNowCheckoutUrl,
|
|
30
|
+
getPostOrderCookieAction,
|
|
31
|
+
getResumeAbandonedCheckoutUrl,
|
|
32
|
+
isEphemeralCart,
|
|
33
|
+
normalizePhoneForRazorpay,
|
|
34
|
+
partitionAbandonedCarts,
|
|
35
|
+
shouldCheckEphemeralCartMetadata,
|
|
36
|
+
shouldSkipToPayment,
|
|
37
|
+
validateAddToCartInput,
|
|
38
|
+
validateCartId,
|
|
39
|
+
validateLineItemDeleteInput,
|
|
40
|
+
validateLineItemUpdateInput,
|
|
41
|
+
validateRazorpayPreflight,
|
|
42
|
+
} from "@core/domain/cart"
|
|
43
|
+
|
|
44
|
+
export async function applyPromotions(codes: string[]) {
|
|
45
|
+
const cartId = await getCartId()
|
|
46
|
+
|
|
47
|
+
if (!cartId) {
|
|
48
|
+
throw new Error("No existing cart found")
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const headers = {
|
|
52
|
+
...(await getAuthHeaders()),
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return sdk.store.cart
|
|
56
|
+
.update(cartId, { promo_codes: codes }, {}, headers)
|
|
57
|
+
.then(async ({ cart }) => {
|
|
58
|
+
const cartCacheTag = await getCacheTag("carts")
|
|
59
|
+
revalidateTag(cartCacheTag)
|
|
60
|
+
|
|
61
|
+
const fulfillmentCacheTag = await getCacheTag("fulfillment")
|
|
62
|
+
revalidateTag(fulfillmentCacheTag)
|
|
63
|
+
|
|
64
|
+
return cart
|
|
65
|
+
})
|
|
66
|
+
.catch(medusaError)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function applyGiftCard(code: string) {
|
|
70
|
+
// const cartId = getCartId()
|
|
71
|
+
// if (!cartId) return "No cartId cookie found"
|
|
72
|
+
// try {
|
|
73
|
+
// await updateCart(cartId, { gift_cards: [{ code }] }).then(() => {
|
|
74
|
+
// revalidateTag("cart")
|
|
75
|
+
// })
|
|
76
|
+
// } catch (error: any) {
|
|
77
|
+
// throw error
|
|
78
|
+
// }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function removeDiscount(code: string) {
|
|
82
|
+
// const cartId = getCartId()
|
|
83
|
+
// if (!cartId) return "No cartId cookie found"
|
|
84
|
+
// try {
|
|
85
|
+
// await deleteDiscount(cartId, code)
|
|
86
|
+
// revalidateTag("cart")
|
|
87
|
+
// } catch (error: any) {
|
|
88
|
+
// throw error
|
|
89
|
+
// }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function removeGiftCard(
|
|
93
|
+
codeToRemove: string,
|
|
94
|
+
giftCards: any[]
|
|
95
|
+
// giftCards: GiftCard[]
|
|
96
|
+
) {
|
|
97
|
+
// const cartId = getCartId()
|
|
98
|
+
// if (!cartId) return "No cartId cookie found"
|
|
99
|
+
// try {
|
|
100
|
+
// await updateCart(cartId, {
|
|
101
|
+
// gift_cards: [...giftCards]
|
|
102
|
+
// .filter((gc) => gc.code !== codeToRemove)
|
|
103
|
+
// .map((gc) => ({ code: gc.code })),
|
|
104
|
+
// }).then(() => {
|
|
105
|
+
// revalidateTag("cart")
|
|
106
|
+
// })
|
|
107
|
+
// } catch (error: any) {
|
|
108
|
+
// throw error
|
|
109
|
+
// }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function submitPromotionForm(currentState: unknown, formData: FormData) {
|
|
113
|
+
const code = formData.get("code") as string
|
|
114
|
+
try {
|
|
115
|
+
await applyPromotions([code])
|
|
116
|
+
} catch (e: any) {
|
|
117
|
+
return e.message
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// TODO: Pass a POJO instead of a form entity here
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use server"
|
|
2
|
+
|
|
3
|
+
import { sdk } from "@core/config"
|
|
4
|
+
import medusaError from "@core/util/medusa-error"
|
|
5
|
+
import { HttpTypes } from "@medusajs/types"
|
|
6
|
+
import { revalidateTag, revalidatePath } from "next/cache"
|
|
7
|
+
import { redirect } from "next/navigation"
|
|
8
|
+
import { headers as getRequestHeaders } from "next/headers"
|
|
9
|
+
import {
|
|
10
|
+
getAuthHeaders,
|
|
11
|
+
getCacheOptions,
|
|
12
|
+
getCacheTag,
|
|
13
|
+
getCartId,
|
|
14
|
+
removeCartId,
|
|
15
|
+
setCartId,
|
|
16
|
+
getHoldCartId,
|
|
17
|
+
setHoldCartId,
|
|
18
|
+
removeHoldCartId,
|
|
19
|
+
setBuyNowCartId,
|
|
20
|
+
removeBuyNowCartId,
|
|
21
|
+
} from "../cookies"
|
|
22
|
+
import { getRegion } from "../regions"
|
|
23
|
+
import { getLocale } from "@core/data/locale-actions"
|
|
24
|
+
import { retrieveCustomer, transferCart } from "@core/data/customer"
|
|
25
|
+
import { cache } from "react"
|
|
26
|
+
import {
|
|
27
|
+
createBuyNowMetadata,
|
|
28
|
+
filterOutCurrentCart,
|
|
29
|
+
getBuyNowCheckoutUrl,
|
|
30
|
+
getPostOrderCookieAction,
|
|
31
|
+
getResumeAbandonedCheckoutUrl,
|
|
32
|
+
isEphemeralCart,
|
|
33
|
+
normalizePhoneForRazorpay,
|
|
34
|
+
partitionAbandonedCarts,
|
|
35
|
+
shouldCheckEphemeralCartMetadata,
|
|
36
|
+
shouldSkipToPayment,
|
|
37
|
+
validateAddToCartInput,
|
|
38
|
+
validateCartId,
|
|
39
|
+
validateLineItemDeleteInput,
|
|
40
|
+
validateLineItemUpdateInput,
|
|
41
|
+
validateRazorpayPreflight,
|
|
42
|
+
} from "@core/domain/cart"
|
|
43
|
+
import { updateCart } from "./mutations"
|
|
44
|
+
|
|
45
|
+
export async function updateRegion(countryCode: string, currentPath: string) {
|
|
46
|
+
const cartId = await getCartId()
|
|
47
|
+
const region = await getRegion(countryCode)
|
|
48
|
+
|
|
49
|
+
if (!region) {
|
|
50
|
+
throw new Error(`Region not found for country code: ${countryCode}`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (cartId) {
|
|
54
|
+
await updateCart({ region_id: region.id })
|
|
55
|
+
const cartCacheTag = await getCacheTag("carts")
|
|
56
|
+
revalidateTag(cartCacheTag)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const regionCacheTag = await getCacheTag("regions")
|
|
60
|
+
revalidateTag(regionCacheTag)
|
|
61
|
+
|
|
62
|
+
const productsCacheTag = await getCacheTag("products")
|
|
63
|
+
revalidateTag(productsCacheTag)
|
|
64
|
+
|
|
65
|
+
redirect(`/${countryCode}${currentPath}`)
|
|
66
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use server"
|
|
2
|
+
|
|
3
|
+
import { sdk } from "@core/config"
|
|
4
|
+
import medusaError from "@core/util/medusa-error"
|
|
5
|
+
import { HttpTypes } from "@medusajs/types"
|
|
6
|
+
import { revalidateTag, revalidatePath } from "next/cache"
|
|
7
|
+
import { redirect } from "next/navigation"
|
|
8
|
+
import { headers as getRequestHeaders } from "next/headers"
|
|
9
|
+
import {
|
|
10
|
+
getAuthHeaders,
|
|
11
|
+
getCacheOptions,
|
|
12
|
+
getCacheTag,
|
|
13
|
+
getCartId,
|
|
14
|
+
removeCartId,
|
|
15
|
+
setCartId,
|
|
16
|
+
getHoldCartId,
|
|
17
|
+
setHoldCartId,
|
|
18
|
+
removeHoldCartId,
|
|
19
|
+
setBuyNowCartId,
|
|
20
|
+
removeBuyNowCartId,
|
|
21
|
+
} from "../cookies"
|
|
22
|
+
import { getRegion } from "../regions"
|
|
23
|
+
import { getLocale } from "@core/data/locale-actions"
|
|
24
|
+
import { retrieveCustomer, transferCart } from "@core/data/customer"
|
|
25
|
+
import { cache } from "react"
|
|
26
|
+
import {
|
|
27
|
+
createBuyNowMetadata,
|
|
28
|
+
filterOutCurrentCart,
|
|
29
|
+
getBuyNowCheckoutUrl,
|
|
30
|
+
getPostOrderCookieAction,
|
|
31
|
+
getResumeAbandonedCheckoutUrl,
|
|
32
|
+
isEphemeralCart,
|
|
33
|
+
normalizePhoneForRazorpay,
|
|
34
|
+
partitionAbandonedCarts,
|
|
35
|
+
shouldCheckEphemeralCartMetadata,
|
|
36
|
+
shouldSkipToPayment,
|
|
37
|
+
validateAddToCartInput,
|
|
38
|
+
validateCartId,
|
|
39
|
+
validateLineItemDeleteInput,
|
|
40
|
+
validateLineItemUpdateInput,
|
|
41
|
+
validateRazorpayPreflight,
|
|
42
|
+
} from "@core/domain/cart"
|
|
43
|
+
|
|
44
|
+
export const retrieveCart = cache(async (cartId?: string, fields?: string) => {
|
|
45
|
+
let id = cartId || (await getCartId())
|
|
46
|
+
const heldId = await getHoldCartId()
|
|
47
|
+
|
|
48
|
+
// AUTO-RESTORE LOGIC:
|
|
49
|
+
// If we're not explicitly asking for a specific cartId and we have an active cart
|
|
50
|
+
if (!cartId && id) {
|
|
51
|
+
try {
|
|
52
|
+
const headerList = await getRequestHeaders()
|
|
53
|
+
const pathname = headerList.get("x-pathname") || headerList.get("referer") || ""
|
|
54
|
+
|
|
55
|
+
if (shouldCheckEphemeralCartMetadata({ explicitCartId: cartId, pathname })) {
|
|
56
|
+
const currentCart = await sdk.client
|
|
57
|
+
.fetch<HttpTypes.StoreCartResponse>(`/store/carts/${id}`, {
|
|
58
|
+
method: "GET",
|
|
59
|
+
query: { fields: "metadata" },
|
|
60
|
+
headers: await getAuthHeaders(),
|
|
61
|
+
cache: "no-store",
|
|
62
|
+
})
|
|
63
|
+
.then(({ cart }) => cart)
|
|
64
|
+
.catch(() => null)
|
|
65
|
+
|
|
66
|
+
if (isEphemeralCart(currentCart?.metadata)) {
|
|
67
|
+
await removeBuyNowCartId()
|
|
68
|
+
id = await getCartId() // Re-fetch ID which will now fall back to the real main cart
|
|
69
|
+
revalidateTag("carts")
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} catch (e) {
|
|
73
|
+
// Silent fail
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fields ??=
|
|
78
|
+
"*items, *region, *items.product, *items.product.thumbnail, *items.product.images, *items.product.options, *items.product.variants, +items.product.variants.inventory_quantity, +items.product.variants.manage_inventory, +items.product.variants.allow_backorder, *items.product.variants.options, *items.variant, +items.variant.inventory_quantity, +items.variant.manage_inventory, +items.variant.allow_backorder, *items.variant.images, *items.variant.product, *items.variant.product.thumbnail, *items.variant.product.images, *items.variant.options, *items.thumbnail, *items.metadata, +items.total, +items.adjustments, *promotions, +shipping_methods.name, +shipping_methods.adjustments"
|
|
79
|
+
|
|
80
|
+
if (!id) {
|
|
81
|
+
return null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const headers = {
|
|
85
|
+
...(await getAuthHeaders()),
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const next = {
|
|
89
|
+
...(await getCacheOptions("carts")),
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return await sdk.client
|
|
93
|
+
.fetch<HttpTypes.StoreCartResponse>(`/store/carts/${id}`, {
|
|
94
|
+
method: "GET",
|
|
95
|
+
query: {
|
|
96
|
+
fields,
|
|
97
|
+
},
|
|
98
|
+
headers,
|
|
99
|
+
next,
|
|
100
|
+
cache: "no-store",
|
|
101
|
+
})
|
|
102
|
+
.then(({ cart }: { cart: HttpTypes.StoreCart }) => {
|
|
103
|
+
return cart
|
|
104
|
+
})
|
|
105
|
+
.catch(() => null)
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
export async function getOrSetCart(countryCode: string) {
|
|
109
|
+
const region = await getRegion(countryCode)
|
|
110
|
+
|
|
111
|
+
if (!region) {
|
|
112
|
+
throw new Error(`Region not found for country code: ${countryCode}`)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let cart = await retrieveCart(undefined, "id,region_id")
|
|
116
|
+
|
|
117
|
+
const headers = {
|
|
118
|
+
...(await getAuthHeaders()),
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!cart) {
|
|
122
|
+
const locale = await getLocale()
|
|
123
|
+
const cartResp = await sdk.store.cart.create(
|
|
124
|
+
{ region_id: region.id, locale: locale || undefined },
|
|
125
|
+
{},
|
|
126
|
+
headers
|
|
127
|
+
)
|
|
128
|
+
cart = cartResp.cart
|
|
129
|
+
|
|
130
|
+
await setCartId(cart.id)
|
|
131
|
+
|
|
132
|
+
const cartCacheTag = await getCacheTag("carts")
|
|
133
|
+
revalidateTag(cartCacheTag)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (cart && cart?.region_id !== region.id) {
|
|
137
|
+
await sdk.store.cart.update(cart.id, { region_id: region.id }, {}, headers)
|
|
138
|
+
const cartCacheTag = await getCacheTag("carts")
|
|
139
|
+
revalidateTag(cartCacheTag)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return cart
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export async function listCartOptions() {
|
|
146
|
+
const cartId = await getCartId()
|
|
147
|
+
const headers = {
|
|
148
|
+
...(await getAuthHeaders()),
|
|
149
|
+
}
|
|
150
|
+
const next = {
|
|
151
|
+
...(await getCacheOptions("shippingOptions")),
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return await sdk.client.fetch<{
|
|
155
|
+
shipping_options: HttpTypes.StoreCartShippingOption[]
|
|
156
|
+
}>("/store/shipping-options", {
|
|
157
|
+
query: { cart_id: cartId },
|
|
158
|
+
next,
|
|
159
|
+
headers,
|
|
160
|
+
cache: "force-cache",
|
|
161
|
+
})
|
|
162
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { sdk } from "@core/config"
|
|
2
|
+
import { HttpTypes } from "@medusajs/types"
|
|
3
|
+
import { getCacheOptions } from "./cookies"
|
|
4
|
+
|
|
5
|
+
export const listCategories = async (query?: Record<string, any>) => {
|
|
6
|
+
try {
|
|
7
|
+
const next = {
|
|
8
|
+
...(await getCacheOptions("categories")),
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const limit = query?.limit || 100
|
|
12
|
+
|
|
13
|
+
return sdk.client
|
|
14
|
+
.fetch<{ product_categories: HttpTypes.StoreProductCategory[] }>(
|
|
15
|
+
"/store/product-categories",
|
|
16
|
+
{
|
|
17
|
+
query: {
|
|
18
|
+
fields:
|
|
19
|
+
"*category_children, *products, *parent_category, *parent_category.parent_category",
|
|
20
|
+
limit,
|
|
21
|
+
...query,
|
|
22
|
+
},
|
|
23
|
+
next: {
|
|
24
|
+
...next,
|
|
25
|
+
revalidate: 0,
|
|
26
|
+
},
|
|
27
|
+
cache: "no-store",
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
.then(({ product_categories }) => product_categories)
|
|
31
|
+
.catch((error) => {
|
|
32
|
+
if (process.env.NODE_ENV === "production" || process.env.CI) {
|
|
33
|
+
return []
|
|
34
|
+
}
|
|
35
|
+
throw error
|
|
36
|
+
})
|
|
37
|
+
} catch (error: any) {
|
|
38
|
+
if (process.env.NODE_ENV === "production" || process.env.CI) {
|
|
39
|
+
return []
|
|
40
|
+
}
|
|
41
|
+
throw error
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const getCategoryByHandle = async (categoryHandle: string[]) => {
|
|
46
|
+
try {
|
|
47
|
+
const handle = `${categoryHandle.join("/")}`
|
|
48
|
+
const decodedHandle = decodeURIComponent(handle)
|
|
49
|
+
|
|
50
|
+
const next = {
|
|
51
|
+
...(await getCacheOptions("categories")),
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const result = await sdk.client.fetch<HttpTypes.StoreProductCategoryListResponse>(
|
|
55
|
+
`/store/product-categories`,
|
|
56
|
+
{
|
|
57
|
+
query: {
|
|
58
|
+
handle: [decodedHandle],
|
|
59
|
+
},
|
|
60
|
+
next: {
|
|
61
|
+
...next,
|
|
62
|
+
revalidate: 0,
|
|
63
|
+
},
|
|
64
|
+
cache: "no-store",
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if (result.product_categories && result.product_categories.length > 0) {
|
|
69
|
+
return result.product_categories[0]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Fallback: Fetch all categories and find manually
|
|
73
|
+
|
|
74
|
+
const allCategories = await listCategories({ limit: "200" })
|
|
75
|
+
const matchedCategory = allCategories.find(
|
|
76
|
+
(c) =>
|
|
77
|
+
c.handle === decodedHandle ||
|
|
78
|
+
c.handle === handle ||
|
|
79
|
+
c.handle?.replace(/-/g, " ") === decodedHandle
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
if (matchedCategory) {
|
|
83
|
+
return matchedCategory
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return null
|
|
87
|
+
} catch (error: any) {
|
|
88
|
+
return null
|
|
89
|
+
}
|
|
90
|
+
}
|