@pradip1995/segment-login-template 0.5.5 → 0.5.6
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 +2 -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.6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@pradip1995/commerce-auth": "^4.0.0",
|
|
37
37
|
"@pradip1995/commerce-core": "^4.0.0",
|
|
38
|
-
"@pradip1995/segment-primitives": "^0.4.
|
|
38
|
+
"@pradip1995/segment-primitives": "^0.4.3",
|
|
39
39
|
"@pradip1995/segment-tokens": "^0.3.7"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
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
|
-
}
|