aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
482 lines (479 loc) • 20.7 kB
JavaScript
'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