feat(spa): add cart coupon input and checkout mobile accordion
This commit is contained in:
1 parent
769afa37fd
commit
fd3abcf487
2 files changed
+59
-7
No files matched your search
@@ -125,6 +125,10 @@ function CartDrawerFooter({ subtotal, onClose }: { subtotal: number; onClose: ()
|
||||
const [isFreeShipping, setIsFreeShipping] = React.useState<boolean>(false)
|
||||
const [couponValid, setCouponValid] = React.useState<boolean>(false)
|
||||
const [activePromos, setActivePromos] = React.useState<any[]>([])
|
||||
|
||||
const [couponInput, setCouponInput] = React.useState<string>('')
|
||||
const [couponLoading, setCouponLoading] = React.useState<boolean>(false)
|
||||
const [couponError, setCouponError] = React.useState<string>('')
|
||||
|
||||
React.useEffect(() => {
|
||||
fetch(`${API_BASE}/promotions/active`)
|
||||
@@ -164,6 +168,21 @@ function CartDrawerFooter({ subtotal, onClose }: { subtotal: number; onClose: ()
|
||||
setDiscountAmount(0)
|
||||
setIsFreeShipping(false)
|
||||
setCouponValid(false)
|
||||
setCouponError('')
|
||||
setCouponInput('')
|
||||
}
|
||||
|
||||
const handleApplyCoupon = async () => {
|
||||
if (!couponInput.trim()) return
|
||||
setCouponLoading(true)
|
||||
setCouponError('')
|
||||
|
||||
// We must validate with subtotalAfterL2, but since we don't have it defined here yet,
|
||||
// we'll calculate it inline or rely on the effect. Actually, we can just save it to localStorage and let the effect handle it.
|
||||
localStorage.setItem('homaroma_active_coupon', couponInput.toUpperCase())
|
||||
setSavedCoupon(couponInput.toUpperCase())
|
||||
setCouponInput('')
|
||||
setCouponLoading(false)
|
||||
}
|
||||
|
||||
// Calculate Level 1 Promo
|
||||
@@ -185,6 +204,26 @@ function CartDrawerFooter({ subtotal, onClose }: { subtotal: number; onClose: ()
|
||||
|
||||
return (
|
||||
<div className="p-5 border-t border-spa-stone/10 bg-spa-light space-y-4">
|
||||
|
||||
{/* Coupon Input */}
|
||||
{!savedCoupon && (
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
value={couponInput}
|
||||
onChange={e => setCouponInput(e.target.value.toUpperCase())}
|
||||
placeholder={t('cart.couponPlaceholder', 'Discount Code')}
|
||||
className="flex-1 bg-white border border-spa-stone/20 rounded-lg px-3 py-2 text-sm text-pop-black focus:border-spa-forest outline-none uppercase tracking-widest placeholder:text-spa-stone/50"
|
||||
/>
|
||||
<button
|
||||
onClick={handleApplyCoupon}
|
||||
disabled={couponLoading || !couponInput.trim()}
|
||||
className="px-4 bg-spa-stone/10 hover:bg-spa-stone/20 border border-spa-stone/10 rounded-lg text-xs font-bold uppercase tracking-widest disabled:opacity-50 transition-all text-pop-black"
|
||||
>
|
||||
{couponLoading ? '...' : t('cart.applyCoupon', 'Apply')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Totals */}
|
||||
<div className="space-y-2 text-sm text-pop-black">
|
||||
|
||||
Reference in new issue
Block a user