'use client'; import React, { useState } from 'react'; import { useCartStore, redirectToCheckout } from '@/hooks/use-shopify-cart'; import { Button } from '@/components/ui/button'; import { Loader } from '@/components/ui/loader'; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetBody, AnimatePresence, } from '@/components/ui/sheet'; import { RiCloseLine, RiImageLine, RiSubtractLine, RiAddLine, } from '@remixicon/react'; import { Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, } from '@/components/ui/empty'; const CartDrawer: React.FC = () => { const isOpen = useCartStore((s) => s.isOpen); const closeCart = useCartStore((s) => s.closeCart); const loading = useCartStore((s) => s.loading); const cart = useCartStore((s) => s.cart); const removeItem = useCartStore((s) => s.removeItem); const updateItemQuantity = useCartStore((s) => s.updateItemQuantity); const applyDiscountCode = useCartStore((s) => s.applyDiscountCode); const [discountCode, setDiscountCode] = useState(''); const [discountError, setDiscountError] = useState(null); const [applyingDiscount, setApplyingDiscount] = useState(false); // The store's `loading` flag is global, so track the specific line being // changed to keep the other rows interactive. const [pendingLineId, setPendingLineId] = useState(null); const runLineAction = async (lineId: string, action: () => Promise) => { if (pendingLineId) return; try { setPendingLineId(lineId); await action(); } catch (err) { console.error('Cart line update failed:', err); } finally { setPendingLineId(null); } }; const items = cart?.lines?.edges?.map((edge) => edge.node) ?? []; const itemCount = items.reduce((sum, item) => sum + item.quantity, 0); const totalAmount = parseFloat(cart?.cost?.totalAmount?.amount ?? '0'); const checkoutUrl = cart?.checkoutUrl ?? null; const appliedDiscounts = cart?.discountCodes?.filter((discount) => discount.applicable) ?? []; const handleCheckout = () => { if (checkoutUrl) { redirectToCheckout(checkoutUrl); } }; const handleApplyDiscount = async (event: React.FormEvent) => { event.preventDefault(); const code = discountCode.trim(); if (!code || applyingDiscount) return; try { setApplyingDiscount(true); setDiscountError(null); const updatedCart = await applyDiscountCode(code); // Shopify accepts unknown codes silently, flagging them as inapplicable. const accepted = updatedCart.discountCodes?.some( (discount) => discount.applicable && discount.code.toLowerCase() === code.toLowerCase() ); if (accepted) { setDiscountCode(''); } else { setDiscountError('That code is not valid for this cart.'); } } catch { setDiscountError('Could not apply that code. Please try again.'); } finally { setApplyingDiscount(false); } }; const getItemImage = (item: (typeof items)[0]) => { return item.merchandise.image?.url; }; const getSelectedOptions = (item: (typeof items)[0]) => { return item.merchandise.selectedOptions ?? []; }; return ( !open && closeCart()} side="right" > {isOpen && ( {/* Header */}
Cart {itemCount}
{/* Cart Items */} {loading && items.length === 0 ? (
) : items.length === 0 ? ( Your cart is empty Add some products to get started! ) : (
{items.map((item) => { const image = getItemImage(item); const selectedOptions = getSelectedOptions(item); const isPending = pendingLineId === item.id; return (
{/* Product Image */}
{image ? ( {item.merchandise.product.title} ) : (
)}
{/* Product Details */}

{item.merchandise.product.title}

$ {parseFloat( item.cost?.totalAmount?.amount ?? item.merchandise.price.amount ).toFixed(2)}
{selectedOptions.length > 0 && (
{selectedOptions .map((option) => option.value) .join(' / ')}
)} {/* Quantity Controls */}
{isPending ? ( ) : ( item.quantity )}
); })}
)}
{/* Footer — discount, total, checkout */} {items.length > 0 && (
{/* Discount Code */}
{ setDiscountCode(event.target.value); setDiscountError(null); }} placeholder="Discount code" aria-label="Discount code" className="flex-1 h-10 rounded-md border border-border px-3 text-sm placeholder:text-muted-foreground focus:outline-none focus:border-foreground transition-colors" />
{discountError && (

{discountError}

)} {appliedDiscounts.length > 0 && (

Applied: {appliedDiscounts.map((d) => d.code).join(', ')}

)} {/* Estimated total */}
Estimated total ${totalAmount.toFixed(2)}

Taxes and shipping calculated at checkout.

)}
)}
); }; export default CartDrawer;