UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

482 lines (479 loc) 20.7 kB
'use client'; import { jsx, jsxs } from 'react/jsx-runtime'; import { useState, useCallback } from 'react'; import { GlassCore } from '../../primitives/GlassCore.js'; import '../../primitives/glass/GlassAdvanced.js'; import '../../primitives/OptimizedGlassCore.js'; import '../../primitives/glass/OptimizedGlassAdvanced.js'; import '../../primitives/MotionNative.js'; import '../../primitives/motion/MotionFramer.js'; import { cn } from '../../lib/utilsComprehensive.js'; import { useEcommerce } from './GlassEcommerceProvider.js'; const CartItemCard = ({ item, onUpdateQuantity, onRemove, onMoveToWishlist, onSaveForLater, compact = false }) => { const [isUpdating, setIsUpdating] = useState(false); const [quantity, setQuantity] = useState(item.quantity); const handleQuantityChange = useCallback(async newQuantity => { if (newQuantity < 1 || newQuantity > item.product.stock) return; setIsUpdating(true); setQuantity(newQuantity); // Simulate API call delay await new Promise(resolve => setTimeout(resolve, 300)); onUpdateQuantity(item.id, newQuantity); setIsUpdating(false); }, [item.id, item.product.stock, onUpdateQuantity]); const itemTotal = item.product.price * quantity; const isOnSale = item.product.originalPrice && item.product.originalPrice > item.product.price; const savings = isOnSale ? (item.product.originalPrice - item.product.price) * quantity : 0; if (compact) { return jsxs("div", { "data-glass-component": true, className: 'glass-flex glass-items-center glass-gap-3 glass-p-3 glass-border-b glass-border-subtle last:border-b-0', children: [jsx("img", { src: item.product.thumbnail || item.product.images[0], alt: item.product.name, className: 'w-12 h-12 object-cover glass-radius' }), jsxs("div", { className: "glass-flex-1 glass-min-w-0", children: [jsx("h3", { className: 'font-medium glass-text-secondary glass-text-sm truncate', children: item.product.name }), jsxs("div", { className: 'glass-flex glass-items-center glass-gap-2 mt-1', children: [jsxs("span", { className: 'glass-text-sm font-medium glass-text-secondary', children: ["$", item.product.price.toFixed(2)] }), isOnSale && jsxs("span", { className: 'glass-text-xs glass-text-secondary line-through', children: ["$", item.product.originalPrice.toFixed(2)] }), jsxs("span", { className: "glass-text-xs glass-text-secondary", children: ["\u00D7 ", quantity] })] })] }), jsxs("div", { className: 'text-right', children: [jsxs("div", { className: 'font-medium glass-text-secondary', children: ["$", itemTotal.toFixed(2)] }), savings > 0 && jsxs("div", { className: 'glass-text-xs text-primary', children: ["Save $", savings.toFixed(2)] })] })] }); } return jsxs("div", { className: 'glass-flex glass-gap-4 glass-p-4 glass-border-b glass-border-subtle last:border-b-0', children: [jsxs("div", { className: 'relative', children: [jsx("img", { src: item.product.thumbnail || item.product.images[0], alt: item.product.name, className: 'w-20 h-20 object-cover glass-radius-lg' }), isOnSale && jsx("div", { className: 'absolute -glass-top-2 -right-2 glass-surface-red text-primary glass-text-xs glass-px-2 glass-py-1 glass-radius-full', children: "SALE" }), item.product.availability !== "in-stock" && jsx("div", { className: 'absolute inset-0 glass-surface-dark glass-opacity-50 glass-flex glass-items-center glass-justify-center glass-radius-lg', children: jsx("span", { className: 'text-primary glass-text-xs font-medium', children: item.product.availability === "out-of-stock" ? "Out of Stock" : "Pre-order" }) })] }), jsxs("div", { className: "glass-flex-1 glass-min-w-0", children: [jsxs("div", { className: "glass-flex glass-items-start glass-justify-between", children: [jsxs("div", { className: "glass-flex-1", children: [jsx("h3", { className: 'font-medium glass-text-secondary mb-1', children: item.product.name }), item.product.brand && jsxs("p", { className: 'glass-text-sm glass-text-secondary mb-1', children: ["Brand: ", item.product.brand] }), item.selectedVariants && jsx("div", { className: 'glass-flex glass-flex-wrap glass-gap-1 mb-2', children: Object.entries(item.selectedVariants).map(([key, value]) => jsxs("span", { className: 'inline-block glass-px-2 glass-py-1 glass-surface-subtle glass-text-secondary glass-text-xs glass-radius', children: [key, ": ", value] }, key)) }), jsxs("div", { className: 'glass-flex glass-items-center glass-gap-2 mb-3', children: [jsxs("span", { className: 'glass-text-lg font-semibold glass-text-secondary', children: ["$", item.product.price.toFixed(2)] }), isOnSale && jsxs("span", { className: 'glass-text-sm glass-text-secondary line-through', children: ["$", item.product.originalPrice.toFixed(2)] }), item.product.availability === "in-stock" && item.product.stock < 10 && jsxs("span", { className: 'glass-text-xs text-primary glass-surface-subtle glass-px-2 glass-py-1 glass-radius', children: ["Only ", item.product.stock, " left"] })] }), item.giftWrap && jsxs("div", { className: 'glass-flex glass-items-center glass-gap-2 mb-2', children: [jsx("span", { className: 'glass-text-sm text-primary', children: "\uD83C\uDF81 Gift wrapped" }), item.giftMessage && jsx("span", { className: "glass-text-xs glass-text-secondary", children: "with message" })] })] }), jsx("button", { onClick: () => onRemove(item.id), className: 'glass-text-secondary hover:text-primary glass-p-1 glass-focus glass-touch-target glass-contrast-guard', title: "Remove from cart", children: "\u2715" })] }), jsxs("div", { className: "glass-flex glass-items-center glass-justify-between", children: [jsxs("div", { className: "glass-flex glass-items-center glass-gap-3", children: [jsxs("div", { className: "glass-flex glass-items-center glass-border glass-border-subtle glass-radius", children: [jsx("button", { onClick: () => handleQuantityChange(quantity - 1), disabled: quantity <= 1 || isUpdating, className: 'glass-px-3 glass-py-1 hover:glass-surface-subtle disabled:opacity-50 disabled:cursor-not-allowed glass-focus glass-touch-target glass-contrast-guard', children: "\u2212" }), jsx("span", { className: 'glass-px-4 glass-py-1 glass-border-x glass-border-subtle min-w-12 text-center', children: isUpdating ? "..." : quantity }), jsx("button", { onClick: () => handleQuantityChange(quantity + 1), disabled: quantity >= item.product.stock || isUpdating, className: 'glass-px-3 glass-py-1 hover:glass-surface-subtle disabled:opacity-50 disabled:cursor-not-allowed glass-focus glass-touch-target glass-contrast-guard', children: "+" })] }), jsxs("div", { className: "glass-flex glass-items-center glass-gap-2", children: [jsx("button", { onClick: () => onSaveForLater(item.id), className: 'glass-text-xs text-primary hover:text-primary underline glass-focus glass-touch-target glass-contrast-guard', children: "Save for later" }), jsx("button", { onClick: () => onMoveToWishlist(item.id), className: 'glass-text-xs text-primary hover:text-primary underline glass-focus glass-touch-target glass-contrast-guard', children: "Move to wishlist" })] })] }), jsxs("div", { className: 'text-right', children: [jsxs("div", { className: 'font-semibold glass-text-secondary', children: ["$", itemTotal.toFixed(2)] }), savings > 0 && jsxs("div", { className: 'glass-text-sm text-primary', children: ["You save $", savings.toFixed(2)] })] })] })] })] }); }; const ShippingCalculator = ({ shippingOptions, selectedShipping, onShippingSelect, cartSubtotal }) => { return jsxs("div", { className: 'space-y-3', children: [jsx("h3", { className: 'font-medium glass-text-secondary', children: "Shipping Options" }), shippingOptions.map(option => { const isFree = option.price === 0 || option.id === "standard" && cartSubtotal >= 50; const price = isFree ? 0 : option.price; return jsxs("label", { className: cn("flex items-center justify-between p-3 border rounded-lg cursor-pointer transition-colors", selectedShipping?.id === option.id ? "border-blue-500 bg-blue-50" : "border-gray-200 hover:border-gray-300"), children: [jsxs("div", { className: "glass-flex glass-items-center glass-gap-3", children: [jsx("input", { type: "radio", name: "shipping", value: option.id, checked: selectedShipping?.id === option.id, onChange: () => onShippingSelect(option), className: 'text-primary' }), jsxs("div", { children: [jsxs("div", { className: 'font-medium glass-text-secondary', children: [option.name, isFree && jsx("span", { className: 'text-primary ml-2', children: "FREE" })] }), jsxs("div", { className: "glass-text-sm glass-text-secondary", children: [option.description, " \u2022 ", option.estimatedDays, " business days"] })] })] }), jsx("div", { className: 'font-medium glass-text-secondary', children: isFree ? "FREE" : `$${price.toFixed(2)}` })] }, option.id); })] }); }; const PromoCodeInput = ({ onApplyPromo, appliedPromo }) => { const [promoCode, setPromoCode] = useState(""); const [isApplying, setIsApplying] = useState(false); const handleApply = async () => { if (!promoCode.trim()) return; setIsApplying(true); await new Promise(resolve => setTimeout(resolve, 1000)); onApplyPromo(promoCode); setPromoCode(""); setIsApplying(false); }; return jsxs("div", { className: 'space-y-3', children: [jsx("h3", { className: 'font-medium glass-text-secondary', children: "Promo Code" }), appliedPromo ? jsxs("div", { className: "glass-flex glass-items-center glass-justify-between glass-p-3 glass-surface-subtle glass-border glass-border-green-200 glass-radius-lg", children: [jsxs("div", { children: [jsxs("div", { className: 'font-medium text-primary', children: ["Code \"", appliedPromo.code, "\" applied"] }), jsxs("div", { className: 'glass-text-sm text-primary', children: ["You save $", appliedPromo.discount.toFixed(2)] })] }), jsx("button", { className: 'text-primary hover:text-primary glass-text-sm underline', children: "Remove" })] }) : jsxs("div", { className: "glass-flex glass-gap-2", children: [jsx("input", { type: "text", placeholder: "Enter promo code", value: promoCode, onChange: e => setPromoCode(e.target.value.toUpperCase()), className: 'glass-flex-1 glass-px-3 glass-py-2 glass-border glass-border-subtle glass-radius-lg focus:outline-none focus:ring-2 focus:ring-blue-500', onKeyDown: e => e.key === "Enter" && handleApply() }), jsx("button", { onClick: handleApply, disabled: !promoCode.trim() || isApplying, className: 'glass-px-4 glass-py-2 glass-surface-blue text-primary glass-radius-lg hover:glass-surface-blue disabled:opacity-50 disabled:cursor-not-allowed glass-focus glass-touch-target glass-contrast-guard glass-focus glass-touch-target glass-contrast-guard', children: isApplying ? "..." : "Apply" })] })] }); }; const GlassSmartShoppingCart = ({ className, variant = "sidebar", showRecommendations = true, showShippingCalculator = true, showPromoCode = true, showSavedItems = false, maxItems = 20, onCheckout, onClose }) => { const { cart, updateCartItem, removeFromCart, addToWishlist, cartSubtotal, cartTax, cartShipping, cartTotal, getCartItemCount, shippingOptions, selectedShipping, setShippingOption } = useEcommerce(); const [appliedPromo, setAppliedPromo] = useState(); const [savedItems, setSavedItems] = useState([]); const handleUpdateQuantity = useCallback((itemId, quantity) => { updateCartItem(itemId, quantity); }, [updateCartItem]); const handleRemove = useCallback(itemId => { removeFromCart(itemId); }, [removeFromCart]); const handleMoveToWishlist = useCallback(itemId => { const item = cart.find(cartItem => cartItem.id === itemId); if (item) { addToWishlist(item.productId); removeFromCart(itemId); } }, [cart, addToWishlist, removeFromCart]); const handleSaveForLater = useCallback(itemId => { const item = cart.find(cartItem => cartItem.id === itemId); if (item) { setSavedItems(prev => [...prev, item]); removeFromCart(itemId); } }, [cart, removeFromCart]); const handleApplyPromo = useCallback(code => { // Mock promo code validation const validCodes = { SAVE10: 10, WELCOME20: 20, FREESHIP: cartShipping }; if (validCodes[code]) { setAppliedPromo({ code, discount: validCodes[code] }); } }, [cartShipping]); const finalTotal = cartTotal - (appliedPromo?.discount || 0); const itemCount = getCartItemCount(); if (cart.length === 0) { return jsx(GlassCore, { className: cn("p-6", className), children: jsxs("div", { className: 'text-center', children: [jsx("div", { className: 'text-6xl mb-4', children: "\uD83D\uDED2" }), jsx("h2", { className: 'glass-text-xl font-semibold glass-text-secondary mb-2', children: "Your cart is empty" }), jsx("p", { className: 'glass-text-secondary mb-6', children: "Looks like you haven't added any items to your cart yet." }), jsx("button", { onClick: onClose, className: 'glass-px-6 glass-py-3 glass-surface-blue text-primary glass-radius-lg hover:glass-surface-blue transition-colors glass-focus glass-touch-target glass-contrast-guard glass-focus glass-touch-target glass-contrast-guard', children: "Continue Shopping" })] }) }); } return jsx(GlassCore, { className: cn("overflow-hidden", className), children: jsxs("div", { className: "glass-flex glass-flex-col glass-h-full", children: [jsxs("div", { className: "glass-flex glass-items-center glass-justify-between glass-p-6 glass-border-b glass-border-subtle", children: [jsxs("div", { children: [jsx("h2", { className: 'glass-text-xl font-semibold glass-text-secondary', children: "Shopping Cart" }), jsxs("p", { className: "glass-text-secondary", children: [itemCount, " ", itemCount === 1 ? "item" : "items"] })] }), onClose && jsx("button", { onClick: onClose, className: 'glass-text-secondary hover:glass-text-secondary glass-p-2 glass-focus glass-touch-target glass-contrast-guard glass-focus glass-touch-target glass-contrast-guard', children: "\u2715" })] }), jsxs("div", { className: 'glass-flex-1 overflow-y-auto', children: [jsxs("div", { className: 'max-h-96 overflow-y-auto', children: [cart.slice(0, maxItems).map(item => jsx(CartItemCard, { item: item, onUpdateQuantity: handleUpdateQuantity, onRemove: handleRemove, onMoveToWishlist: handleMoveToWishlist, onSaveForLater: handleSaveForLater, compact: variant === "dropdown" }, item.id)), cart.length > maxItems && jsxs("div", { className: 'glass-p-4 text-center glass-text-secondary', children: ["And ", cart.length - maxItems, " more items..."] })] }), showSavedItems && savedItems.length > 0 && jsxs("div", { className: "glass-border-t glass-border-subtle glass-p-4", children: [jsxs("h3", { className: 'font-medium glass-text-secondary mb-3', children: ["Saved for Later (", savedItems.length, ")"] }), jsx("div", { className: 'space-y-2', children: savedItems.map(item => jsx(CartItemCard, { item: item, onUpdateQuantity: () => {}, onRemove: id => setSavedItems(prev => prev.filter(item => item.id !== id)), onMoveToWishlist: handleMoveToWishlist, onSaveForLater: () => {}, compact: true }, item.id)) })] })] }), jsxs("div", { className: 'glass-border-t glass-border-subtle glass-p-6 space-y-4', children: [showShippingCalculator && jsx(ShippingCalculator, { shippingOptions: shippingOptions, selectedShipping: selectedShipping, onShippingSelect: setShippingOption, cartSubtotal: cartSubtotal }), showPromoCode && jsx(PromoCodeInput, { onApplyPromo: handleApplyPromo, appliedPromo: appliedPromo }), jsxs("div", { className: 'space-y-2 pt-4 glass-border-t glass-border-subtle', children: [jsxs("div", { className: "glass-flex glass-justify-between glass-text-sm", children: [jsx("span", { children: "Subtotal:" }), jsxs("span", { children: ["$", cartSubtotal.toFixed(2)] })] }), cartShipping > 0 && jsxs("div", { className: "glass-flex glass-justify-between glass-text-sm", children: [jsx("span", { children: "Shipping:" }), jsxs("span", { children: ["$", cartShipping.toFixed(2)] })] }), jsxs("div", { className: "glass-flex glass-justify-between glass-text-sm", children: [jsx("span", { children: "Tax:" }), jsxs("span", { children: ["$", cartTax.toFixed(2)] })] }), appliedPromo && jsxs("div", { className: 'glass-flex glass-justify-between glass-text-sm text-primary', children: [jsxs("span", { children: ["Promo (", appliedPromo.code, "):"] }), jsxs("span", { children: ["-$", appliedPromo.discount.toFixed(2)] })] }), jsxs("div", { className: 'glass-flex glass-justify-between glass-text-lg font-semibold pt-2 glass-border-t glass-border-subtle', children: [jsx("span", { children: "Total:" }), jsxs("span", { children: ["$", finalTotal.toFixed(2)] })] })] }), jsx("button", { onClick: onCheckout, className: 'glass-w-full glass-py-3 glass-surface-blue text-primary font-medium glass-radius-lg hover:glass-surface-blue transition-colors glass-focus glass-touch-target glass-contrast-guard glass-focus glass-touch-target glass-contrast-guard', children: "Proceed to Checkout" }), jsxs("div", { className: "glass-flex glass-items-center glass-justify-center glass-gap-2 glass-text-xs glass-text-secondary", children: [jsx("span", { children: "\uD83D\uDD12" }), jsx("span", { children: "Secure checkout with 256-bit SSL encryption" })] })] })] }) }); }; export { GlassSmartShoppingCart }; //# sourceMappingURL=GlassSmartShoppingCart.js.map