medusa-storefront-data 1.0.0 → 2.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/dist/cookies.d.ts +2 -2
- package/dist/cookies.d.ts.map +1 -1
- package/dist/edge.d.ts +3 -0
- package/dist/edge.d.ts.map +1 -0
- package/dist/edge.js +1 -0
- package/dist/middleware.d.ts +3 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +1 -0
- package/dist/server/cart.d.ts +9 -5
- package/dist/server/cart.d.ts.map +1 -1
- package/dist/server/cart.js +164 -194
- package/dist/server/categories.d.ts +3 -2
- package/dist/server/categories.d.ts.map +1 -1
- package/dist/server/categories.js +14 -51
- package/dist/server/collections.d.ts.map +1 -1
- package/dist/server/collections.js +16 -61
- package/dist/server/contact.d.ts +34 -0
- package/dist/server/contact.d.ts.map +1 -0
- package/dist/server/contact.js +57 -0
- package/dist/server/customer.d.ts +7 -7
- package/dist/server/customer.d.ts.map +1 -1
- package/dist/server/customer.js +95 -145
- package/dist/server/dynamic-config.d.ts.map +1 -1
- package/dist/server/dynamic-config.js +5 -2
- package/dist/server/fulfillment.d.ts +4 -3
- package/dist/server/fulfillment.d.ts.map +1 -1
- package/dist/server/fulfillment.js +16 -41
- package/dist/server/guest.d.ts +35 -63
- package/dist/server/guest.d.ts.map +1 -1
- package/dist/server/guest.js +81 -202
- package/dist/server/home.d.ts +15 -0
- package/dist/server/home.d.ts.map +1 -0
- package/dist/server/home.js +45 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -0
- package/dist/server/locale-actions.d.ts +1 -1
- package/dist/server/locale-actions.d.ts.map +1 -1
- package/dist/server/locale-actions.js +8 -13
- package/dist/server/locales.d.ts +2 -4
- package/dist/server/locales.d.ts.map +1 -1
- package/dist/server/locales.js +5 -13
- package/dist/server/orders.d.ts +5 -11
- package/dist/server/orders.d.ts.map +1 -1
- package/dist/server/orders.js +126 -267
- package/dist/server/payment-details.d.ts +4 -4
- package/dist/server/payment-details.d.ts.map +1 -1
- package/dist/server/payment-details.js +17 -42
- package/dist/server/payment.d.ts +2 -1
- package/dist/server/payment.d.ts.map +1 -1
- package/dist/server/payment.js +9 -21
- package/dist/server/pincode.d.ts +7 -0
- package/dist/server/pincode.d.ts.map +1 -0
- package/dist/server/pincode.js +30 -0
- package/dist/server/products.d.ts +15 -19
- package/dist/server/products.d.ts.map +1 -1
- package/dist/server/products.js +47 -178
- package/dist/server/regions.d.ts +1 -1
- package/dist/server/regions.d.ts.map +1 -1
- package/dist/server/regions.js +6 -3
- package/dist/server/returns.d.ts +4 -4
- package/dist/server/returns.d.ts.map +1 -1
- package/dist/server/returns.js +50 -154
- package/dist/server/swaps.d.ts +3 -3
- package/dist/server/swaps.d.ts.map +1 -1
- package/dist/server/swaps.js +22 -56
- package/dist/server/variants.d.ts.map +1 -1
- package/dist/server/variants.js +11 -22
- package/dist/server/wishlist.d.ts +11 -0
- package/dist/server/wishlist.d.ts.map +1 -0
- package/dist/server/wishlist.js +49 -0
- package/dist/util/get-locale-header.d.ts +1 -1
- package/dist/util/revalidate-cart.d.ts +2 -0
- package/dist/util/revalidate-cart.d.ts.map +1 -0
- package/dist/util/revalidate-cart.js +8 -0
- package/dist/util/sort-products.d.ts +3 -0
- package/dist/util/sort-products.d.ts.map +1 -0
- package/dist/util/sort-products.js +1 -0
- package/dist/util/store-client.d.ts +13 -0
- package/dist/util/store-client.d.ts.map +1 -0
- package/dist/util/store-client.js +77 -0
- package/package.json +95 -37
- package/src/edge.ts +2 -0
- package/src/middleware.ts +2 -2
- package/src/server/cart.ts +214 -267
- package/src/server/categories.ts +19 -72
- package/src/server/collections.ts +25 -82
- package/src/server/contact.ts +92 -0
- package/src/server/customer.ts +140 -189
- package/src/server/dynamic-config.ts +6 -2
- package/src/server/fulfillment.ts +27 -53
- package/src/server/guest.ts +159 -276
- package/src/server/home.ts +68 -0
- package/src/server/index.ts +1 -0
- package/src/server/locale-actions.ts +8 -15
- package/src/server/locales.ts +6 -18
- package/src/server/orders.ts +167 -337
- package/src/server/payment-details.ts +24 -52
- package/src/server/payment.ts +8 -28
- package/src/server/pincode.ts +49 -0
- package/src/server/products.ts +72 -235
- package/src/server/regions.ts +10 -6
- package/src/server/returns.ts +75 -189
- package/src/server/swaps.ts +90 -121
- package/src/server/variants.ts +9 -28
- package/src/util/revalidate-cart.ts +10 -0
- package/src/util/sort-products.ts +2 -47
- package/src/util/store-client.ts +93 -0
- package/src/services/middleware.ts +0 -54
package/src/server/customer.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use server"
|
|
2
2
|
|
|
3
|
-
import { sdk } from "../config"
|
|
4
3
|
import medusaError from "../util/medusa-error"
|
|
5
4
|
import { HttpTypes } from "@medusajs/types"
|
|
6
5
|
import { revalidateTag } from "next/cache"
|
|
@@ -8,7 +7,6 @@ import { redirect } from "next/navigation"
|
|
|
8
7
|
import { cookies } from "next/headers"
|
|
9
8
|
import {
|
|
10
9
|
getAuthHeaders,
|
|
11
|
-
getCacheOptions,
|
|
12
10
|
getCacheTag,
|
|
13
11
|
getCartId,
|
|
14
12
|
removeAuthToken,
|
|
@@ -17,35 +15,48 @@ import {
|
|
|
17
15
|
setAuthToken,
|
|
18
16
|
setCartId,
|
|
19
17
|
} from "../cookies"
|
|
18
|
+
import {
|
|
19
|
+
medusaAuthLogin,
|
|
20
|
+
medusaAuthLogout,
|
|
21
|
+
medusaAuthRegister,
|
|
22
|
+
} from "medusa-services/auth"
|
|
23
|
+
import {
|
|
24
|
+
isAccountDeletionPendingError,
|
|
25
|
+
medusaCustomerCreate,
|
|
26
|
+
medusaCustomerCreateAddress,
|
|
27
|
+
medusaCustomerDeleteAddress,
|
|
28
|
+
medusaCustomerRetrieve,
|
|
29
|
+
medusaCustomerUpdate,
|
|
30
|
+
medusaCustomerUpdateAddress,
|
|
31
|
+
} from "medusa-services/customer"
|
|
32
|
+
import { medusaCartMerge, medusaCartTransfer } from "medusa-services/cart"
|
|
33
|
+
import {
|
|
34
|
+
getAuthClientOptions,
|
|
35
|
+
getMedusaBackendUrl,
|
|
36
|
+
getStoreCartClientOptions,
|
|
37
|
+
} from "../util/store-client"
|
|
20
38
|
|
|
21
39
|
import { cache } from "react"
|
|
22
40
|
|
|
41
|
+
function throwCustomerError(error: unknown): never {
|
|
42
|
+
if (error && typeof error === "object" && "response" in error) {
|
|
43
|
+
medusaError(error)
|
|
44
|
+
}
|
|
45
|
+
throw error instanceof Error ? error : new Error(String(error))
|
|
46
|
+
}
|
|
47
|
+
|
|
23
48
|
export const retrieveCustomer = cache(
|
|
24
49
|
async (): Promise<HttpTypes.StoreCustomer | null> => {
|
|
25
50
|
const authHeaders = await getAuthHeaders()
|
|
26
51
|
|
|
27
|
-
if (!authHeaders) return null
|
|
28
|
-
|
|
29
|
-
const headers = {
|
|
30
|
-
...authHeaders,
|
|
31
|
-
}
|
|
52
|
+
if (!("authorization" in authHeaders)) return null
|
|
32
53
|
|
|
33
54
|
try {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
headers: headers as Record<string, string>,
|
|
40
|
-
cache: "no-store",
|
|
41
|
-
}
|
|
42
|
-
)
|
|
43
|
-
return customer
|
|
44
|
-
} catch (error: any) {
|
|
45
|
-
const errStr = error.toString().toLowerCase()
|
|
46
|
-
// If the error indicates a pending deletion, return a special object
|
|
47
|
-
if (errStr.includes("active account deletion request") ||
|
|
48
|
-
(error.message && error.message.toLowerCase().includes("active account deletion request"))) {
|
|
55
|
+
const options = await getStoreCartClientOptions()
|
|
56
|
+
const { customer } = await medusaCustomerRetrieve(options, { fields: "*addresses" })
|
|
57
|
+
return customer as unknown as HttpTypes.StoreCustomer
|
|
58
|
+
} catch (error: unknown) {
|
|
59
|
+
if (isAccountDeletionPendingError(error)) {
|
|
49
60
|
const cookieStore = await cookies()
|
|
50
61
|
const cookieEmail = cookieStore.get("_medusa_customer_email")?.value
|
|
51
62
|
return { id: "pending_deletion", email: cookieEmail || "pending" } as any
|
|
@@ -56,19 +67,17 @@ export const retrieveCustomer = cache(
|
|
|
56
67
|
)
|
|
57
68
|
|
|
58
69
|
export const updateCustomer = async (body: HttpTypes.StoreUpdateCustomer) => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const updateRes = await sdk.store.customer
|
|
64
|
-
.update(body, {}, headers)
|
|
65
|
-
.then(({ customer }) => customer)
|
|
66
|
-
.catch(medusaError)
|
|
70
|
+
try {
|
|
71
|
+
const options = await getStoreCartClientOptions()
|
|
72
|
+
const { customer } = await medusaCustomerUpdate(body as Record<string, unknown>, options)
|
|
67
73
|
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
const cacheTag = await getCacheTag("customers")
|
|
75
|
+
revalidateTag(cacheTag)
|
|
70
76
|
|
|
71
|
-
|
|
77
|
+
return customer as unknown as HttpTypes.StoreCustomer
|
|
78
|
+
} catch (e) {
|
|
79
|
+
throwCustomerError(e)
|
|
80
|
+
}
|
|
72
81
|
}
|
|
73
82
|
|
|
74
83
|
export async function signup(_currentState: unknown, formData: FormData) {
|
|
@@ -81,34 +90,28 @@ export async function signup(_currentState: unknown, formData: FormData) {
|
|
|
81
90
|
}
|
|
82
91
|
|
|
83
92
|
try {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
93
|
+
const authOptions = await getAuthClientOptions()
|
|
94
|
+
const token = await medusaAuthRegister(
|
|
95
|
+
{ email: customerForm.email, password },
|
|
96
|
+
authOptions
|
|
97
|
+
)
|
|
88
98
|
|
|
89
|
-
await setAuthToken(token
|
|
99
|
+
await setAuthToken(token)
|
|
90
100
|
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
}
|
|
101
|
+
const options = await getStoreCartClientOptions()
|
|
102
|
+
const { customer: createdCustomer } = await medusaCustomerCreate(customerForm, options)
|
|
94
103
|
|
|
95
|
-
const
|
|
96
|
-
customerForm,
|
|
97
|
-
|
|
98
|
-
headers
|
|
104
|
+
const loginToken = await medusaAuthLogin(
|
|
105
|
+
{ email: customerForm.email, password },
|
|
106
|
+
authOptions
|
|
99
107
|
)
|
|
100
108
|
|
|
101
|
-
|
|
102
|
-
email: customerForm.email,
|
|
103
|
-
password,
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
await setAuthToken(loginToken as string)
|
|
109
|
+
await setAuthToken(loginToken)
|
|
107
110
|
|
|
108
111
|
const customerCacheTag = await getCacheTag("customers")
|
|
109
112
|
revalidateTag(customerCacheTag)
|
|
110
113
|
|
|
111
|
-
await transferCart(loginToken
|
|
114
|
+
await transferCart(loginToken)
|
|
112
115
|
|
|
113
116
|
return createdCustomer
|
|
114
117
|
} catch (error: any) {
|
|
@@ -120,8 +123,6 @@ export async function login(_currentState: unknown, formData: FormData) {
|
|
|
120
123
|
let email = formData.get("email_or_phone") as string
|
|
121
124
|
const password = formData.get("password") as string
|
|
122
125
|
|
|
123
|
-
// Sanitize phone number: remove spaces, dashes, etc if it looks like a phone number
|
|
124
|
-
// If it doesn't have '@', we treat it as a potential phone number and clean it
|
|
125
126
|
if (email && !email.includes("@")) {
|
|
126
127
|
email = email.replace(/[^\d+]/g, "")
|
|
127
128
|
}
|
|
@@ -130,30 +131,28 @@ export async function login(_currentState: unknown, formData: FormData) {
|
|
|
130
131
|
let countryCode = "in"
|
|
131
132
|
|
|
132
133
|
try {
|
|
133
|
-
const
|
|
134
|
-
await
|
|
134
|
+
const authOptions = await getAuthClientOptions()
|
|
135
|
+
const token = await medusaAuthLogin({ email_or_phone: email, password }, authOptions)
|
|
136
|
+
await setAuthToken(token)
|
|
135
137
|
|
|
136
|
-
// Store email in cookie for deletion flow (needed for cancellation modal)
|
|
137
138
|
const cookieStore = await cookies()
|
|
138
139
|
cookieStore.set("_medusa_customer_email", email, { maxAge: 60 * 60 * 24 * 7, path: "/" })
|
|
139
140
|
|
|
140
|
-
// Force a check to see if we are blocked
|
|
141
141
|
try {
|
|
142
|
-
await
|
|
143
|
-
|
|
142
|
+
const options = await getStoreCartClientOptions()
|
|
143
|
+
await medusaCustomerRetrieve({
|
|
144
|
+
...options,
|
|
145
|
+
authorization: `Bearer ${token}`,
|
|
144
146
|
})
|
|
145
|
-
} catch (err:
|
|
146
|
-
|
|
147
|
-
if (errStr.includes("active account deletion request")) {
|
|
147
|
+
} catch (err: unknown) {
|
|
148
|
+
if (isAccountDeletionPendingError(err)) {
|
|
148
149
|
return "ACCOUNT_DELETION_PENDING"
|
|
149
150
|
}
|
|
150
|
-
// If it's another error, we might still want to know, but deletion is our priority
|
|
151
151
|
throw err
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
// Transfer cart after login success - Moved here to ensure execution
|
|
155
154
|
try {
|
|
156
|
-
await transferCart(token
|
|
155
|
+
await transferCart(token)
|
|
157
156
|
} catch (e) {
|
|
158
157
|
console.error("Transfer cart failed in login:", e)
|
|
159
158
|
}
|
|
@@ -161,43 +160,42 @@ export async function login(_currentState: unknown, formData: FormData) {
|
|
|
161
160
|
const customerCacheTag = await getCacheTag("customers")
|
|
162
161
|
revalidateTag(customerCacheTag)
|
|
163
162
|
|
|
164
|
-
countryCode = formData.get("country_code") as string || "in"
|
|
163
|
+
countryCode = (formData.get("country_code") as string) || "in"
|
|
165
164
|
shouldRedirect = true
|
|
166
|
-
} catch (error:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (errorStr.includes("active account deletion request") ||
|
|
170
|
-
(error.message && error.message.toLowerCase().includes("active account deletion request"))) {
|
|
171
|
-
// Still set email cookie even if blocked
|
|
165
|
+
} catch (error: unknown) {
|
|
166
|
+
if (isAccountDeletionPendingError(error)) {
|
|
172
167
|
const cookieStore = await cookies()
|
|
173
168
|
cookieStore.set("_medusa_customer_email", email, { maxAge: 60 * 60 * 24 * 7, path: "/" })
|
|
174
169
|
return "ACCOUNT_DELETION_PENDING"
|
|
175
170
|
}
|
|
176
171
|
|
|
172
|
+
const errorStr = String(error).toLowerCase()
|
|
177
173
|
if (errorStr.includes("invalid") || errorStr.includes("401") || errorStr.includes("not found")) {
|
|
178
174
|
return "Invalid credentials. Please try again."
|
|
179
175
|
}
|
|
180
|
-
|
|
176
|
+
|
|
177
|
+
return error instanceof Error ? error.message : String(error)
|
|
181
178
|
}
|
|
182
179
|
|
|
183
180
|
if (shouldRedirect) {
|
|
184
181
|
const redirectUrl = formData.get("redirect_url") as string
|
|
185
|
-
|
|
186
|
-
// Check if it's a "keep-me-here" context (Wishlist or Review Popups)
|
|
187
182
|
const hasKeepContext = redirectUrl?.includes("login_context=keep")
|
|
188
183
|
|
|
189
|
-
// Security + Context check
|
|
190
184
|
if (redirectUrl && redirectUrl.startsWith("/") && hasKeepContext) {
|
|
191
185
|
redirect(redirectUrl)
|
|
192
186
|
} else {
|
|
193
|
-
// DEFAULT: Always Home Page
|
|
194
187
|
redirect(`/${countryCode}`)
|
|
195
188
|
}
|
|
196
189
|
}
|
|
197
190
|
}
|
|
198
191
|
|
|
199
192
|
export async function signout(countryCode: string) {
|
|
200
|
-
|
|
193
|
+
try {
|
|
194
|
+
const authOptions = await getAuthClientOptions()
|
|
195
|
+
await medusaAuthLogout(authOptions)
|
|
196
|
+
} catch {
|
|
197
|
+
// Continue local cleanup even if remote logout fails
|
|
198
|
+
}
|
|
201
199
|
|
|
202
200
|
await removeAuthToken()
|
|
203
201
|
await removeCartId()
|
|
@@ -216,58 +214,38 @@ export async function signout(countryCode: string) {
|
|
|
216
214
|
|
|
217
215
|
export async function transferCart(token?: string) {
|
|
218
216
|
const cartId = await getCartId()
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
:
|
|
217
|
+
const options = await getStoreCartClientOptions()
|
|
218
|
+
const mergeOptions = token
|
|
219
|
+
? { ...options, authorization: `Bearer ${token}` }
|
|
220
|
+
: options
|
|
222
221
|
|
|
223
222
|
console.log("--- TransferCart Debug ---")
|
|
224
223
|
console.log("Token provided:", !!token)
|
|
225
224
|
console.log("Guest Cart ID:", cartId)
|
|
226
225
|
|
|
227
|
-
const publishableKey = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY
|
|
228
|
-
const backendUrl = process.env.MEDUSA_BACKEND_URL || process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL || "http://localhost:9000"
|
|
229
|
-
|
|
230
226
|
try {
|
|
231
227
|
console.log("Calling merge API (always)...")
|
|
232
|
-
|
|
233
|
-
const response = await fetch(`${backendUrl}/store/carts/merge`, {
|
|
234
|
-
method: "POST",
|
|
235
|
-
headers: {
|
|
236
|
-
"Content-Type": "application/json",
|
|
237
|
-
"x-publishable-api-key": publishableKey || "",
|
|
238
|
-
...(authHeaders as any),
|
|
239
|
-
},
|
|
240
|
-
// Only include body if cartId exists
|
|
241
|
-
...(cartId ? { body: JSON.stringify({ cart_id: cartId }) } : {}),
|
|
242
|
-
cache: "no-store",
|
|
243
|
-
})
|
|
244
228
|
|
|
245
|
-
|
|
246
|
-
|
|
229
|
+
const data = await medusaCartMerge(mergeOptions, cartId ?? undefined)
|
|
230
|
+
|
|
231
|
+
if (data) {
|
|
247
232
|
console.log("--- Login Merge Response (JSON) ---")
|
|
248
233
|
console.log(JSON.stringify(data, null, 2))
|
|
249
234
|
console.log("-----------------------------------")
|
|
250
|
-
|
|
235
|
+
|
|
251
236
|
const activeCartId = data.cart?.id || data.id || data.cart_id
|
|
252
|
-
|
|
253
|
-
if (activeCartId) {
|
|
237
|
+
|
|
238
|
+
if (activeCartId && typeof activeCartId === "string") {
|
|
254
239
|
console.log("Storing Cart ID in cookie:", activeCartId)
|
|
255
240
|
await setCartId(activeCartId)
|
|
256
241
|
}
|
|
257
|
-
} else if (response.status === 404) {
|
|
258
|
-
// 404 is fine - it just means the customer has no active cart yet
|
|
259
|
-
console.log("No active cart found for this customer (expected).")
|
|
260
242
|
} else {
|
|
261
|
-
|
|
262
|
-
console.log(`Merge API Info (${response.status}):`, errorText)
|
|
263
|
-
if (cartId) {
|
|
264
|
-
await sdk.store.cart.transferCart(cartId, {}, authHeaders).catch(() => { })
|
|
265
|
-
}
|
|
243
|
+
console.log("No active cart found for this customer (expected).")
|
|
266
244
|
}
|
|
267
|
-
} catch (error:
|
|
268
|
-
console.error("Merge API error:", error.message)
|
|
245
|
+
} catch (error: unknown) {
|
|
246
|
+
console.error("Merge API error:", error instanceof Error ? error.message : error)
|
|
269
247
|
if (cartId) {
|
|
270
|
-
await
|
|
248
|
+
await medusaCartTransfer(cartId, mergeOptions).catch(() => {})
|
|
271
249
|
}
|
|
272
250
|
}
|
|
273
251
|
|
|
@@ -298,42 +276,34 @@ export const addCustomerAddress = async (
|
|
|
298
276
|
is_default_shipping: isDefaultShipping,
|
|
299
277
|
metadata: {
|
|
300
278
|
address_type: (formData.get("address_type") as string) || "HOME",
|
|
301
|
-
}
|
|
279
|
+
},
|
|
302
280
|
}
|
|
303
281
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
282
|
+
try {
|
|
283
|
+
const options = await getStoreCartClientOptions()
|
|
284
|
+
await medusaCustomerCreateAddress(address, options)
|
|
307
285
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
})
|
|
315
|
-
.catch((err) => {
|
|
316
|
-
return { success: false, error: err.toString() }
|
|
317
|
-
})
|
|
286
|
+
const customerCacheTag = await getCacheTag("customers")
|
|
287
|
+
revalidateTag(customerCacheTag)
|
|
288
|
+
return { success: true, error: null }
|
|
289
|
+
} catch (err) {
|
|
290
|
+
return { success: false, error: String(err) }
|
|
291
|
+
}
|
|
318
292
|
}
|
|
319
293
|
|
|
320
294
|
export const deleteCustomerAddress = async (
|
|
321
295
|
addressId: string
|
|
322
296
|
): Promise<void> => {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
297
|
+
try {
|
|
298
|
+
const options = await getStoreCartClientOptions()
|
|
299
|
+
await medusaCustomerDeleteAddress(addressId, options)
|
|
326
300
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
})
|
|
334
|
-
.catch((err) => {
|
|
335
|
-
return { success: false, error: err.toString() }
|
|
336
|
-
})
|
|
301
|
+
const customerCacheTag = await getCacheTag("customers")
|
|
302
|
+
revalidateTag(customerCacheTag)
|
|
303
|
+
return { success: true, error: null } as any
|
|
304
|
+
} catch (err) {
|
|
305
|
+
return { success: false, error: String(err) } as any
|
|
306
|
+
}
|
|
337
307
|
}
|
|
338
308
|
|
|
339
309
|
export const updateCustomerAddress = async (
|
|
@@ -359,7 +329,7 @@ export const updateCustomerAddress = async (
|
|
|
359
329
|
country_code: formData.get("country_code") as string,
|
|
360
330
|
metadata: {
|
|
361
331
|
address_type: (formData.get("address_type") as string) || "HOME",
|
|
362
|
-
}
|
|
332
|
+
},
|
|
363
333
|
} as any
|
|
364
334
|
|
|
365
335
|
const phone = formData.get("phone") as string
|
|
@@ -368,42 +338,34 @@ export const updateCustomerAddress = async (
|
|
|
368
338
|
address.phone = phone
|
|
369
339
|
}
|
|
370
340
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
341
|
+
try {
|
|
342
|
+
const options = await getStoreCartClientOptions()
|
|
343
|
+
await medusaCustomerUpdateAddress(addressId, address, options)
|
|
374
344
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
})
|
|
382
|
-
.catch((err) => {
|
|
383
|
-
return { success: false, error: err.toString() }
|
|
384
|
-
})
|
|
345
|
+
const customerCacheTag = await getCacheTag("customers")
|
|
346
|
+
revalidateTag(customerCacheTag)
|
|
347
|
+
return { success: true, error: null }
|
|
348
|
+
} catch (err) {
|
|
349
|
+
return { success: false, error: String(err) }
|
|
350
|
+
}
|
|
385
351
|
}
|
|
386
352
|
|
|
387
353
|
export const setDefaultAddress = async (addressId: string) => {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
354
|
+
try {
|
|
355
|
+
const options = await getStoreCartClientOptions()
|
|
356
|
+
await medusaCustomerUpdateAddress(addressId, { is_default_shipping: true }, options)
|
|
391
357
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
})
|
|
399
|
-
.catch((err) => {
|
|
400
|
-
return { success: false, error: err.toString() }
|
|
401
|
-
})
|
|
358
|
+
const customerCacheTag = await getCacheTag("customers")
|
|
359
|
+
revalidateTag(customerCacheTag)
|
|
360
|
+
return { success: true, error: null }
|
|
361
|
+
} catch (err) {
|
|
362
|
+
return { success: false, error: String(err) }
|
|
363
|
+
}
|
|
402
364
|
}
|
|
403
365
|
|
|
404
366
|
export async function initiateGoogleAuth() {
|
|
405
367
|
try {
|
|
406
|
-
const backendUrl =
|
|
368
|
+
const backendUrl = getMedusaBackendUrl()
|
|
407
369
|
|
|
408
370
|
if (!backendUrl) {
|
|
409
371
|
return { error: "Backend URL not configured" }
|
|
@@ -428,25 +390,19 @@ export async function initiateGoogleAuth() {
|
|
|
428
390
|
return { error: "No redirect URL received from Google OAuth" }
|
|
429
391
|
}
|
|
430
392
|
|
|
431
|
-
// Fix redirect URL: Remove country code prefix from callback URL if present
|
|
432
|
-
// Example: https://chocomelon.in/in/auth/customer/google/callback -> https://chocomelon.in/auth/customer/google/callback
|
|
433
393
|
try {
|
|
434
394
|
const url = new URL(redirectUrl)
|
|
435
|
-
const pathParts = url.pathname.split(
|
|
395
|
+
const pathParts = url.pathname.split("/").filter(Boolean)
|
|
436
396
|
|
|
437
|
-
// Check if path starts with country code pattern (2-3 letter code)
|
|
438
397
|
if (pathParts.length > 0 && /^[a-z]{2,3}$/i.test(pathParts[0])) {
|
|
439
|
-
|
|
440
|
-
if (pathParts.length > 1 && pathParts[1] === 'auth') {
|
|
441
|
-
// Remove country code from path
|
|
398
|
+
if (pathParts.length > 1 && pathParts[1] === "auth") {
|
|
442
399
|
pathParts.shift()
|
|
443
|
-
url.pathname =
|
|
400
|
+
url.pathname = "/" + pathParts.join("/")
|
|
444
401
|
redirectUrl = url.toString()
|
|
445
402
|
}
|
|
446
403
|
}
|
|
447
404
|
} catch (e) {
|
|
448
405
|
// If URL parsing fails, use original redirectUrl
|
|
449
|
-
|
|
450
406
|
}
|
|
451
407
|
|
|
452
408
|
return { redirectUrl }
|
|
@@ -461,7 +417,7 @@ export async function handleGoogleAuthCallback(params: Record<string, string>) {
|
|
|
461
417
|
return { error: "Missing authentication parameters" }
|
|
462
418
|
}
|
|
463
419
|
|
|
464
|
-
const backendUrl =
|
|
420
|
+
const backendUrl = getMedusaBackendUrl()
|
|
465
421
|
|
|
466
422
|
if (!backendUrl) {
|
|
467
423
|
return { error: "Backend URL not configured" }
|
|
@@ -502,23 +458,22 @@ export async function handleGoogleCallback(token: string, email?: string, first_
|
|
|
502
458
|
}
|
|
503
459
|
|
|
504
460
|
await setAuthToken(token)
|
|
505
|
-
await transferCart(token).catch(() => {
|
|
461
|
+
await transferCart(token).catch(() => {})
|
|
506
462
|
|
|
507
463
|
if (email && typeof email === "string") {
|
|
508
464
|
const cookieStore = await cookies()
|
|
509
465
|
cookieStore.set("_medusa_customer_email", email, { maxAge: 60 * 60 * 24 * 7, path: "/" })
|
|
510
466
|
|
|
511
|
-
const
|
|
512
|
-
if (
|
|
467
|
+
const options = await getStoreCartClientOptions()
|
|
468
|
+
if (options.authorization) {
|
|
513
469
|
try {
|
|
514
|
-
await
|
|
470
|
+
await medusaCustomerCreate(
|
|
515
471
|
{ email, ...(first_name && { first_name }), ...(last_name && { last_name }) },
|
|
516
|
-
|
|
517
|
-
headers
|
|
472
|
+
options
|
|
518
473
|
)
|
|
519
474
|
} catch (err: any) {
|
|
520
475
|
if (!err.message?.includes("already exists") && !err.message?.includes("duplicate")) {
|
|
521
|
-
|
|
476
|
+
// Ignore duplicate customer errors for OAuth sign-in
|
|
522
477
|
}
|
|
523
478
|
}
|
|
524
479
|
}
|
|
@@ -541,7 +496,6 @@ export async function uploadProfileImage(formData: FormData) {
|
|
|
541
496
|
return { error: "No image file provided" }
|
|
542
497
|
}
|
|
543
498
|
|
|
544
|
-
// Create new FormData with 'files' field as expected by the backend
|
|
545
499
|
const uploadFormData = new FormData()
|
|
546
500
|
uploadFormData.append("files", imageFile)
|
|
547
501
|
|
|
@@ -557,7 +511,6 @@ export async function uploadProfileImage(formData: FormData) {
|
|
|
557
511
|
throw new Error("No image URL returned from server")
|
|
558
512
|
}
|
|
559
513
|
|
|
560
|
-
// Fetch current customer to preserve existing metadata
|
|
561
514
|
const currentCustomer = await retrieveCustomer()
|
|
562
515
|
const existingMetadata = (currentCustomer?.metadata as Record<string, any>) || {}
|
|
563
516
|
const newMetadata = {
|
|
@@ -565,7 +518,6 @@ export async function uploadProfileImage(formData: FormData) {
|
|
|
565
518
|
profile_image_url: imageUrl,
|
|
566
519
|
}
|
|
567
520
|
|
|
568
|
-
// Update customer metadata
|
|
569
521
|
await updateCustomer({ metadata: newMetadata })
|
|
570
522
|
|
|
571
523
|
const customerCacheTag = await getCacheTag("customers")
|
|
@@ -575,7 +527,6 @@ export async function uploadProfileImage(formData: FormData) {
|
|
|
575
527
|
|
|
576
528
|
return { success: true, imageUrl }
|
|
577
529
|
} catch (error: any) {
|
|
578
|
-
|
|
579
530
|
return { error: error.message || "Failed to upload image" }
|
|
580
531
|
}
|
|
581
532
|
}
|
|
@@ -260,7 +260,7 @@ export const getFeaturesFromConfig = async (): Promise<{ title: string; features
|
|
|
260
260
|
|
|
261
261
|
if (!homepageConfig) return null
|
|
262
262
|
|
|
263
|
-
const title = homepageConfig["why-choose-us-title"] || "Why Choose
|
|
263
|
+
const title = homepageConfig["why-choose-us-title"] || "Why Choose Us?"
|
|
264
264
|
const featuresRaw = homepageConfig["why-choose-us-features"] || []
|
|
265
265
|
|
|
266
266
|
const features = featuresRaw.map((item: any) => {
|
|
@@ -293,7 +293,11 @@ export const getContactInfoFromConfig = async (): Promise<{ phone?: string; emai
|
|
|
293
293
|
|
|
294
294
|
return {
|
|
295
295
|
phone: contactConfig["contact-phone"],
|
|
296
|
-
email:
|
|
296
|
+
email:
|
|
297
|
+
typeof contactConfig["contact-email"] === "string" &&
|
|
298
|
+
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(contactConfig["contact-email"].trim())
|
|
299
|
+
? contactConfig["contact-email"].trim()
|
|
300
|
+
: undefined,
|
|
297
301
|
address: contactConfig["contact-address"],
|
|
298
302
|
}
|
|
299
303
|
} catch (error) {
|