@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.
Files changed (82) hide show
  1. package/README.md +15 -0
  2. package/package.json +70 -0
  3. package/src/analytics/ga4-ecommerce.ts +96 -0
  4. package/src/config.ts +36 -0
  5. package/src/constants.tsx +84 -0
  6. package/src/context/modal-context.tsx +40 -0
  7. package/src/context/wishlist-context.tsx +96 -0
  8. package/src/data/cart/abandoned.ts +111 -0
  9. package/src/data/cart/buyNow.ts +184 -0
  10. package/src/data/cart/checkout.ts +487 -0
  11. package/src/data/cart/index.ts +7 -0
  12. package/src/data/cart/mutations.ts +189 -0
  13. package/src/data/cart/promotions.ts +121 -0
  14. package/src/data/cart/region.ts +66 -0
  15. package/src/data/cart/retrieve.ts +162 -0
  16. package/src/data/categories.ts +90 -0
  17. package/src/data/collections.ts +109 -0
  18. package/src/data/contact.ts +143 -0
  19. package/src/data/cookies.ts +170 -0
  20. package/src/data/customer-registration.ts +365 -0
  21. package/src/data/customer.ts +638 -0
  22. package/src/data/dynamic-config.ts +420 -0
  23. package/src/data/fulfillment.ts +95 -0
  24. package/src/data/guest.ts +357 -0
  25. package/src/data/locale-actions.ts +74 -0
  26. package/src/data/locales.ts +28 -0
  27. package/src/data/newsletter.ts +41 -0
  28. package/src/data/notifications.ts +22 -0
  29. package/src/data/onboarding.ts +9 -0
  30. package/src/data/orders.ts +500 -0
  31. package/src/data/payment-details.ts +68 -0
  32. package/src/data/payment.ts +32 -0
  33. package/src/data/products.ts +424 -0
  34. package/src/data/regions.ts +64 -0
  35. package/src/data/returns.ts +305 -0
  36. package/src/data/reviews.ts +279 -0
  37. package/src/data/swaps.ts +154 -0
  38. package/src/data/variants.ts +38 -0
  39. package/src/data/wishlist.ts +292 -0
  40. package/src/domain/cart/abandoned-carts.ts +49 -0
  41. package/src/domain/cart/buy-now.ts +15 -0
  42. package/src/domain/cart/checkout.ts +25 -0
  43. package/src/domain/cart/index.ts +8 -0
  44. package/src/domain/cart/metadata.ts +21 -0
  45. package/src/domain/cart/payment.ts +21 -0
  46. package/src/domain/cart/phone.ts +17 -0
  47. package/src/domain/cart/reorder.ts +19 -0
  48. package/src/domain/cart/validation.ts +43 -0
  49. package/src/domain/product/pricing.ts +49 -0
  50. package/src/domain/product/variant-selection.ts +193 -0
  51. package/src/firebase.ts +48 -0
  52. package/src/hooks/index.ts +8 -0
  53. package/src/hooks/use-add-to-cart.ts +63 -0
  54. package/src/hooks/use-cart.ts +132 -0
  55. package/src/hooks/use-checkout.ts +62 -0
  56. package/src/hooks/use-in-view.tsx +29 -0
  57. package/src/hooks/use-product-actions.ts +190 -0
  58. package/src/hooks/use-product-reviews.ts +18 -0
  59. package/src/hooks/use-product-variant.ts +142 -0
  60. package/src/hooks/use-server-action.ts +30 -0
  61. package/src/hooks/use-toggle-state.tsx +46 -0
  62. package/src/hooks/use-wishlist.ts +3 -0
  63. package/src/theme/inline-vars.ts +12 -0
  64. package/src/types/account.ts +21 -0
  65. package/src/types/cart.ts +13 -0
  66. package/src/types/home.ts +52 -0
  67. package/src/types/layout.ts +29 -0
  68. package/src/types/product-card.ts +17 -0
  69. package/src/util/compare-addresses.ts +28 -0
  70. package/src/util/env.ts +3 -0
  71. package/src/util/get-locale-header.ts +8 -0
  72. package/src/util/get-percentage-diff.ts +6 -0
  73. package/src/util/get-product-price.ts +78 -0
  74. package/src/util/google-oauth.ts +28 -0
  75. package/src/util/isEmpty.ts +11 -0
  76. package/src/util/medusa-error.ts +18 -0
  77. package/src/util/money.ts +26 -0
  78. package/src/util/order-status.tsx +179 -0
  79. package/src/util/product.ts +431 -0
  80. package/src/util/repeat.ts +5 -0
  81. package/src/util/returns.ts +71 -0
  82. package/src/util/sort-products.ts +48 -0
@@ -0,0 +1,420 @@
1
+ "use server"
2
+
3
+ import { cache } from "react"
4
+ import { getAuthHeaders } from "./cookies"
5
+
6
+ // Define the structure based on the actual API response and client usage
7
+ export interface DynamicConfig {
8
+ "homepage-config"?: {
9
+ logo?: string
10
+ "homepage-banner-array"?: Array<{
11
+ "homepage-banner"?: {
12
+ "homepage-banner-image"?: string
13
+ "homepage-banner-title"?: string
14
+ "homepage-banner-subtitle"?: string
15
+ "homepage-banner-description"?: string
16
+ "homepage-banner-button-name"?: string
17
+ "homepage-banner-button-link"?: string
18
+ }
19
+ }>
20
+ "app-banner-array"?: Array<{
21
+ "app-banner"?: {
22
+ "app-banner-image"?: string
23
+ "app-banner-title"?: string
24
+ "app-banner-subtitle"?: string
25
+ "app-banner-description"?: string
26
+ "app-banner-button-name"?: string
27
+ "app-banner-button-link"?: string
28
+ "app-banner-link"?: string
29
+ }
30
+ }>
31
+ "website-description"?: string
32
+ website_description?: string
33
+ "why-choose-us-title"?: string
34
+ "why-choose-us-features"?: Array<{
35
+ feature?: {
36
+ "feature-name"?: string
37
+ "feature-icon"?: string
38
+ }
39
+ // Handle potential direct structure if any
40
+ "feature-name"?: string
41
+ "feature-icon"?: string
42
+ }>
43
+ "contact-us"?: {
44
+ "contact-phone"?: string
45
+ "contact-email"?: string
46
+ "contact-address"?: string
47
+ }
48
+ "social-links"?: Array<{
49
+ "social-link"?: {
50
+ "social-platform-name"?: string
51
+ "social-platform-icon"?: string
52
+ "social-platform-url"?: string
53
+ }
54
+ // Handle potential direct structure if any
55
+ "social-platform-name"?: string
56
+ "social-platform-icon"?: string
57
+ "social-platform-url"?: string
58
+ }>
59
+ "promo-bar"?: {
60
+ "promo-text"?: string
61
+ "promo-code"?: string
62
+ "promo-value"?: string
63
+ "promo-active"?: boolean
64
+ }
65
+ // Allow for other properties
66
+ [key: string]: any
67
+ }
68
+ }
69
+
70
+ export const getDynamicConfig = cache(async (): Promise<DynamicConfig | null> => {
71
+ try {
72
+ const publishableKey = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY
73
+ const baseUrl = process.env.MEDUSA_BACKEND_URL || "http://localhost:9000"
74
+
75
+ if (!publishableKey) {
76
+ return null
77
+ }
78
+
79
+ const authHeaders = await getAuthHeaders()
80
+
81
+ const headers: Record<string, string> = {
82
+ "Content-Type": "application/json",
83
+ Accept: "application/json",
84
+ "x-publishable-api-key": publishableKey,
85
+ }
86
+
87
+ if (authHeaders && "authorization" in authHeaders) {
88
+ headers["authorization"] = authHeaders.authorization
89
+ }
90
+
91
+ const fetchStart = Date.now()
92
+ const response = await fetch(`${baseUrl}/store/dynamic-config`, {
93
+ method: "GET",
94
+ headers,
95
+ cache: "no-store",
96
+ })
97
+ const duration = Date.now() - fetchStart
98
+
99
+ if (!response.ok) {
100
+ return null
101
+ }
102
+
103
+ const data = await response.json()
104
+
105
+ return data
106
+ } catch (error) {
107
+ return null
108
+ }
109
+ })
110
+
111
+ export const getLogoFromConfig = async (): Promise<string | null> => {
112
+ try {
113
+ const config = await getDynamicConfig()
114
+ const logo = config?.["homepage-config"]?.logo
115
+
116
+ return logo || null
117
+ } catch (error) {
118
+ return null
119
+ }
120
+ }
121
+
122
+ export const getBannerImageFromConfig = async (): Promise<string | null> => {
123
+ try {
124
+ const config = await getDynamicConfig()
125
+ const bannerArray = config?.["homepage-config"]?.["homepage-banner-array"]
126
+
127
+ if (bannerArray && bannerArray.length > 0) {
128
+ const firstBanner = bannerArray[0]
129
+ const image = firstBanner?.["homepage-banner"]?.["homepage-banner-image"]
130
+
131
+ return image || null
132
+ }
133
+
134
+ return null
135
+ } catch (error) {
136
+ return null
137
+ }
138
+ }
139
+
140
+ export const getMobileBannerFromConfig = async (): Promise<{
141
+ image: string | null
142
+ link: string | null
143
+ }> => {
144
+ try {
145
+ const config = await getDynamicConfig()
146
+ const bannerArray = config?.["homepage-config"]?.["app-banner-array"]
147
+
148
+ if (bannerArray && bannerArray.length > 0) {
149
+ const firstBanner = bannerArray[0]
150
+ const image = firstBanner?.["app-banner"]?.["app-banner-image"] || null
151
+ const link =
152
+ firstBanner?.["app-banner"]?.["app-banner-button-link"] ||
153
+ firstBanner?.["app-banner"]?.["app-banner-link"] ||
154
+ null
155
+
156
+ return { image, link }
157
+ }
158
+
159
+ return { image: null, link: null }
160
+ } catch (error) {
161
+ return { image: null, link: null }
162
+ }
163
+ }
164
+
165
+ export const getHomeBannersFromConfig = async (): Promise<Array<{
166
+ image?: string
167
+ title?: string
168
+ subtitle?: string
169
+ description?: string
170
+ buttonName?: string
171
+ buttonLink?: string
172
+ }> | null> => {
173
+ try {
174
+ const config = await getDynamicConfig()
175
+ const bannerArray = config?.["homepage-config"]?.["homepage-banner-array"]
176
+
177
+ if (bannerArray && bannerArray.length > 0) {
178
+ return bannerArray.map((item) => {
179
+ const banner = item["homepage-banner"]
180
+ return {
181
+ image: banner?.["homepage-banner-image"],
182
+ title: banner?.["homepage-banner-title"],
183
+ subtitle: banner?.["homepage-banner-subtitle"],
184
+ description: banner?.["homepage-banner-description"],
185
+ buttonName: banner?.["homepage-banner-button-name"],
186
+ buttonLink: banner?.["homepage-banner-button-link"],
187
+ }
188
+ })
189
+ }
190
+ return null
191
+ } catch (error) {
192
+ return null
193
+ }
194
+ }
195
+
196
+ export const getAppBannersFromConfig = async (): Promise<Array<{
197
+ image?: string
198
+ title?: string
199
+ subtitle?: string
200
+ description?: string
201
+ buttonName?: string
202
+ buttonLink?: string
203
+ }> | null> => {
204
+ try {
205
+ const config = await getDynamicConfig()
206
+ const bannerArray = config?.["homepage-config"]?.["app-banner-array"]
207
+
208
+ if (bannerArray && bannerArray.length > 0) {
209
+ return bannerArray.map((item) => {
210
+ const banner = item["app-banner"]
211
+ return {
212
+ image: banner?.["app-banner-image"],
213
+ title: banner?.["app-banner-title"],
214
+ subtitle: banner?.["app-banner-subtitle"],
215
+ description: banner?.["app-banner-description"],
216
+ buttonName: banner?.["app-banner-button-name"],
217
+ buttonLink: banner?.["app-banner-button-link"],
218
+ }
219
+ })
220
+ }
221
+ return null
222
+ } catch (error) {
223
+ return null
224
+ }
225
+ }
226
+
227
+ // Legacy function for backward compatibility
228
+ export const getMobileBannerImageFromConfig = async (): Promise<string | null> => {
229
+ const { image } = await getMobileBannerFromConfig()
230
+ return image
231
+ }
232
+
233
+ export const getWebsiteDescriptionFromConfig = async (): Promise<string | null> => {
234
+ try {
235
+ const config = await getDynamicConfig()
236
+ const homepageConfig = config?.["homepage-config"]
237
+ const desc =
238
+ homepageConfig?.["website-description"] || homepageConfig?.["website_description"]
239
+
240
+ return desc || null
241
+ } catch (error) {
242
+ return null
243
+ }
244
+ }
245
+
246
+ export const getFeaturesFromConfig = async (): Promise<{
247
+ title: string
248
+ features: Array<{ name: string; icon: string }>
249
+ } | null> => {
250
+ try {
251
+ const config = await getDynamicConfig()
252
+ const homepageConfig = config?.["homepage-config"]
253
+
254
+ if (!homepageConfig) return null
255
+
256
+ const title = homepageConfig["why-choose-us-title"] || "Why Choose Chocomelon?"
257
+ const featuresRaw = homepageConfig["why-choose-us-features"] || []
258
+
259
+ const features = featuresRaw
260
+ .map((item: any) => {
261
+ const feature = item?.feature || item
262
+ return {
263
+ name: feature?.["feature-name"] || "",
264
+ icon: feature?.["feature-icon"] || "",
265
+ }
266
+ })
267
+ .filter((f: any) => f.name && f.icon)
268
+
269
+ return { title, features }
270
+ } catch (error) {
271
+ return null
272
+ }
273
+ }
274
+
275
+ export const getContactInfoFromConfig = async (): Promise<{
276
+ phone?: string
277
+ email?: string
278
+ address?: string
279
+ } | null> => {
280
+ try {
281
+ const config = await getDynamicConfig()
282
+ const contactConfig = config?.["homepage-config"]?.["contact-us"]
283
+
284
+ if (!contactConfig) {
285
+ return null
286
+ }
287
+
288
+ return {
289
+ phone: contactConfig["contact-phone"],
290
+ email: contactConfig["contact-email"],
291
+ address: contactConfig["contact-address"],
292
+ }
293
+ } catch (error) {
294
+ return null
295
+ }
296
+ }
297
+
298
+ export const getTestimonialsFromConfig = async (): Promise<{
299
+ title: string
300
+ testimonials: Array<{
301
+ id: string
302
+ text: string
303
+ name: string
304
+ rating: number
305
+ avatar?: string
306
+ }>
307
+ } | null> => {
308
+ try {
309
+ const config = await getDynamicConfig()
310
+ const homepageConfig = config?.["homepage-config"]
311
+
312
+ if (!homepageConfig) return null
313
+
314
+ const title = homepageConfig["rating-title"] || "Happy Parents Say About Us"
315
+ const ratings = homepageConfig["ratings"] || []
316
+
317
+ const testimonials = ratings
318
+ .map((item: any, index: number) => {
319
+ const review = item?.review || item
320
+ return {
321
+ id: `review-${index}`,
322
+ text: review?.["review-description"] || "",
323
+ name: review?.["review-user-name"] || "",
324
+ rating: parseFloat(review?.["review-rating"] || "5"),
325
+ avatar: review?.["review-profile-image"] || undefined,
326
+ }
327
+ })
328
+ .filter((t: any) => t.text && t.name)
329
+
330
+ return { title, testimonials }
331
+ } catch (error) {
332
+ return null
333
+ }
334
+ }
335
+
336
+ export const getSocialLinksFromConfig = async (): Promise<Array<{
337
+ name: string
338
+ url: string
339
+ icon?: string
340
+ }> | null> => {
341
+ try {
342
+ const config = await getDynamicConfig()
343
+ const socialLinksRaw = config?.["homepage-config"]?.["social-links"] || []
344
+
345
+ const socialLinks = socialLinksRaw
346
+ .map((item: any) => {
347
+ const link = item?.["social-link"] || item
348
+ return {
349
+ name: link?.["social-platform-name"] || "",
350
+ url: link?.["social-platform-url"] || "",
351
+ icon: link?.["social-platform-icon"] || undefined,
352
+ }
353
+ })
354
+ .filter((l: any) => l.name && l.url)
355
+
356
+ return socialLinks.length > 0 ? socialLinks : null
357
+ } catch (error) {
358
+ return null
359
+ }
360
+ }
361
+
362
+ export const getFaqsFromConfig = async (): Promise<Array<{
363
+ category: string
364
+ items: Array<{ q: string; a: string }>
365
+ }> | null> => {
366
+ try {
367
+ const config = await getDynamicConfig()
368
+ const faqsRaw = config?.["homepage-config"]?.["faq-array"] || []
369
+
370
+ if (!Array.isArray(faqsRaw) || faqsRaw.length === 0) return null
371
+
372
+ const categoriesMap: Record<
373
+ string,
374
+ { displayCategory: string; items: Array<{ q: string; a: string }> }
375
+ > = {}
376
+
377
+ faqsRaw.forEach((item: any) => {
378
+ const faq = item?.["faq"] || item
379
+ const displayCategory = (faq?.["faq-category"] || "General Questions").trim()
380
+ const categoryKey = displayCategory.toLowerCase()
381
+ const q = (faq?.["faq-question"] || "").trim()
382
+ const a = (faq?.["faq-answer"] || "").trim()
383
+
384
+ if (q && a) {
385
+ if (!categoriesMap[categoryKey])
386
+ categoriesMap[categoryKey] = { displayCategory, items: [] }
387
+ categoriesMap[categoryKey].items.push({ q, a })
388
+ }
389
+ })
390
+
391
+ const faqs = Object.values(categoriesMap).map((catData) => ({
392
+ category: catData.displayCategory,
393
+ items: catData.items,
394
+ }))
395
+
396
+ return faqs.length > 0 ? faqs : null
397
+ } catch (error) {
398
+ return null
399
+ }
400
+ }
401
+ export const getPromoBarConfig = async (): Promise<{
402
+ text: string | null
403
+ code: string | null
404
+ value: string | null
405
+ active: boolean
406
+ }> => {
407
+ try {
408
+ const config = await getDynamicConfig()
409
+ const promoConfig = config?.["homepage-config"]?.["promo-bar"]
410
+
411
+ return {
412
+ text: promoConfig?.["promo-text"] || null,
413
+ code: promoConfig?.["promo-code"] || null,
414
+ value: promoConfig?.["promo-value"] || null,
415
+ active: promoConfig?.["promo-active"] ?? false,
416
+ }
417
+ } catch (error) {
418
+ return { text: null, code: null, value: null, active: false }
419
+ }
420
+ }
@@ -0,0 +1,95 @@
1
+ "use server"
2
+
3
+ import { sdk } from "@core/config"
4
+ import { HttpTypes } from "@medusajs/types"
5
+ import { getAuthHeaders, getCacheOptions } from "./cookies"
6
+
7
+ export const listCartShippingMethods = async (cartId: string) => {
8
+ const headers = {
9
+ ...(await getAuthHeaders()),
10
+ }
11
+
12
+ const next = {
13
+ ...(await getCacheOptions("fulfillment")),
14
+ }
15
+
16
+ return sdk.client
17
+ .fetch<HttpTypes.StoreShippingOptionListResponse>(`/store/shipping-options`, {
18
+ method: "GET",
19
+ query: {
20
+ cart_id: cartId,
21
+ },
22
+ headers,
23
+ next,
24
+ cache: "force-cache",
25
+ })
26
+ .then(({ shipping_options }) => shipping_options)
27
+ .catch(() => {
28
+ return null
29
+ })
30
+ }
31
+
32
+ export const calculatePriceForShippingOption = async (
33
+ optionId: string,
34
+ cartId: string,
35
+ data?: Record<string, unknown>
36
+ ) => {
37
+ const headers = {
38
+ ...(await getAuthHeaders()),
39
+ }
40
+
41
+ const next = {
42
+ ...(await getCacheOptions("fulfillment")),
43
+ }
44
+
45
+ const body = { cart_id: cartId, data }
46
+
47
+ if (data) {
48
+ body.data = data
49
+ }
50
+
51
+ return sdk.client
52
+ .fetch<{ shipping_option: HttpTypes.StoreCartShippingOption }>(
53
+ `/store/shipping-options/${optionId}/calculate`,
54
+ {
55
+ method: "POST",
56
+ body,
57
+ headers,
58
+ next,
59
+ }
60
+ )
61
+ .then(({ shipping_option }) => shipping_option)
62
+ .catch((e) => {
63
+ return null
64
+ })
65
+ }
66
+
67
+ export const getShiprocketServiceability = async (
68
+ pincode: string,
69
+ variant_id: string,
70
+ cod: number = 0
71
+ ) => {
72
+ const headers = {
73
+ ...(await getAuthHeaders()),
74
+ }
75
+
76
+ return sdk.client
77
+ .fetch<any>(`/store/shiprocket/serviceability`, {
78
+ method: "GET",
79
+ query: {
80
+ pincode,
81
+ variant_id,
82
+ cod: cod.toString(),
83
+ },
84
+ headers,
85
+ cache: "no-store",
86
+ })
87
+ .then((data) => data)
88
+ .catch(async (e) => {
89
+ if (e.response) {
90
+ const errorData = await e.response.json()
91
+ throw new Error(errorData.message || "Failed to check serviceability")
92
+ }
93
+ throw e
94
+ })
95
+ }