@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,109 @@
1
+ "use server"
2
+
3
+ import { sdk } from "@core/config"
4
+ import { HttpTypes } from "@medusajs/types"
5
+ import { getCacheOptions } from "./cookies"
6
+
7
+ export const retrieveCollection = async (id: string) => {
8
+ const next = {
9
+ ...(await getCacheOptions("collections")),
10
+ }
11
+
12
+ return sdk.client
13
+ .fetch<{ collection: HttpTypes.StoreCollection }>(`/store/collections/${id}`, {
14
+ next: {
15
+ ...next,
16
+ revalidate: 0,
17
+ },
18
+ cache: "no-store",
19
+ })
20
+ .then(({ collection }) => collection)
21
+ }
22
+
23
+ export const listCollections = async (
24
+ queryParams: Record<string, string> = {}
25
+ ): Promise<{ collections: HttpTypes.StoreCollection[]; count: number }> => {
26
+ try {
27
+ const next = {
28
+ ...(await getCacheOptions("collections")),
29
+ }
30
+
31
+ queryParams.limit = queryParams.limit || "100"
32
+ queryParams.offset = queryParams.offset || "0"
33
+
34
+ return sdk.client
35
+ .fetch<{ collections: HttpTypes.StoreCollection[]; count: number }>(
36
+ "/store/collections",
37
+ {
38
+ query: queryParams,
39
+ next: {
40
+ ...next,
41
+ revalidate: 0,
42
+ },
43
+ cache: "no-store",
44
+ }
45
+ )
46
+ .then(({ collections }) => ({ collections, count: collections.length }))
47
+ .catch((error) => {
48
+ if (process.env.NODE_ENV === "production" || process.env.CI) {
49
+ return { collections: [], count: 0 }
50
+ }
51
+ throw error
52
+ })
53
+ } catch (error: any) {
54
+ if (process.env.NODE_ENV === "production" || process.env.CI) {
55
+ return { collections: [], count: 0 }
56
+ }
57
+ throw error
58
+ }
59
+ }
60
+
61
+ export const getCollectionByHandle = async (
62
+ handle: string
63
+ ): Promise<HttpTypes.StoreCollection | null> => {
64
+ try {
65
+ const next = {
66
+ ...(await getCacheOptions("collections")),
67
+ }
68
+
69
+ // Ensure handle is decoded
70
+ const decodedHandle = decodeURIComponent(handle)
71
+
72
+ // Try array-based handle filter (standard for v2)
73
+ const result = await sdk.client.fetch<HttpTypes.StoreCollectionListResponse>(
74
+ `/store/collections`,
75
+ {
76
+ query: {
77
+ handle: [decodedHandle],
78
+ },
79
+ next: {
80
+ ...next,
81
+ revalidate: 0,
82
+ },
83
+ cache: "no-store",
84
+ }
85
+ )
86
+
87
+ if (result.collections && result.collections.length > 0) {
88
+ return result.collections[0]
89
+ }
90
+
91
+ // Fallback: Fetch all and find manually (useful for handles with spaces/special chars)
92
+
93
+ const { collections } = await listCollections({ limit: "100" })
94
+ const matchedCollection = collections.find(
95
+ (c) =>
96
+ c.handle === decodedHandle ||
97
+ c.handle === handle ||
98
+ c.handle?.replace(/-/g, " ") === decodedHandle
99
+ )
100
+
101
+ if (matchedCollection) {
102
+ return matchedCollection
103
+ }
104
+
105
+ return null
106
+ } catch (error: any) {
107
+ return null
108
+ }
109
+ }
@@ -0,0 +1,143 @@
1
+ "use server"
2
+
3
+ const getBaseUrl = () => {
4
+ return process.env.MEDUSA_BACKEND_URL || "http://localhost:9000"
5
+ }
6
+
7
+ const getPublishableKey = () => {
8
+ return process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY
9
+ }
10
+
11
+ /**
12
+ * Submit a contact request
13
+ */
14
+ export async function submitContactRequest({
15
+ email,
16
+ payload,
17
+ metadata,
18
+ source = "storefront",
19
+ }: {
20
+ email: string
21
+ payload: {
22
+ full_name?: string
23
+ phone?: string
24
+ topic?: string
25
+ subject?: string
26
+ message: string
27
+ }
28
+ metadata?: Record<string, any>
29
+ source?: string
30
+ }) {
31
+ try {
32
+ const publishableKey = getPublishableKey()
33
+ const baseUrl = getBaseUrl()
34
+
35
+ if (!publishableKey) {
36
+ return {
37
+ success: false,
38
+ error: "Configuration error: Publishable API key is missing.",
39
+ }
40
+ }
41
+
42
+ const headers: Record<string, string> = {
43
+ "Content-Type": "application/json",
44
+ "x-publishable-api-key": publishableKey,
45
+ }
46
+
47
+ const requestBody: any = {
48
+ email,
49
+ payload,
50
+ source,
51
+ }
52
+
53
+ if (metadata) {
54
+ requestBody.metadata = metadata
55
+ }
56
+
57
+ const response = await fetch(`${baseUrl}/store/contact-requests`, {
58
+ method: "POST",
59
+ headers,
60
+ body: JSON.stringify(requestBody),
61
+ })
62
+
63
+ if (!response.ok) {
64
+ const error = await response.json().catch(() => ({ message: "Unknown error" }))
65
+ return {
66
+ success: false,
67
+ error:
68
+ error.message || `HTTP ${response.status}: Failed to submit contact request`,
69
+ }
70
+ }
71
+
72
+ const data = await response.json()
73
+ return {
74
+ success: true,
75
+ data,
76
+ }
77
+ } catch (error: any) {
78
+ return {
79
+ success: false,
80
+ error: error.message || "An error occurred while submitting the contact request",
81
+ }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Subscribe to email newsletter
87
+ */
88
+ export async function subscribeToNewsletter({
89
+ email,
90
+ status = "subscribed",
91
+ source = "footer",
92
+ }: {
93
+ email: string
94
+ status?: "subscribed" | "unsubscribed"
95
+ source?: string
96
+ }) {
97
+ try {
98
+ const publishableKey = getPublishableKey()
99
+ const baseUrl = getBaseUrl()
100
+
101
+ if (!publishableKey) {
102
+ return {
103
+ success: false,
104
+ error: "Configuration error: Publishable API key is missing.",
105
+ }
106
+ }
107
+
108
+ const headers: Record<string, string> = {
109
+ "Content-Type": "application/json",
110
+ "x-publishable-api-key": publishableKey,
111
+ }
112
+
113
+ const response = await fetch(`${baseUrl}/store/contact-email-subscriptions`, {
114
+ method: "POST",
115
+ headers,
116
+ body: JSON.stringify({
117
+ email,
118
+ status,
119
+ source,
120
+ }),
121
+ })
122
+
123
+ if (!response.ok) {
124
+ const error = await response.json().catch(() => ({ message: "Unknown error" }))
125
+ return {
126
+ success: false,
127
+ error:
128
+ error.message || `HTTP ${response.status}: Failed to subscribe to newsletter`,
129
+ }
130
+ }
131
+
132
+ const data = await response.json()
133
+ return {
134
+ success: true,
135
+ data,
136
+ }
137
+ } catch (error: any) {
138
+ return {
139
+ success: false,
140
+ error: error.message || "An error occurred while subscribing to newsletter",
141
+ }
142
+ }
143
+ }
@@ -0,0 +1,170 @@
1
+ import "server-only"
2
+ import { cookies as nextCookies, headers } from "next/headers"
3
+
4
+ export const getAuthHeaders = async (): Promise<{ authorization: string } | {}> => {
5
+ try {
6
+ const cookies = await nextCookies()
7
+ const token = cookies.get("_medusa_jwt")?.value
8
+
9
+ if (!token) {
10
+ return {}
11
+ }
12
+
13
+ return { authorization: `Bearer ${token}` }
14
+ } catch {
15
+ return {}
16
+ }
17
+ }
18
+
19
+ export const getGuestAuthHeaders = async (): Promise<
20
+ { authorization: string } | {}
21
+ > => {
22
+ try {
23
+ const cookies = await nextCookies()
24
+ const token = cookies.get("_medusa_guest_jwt")?.value
25
+
26
+ if (!token) {
27
+ return {}
28
+ }
29
+
30
+ return { authorization: `Bearer ${token}` }
31
+ } catch {
32
+ return {}
33
+ }
34
+ }
35
+
36
+ export const getCacheTag = async (tag: string): Promise<string> => {
37
+ try {
38
+ const cookies = await nextCookies()
39
+ const cacheId = cookies.get("_medusa_cache_id")?.value
40
+
41
+ if (!cacheId) {
42
+ return ""
43
+ }
44
+
45
+ return `${tag}-${cacheId}`
46
+ } catch (error) {
47
+ return ""
48
+ }
49
+ }
50
+
51
+ export const getCacheOptions = async (
52
+ tag: string
53
+ ): Promise<{ tags: string[] } | {}> => {
54
+ if (typeof window !== "undefined") {
55
+ return {}
56
+ }
57
+
58
+ const cacheTag = await getCacheTag(tag)
59
+
60
+ if (!cacheTag) {
61
+ return {}
62
+ }
63
+
64
+ return { tags: [`${cacheTag}`] }
65
+ }
66
+
67
+ export const setAuthToken = async (token: string) => {
68
+ const cookies = await nextCookies()
69
+ cookies.set("_medusa_jwt", token, {
70
+ maxAge: 60 * 60 * 24 * 7,
71
+ httpOnly: true,
72
+ sameSite: "strict",
73
+ secure: process.env.NODE_ENV === "production",
74
+ })
75
+ }
76
+
77
+ export const removeAuthToken = async () => {
78
+ const cookies = await nextCookies()
79
+ cookies.set("_medusa_jwt", "", {
80
+ maxAge: -1,
81
+ })
82
+ }
83
+
84
+ export const getCartId = async () => {
85
+ const cookies = await nextCookies()
86
+ const headerList = await headers()
87
+
88
+ // Check for x-cart-id header FIRST (as it's the most up-to-date from middleware)
89
+ const headerId = headerList.get("x-cart-id")
90
+ if (headerId) {
91
+ return headerId
92
+ }
93
+
94
+ // Prioritize buy_now_cart_id if it exists
95
+ const buyNowId = cookies.get("buy_now_cart_id")?.value
96
+ if (buyNowId) {
97
+ return buyNowId
98
+ }
99
+
100
+ // Fallback to regular cart cookies
101
+ const id =
102
+ cookies.get("_medusa_cart_id")?.value ||
103
+ cookies.get("cart_id")?.value ||
104
+ cookies.get("medusa_cart_id")?.value
105
+
106
+ return id
107
+ }
108
+
109
+ export const setCartId = async (cartId: string) => {
110
+ const cookies = await nextCookies()
111
+ cookies.set("_medusa_cart_id", cartId, {
112
+ maxAge: 60 * 60 * 24 * 7,
113
+ httpOnly: true,
114
+ sameSite: "strict",
115
+ secure: process.env.NODE_ENV === "production",
116
+ })
117
+ }
118
+
119
+ export const removeCartId = async () => {
120
+ const cookies = await nextCookies()
121
+ cookies.set("_medusa_cart_id", "", {
122
+ maxAge: -1,
123
+ })
124
+ }
125
+
126
+ export const removeSyncLock = async () => {
127
+ const cookies = await nextCookies()
128
+ cookies.set("_medusa_cart_synced", "", {
129
+ maxAge: -1,
130
+ })
131
+ }
132
+
133
+ export const setHoldCartId = async (cartId: string) => {
134
+ const cookies = await nextCookies()
135
+ cookies.set("_medusa_hold_cart_id", cartId, {
136
+ maxAge: 60 * 60 * 24,
137
+ httpOnly: true,
138
+ sameSite: "strict",
139
+ secure: process.env.NODE_ENV === "production",
140
+ })
141
+ }
142
+
143
+ export const getHoldCartId = async () => {
144
+ const cookies = await nextCookies()
145
+ return cookies.get("_medusa_hold_cart_id")?.value
146
+ }
147
+
148
+ export const removeHoldCartId = async () => {
149
+ const cookies = await nextCookies()
150
+ cookies.set("_medusa_hold_cart_id", "", {
151
+ maxAge: -1,
152
+ })
153
+ }
154
+
155
+ export const setBuyNowCartId = async (cartId: string) => {
156
+ const cookies = await nextCookies()
157
+ cookies.set("buy_now_cart_id", cartId, {
158
+ maxAge: 60 * 60 * 24 * 7,
159
+ httpOnly: true,
160
+ sameSite: "strict",
161
+ secure: process.env.NODE_ENV === "production",
162
+ })
163
+ }
164
+
165
+ export const removeBuyNowCartId = async () => {
166
+ const cookies = await nextCookies()
167
+ cookies.set("buy_now_cart_id", "", {
168
+ maxAge: -1,
169
+ })
170
+ }