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 { useCartStore } from '../store/cartStore' import { useAuthStore } from '../store/authStore' import { Loader2 } from 'lucide-react' export default function CheckoutPage() { const navigate = useNavigate() const { items, getCartTotal, clearCart } = useCartStore() const { customer } = useAuthStore() const [categories, setCategories] = useState([]) const [shippingFee, setShippingFee] = useState(35) const [loading, setLoading] = useState(false) const [loadingSettings, setLoadingSettings] = useState(true) const [couponCode, setCouponCode] = useState('') const [appliedCoupon, setAppliedCoupon] = useState(null) const [discountAmount, setDiscountAmount] = useState(0) const [isFreeShipping, setIsFreeShipping] = useState(false) const [couponLoading, setCouponLoading] = useState(false) const [couponError, setCouponError] = useState('') const [formData, setFormData] = useState({ name: '', email: '', phone: '', address: '' }) // Prefill form with LINE customer data useEffect(() => { if (customer) { setFormData(prev => ({ ...prev, name: prev.name || customer.displayName || '', email: prev.email || customer.email || '', phone: prev.phone || customer.phone || '' })) } }, [customer]) // Load Settings (for dynamic shipping fee) useEffect(() => { fetch(`${API_BASE}/settings`) .then(res => res.json()) .then(data => { if (data.shippingFee !== undefined) setShippingFee(data.shippingFee) }) .catch(err => console.error("Could not load settings:", err)) .finally(() => setLoadingSettings(false)) fetch(`${API_BASE}/categories`) .then(res => res.json()) .then(setCategories) // Check if there's an active coupon saved in localStorage const savedCoupon = localStorage.getItem('homaroma_active_coupon') if (savedCoupon) { setCouponCode(savedCoupon) // We will trigger handleApplyCoupon but we need to wait for items/subtotal to be ready. // So we'll handle this in another effect or let the user click apply if needed. // Better yet, we can validate it immediately if subtotal is available. } }, []) // Kick out if cart empty useEffect(() => { if (items.length === 0) { navigate('/shop') } }, [items, navigate]) const subtotal = getCartTotal() const effectiveShippingFee = isFreeShipping ? 0 : shippingFee const total = Math.max(0, subtotal + effectiveShippingFee - discountAmount) // Auto-apply saved coupon if subtotal is ready useEffect(() => { const savedCoupon = localStorage.getItem('homaroma_active_coupon') if (savedCoupon && subtotal > 0 && !appliedCoupon && !couponError && !couponLoading) { setCouponCode(savedCoupon) // trigger fetch to validate fetch(`${API_BASE}/coupons/validate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code: savedCoupon, cartTotal: subtotal }) }) .then(r => r.json()) .then(data => { if (data.valid) { setAppliedCoupon(data.coupon.code) setDiscountAmount(data.discountAmount) setIsFreeShipping(data.isFreeShipping) } else { localStorage.removeItem('homaroma_active_coupon') // Remove invalid } }) .catch(console.error) } }, [subtotal, appliedCoupon]) // Re-validate applied coupon if subtotal changes useEffect(() => { if (appliedCoupon && subtotal > 0) { fetch(`${API_BASE}/coupons/validate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code: appliedCoupon, cartTotal: subtotal }) }) .then(r => r.json()) .then(data => { if (data.valid) { setDiscountAmount(data.discountAmount) setIsFreeShipping(data.isFreeShipping) } else { removeCoupon() setCouponError(data.error || 'Coupon is no longer valid for this cart') } }) } }, [subtotal, appliedCoupon]) const handleApplyCoupon = async () => { if (!couponCode.trim()) return setCouponLoading(true) setCouponError('') try { const res = await fetch(`${API_BASE}/coupons/validate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code: couponCode, cartTotal: subtotal }) }) const data = await res.json() if (res.ok && data.valid) { setAppliedCoupon(data.coupon.code) setDiscountAmount(data.discountAmount) setIsFreeShipping(data.isFreeShipping) } else { setCouponError(data.error || 'Invalid coupon') setAppliedCoupon(null) setDiscountAmount(0) setIsFreeShipping(false) } } catch (err) { setCouponError('Error validating coupon') } finally { setCouponLoading(false) } } const removeCoupon = () => { setAppliedCoupon(null) setCouponCode('') setDiscountAmount(0) setIsFreeShipping(false) setCouponError('') localStorage.removeItem('homaroma_active_coupon') } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setLoading(true) try { const orderData = { customerId: customer ? customer.id : null, customerName: formData.name, customerEmail: formData.email, customerPhone: formData.phone, shippingAddress: formData.address, totalAmount: total, shippingFee: effectiveShippingFee, couponCode: appliedCoupon || undefined, discountAmount: discountAmount || undefined, items: items.map(item => ({ productId: item.productId, variantId: item.variantId, quantity: item.quantity, priceAtPurchase: item.price, productName: item.productName, variantSize: item.variantSize, productImage: item.productImage })) } const res = await fetch(`${API_BASE}/orders`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(orderData) }) const responseData = await res.json() if (res.ok) { clearCart() const existingStr = localStorage.getItem('homaroma_local_orders') const existing = existingStr ? JSON.parse(existingStr) : [] if (!existing.includes(responseData.id)) { localStorage.setItem('homaroma_local_orders', JSON.stringify([responseData.id, ...existing])) } navigate(`/order/${responseData.id}`) } else { alert(responseData.error || 'Failed to place order') } } catch (err) { console.error(err) alert('An error occurred. Please try again.') } finally { setLoading(false) } } return (

Checkout

{/* Form Section */}

Shipping Information

setFormData({ ...formData, name: e.target.value })} className="w-full bg-night-950 border border-white/10 rounded-lg p-3 text-white focus:border-cyan-glow focus:ring-1 focus:ring-cyan-glow outline-none transition-all" placeholder="Jane Doe" />
setFormData({ ...formData, phone: e.target.value })} className="w-full bg-night-950 border border-white/10 rounded-lg p-3 text-white focus:border-cyan-glow focus:ring-1 focus:ring-cyan-glow outline-none transition-all" placeholder="0812345678" />
setFormData({ ...formData, email: e.target.value })} className="w-full bg-night-950 border border-white/10 rounded-lg p-3 text-white focus:border-cyan-glow focus:ring-1 focus:ring-cyan-glow outline-none transition-all" placeholder="jane@example.com" />