@pradip1995/segment-login-template 0.5.5 → 0.5.7
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/package.json +7 -7
- package/src/account-addresses.tsx +72 -2
- package/src/account-profile.tsx +8 -4
- package/src/auth-server.ts +5 -1
- package/src/forgot-password-form.tsx +3 -1
- package/src/guest-order-modal.tsx +5 -2
- package/src/is-next-redirect.ts +60 -0
- package/src/login-form.tsx +5 -18
- package/src/otp-unified-form.tsx +4 -18
- package/src/register-form.tsx +6 -18
- package/src/reset-password-form.tsx +2 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pradip1995/segment-login-template",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -20,10 +20,6 @@
|
|
|
20
20
|
"./google-auth-section": "./src/google-auth-section.tsx",
|
|
21
21
|
"./otp-input": "./src/otp-input.tsx"
|
|
22
22
|
},
|
|
23
|
-
"scripts": {
|
|
24
|
-
"typecheck": "tsc --noEmit",
|
|
25
|
-
"lint": "tsc --noEmit"
|
|
26
|
-
},
|
|
27
23
|
"peerDependencies": {
|
|
28
24
|
"@pradip1995/commerce-auth": "^4.0.0",
|
|
29
25
|
"@pradip1995/commerce-core": "^4.0.0",
|
|
@@ -35,7 +31,7 @@
|
|
|
35
31
|
"dependencies": {
|
|
36
32
|
"@pradip1995/commerce-auth": "^4.0.0",
|
|
37
33
|
"@pradip1995/commerce-core": "^4.0.0",
|
|
38
|
-
"@pradip1995/segment-primitives": "^0.4.
|
|
34
|
+
"@pradip1995/segment-primitives": "^0.4.3",
|
|
39
35
|
"@pradip1995/segment-tokens": "^0.3.7"
|
|
40
36
|
},
|
|
41
37
|
"devDependencies": {
|
|
@@ -43,5 +39,9 @@
|
|
|
43
39
|
"@types/react": "^19",
|
|
44
40
|
"react": "19.0.3",
|
|
45
41
|
"typescript": "^5.7.2"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"lint": "tsc --noEmit"
|
|
46
46
|
}
|
|
47
|
-
}
|
|
47
|
+
}
|
|
@@ -5,6 +5,7 @@ import type { HttpTypes } from "@medusajs/types"
|
|
|
5
5
|
import {
|
|
6
6
|
addCustomerAddress,
|
|
7
7
|
deleteCustomerAddress,
|
|
8
|
+
setDefaultAddress,
|
|
8
9
|
updateCustomerAddress,
|
|
9
10
|
} from "@pradip1995/commerce-core/data/customer"
|
|
10
11
|
import { acct } from "./account-theme"
|
|
@@ -19,6 +20,7 @@ export default function AccountAddresses({
|
|
|
19
20
|
const addresses = customer.addresses ?? []
|
|
20
21
|
const [editingId, setEditingId] = useState<string | null>(null)
|
|
21
22
|
const [showAdd, setShowAdd] = useState(false)
|
|
23
|
+
const hasDefault = addresses.some((a) => a.is_default_shipping || a.is_default_billing)
|
|
22
24
|
|
|
23
25
|
return (
|
|
24
26
|
<div className="space-y-8">
|
|
@@ -46,6 +48,7 @@ export default function AccountAddresses({
|
|
|
46
48
|
countryCode={countryCode}
|
|
47
49
|
address={address}
|
|
48
50
|
addressId={address.id}
|
|
51
|
+
defaultChecked={!!(address.is_default_shipping || address.is_default_billing)}
|
|
49
52
|
onDone={() => setEditingId(null)}
|
|
50
53
|
onCancel={() => setEditingId(null)}
|
|
51
54
|
/>
|
|
@@ -72,7 +75,10 @@ export default function AccountAddresses({
|
|
|
72
75
|
</p>
|
|
73
76
|
)}
|
|
74
77
|
</div>
|
|
75
|
-
<div className="flex gap-2 shrink-0">
|
|
78
|
+
<div className="flex flex-col sm:flex-row gap-2 shrink-0 items-end sm:items-center">
|
|
79
|
+
{!address.is_default_shipping && (
|
|
80
|
+
<MakeDefaultButton addressId={address.id!} />
|
|
81
|
+
)}
|
|
76
82
|
<button
|
|
77
83
|
type="button"
|
|
78
84
|
onClick={() => setEditingId(address.id!)}
|
|
@@ -93,6 +99,7 @@ export default function AccountAddresses({
|
|
|
93
99
|
<h3 className="text-sm font-semibold text-heading mb-4">New address</h3>
|
|
94
100
|
<AddressForm
|
|
95
101
|
countryCode={countryCode}
|
|
102
|
+
defaultChecked={addresses.length === 0 || !hasDefault}
|
|
96
103
|
onDone={() => setShowAdd(false)}
|
|
97
104
|
onCancel={() => setShowAdd(false)}
|
|
98
105
|
/>
|
|
@@ -106,23 +113,41 @@ function AddressForm({
|
|
|
106
113
|
countryCode,
|
|
107
114
|
address,
|
|
108
115
|
addressId,
|
|
116
|
+
defaultChecked = false,
|
|
109
117
|
onDone,
|
|
110
118
|
onCancel,
|
|
111
119
|
}: {
|
|
112
120
|
countryCode: string
|
|
113
121
|
address?: HttpTypes.StoreCustomerAddress
|
|
114
122
|
addressId?: string
|
|
123
|
+
defaultChecked?: boolean
|
|
115
124
|
onDone: () => void
|
|
116
125
|
onCancel: () => void
|
|
117
126
|
}) {
|
|
118
127
|
const action = addressId ? updateCustomerAddress : addCustomerAddress
|
|
119
128
|
const [state, formAction, pending] = useActionState(
|
|
120
129
|
async (prev: Record<string, unknown>, formData: FormData) => {
|
|
130
|
+
const makeDefault = formData.get("is_default") === "on"
|
|
121
131
|
const result = await action(
|
|
122
|
-
addressId
|
|
132
|
+
addressId
|
|
133
|
+
? { ...prev, addressId }
|
|
134
|
+
: {
|
|
135
|
+
...prev,
|
|
136
|
+
isDefaultShipping: makeDefault,
|
|
137
|
+
isDefaultBilling: makeDefault,
|
|
138
|
+
},
|
|
123
139
|
formData
|
|
124
140
|
)
|
|
125
141
|
if (result?.success) {
|
|
142
|
+
if (addressId && makeDefault && !address?.is_default_shipping) {
|
|
143
|
+
const defaultResult = await setDefaultAddress(addressId)
|
|
144
|
+
if (!defaultResult?.success) {
|
|
145
|
+
return {
|
|
146
|
+
success: false,
|
|
147
|
+
error: defaultResult?.error || "Failed to set default address",
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
126
151
|
onDone()
|
|
127
152
|
window.location.reload()
|
|
128
153
|
}
|
|
@@ -146,6 +171,15 @@ function AddressForm({
|
|
|
146
171
|
defaultValue={address?.country_code || countryCode}
|
|
147
172
|
/>
|
|
148
173
|
<Field label="Phone" name="phone" type="tel" defaultValue={address?.phone || ""} />
|
|
174
|
+
<label className="sm:col-span-2 flex items-center gap-2 text-sm text-body cursor-pointer">
|
|
175
|
+
<input
|
|
176
|
+
type="checkbox"
|
|
177
|
+
name="is_default"
|
|
178
|
+
defaultChecked={defaultChecked}
|
|
179
|
+
className="size-4 accent-[var(--color-brand-accent,#7c3aed)]"
|
|
180
|
+
/>
|
|
181
|
+
<span>Set as default shipping address</span>
|
|
182
|
+
</label>
|
|
149
183
|
{state?.error && (
|
|
150
184
|
<p className="sm:col-span-2 text-sm text-red-600">{String(state.error)}</p>
|
|
151
185
|
)}
|
|
@@ -161,6 +195,42 @@ function AddressForm({
|
|
|
161
195
|
)
|
|
162
196
|
}
|
|
163
197
|
|
|
198
|
+
function MakeDefaultButton({ addressId }: { addressId: string }) {
|
|
199
|
+
const [pending, setPending] = useState(false)
|
|
200
|
+
const [error, setError] = useState<string | null>(null)
|
|
201
|
+
|
|
202
|
+
async function handleDefault() {
|
|
203
|
+
setPending(true)
|
|
204
|
+
setError(null)
|
|
205
|
+
try {
|
|
206
|
+
const result = await setDefaultAddress(addressId)
|
|
207
|
+
if (!result?.success) {
|
|
208
|
+
setError(result?.error || "Failed to set default address")
|
|
209
|
+
setPending(false)
|
|
210
|
+
return
|
|
211
|
+
}
|
|
212
|
+
window.location.reload()
|
|
213
|
+
} catch (err) {
|
|
214
|
+
setError(err instanceof Error ? err.message : "Failed to set default address")
|
|
215
|
+
setPending(false)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<div className="flex flex-col items-end gap-1">
|
|
221
|
+
<button
|
|
222
|
+
type="button"
|
|
223
|
+
onClick={handleDefault}
|
|
224
|
+
disabled={pending}
|
|
225
|
+
className="text-xs text-brand-accent hover:underline disabled:opacity-60"
|
|
226
|
+
>
|
|
227
|
+
{pending ? "Setting…" : "Make default"}
|
|
228
|
+
</button>
|
|
229
|
+
{error && <p className="text-xs text-red-600 max-w-[12rem] text-right">{error}</p>}
|
|
230
|
+
</div>
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
164
234
|
function DeleteAddressButton({ addressId }: { addressId: string }) {
|
|
165
235
|
const [pending, setPending] = useState(false)
|
|
166
236
|
|
package/src/account-profile.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import type { OtpVerificationComponent } from "./otp-component"
|
|
11
11
|
import OtpVerificationModal from "./otp-verification-modal"
|
|
12
12
|
import { acct } from "./account-theme"
|
|
13
|
+
import { isNextRedirect, safeErrorMessage } from "./is-next-redirect"
|
|
13
14
|
|
|
14
15
|
export default function AccountProfile({
|
|
15
16
|
customer,
|
|
@@ -41,9 +42,10 @@ export default function AccountProfile({
|
|
|
41
42
|
})
|
|
42
43
|
return { ok: true as const, error: null as string | null }
|
|
43
44
|
} catch (err) {
|
|
45
|
+
if (isNextRedirect(err)) throw err
|
|
44
46
|
return {
|
|
45
47
|
ok: false as const,
|
|
46
|
-
error: err
|
|
48
|
+
error: safeErrorMessage(err, "Failed to update profile"),
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
}
|
|
@@ -61,7 +63,8 @@ export default function AccountProfile({
|
|
|
61
63
|
setOtp("")
|
|
62
64
|
setOtpOpen(true)
|
|
63
65
|
} catch (err) {
|
|
64
|
-
|
|
66
|
+
if (isNextRedirect(err)) throw err
|
|
67
|
+
setOtpError(safeErrorMessage(err, "Failed to send code"))
|
|
65
68
|
} finally {
|
|
66
69
|
setOtpPending(false)
|
|
67
70
|
}
|
|
@@ -76,14 +79,15 @@ export default function AccountProfile({
|
|
|
76
79
|
otpToken: otpToken || "",
|
|
77
80
|
code: otp,
|
|
78
81
|
countryCode,
|
|
82
|
+
skipRedirect: true,
|
|
79
83
|
})
|
|
80
84
|
if (!res.success) throw new Error(res.error || "Invalid code")
|
|
81
85
|
setOtpOpen(false)
|
|
82
86
|
setMessage("Verification successful.")
|
|
83
87
|
window.location.reload()
|
|
84
88
|
} catch (err) {
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
if (isNextRedirect(err)) throw err
|
|
90
|
+
setOtpError(safeErrorMessage(err, "Verification failed"))
|
|
87
91
|
setOtpPending(false)
|
|
88
92
|
}
|
|
89
93
|
}
|
package/src/auth-server.ts
CHANGED
|
@@ -203,6 +203,8 @@ export async function verifyRegistrationOtp(input: {
|
|
|
203
203
|
otpToken: string
|
|
204
204
|
code: string
|
|
205
205
|
countryCode: string
|
|
206
|
+
/** When true, do not redirect after login (account profile verify flow). */
|
|
207
|
+
skipRedirect?: boolean
|
|
206
208
|
}) {
|
|
207
209
|
const response = await fetch(`${getBaseUrl()}/store/customers/otp/verify`, {
|
|
208
210
|
method: "POST",
|
|
@@ -239,7 +241,9 @@ export async function verifyRegistrationOtp(input: {
|
|
|
239
241
|
}
|
|
240
242
|
const customerCacheTag = await getCacheTag("customers")
|
|
241
243
|
revalidateTag(customerCacheTag)
|
|
242
|
-
|
|
244
|
+
if (!input.skipRedirect) {
|
|
245
|
+
redirect(`/${input.countryCode || "in"}`)
|
|
246
|
+
}
|
|
243
247
|
}
|
|
244
248
|
|
|
245
249
|
return {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
import { isNextRedirect, safeErrorMessage } from "./is-next-redirect"
|
|
3
4
|
import { useState } from "react"
|
|
4
5
|
import { checkEmailRegistered, requestPasswordReset } from "./auth-server"
|
|
5
6
|
import { auth } from "./account-theme"
|
|
@@ -36,7 +37,8 @@ export default function ForgotPasswordForm({ onBack }: { onBack: () => void }) {
|
|
|
36
37
|
setSuccess(true)
|
|
37
38
|
setMessage(result.message || "If an account exists, you will receive a reset link shortly.")
|
|
38
39
|
} catch (err) {
|
|
39
|
-
|
|
40
|
+
if (isNextRedirect(err)) throw err
|
|
41
|
+
setError(safeErrorMessage(err, "Something went wrong"))
|
|
40
42
|
} finally {
|
|
41
43
|
setPending(false)
|
|
42
44
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
import { isNextRedirect, safeErrorMessage } from "./is-next-redirect"
|
|
3
4
|
import { useEffect, useRef, useState } from "react"
|
|
4
5
|
import { sendOTP, verifyOTP } from "./auth-server"
|
|
5
6
|
import OtpVerificationModal from "./otp-verification-modal"
|
|
@@ -61,7 +62,8 @@ export default function GuestOrderModal({
|
|
|
61
62
|
setOtp("")
|
|
62
63
|
setStep("otp")
|
|
63
64
|
} catch (err) {
|
|
64
|
-
|
|
65
|
+
if (isNextRedirect(err)) throw err
|
|
66
|
+
setError(safeErrorMessage(err, "Failed to send code"))
|
|
65
67
|
setStep("email")
|
|
66
68
|
} finally {
|
|
67
69
|
setPending(false)
|
|
@@ -84,7 +86,8 @@ export default function GuestOrderModal({
|
|
|
84
86
|
window.location.href = `/${countryCode}/account/guest-orders`
|
|
85
87
|
}, 900)
|
|
86
88
|
} catch (err) {
|
|
87
|
-
|
|
89
|
+
if (isNextRedirect(err)) throw err
|
|
90
|
+
setError(safeErrorMessage(err, "Verification failed"))
|
|
88
91
|
setPending(false)
|
|
89
92
|
}
|
|
90
93
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Next.js redirect/notFound detection for segment-login-template.
|
|
3
|
+
* Keep in sync with @pradip1995/segment-primitives/is-next-redirect.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const CONTROL_FLOW_RE = /NEXT_REDIRECT|NEXT_REDIRECTION|NEXT_NOT_FOUND|NEXT_HTTP_ERROR_FALLBACK/i
|
|
7
|
+
|
|
8
|
+
function textLooksLikeControlFlow(value: string): boolean {
|
|
9
|
+
return CONTROL_FLOW_RE.test(value)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function isNextRedirect(err: unknown): boolean {
|
|
13
|
+
if (err == null) return false
|
|
14
|
+
|
|
15
|
+
if (typeof err === "string") {
|
|
16
|
+
return textLooksLikeControlFlow(err)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (typeof err !== "object") {
|
|
20
|
+
return textLooksLikeControlFlow(String(err))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const digest =
|
|
24
|
+
"digest" in err ? String((err as { digest?: unknown }).digest ?? "") : ""
|
|
25
|
+
if (textLooksLikeControlFlow(digest)) {
|
|
26
|
+
return true
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const message =
|
|
30
|
+
err instanceof Error
|
|
31
|
+
? err.message
|
|
32
|
+
: "message" in err
|
|
33
|
+
? String((err as { message?: unknown }).message ?? "")
|
|
34
|
+
: ""
|
|
35
|
+
|
|
36
|
+
if (textLooksLikeControlFlow(message)) {
|
|
37
|
+
return true
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
return textLooksLikeControlFlow(String(err))
|
|
42
|
+
} catch {
|
|
43
|
+
return false
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function safeErrorMessage(err: unknown, fallback: string): string {
|
|
48
|
+
if (isNextRedirect(err)) return fallback
|
|
49
|
+
if (err instanceof Error) {
|
|
50
|
+
const msg = err.message?.trim()
|
|
51
|
+
if (!msg || textLooksLikeControlFlow(msg)) return fallback
|
|
52
|
+
return msg
|
|
53
|
+
}
|
|
54
|
+
if (typeof err === "string") {
|
|
55
|
+
const msg = err.trim()
|
|
56
|
+
if (!msg || textLooksLikeControlFlow(msg)) return fallback
|
|
57
|
+
return msg
|
|
58
|
+
}
|
|
59
|
+
return fallback
|
|
60
|
+
}
|
package/src/login-form.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
import { isNextRedirect, safeErrorMessage } from "./is-next-redirect"
|
|
3
4
|
import { useActionState, useState } from "react"
|
|
4
5
|
import { login } from "@pradip1995/commerce-core/client/actions/customer"
|
|
5
6
|
import { sendAuthOtp, verifyAuthOtpAndLogin } from "./auth-server"
|
|
@@ -216,7 +217,8 @@ function OtpLoginForm({
|
|
|
216
217
|
setOtp("")
|
|
217
218
|
setShowOtpModal(true)
|
|
218
219
|
} catch (err) {
|
|
219
|
-
|
|
220
|
+
if (isNextRedirect(err)) throw err
|
|
221
|
+
setError(safeErrorMessage(err, "Failed to send code"))
|
|
220
222
|
} finally {
|
|
221
223
|
setPending(false)
|
|
222
224
|
}
|
|
@@ -240,7 +242,7 @@ function OtpLoginForm({
|
|
|
240
242
|
setOtpToken(res.token ?? null)
|
|
241
243
|
setOtp("")
|
|
242
244
|
} catch (err) {
|
|
243
|
-
setError(err
|
|
245
|
+
setError(safeErrorMessage(err, "Failed to resend code"))
|
|
244
246
|
} finally {
|
|
245
247
|
setPending(false)
|
|
246
248
|
}
|
|
@@ -269,7 +271,7 @@ function OtpLoginForm({
|
|
|
269
271
|
}
|
|
270
272
|
} catch (err) {
|
|
271
273
|
if (isNextRedirect(err)) throw err
|
|
272
|
-
setError(err
|
|
274
|
+
setError(safeErrorMessage(err, "Verification failed"))
|
|
273
275
|
setPending(false)
|
|
274
276
|
}
|
|
275
277
|
}
|
|
@@ -437,21 +439,6 @@ function Chip({
|
|
|
437
439
|
)
|
|
438
440
|
}
|
|
439
441
|
|
|
440
|
-
function isNextRedirect(err: unknown) {
|
|
441
|
-
if (!err || typeof err !== "object") return false
|
|
442
|
-
const digest =
|
|
443
|
-
"digest" in err ? String((err as { digest?: unknown }).digest ?? "") : ""
|
|
444
|
-
if (digest.includes("NEXT_REDIRECT") || digest.includes("NEXT_NOT_FOUND")) {
|
|
445
|
-
return true
|
|
446
|
-
}
|
|
447
|
-
const message =
|
|
448
|
-
err instanceof Error
|
|
449
|
-
? err.message
|
|
450
|
-
: "message" in err
|
|
451
|
-
? String((err as { message?: unknown }).message ?? "")
|
|
452
|
-
: ""
|
|
453
|
-
return message === "NEXT_REDIRECT" || message.includes("NEXT_REDIRECT")
|
|
454
|
-
}
|
|
455
442
|
|
|
456
443
|
function GuestPackageIcon() {
|
|
457
444
|
return (
|
package/src/otp-unified-form.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
import { isNextRedirect, safeErrorMessage } from "./is-next-redirect"
|
|
3
4
|
import { useEffect, useState } from "react"
|
|
4
5
|
import { SplitPhoneInput } from "@pradip1995/commerce-core/components/split-phone-input"
|
|
5
6
|
import {
|
|
@@ -80,8 +81,8 @@ export default function OtpUnifiedForm({
|
|
|
80
81
|
setOtp("")
|
|
81
82
|
setResendIn(RESEND_COOLDOWN_SEC)
|
|
82
83
|
} catch (err) {
|
|
83
|
-
|
|
84
|
-
setError(
|
|
84
|
+
if (isNextRedirect(err)) throw err
|
|
85
|
+
setError(safeErrorMessage(err, "Failed to send code"))
|
|
85
86
|
if (!options?.resend) {
|
|
86
87
|
setStep("identifier")
|
|
87
88
|
}
|
|
@@ -112,7 +113,7 @@ export default function OtpUnifiedForm({
|
|
|
112
113
|
}
|
|
113
114
|
} catch (err) {
|
|
114
115
|
if (isNextRedirect(err)) throw err
|
|
115
|
-
setError(err
|
|
116
|
+
setError(safeErrorMessage(err, "Verification failed"))
|
|
116
117
|
setVerifying(false)
|
|
117
118
|
}
|
|
118
119
|
}
|
|
@@ -330,18 +331,3 @@ function ModeButton({
|
|
|
330
331
|
)
|
|
331
332
|
}
|
|
332
333
|
|
|
333
|
-
function isNextRedirect(err: unknown) {
|
|
334
|
-
if (!err || typeof err !== "object") return false
|
|
335
|
-
const digest =
|
|
336
|
-
"digest" in err ? String((err as { digest?: unknown }).digest ?? "") : ""
|
|
337
|
-
if (digest.includes("NEXT_REDIRECT") || digest.includes("NEXT_NOT_FOUND")) {
|
|
338
|
-
return true
|
|
339
|
-
}
|
|
340
|
-
const message =
|
|
341
|
-
err instanceof Error
|
|
342
|
-
? err.message
|
|
343
|
-
: "message" in err
|
|
344
|
-
? String((err as { message?: unknown }).message ?? "")
|
|
345
|
-
: ""
|
|
346
|
-
return message === "NEXT_REDIRECT" || message.includes("NEXT_REDIRECT")
|
|
347
|
-
}
|
package/src/register-form.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
import { isNextRedirect, safeErrorMessage } from "./is-next-redirect"
|
|
3
4
|
import { useState } from "react"
|
|
4
5
|
import {
|
|
5
6
|
registerCustomer,
|
|
@@ -87,7 +88,8 @@ export default function RegisterForm({
|
|
|
87
88
|
setStep("otp")
|
|
88
89
|
setShowOtpModal(true)
|
|
89
90
|
} catch (err) {
|
|
90
|
-
|
|
91
|
+
if (isNextRedirect(err)) throw err
|
|
92
|
+
setError(safeErrorMessage(err, "Registration failed"))
|
|
91
93
|
} finally {
|
|
92
94
|
setPending(false)
|
|
93
95
|
}
|
|
@@ -117,7 +119,7 @@ export default function RegisterForm({
|
|
|
117
119
|
}, 2000)
|
|
118
120
|
} catch (err) {
|
|
119
121
|
if (isNextRedirect(err)) throw err
|
|
120
|
-
setError(err
|
|
122
|
+
setError(safeErrorMessage(err, "Verification failed"))
|
|
121
123
|
} finally {
|
|
122
124
|
setPending(false)
|
|
123
125
|
}
|
|
@@ -136,7 +138,8 @@ export default function RegisterForm({
|
|
|
136
138
|
setOtpToken(result.token ?? null)
|
|
137
139
|
setOtp("")
|
|
138
140
|
} catch (err) {
|
|
139
|
-
|
|
141
|
+
if (isNextRedirect(err)) throw err
|
|
142
|
+
setError(safeErrorMessage(err, "Failed to resend code"))
|
|
140
143
|
} finally {
|
|
141
144
|
setPending(false)
|
|
142
145
|
}
|
|
@@ -296,21 +299,6 @@ export default function RegisterForm({
|
|
|
296
299
|
)
|
|
297
300
|
}
|
|
298
301
|
|
|
299
|
-
function isNextRedirect(err: unknown) {
|
|
300
|
-
if (!err || typeof err !== "object") return false
|
|
301
|
-
const digest =
|
|
302
|
-
"digest" in err ? String((err as { digest?: unknown }).digest ?? "") : ""
|
|
303
|
-
if (digest.includes("NEXT_REDIRECT") || digest.includes("NEXT_NOT_FOUND")) {
|
|
304
|
-
return true
|
|
305
|
-
}
|
|
306
|
-
const message =
|
|
307
|
-
err instanceof Error
|
|
308
|
-
? err.message
|
|
309
|
-
: "message" in err
|
|
310
|
-
? String((err as { message?: unknown }).message ?? "")
|
|
311
|
-
: ""
|
|
312
|
-
return message === "NEXT_REDIRECT" || message.includes("NEXT_REDIRECT")
|
|
313
|
-
}
|
|
314
302
|
|
|
315
303
|
function VerificationToggle({
|
|
316
304
|
active,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
import { isNextRedirect, safeErrorMessage } from "./is-next-redirect"
|
|
3
4
|
import { useState } from "react"
|
|
4
5
|
import { useSearchParams } from "next/navigation"
|
|
5
6
|
import { completePasswordResetAction } from "./auth-server"
|
|
@@ -49,7 +50,7 @@ export default function ResetPasswordForm({ countryCode }: { countryCode: string
|
|
|
49
50
|
}
|
|
50
51
|
} catch (err) {
|
|
51
52
|
if (isNextRedirect(err)) throw err
|
|
52
|
-
setError(err
|
|
53
|
+
setError(safeErrorMessage(err, "Failed to reset password"))
|
|
53
54
|
setPending(false)
|
|
54
55
|
}
|
|
55
56
|
}
|
|
@@ -100,18 +101,3 @@ export default function ResetPasswordForm({ countryCode }: { countryCode: string
|
|
|
100
101
|
)
|
|
101
102
|
}
|
|
102
103
|
|
|
103
|
-
function isNextRedirect(err: unknown) {
|
|
104
|
-
if (!err || typeof err !== "object") return false
|
|
105
|
-
const digest =
|
|
106
|
-
"digest" in err ? String((err as { digest?: unknown }).digest ?? "") : ""
|
|
107
|
-
if (digest.includes("NEXT_REDIRECT") || digest.includes("NEXT_NOT_FOUND")) {
|
|
108
|
-
return true
|
|
109
|
-
}
|
|
110
|
-
const message =
|
|
111
|
-
err instanceof Error
|
|
112
|
-
? err.message
|
|
113
|
-
: "message" in err
|
|
114
|
-
? String((err as { message?: unknown }).message ?? "")
|
|
115
|
-
: ""
|
|
116
|
-
return message === "NEXT_REDIRECT" || message.includes("NEXT_REDIRECT")
|
|
117
|
-
}
|