feat: implement user profile, order history, and address book with checkout integration
This commit is contained in:
1 parent
bae945b9d4
commit
0c3c450e1f
9 files changed
+1109
-32
No files matched your search
@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import Navbar from '../components/Navbar'
|
||||
import Footer from '../components/Footer'
|
||||
import { API_BASE, formatPrice, type Category } from '../types'
|
||||
import { API_BASE, formatPrice, type Category, type CustomerAddress } from '../types'
|
||||
import { useCartStore } from '../store/cartStore'
|
||||
import { useAuthStore } from '../store/authStore'
|
||||
import { Loader2 } from 'lucide-react'
|
||||
@@ -36,6 +36,7 @@ export default function CheckoutPage() {
|
||||
phone: '',
|
||||
address: ''
|
||||
})
|
||||
const [savedAddresses, setSavedAddresses] = useState<CustomerAddress[]>([])
|
||||
|
||||
// Prefill form with LINE customer data and last used address
|
||||
useEffect(() => {
|
||||
@@ -47,20 +48,42 @@ export default function CheckoutPage() {
|
||||
phone: prev.phone || customer.phone || ''
|
||||
}))
|
||||
|
||||
// Fetch latest order to pre-fill address acting as an automatic Address Book
|
||||
fetch(`${API_BASE}/orders/customer/${customer.id}`)
|
||||
// Fetch saved addresses first
|
||||
fetch(`${API_BASE}/profile/${customer.id}/addresses`)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (Array.isArray(data) && data.length > 0) {
|
||||
const lastOrder = data[0];
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
name: prev.name || lastOrder.customerName || '',
|
||||
phone: prev.phone || lastOrder.customerPhone || '',
|
||||
email: prev.email || lastOrder.customerEmail || '',
|
||||
address: prev.address || lastOrder.shippingAddress || ''
|
||||
}))
|
||||
if (Array.isArray(data)) {
|
||||
setSavedAddresses(data)
|
||||
// If default address exists, pre-fill with it immediately
|
||||
const defAddr = data.find(a => a.isDefault)
|
||||
if (defAddr) {
|
||||
const formatted = `${defAddr.addressLine} ต.${defAddr.subdistrict} อ.${defAddr.district} จ.${defAddr.province} ${defAddr.zipcode}`
|
||||
setFormData({
|
||||
name: defAddr.recipientName,
|
||||
phone: defAddr.phone,
|
||||
email: customer.email || '',
|
||||
address: formatted
|
||||
})
|
||||
return // Skip order fallback
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Fetch latest order to pre-fill address
|
||||
fetch(`${API_BASE}/orders/customer/${customer.id}`)
|
||||
.then(res => res.json())
|
||||
.then(ordersData => {
|
||||
if (Array.isArray(ordersData) && ordersData.length > 0) {
|
||||
const lastOrder = ordersData[0];
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
name: prev.name || lastOrder.customerName || '',
|
||||
phone: prev.phone || lastOrder.customerPhone || '',
|
||||
email: prev.email || lastOrder.customerEmail || '',
|
||||
address: prev.address || lastOrder.shippingAddress || ''
|
||||
}))
|
||||
}
|
||||
})
|
||||
.catch(console.error)
|
||||
})
|
||||
.catch(console.error)
|
||||
|
||||
@@ -351,6 +374,31 @@ export default function CheckoutPage() {
|
||||
className="w-full bg-spa-light border border-spa-stone/20 rounded-lg p-3 text-pop-black focus:border-spa-forest focus:ring-1 focus:ring-spa-forest outline-none transition-all resize-none placeholder:text-spa-stone/50"
|
||||
placeholder="123 Serenity Street..."
|
||||
/>
|
||||
{savedAddresses.length > 0 && (
|
||||
<div className="mt-2 space-y-2">
|
||||
<p className="text-[10px] uppercase font-bold tracking-widest text-spa-stone/70">เลือกดึงที่อยู่จัดส่งจากโปรไฟล์:</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{savedAddresses.map(addr => {
|
||||
const formatted = `${addr.addressLine} ต.${addr.subdistrict} อ.${addr.district} จ.${addr.province} ${addr.zipcode}`
|
||||
return (
|
||||
<button
|
||||
key={addr.id}
|
||||
type="button"
|
||||
onClick={() => setFormData({
|
||||
name: addr.recipientName,
|
||||
phone: addr.phone,
|
||||
email: formData.email,
|
||||
address: formatted
|
||||
})}
|
||||
className="px-3 py-1.5 bg-spa-sage/10 hover:bg-spa-sage/20 border border-spa-stone/15 text-[10px] font-bold rounded-lg text-spa-forest transition-all text-left max-w-full truncate"
|
||||
>
|
||||
{addr.recipientName} ({addr.province}) {addr.isDefault && '⭐️'}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user