@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,78 @@
1
+ import { HttpTypes } from "@medusajs/types"
2
+ import { getPercentageDiff } from "./get-percentage-diff"
3
+ import { convertToLocale } from "./money"
4
+
5
+ export const getPricesForVariant = (variant: any) => {
6
+ if (!variant?.calculated_price?.calculated_amount) {
7
+ return null
8
+ }
9
+
10
+ return {
11
+ calculated_price_number: variant.calculated_price.calculated_amount,
12
+ calculated_price: convertToLocale({
13
+ amount: variant.calculated_price.calculated_amount,
14
+ currency_code: variant.calculated_price.currency_code,
15
+ }),
16
+ original_price_number: variant.calculated_price.original_amount,
17
+ original_price: convertToLocale({
18
+ amount: variant.calculated_price.original_amount,
19
+ currency_code: variant.calculated_price.currency_code,
20
+ }),
21
+ currency_code: variant.calculated_price.currency_code,
22
+ price_type: variant.calculated_price.calculated_price.price_list_type,
23
+ percentage_diff: getPercentageDiff(
24
+ variant.calculated_price.original_amount,
25
+ variant.calculated_price.calculated_amount
26
+ ),
27
+ }
28
+ }
29
+
30
+ export function getProductPrice({
31
+ product,
32
+ variantId,
33
+ }: {
34
+ product: HttpTypes.StoreProduct
35
+ variantId?: string
36
+ }) {
37
+ if (!product || !product.id) {
38
+ throw new Error("No product provided")
39
+ }
40
+
41
+ const cheapestPrice = () => {
42
+ if (!product || !product.variants?.length) {
43
+ return null
44
+ }
45
+
46
+ const cheapestVariant: any = product.variants
47
+ .filter((v: any) => !!v.calculated_price)
48
+ .sort((a: any, b: any) => {
49
+ return (
50
+ a.calculated_price.calculated_amount - b.calculated_price.calculated_amount
51
+ )
52
+ })[0]
53
+
54
+ return getPricesForVariant(cheapestVariant)
55
+ }
56
+
57
+ const variantPrice = () => {
58
+ if (!product || !variantId) {
59
+ return null
60
+ }
61
+
62
+ const variant: any = product.variants?.find(
63
+ (v) => v.id === variantId || v.sku === variantId
64
+ )
65
+
66
+ if (!variant) {
67
+ return null
68
+ }
69
+
70
+ return getPricesForVariant(variant)
71
+ }
72
+
73
+ return {
74
+ product,
75
+ cheapestPrice: cheapestPrice(),
76
+ variantPrice: variantPrice(),
77
+ }
78
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * OAuth redirect_uri must exactly match a URI registered in Google Cloud Console.
3
+ * That is the storefront callback path (often includes country code), NOT the backend API path.
4
+ *
5
+ * Set NEXT_PUBLIC_GOOGLE_OAUTH_CALLBACK_URL to override (must match Console exactly).
6
+ */
7
+ export function getGoogleOAuthCallbackUrl(countryCode?: string): string {
8
+ const explicit = process.env.NEXT_PUBLIC_GOOGLE_OAUTH_CALLBACK_URL?.trim()
9
+ if (explicit) {
10
+ return explicit
11
+ }
12
+
13
+ const base =
14
+ process.env.NEXT_PUBLIC_BASE_URL ||
15
+ process.env.STOREFRONT_URL ||
16
+ "http://localhost:8000"
17
+ const normalized = base.replace(/\/$/, "")
18
+ const region =
19
+ countryCode?.trim().toLowerCase() ||
20
+ process.env.NEXT_PUBLIC_DEFAULT_REGION?.trim().toLowerCase() ||
21
+ ""
22
+
23
+ if (region && /^[a-z]{2,3}$/i.test(region)) {
24
+ return `${normalized}/${region}/auth/customer/google/callback`
25
+ }
26
+
27
+ return `${normalized}/auth/customer/google/callback`
28
+ }
@@ -0,0 +1,11 @@
1
+ export const isObject = (input: any) => input instanceof Object
2
+ export const isArray = (input: any) => Array.isArray(input)
3
+ export const isEmpty = (input: any) => {
4
+ return (
5
+ input === null ||
6
+ input === undefined ||
7
+ (isObject(input) && Object.keys(input).length === 0) ||
8
+ (isArray(input) && (input as any[]).length === 0) ||
9
+ (typeof input === "string" && input.trim().length === 0)
10
+ )
11
+ }
@@ -0,0 +1,18 @@
1
+ export default function medusaError(error: any): never {
2
+ if (error.response) {
3
+ // The request was made and the server responded with a status code
4
+ // that falls out of the range of 2xx
5
+ const u = new URL(error.config.url, error.config.baseURL)
6
+
7
+ // Extracting the error message from the response data
8
+ const message = error.response.data.message || error.response.data
9
+
10
+ throw new Error(message.charAt(0).toUpperCase() + message.slice(1) + ".")
11
+ } else if (error.request) {
12
+ // The request was made but no response was received
13
+ throw new Error("No response received: " + error.request)
14
+ } else {
15
+ // Something happened in setting up the request that triggered an Error
16
+ throw new Error("Error setting up the request: " + error.message)
17
+ }
18
+ }
@@ -0,0 +1,26 @@
1
+ import { isEmpty } from "./isEmpty"
2
+
3
+ type ConvertToLocaleParams = {
4
+ amount: number
5
+ currency_code: string
6
+ minimumFractionDigits?: number
7
+ maximumFractionDigits?: number
8
+ locale?: string
9
+ }
10
+
11
+ export const convertToLocale = ({
12
+ amount,
13
+ currency_code,
14
+ minimumFractionDigits,
15
+ maximumFractionDigits,
16
+ locale = "en-US",
17
+ }: ConvertToLocaleParams) => {
18
+ return currency_code && !isEmpty(currency_code)
19
+ ? new Intl.NumberFormat(locale, {
20
+ style: "currency",
21
+ currency: currency_code,
22
+ minimumFractionDigits,
23
+ maximumFractionDigits,
24
+ }).format(amount)
25
+ : amount.toString()
26
+ }
@@ -0,0 +1,179 @@
1
+ import Delivered from "@modules/common/icons/delivered"
2
+ import { HttpTypes } from "@medusajs/types"
3
+ import { ReactNode } from "react"
4
+
5
+ export type OrderStatusConfig = {
6
+ label: string
7
+ bgColor: string
8
+ textColor: string
9
+ iconBg: string
10
+ icon: ReactNode | string
11
+ }
12
+
13
+ export const getStatusConfig = (status: string): OrderStatusConfig => {
14
+ const statusLower = status?.toLowerCase() || ""
15
+
16
+ if (statusLower.includes("cancel")) {
17
+ return {
18
+ label: "Cancelled",
19
+ bgColor: "bg-[#FFF1F2]",
20
+ textColor: "text-[#BE123C]",
21
+ iconBg: "bg-[#BE123C]",
22
+ icon: "×",
23
+ }
24
+ }
25
+
26
+ if (
27
+ statusLower === "delivered" ||
28
+ statusLower === "complete" ||
29
+ statusLower === "completed"
30
+ ) {
31
+ return {
32
+ label: "Delivered",
33
+ bgColor: "bg-[#E6F4F0]",
34
+ textColor: "text-[#008A5D]",
35
+ iconBg: "bg-[#008A5D]",
36
+ icon: <Delivered />,
37
+ }
38
+ }
39
+
40
+ if (statusLower === "shipped" || statusLower === "partially_shipped") {
41
+ return {
42
+ label: "Out For Delivery",
43
+ bgColor: "bg-[#EBF5FF]",
44
+ textColor: "text-[#0068D2]",
45
+ iconBg: "bg-[#0068D2]",
46
+ icon: (
47
+ <svg
48
+ width="20"
49
+ height="20"
50
+ viewBox="0 0 24 24"
51
+ fill="none"
52
+ stroke="white"
53
+ strokeWidth="2.5"
54
+ strokeLinecap="round"
55
+ strokeLinejoin="round"
56
+ >
57
+ <rect x="1" y="3" width="15" height="13" />
58
+ <polygon points="16 8 20 8 23 11 23 16 16 16 16 8" />
59
+ <circle cx="5.5" cy="18.5" r="2.5" />
60
+ <circle cx="18.5" cy="18.5" r="2.5" />
61
+ </svg>
62
+ ),
63
+ }
64
+ }
65
+
66
+ if (statusLower === "fulfilled" || statusLower === "partially_fulfilled") {
67
+ return {
68
+ label: "Shipped",
69
+ bgColor: "bg-[#F3E8FF]",
70
+ textColor: "text-[#8B5AB1]",
71
+ iconBg: "bg-[#8B5AB1]",
72
+ icon: (
73
+ <svg
74
+ width="20"
75
+ height="20"
76
+ viewBox="0 0 24 24"
77
+ fill="none"
78
+ stroke="white"
79
+ strokeWidth="2.5"
80
+ strokeLinecap="round"
81
+ strokeLinejoin="round"
82
+ >
83
+ <path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z" />
84
+ <polyline points="3.29 7 12 12 20.71 7" />
85
+ <line x1="12" y1="22" x2="12" y2="12" />
86
+ </svg>
87
+ ),
88
+ }
89
+ }
90
+
91
+ if (statusLower === "returned" || statusLower === "partially_returned") {
92
+ return {
93
+ label: statusLower === "returned" ? "Returned" : "Partially Returned",
94
+ bgColor: "bg-[#F0F9FF]",
95
+ textColor: "text-[#0284C7]",
96
+ iconBg: "bg-[#0284C7]",
97
+ icon: (
98
+ <svg
99
+ width="20"
100
+ height="20"
101
+ viewBox="0 0 24 24"
102
+ fill="none"
103
+ stroke="white"
104
+ strokeWidth="2.5"
105
+ strokeLinecap="round"
106
+ strokeLinejoin="round"
107
+ >
108
+ <path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" />
109
+ <path d="M21 3v5h-5" />
110
+ <path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" />
111
+ <path d="M3 21v-5h5" />
112
+ </svg>
113
+ ),
114
+ }
115
+ }
116
+
117
+ if (statusLower === "return_requested") {
118
+ return {
119
+ label: "Return Requested",
120
+ bgColor: "bg-[#FEFCE8]",
121
+ textColor: "text-[#D97706]",
122
+ iconBg: "bg-[#CA8A04]",
123
+ icon: (
124
+ <svg
125
+ width="20"
126
+ height="20"
127
+ viewBox="0 0 24 24"
128
+ fill="none"
129
+ stroke="white"
130
+ strokeWidth="2.5"
131
+ strokeLinecap="round"
132
+ strokeLinejoin="round"
133
+ >
134
+ <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" />
135
+ <polyline points="22,6 12,13 2,6" />
136
+ <path d="M12 13v5" />
137
+ </svg>
138
+ ),
139
+ }
140
+ }
141
+
142
+ return {
143
+ label: "Order Confirmed",
144
+ bgColor: "bg-[#F0FDF4]",
145
+ textColor: "text-[#16A34A]",
146
+ iconBg: "bg-[#16A34A]",
147
+ icon: (
148
+ <svg
149
+ width="20"
150
+ height="20"
151
+ viewBox="0 0 24 24"
152
+ fill="none"
153
+ stroke="white"
154
+ strokeWidth="3"
155
+ strokeLinecap="round"
156
+ strokeLinejoin="round"
157
+ >
158
+ <polyline points="20 6 9 17 4 12" />
159
+ </svg>
160
+ ),
161
+ }
162
+ }
163
+
164
+ export const getOrderDisplayStatus = (order: HttpTypes.StoreOrder): string => {
165
+ const isCancelled = order.status === "canceled" || order.status === "cancelled"
166
+
167
+ const returns =
168
+ (order as HttpTypes.StoreOrder & { returns?: { status: string }[] }).returns || []
169
+ const isReviewedReturn = returns.some(
170
+ (r) => r.status === "received" || r.status === "partially_received"
171
+ )
172
+ const isRequestedReturn = returns.some((r) => r.status === "requested")
173
+
174
+ if (isCancelled) return "canceled"
175
+ if (isReviewedReturn) return "returned"
176
+ if (isRequestedReturn) return "return_requested"
177
+
178
+ return order.fulfillment_status || order.status || "pending"
179
+ }