@pradip1995/segment-login-template 0.5.9 → 0.5.11
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 +6 -6
- package/src/account-orders.tsx +75 -32
- package/src/account-profile-logic.ts +6 -2
- package/src/auth-server.ts +32 -11
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.11",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -22,10 +22,6 @@
|
|
|
22
22
|
"./google-auth-section": "./src/google-auth-section.tsx",
|
|
23
23
|
"./otp-input": "./src/otp-input.tsx"
|
|
24
24
|
},
|
|
25
|
-
"scripts": {
|
|
26
|
-
"typecheck": "tsc --noEmit",
|
|
27
|
-
"lint": "tsc --noEmit"
|
|
28
|
-
},
|
|
29
25
|
"peerDependencies": {
|
|
30
26
|
"@pradip1995/commerce-auth": "^4.0.0",
|
|
31
27
|
"@pradip1995/commerce-core": "^4.0.0",
|
|
@@ -45,5 +41,9 @@
|
|
|
45
41
|
"@types/react": "^19",
|
|
46
42
|
"react": "19.0.3",
|
|
47
43
|
"typescript": "^5.7.2"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"lint": "tsc --noEmit"
|
|
48
48
|
}
|
|
49
|
-
}
|
|
49
|
+
}
|
package/src/account-orders.tsx
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import { useMemo, useState } from "react"
|
|
3
|
+
import { useMemo, useState, type MouseEvent } from "react"
|
|
4
|
+
import { usePathname, useRouter } from "next/navigation"
|
|
4
5
|
import type { HttpTypes } from "@medusajs/types"
|
|
6
|
+
import { addToCart } from "@pradip1995/commerce-core/client/actions/cart"
|
|
5
7
|
import LocalizedLink from "@pradip1995/segment-primitives/localized-link"
|
|
6
8
|
import { formatPrice } from "@pradip1995/segment-primitives/format-price"
|
|
7
9
|
import { acct } from "./account-theme"
|
|
8
10
|
|
|
9
|
-
function
|
|
10
|
-
const
|
|
11
|
-
|
|
11
|
+
function isCancelled(order: HttpTypes.StoreOrder) {
|
|
12
|
+
const status = (order.status || "").toLowerCase()
|
|
13
|
+
return status === "canceled" || status === "cancelled"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function canReorder(order: HttpTypes.StoreOrder) {
|
|
17
|
+
if (isCancelled(order)) return false
|
|
18
|
+
const fulfillment = (order.fulfillment_status || "").toLowerCase()
|
|
19
|
+
return ["delivered", "partially_delivered"].includes(fulfillment)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function statusStyle(order: HttpTypes.StoreOrder) {
|
|
23
|
+
if (isCancelled(order)) {
|
|
12
24
|
return "bg-[#FFF1F2] text-[#BE123C] border-[#BE123C]/20"
|
|
13
25
|
}
|
|
26
|
+
const s = (order.fulfillment_status || order.status || "").toLowerCase()
|
|
14
27
|
if (s === "delivered" || s === "complete" || s === "completed") {
|
|
15
28
|
return "bg-[#E6F4F0] text-[#008A5D] border-[#008A5D]/20"
|
|
16
29
|
}
|
|
@@ -23,16 +36,27 @@ function statusStyle(status?: string, fulfillment?: string) {
|
|
|
23
36
|
return "bg-surface-muted text-muted border-cart-border"
|
|
24
37
|
}
|
|
25
38
|
|
|
39
|
+
function statusLabel(order: HttpTypes.StoreOrder) {
|
|
40
|
+
if (isCancelled(order)) return "Cancelled"
|
|
41
|
+
return (order.fulfillment_status || order.status || "").replace(/_/g, " ")
|
|
42
|
+
}
|
|
43
|
+
|
|
26
44
|
export default function AccountOrders({
|
|
27
45
|
orders,
|
|
28
46
|
}: {
|
|
29
47
|
orders?: HttpTypes.StoreOrder[] | { orders?: HttpTypes.StoreOrder[] } | null
|
|
30
48
|
}) {
|
|
31
49
|
const [query, setQuery] = useState("")
|
|
50
|
+
const [reorderingId, setReorderingId] = useState<string | null>(null)
|
|
51
|
+
const router = useRouter()
|
|
52
|
+
const pathname = usePathname() || ""
|
|
53
|
+
const countryCode = pathname.split("/").filter(Boolean)[0] || "in"
|
|
32
54
|
|
|
33
55
|
const safeOrders: HttpTypes.StoreOrder[] = useMemo(() => {
|
|
34
56
|
if (Array.isArray(orders)) return orders
|
|
35
|
-
if (Array.isArray((orders as
|
|
57
|
+
if (Array.isArray((orders as { orders?: HttpTypes.StoreOrder[] })?.orders)) {
|
|
58
|
+
return (orders as { orders: HttpTypes.StoreOrder[] }).orders
|
|
59
|
+
}
|
|
36
60
|
return []
|
|
37
61
|
}, [orders])
|
|
38
62
|
|
|
@@ -41,16 +65,31 @@ export default function AccountOrders({
|
|
|
41
65
|
if (!q) return safeOrders
|
|
42
66
|
return safeOrders.filter((order) => {
|
|
43
67
|
const id = String(order.display_id ?? order.id)
|
|
44
|
-
const status =
|
|
45
|
-
|
|
46
|
-
return (
|
|
47
|
-
id.includes(q) ||
|
|
48
|
-
status.toLowerCase().includes(q) ||
|
|
49
|
-
fulfillment.toLowerCase().includes(q)
|
|
50
|
-
)
|
|
68
|
+
const status = statusLabel(order)
|
|
69
|
+
return id.includes(q) || status.toLowerCase().includes(q)
|
|
51
70
|
})
|
|
52
71
|
}, [safeOrders, query])
|
|
53
72
|
|
|
73
|
+
async function handleReorder(event: MouseEvent, order: HttpTypes.StoreOrder) {
|
|
74
|
+
event.preventDefault()
|
|
75
|
+
event.stopPropagation()
|
|
76
|
+
if (!canReorder(order) || reorderingId) return
|
|
77
|
+
setReorderingId(order.id)
|
|
78
|
+
try {
|
|
79
|
+
for (const item of order.items || []) {
|
|
80
|
+
if (!item.variant_id) continue
|
|
81
|
+
await addToCart({
|
|
82
|
+
variantId: item.variant_id,
|
|
83
|
+
quantity: item.quantity || 1,
|
|
84
|
+
countryCode,
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
router.push(`/${countryCode}/cart`)
|
|
88
|
+
} catch {
|
|
89
|
+
setReorderingId(null)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
54
93
|
return (
|
|
55
94
|
<div className="space-y-6">
|
|
56
95
|
<div className="pb-6 border-b border-cart-border">
|
|
@@ -84,28 +123,22 @@ export default function AccountOrders({
|
|
|
84
123
|
) : (
|
|
85
124
|
<ul className="space-y-4">
|
|
86
125
|
{filtered.map((order) => {
|
|
87
|
-
const label = (
|
|
88
|
-
|
|
89
|
-
order.status ||
|
|
90
|
-
""
|
|
91
|
-
).replace(/_/g, " ")
|
|
126
|
+
const label = statusLabel(order)
|
|
127
|
+
const showReorder = canReorder(order)
|
|
92
128
|
return (
|
|
93
129
|
<li key={order.id}>
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
className={`${acct.card} p-5 flex flex-wrap items-center justify-between gap-4 hover:border-brand-accent transition-colors block`}
|
|
130
|
+
<div
|
|
131
|
+
className={`${acct.card} p-5 flex flex-wrap items-center justify-between gap-4`}
|
|
97
132
|
>
|
|
98
|
-
<
|
|
133
|
+
<LocalizedLink
|
|
134
|
+
href={`/orders/${order.id}`}
|
|
135
|
+
className="space-y-2 min-w-0 flex-1 hover:opacity-90 transition-opacity"
|
|
136
|
+
>
|
|
99
137
|
<div className="flex flex-wrap items-center gap-2">
|
|
100
138
|
<p className={`font-bold ${acct.heading}`}>
|
|
101
139
|
Order #{order.display_id}
|
|
102
140
|
</p>
|
|
103
|
-
<span
|
|
104
|
-
className={`${acct.badge} capitalize ${statusStyle(
|
|
105
|
-
order.status,
|
|
106
|
-
order.fulfillment_status
|
|
107
|
-
)}`}
|
|
108
|
-
>
|
|
141
|
+
<span className={`${acct.badge} capitalize ${statusStyle(order)}`}>
|
|
109
142
|
{label}
|
|
110
143
|
</span>
|
|
111
144
|
</div>
|
|
@@ -118,11 +151,21 @@ export default function AccountOrders({
|
|
|
118
151
|
{order.items?.length ?? 0} item
|
|
119
152
|
{(order.items?.length ?? 0) === 1 ? "" : "s"}
|
|
120
153
|
</p>
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
</
|
|
125
|
-
|
|
154
|
+
<p className={`text-base font-bold ${acct.accent}`}>
|
|
155
|
+
{formatPrice(order.total, order.currency_code)}
|
|
156
|
+
</p>
|
|
157
|
+
</LocalizedLink>
|
|
158
|
+
{showReorder ? (
|
|
159
|
+
<button
|
|
160
|
+
type="button"
|
|
161
|
+
className={acct.btnPrimary}
|
|
162
|
+
disabled={reorderingId === order.id}
|
|
163
|
+
onClick={(event) => handleReorder(event, order)}
|
|
164
|
+
>
|
|
165
|
+
{reorderingId === order.id ? "Adding…" : "Reorder"}
|
|
166
|
+
</button>
|
|
167
|
+
) : null}
|
|
168
|
+
</div>
|
|
126
169
|
</li>
|
|
127
170
|
)
|
|
128
171
|
})}
|
|
@@ -130,7 +130,9 @@ export function useAccountProfileLogic(
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
const res = await sendRegistrationOtp(customer.id, type)
|
|
133
|
-
if (!res
|
|
133
|
+
if (!res?.success) {
|
|
134
|
+
throw new Error(res?.error || "Failed to send code")
|
|
135
|
+
}
|
|
134
136
|
setOtpToken(res.token ?? null)
|
|
135
137
|
setOtp("")
|
|
136
138
|
setOtpOpen(true)
|
|
@@ -157,7 +159,9 @@ export function useAccountProfileLogic(
|
|
|
157
159
|
countryCode,
|
|
158
160
|
skipRedirect: true,
|
|
159
161
|
})
|
|
160
|
-
if (!res
|
|
162
|
+
if (!res?.success) {
|
|
163
|
+
throw new Error(res?.error || "Invalid code")
|
|
164
|
+
}
|
|
161
165
|
setOtpOpen(false)
|
|
162
166
|
if (otpType === "phone_verification") {
|
|
163
167
|
setPhoneVerified(true)
|
package/src/auth-server.ts
CHANGED
|
@@ -258,21 +258,42 @@ export async function sendRegistrationOtp(
|
|
|
258
258
|
customerId: string,
|
|
259
259
|
type: "email_verification" | "phone_verification"
|
|
260
260
|
) {
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
261
|
+
const response = await fetch(`${getBaseUrl()}/store/customers/otp/send`, {
|
|
262
|
+
method: "POST",
|
|
263
|
+
headers: getHeaders(),
|
|
264
|
+
body: JSON.stringify({
|
|
265
|
+
customer_id: customerId,
|
|
266
|
+
type,
|
|
267
|
+
}),
|
|
268
|
+
cache: "no-store",
|
|
269
|
+
})
|
|
265
270
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
success: false as const,
|
|
270
|
-
error:
|
|
271
|
-
"Verification email is not configured on the backend. Rebuild and restart the Medusa server with customer-registration OTP settings.",
|
|
271
|
+
if (!response.ok) {
|
|
272
|
+
const err = (await response.json().catch(() => ({}))) as {
|
|
273
|
+
message?: string
|
|
272
274
|
}
|
|
275
|
+
const message = err.message || "Failed to send verification code"
|
|
276
|
+
if (message.includes("Channel configuration not found")) {
|
|
277
|
+
return {
|
|
278
|
+
success: false as const,
|
|
279
|
+
error:
|
|
280
|
+
"Verification is not configured on the backend. Rebuild and restart the Medusa server with customer-registration OTP settings.",
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return { success: false as const, error: message }
|
|
273
284
|
}
|
|
274
285
|
|
|
275
|
-
|
|
286
|
+
const data = (await response.json()) as {
|
|
287
|
+
token?: string
|
|
288
|
+
expires_at?: string
|
|
289
|
+
message?: string
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return {
|
|
293
|
+
success: true as const,
|
|
294
|
+
token: data.token,
|
|
295
|
+
message: data.message || "OTP sent successfully",
|
|
296
|
+
}
|
|
276
297
|
}
|
|
277
298
|
|
|
278
299
|
export async function initiateGoogleAuth(countryCode?: string) {
|