funuicss 3.8.7 → 3.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,8 +12,6 @@ interface CartModalProps {
12
12
  cartBadgeColor?: string;
13
13
  checkoutText?: string;
14
14
  checkoutIcon?: React.ReactNode;
15
- small?: boolean;
16
- big?: boolean;
17
15
  persistCart?: boolean;
18
16
  }
19
17
  declare const CartModal: React.FC<CartModalProps>;
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // components/products/CartModal.tsx
3
2
  'use client';
4
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
5
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -15,71 +14,92 @@ var Div_1 = __importDefault(require("../div/Div"));
15
14
  var Button_1 = __importDefault(require("../button/Button"));
16
15
  var Circle_1 = __importDefault(require("../specials/Circle"));
17
16
  var Flex_1 = __importDefault(require("../flex/Flex"));
18
- var generateCartItemId = function (product, options) {
17
+ var ImageScaler_1 = __importDefault(require("../components/ImageScaler"));
18
+ var tb_1 = require("react-icons/tb");
19
+ var Empty_1 = __importDefault(require("../empty/Empty"));
20
+ var generateCartItemId = function (item) {
21
+ var _a;
19
22
  var parts = [
20
- product.id,
21
- (options === null || options === void 0 ? void 0 : options.color) || '',
22
- (options === null || options === void 0 ? void 0 : options.size) || ''
23
+ item.product.id,
24
+ ((_a = item.variant) === null || _a === void 0 ? void 0 : _a.id) || '',
25
+ item.selectedColor || '',
26
+ item.selectedSize || ''
23
27
  ].filter(Boolean);
24
28
  return parts.join('_');
25
29
  };
26
30
  var CartModal = function (_a) {
27
- var cart = _a.cart, isOpen = _a.isOpen, setIsOpen = _a.setIsOpen, _b = _a.currency, currency = _b === void 0 ? '$' : _b, updateQuantity = _a.updateQuantity, removeFromCart = _a.removeFromCart, clearCart = _a.clearCart, handleCheckout = _a.handleCheckout, _c = _a.cartBadgeColor, cartBadgeColor = _c === void 0 ? 'error' : _c, _d = _a.checkoutText, checkoutText = _d === void 0 ? 'Checkout' : _d, checkoutIcon = _a.checkoutIcon, _e = _a.small, small = _e === void 0 ? false : _e, _f = _a.big, big = _f === void 0 ? false : _f, _g = _a.persistCart, persistCart = _g === void 0 ? true : _g;
31
+ var cart = _a.cart, isOpen = _a.isOpen, setIsOpen = _a.setIsOpen, _b = _a.currency, currency = _b === void 0 ? '$' : _b, updateQuantity = _a.updateQuantity, removeFromCart = _a.removeFromCart, clearCart = _a.clearCart, handleCheckout = _a.handleCheckout, _c = _a.cartBadgeColor, cartBadgeColor = _c === void 0 ? 'error' : _c, _d = _a.checkoutText, checkoutText = _d === void 0 ? 'Checkout' : _d, checkoutIcon = _a.checkoutIcon, _e = _a.persistCart, persistCart = _e === void 0 ? true : _e;
28
32
  var totalItems = cart.reduce(function (sum, item) { return sum + item.quantity; }, 0);
29
- var subtotal = cart.reduce(function (sum, item) { return sum + (item.product.price * item.quantity); }, 0);
33
+ var subtotal = cart.reduce(function (sum, item) {
34
+ var _a;
35
+ var price = ((_a = item.variant) === null || _a === void 0 ? void 0 : _a.price) || item.product.price;
36
+ return sum + (price * item.quantity);
37
+ }, 0);
38
+ // Calculate total savings from discounts
39
+ var totalSavings = cart.reduce(function (sum, item) {
40
+ var _a;
41
+ var originalPrice = item.originalPrice || item.product.comparePrice || item.product.price;
42
+ var currentPrice = ((_a = item.variant) === null || _a === void 0 ? void 0 : _a.price) || item.product.price;
43
+ var savings = originalPrice !== currentPrice ? (originalPrice - currentPrice) * item.quantity : 0;
44
+ return sum + savings;
45
+ }, 0);
30
46
  var handleRemoveItem = function (item) {
31
- var cartItemId = generateCartItemId(item.product, {
32
- color: item.selectedColor,
33
- size: item.selectedSize
34
- });
47
+ var cartItemId = generateCartItemId(item);
35
48
  removeFromCart(cartItemId);
36
49
  };
37
50
  var handleUpdateQuantity = function (item, newQuantity) {
38
- var cartItemId = generateCartItemId(item.product, {
39
- color: item.selectedColor,
40
- size: item.selectedSize
41
- });
51
+ var cartItemId = generateCartItemId(item);
42
52
  updateQuantity(cartItemId, newQuantity);
43
53
  };
44
- return (react_1.default.createElement(Modal_1.default, { animation: "SlideLeft", position: "right", duration: 0.3, open: isOpen, setOpen: setIsOpen, funcss: "funui_products_cart_modal width-400 sm:width-500", title: react_1.default.createElement(Text_1.default, { text: "Your Cart", size: "h3" }), body: react_1.default.createElement(Div_1.default, { funcss: "funui_products_cart_body max-height-70vh overflow-y-auto" }, cart.length === 0 ? (react_1.default.createElement(Div_1.default, { funcss: "flex-center padding-40" },
45
- react_1.default.createElement(Text_1.default, { text: "Your cart is empty", color: "text-light", size: "large" }))) : (react_1.default.createElement(react_1.default.Fragment, null,
54
+ return (react_1.default.createElement(Modal_1.default, { animation: "SlideDown", duration: 0.3, open: isOpen, setOpen: setIsOpen, maxWidth: '600px', title: react_1.default.createElement(Text_1.default, { text: "Your Cart", size: "h3" }), body: react_1.default.createElement(Div_1.default, { funcss: "pt pb" }, cart.length === 0 ? (react_1.default.createElement(Div_1.default, null,
55
+ react_1.default.createElement(Empty_1.default, { title: "Your cart is empty", showCta: true, description: "Add items to your cart to checkout", ctaText: "Continue Shopping", ctaOnClick: function () { return setIsOpen(false); }, ctaIcon: react_1.default.createElement(pi_1.PiBag, null) }))) : (react_1.default.createElement(react_1.default.Fragment, null,
46
56
  cart.map(function (item, index) {
47
- var _a;
48
- var cartItemId = generateCartItemId(item.product, {
49
- color: item.selectedColor,
50
- size: item.selectedSize
51
- });
52
- return (react_1.default.createElement(RowFlex_1.default, { key: "".concat(cartItemId, "-").concat(index), funcss: "lighter p round-edge section", alignItems: "center", justify: 'space-between', gap: 1 },
53
- react_1.default.createElement(Div_1.default, { funcss: " width-80 height-80" }, ((_a = item.product.images) === null || _a === void 0 ? void 0 : _a[0]) ? (react_1.default.createElement("img", { src: item.product.images[0], alt: item.product.name, loading: "lazy", className: "fit round-edge" })) : (react_1.default.createElement(Div_1.default, { funcss: "w-80 h-80 flex central" },
57
+ var _a, _b, _c;
58
+ var cartItemId = generateCartItemId(item);
59
+ var currentPrice = ((_a = item.variant) === null || _a === void 0 ? void 0 : _a.price) || item.product.price;
60
+ var originalPrice = item.originalPrice || item.product.comparePrice || currentPrice;
61
+ var hasDiscount = originalPrice > currentPrice;
62
+ var isFirst = index === 0;
63
+ var isLast = index === cart.length - 1;
64
+ return (react_1.default.createElement(Flex_1.default, { key: "".concat(cartItemId, "-").concat(index), funcss: "bt pt pb ".concat(isLast ? "bb" : ""), alignItems: "center", justify: 'space-between', gap: 1, width: '100%' },
65
+ react_1.default.createElement(Div_1.default, { funcss: " width-80 height-80" }, ((_b = item.product.images) === null || _b === void 0 ? void 0 : _b[0]) ? (react_1.default.createElement(ImageScaler_1.default, { src: item.product.images[0], size: '80px' })) : (react_1.default.createElement(Div_1.default, { funcss: "w-80 h-80 flex central" },
54
66
  react_1.default.createElement(Text_1.default, { text: "No Image", color: "text-light", size: "sm" })))),
55
- react_1.default.createElement(Div_1.default, { funcss: "funui_products_cart_details flex-1 min-width-0" },
56
- react_1.default.createElement(Text_1.default, { text: item.product.name, block: true }),
57
- (item.selectedColor || item.selectedSize) && (react_1.default.createElement(Text_1.default, { text: "".concat(item.selectedColor ? "Color: ".concat(item.selectedColor) : '', " ").concat(item.selectedSize ? "Size: ".concat(item.selectedSize) : ''), size: 'sm' })),
58
- react_1.default.createElement(Text_1.default, { text: "".concat(item.product.currency || currency).concat((item.product.price * item.quantity).toFixed(2)), block: true, size: 'lg' })),
67
+ react_1.default.createElement(Div_1.default, { funcss: 'w-200' },
68
+ react_1.default.createElement(Text_1.default, { text: item.product.name, block: true, weight: 600 }),
69
+ ((_c = item.variant) === null || _c === void 0 ? void 0 : _c.name) && (react_1.default.createElement(Text_1.default, { text: item.variant.name, size: 'sm', color: "text-light" })),
70
+ (item.selectedColor || item.selectedSize) && (react_1.default.createElement(Text_1.default, { text: "".concat(item.selectedColor ? "Color: ".concat(item.selectedColor) : '', " ").concat(item.selectedSize ? "Size: ".concat(item.selectedSize) : ''), size: 'sm', color: "text-light" })),
71
+ react_1.default.createElement(Flex_1.default, { gap: 0.2 },
72
+ hasDiscount && (react_1.default.createElement(Text_1.default, { text: "".concat(currency).concat(originalPrice.toFixed(2)), size: 'sm', color: "text-light", style: { textDecoration: 'line-through' } })),
73
+ react_1.default.createElement(Text_1.default, { text: "".concat(currency).concat(currentPrice.toFixed(2)).concat(hasDiscount ? " (Save ".concat(currency).concat((originalPrice - currentPrice).toFixed(2), ")") : ''), color: hasDiscount ? 'success' : 'text', size: 'xs' }))),
59
74
  react_1.default.createElement("div", { className: "col" },
60
75
  react_1.default.createElement(Flex_1.default, { width: '100%', gap: 0.5, alignItems: 'center' },
61
- react_1.default.createElement(Circle_1.default, { size: 2.5, bg: 'bg', body: react_1.default.createElement(pi_1.PiMinus, null), onClick: function () { return handleUpdateQuantity(item, item.quantity - 1); } }),
62
- react_1.default.createElement("div", { className: "w-90" },
76
+ react_1.default.createElement(Circle_1.default, { size: 1.5, bg: 'lighter', body: react_1.default.createElement(pi_1.PiMinus, { size: 12 }), onClick: function () { return handleUpdateQuantity(item, item.quantity - 1); }, "aria-label": "Decrease quantity of ".concat(item.product.name) }),
77
+ react_1.default.createElement("div", { className: "w-70" },
63
78
  react_1.default.createElement(Input_1.default, { type: "number", value: item.quantity, onChange: function (e) {
64
79
  var value = parseInt(e.target.value);
65
80
  if (!isNaN(value)) {
66
81
  handleUpdateQuantity(item, Math.max(1, value));
67
82
  }
68
- }, fullWidth: true, bordered: true })),
69
- react_1.default.createElement(Circle_1.default, { bg: 'bg', size: 2.5, body: react_1.default.createElement(pi_1.PiPlus, null), onClick: function () { return handleUpdateQuantity(item, item.quantity + 1); } }))),
70
- react_1.default.createElement(Circle_1.default, { size: 2.5, body: react_1.default.createElement(pi_1.PiTrash, null), onClick: function () { return handleRemoveItem(item); }, bg: 'error' })));
83
+ }, fullWidth: true, bordered: true, "aria-label": "Quantity for ".concat(item.product.name) })),
84
+ react_1.default.createElement(Circle_1.default, { bg: 'lighter', size: 1.5, body: react_1.default.createElement(pi_1.PiPlus, { size: 12 }), onClick: function () { return handleUpdateQuantity(item, item.quantity + 1); }, "aria-label": "Increase quantity of ".concat(item.product.name) }),
85
+ react_1.default.createElement("div", null),
86
+ react_1.default.createElement(Circle_1.default, { size: 1.5, body: react_1.default.createElement(pi_1.PiTrash, { size: 12 }), onClick: function () { return handleRemoveItem(item); }, bg: 'error', "aria-label": "Remove ".concat(item.product.name, " from cart") })))));
71
87
  }),
72
- react_1.default.createElement(Div_1.default, { funcss: "funui_products_cart_summary padding-20 space-y-3" },
73
- react_1.default.createElement(RowFlex_1.default, { justify: "space-between" },
74
- react_1.default.createElement(Text_1.default, { text: "Subtotal", color: "text-light" }),
75
- react_1.default.createElement(Text_1.default, { text: "".concat(currency).concat(subtotal.toFixed(2)) })),
88
+ react_1.default.createElement("div", { className: "section" }, persistCart && (react_1.default.createElement(Button_1.default, { text: "Clear Cart", onClick: clearCart, startIcon: react_1.default.createElement(tb_1.TbShoppingBagX, null), bg: "error-light", color: "error", funcss: "full-width" }))),
89
+ react_1.default.createElement(Div_1.default, { funcss: 'mt' },
76
90
  react_1.default.createElement(RowFlex_1.default, { justify: "space-between" },
77
91
  react_1.default.createElement(Text_1.default, { text: "Items", color: "text-light" }),
78
- react_1.default.createElement(Text_1.default, { text: totalItems.toString() })))))), footer: cart.length > 0 ? (react_1.default.createElement(Div_1.default, { funcss: "funui_products_cart_footer padding-20 border-top border-light" },
92
+ react_1.default.createElement(Text_1.default, { text: totalItems.toString() })),
93
+ totalSavings > 0 && (react_1.default.createElement(RowFlex_1.default, { justify: "space-between" },
94
+ react_1.default.createElement(Text_1.default, { text: "Total Savings", color: "text-light" }),
95
+ react_1.default.createElement(Text_1.default, { text: "-".concat(currency).concat(totalSavings.toFixed(2)), color: "success" }))),
96
+ react_1.default.createElement(RowFlex_1.default, { justify: "space-between" },
97
+ react_1.default.createElement(Text_1.default, { text: "Subtotal", color: "text-light" }),
98
+ react_1.default.createElement(Text_1.default, { text: "".concat(currency).concat(subtotal.toFixed(2)) })))))), footer: cart.length > 0 ? (react_1.default.createElement(Div_1.default, { funcss: "pt pb" },
79
99
  react_1.default.createElement(RowFlex_1.default, { justify: "space-between", alignItems: "center" },
80
100
  react_1.default.createElement(Div_1.default, null,
81
101
  react_1.default.createElement(Text_1.default, { text: "Total", color: "text-light", size: "sm", block: true }),
82
102
  react_1.default.createElement(Text_1.default, { text: "".concat(currency).concat(subtotal.toFixed(2)), size: "h4" })),
83
- react_1.default.createElement(Button_1.default, { text: checkoutText, bg: "primary", raised: true, onClick: handleCheckout, funcss: "padding-x-30", startIcon: checkoutIcon, small: small, big: big })))) : react_1.default.createElement(react_1.default.Fragment, null) }));
103
+ react_1.default.createElement(Button_1.default, { text: checkoutText, bg: "primary", raised: true, onClick: handleCheckout, funcss: "padding-x-30", startIcon: checkoutIcon })))) : react_1.default.createElement(react_1.default.Fragment, null) }));
84
104
  };
85
105
  exports.default = CartModal;
@@ -15,42 +15,29 @@ var ProductCard = function (_a) {
15
15
  var discountPercent = hasDiscount
16
16
  ? Math.round(((product.comparePrice - product.price) / product.comparePrice) * 100)
17
17
  : 0;
18
- var stockAvailable = product.stock === undefined || product.stock > 0;
19
18
  var handleClick = function () {
20
19
  onClick === null || onClick === void 0 ? void 0 : onClick(product);
21
20
  };
22
- var handleAddToCart = function (e) {
23
- e.stopPropagation();
24
- onAddToCart === null || onAddToCart === void 0 ? void 0 : onAddToCart(product);
25
- };
26
21
  var getDisplayPrice = function () {
27
22
  var price = product.price || 0;
28
23
  var productCurrency = product.currency || currency;
29
24
  return "".concat(productCurrency).concat(price.toFixed(2));
30
25
  };
31
26
  return (react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-card ".concat(className, " ").concat(funcss), onClick: handleClick, customStyle: { cursor: 'pointer' } },
32
- react_1.default.createElement(Div_1.default, { funcss: "funui_store_image-container" },
33
- ((_b = product.images) === null || _b === void 0 ? void 0 : _b[0]) ? (react_1.default.createElement("img", { src: product.images[0], alt: product.name, loading: "lazy", className: "funui_store_product-image" })) : (react_1.default.createElement(Div_1.default, { funcss: "funui_store_no-image" },
34
- react_1.default.createElement(Text_1.default, { text: "No Image", color: "text-muted", size: "sm" }))),
35
- showBadges && (react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-badges" }, product.isSale && (react_1.default.createElement("span", { className: "funui_store_badge sale" }, "Sale"))))),
36
- react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-info" },
37
- react_1.default.createElement(Flex_1.default, { fit: true, justify: 'space-between', alignItems: 'center', gap: 1 },
38
- product.category && (react_1.default.createElement("span", { className: "funui_store_product-category" }, product.category)),
39
- product.isNew && (react_1.default.createElement(Text_1.default, { size: 'xs', color: 'success', weight: 600 }, "New"))),
40
- react_1.default.createElement(Flex_1.default, { gap: 0.5, direction: 'column', width: '100%' },
41
- react_1.default.createElement(Text_1.default, { block: true, size: 'lg', truncate: 2 }, product.name),
42
- react_1.default.createElement(Flex_1.default, { width: '100%', gap: 1, justify: 'space-between' },
27
+ react_1.default.createElement(Div_1.default, { funcss: "funui_store_image-container round-edge" }, ((_b = product.images) === null || _b === void 0 ? void 0 : _b[0]) ? (react_1.default.createElement("img", { src: product.images[0], alt: product.name, loading: "lazy", className: "funui_store_product-image" })) : (react_1.default.createElement(Div_1.default, { funcss: "funui_store_no-image" },
28
+ react_1.default.createElement(Text_1.default, { text: "No Image", color: "text-muted", size: "sm" })))),
29
+ react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-info " },
30
+ product.category && (react_1.default.createElement(Text_1.default, { size: 'xs', opacity: 4, uppercase: true }, product.category)),
31
+ react_1.default.createElement(Flex_1.default, { width: '100%', gap: 0.5, direction: 'column' },
32
+ react_1.default.createElement(Text_1.default, { block: true, weight: 500, truncate: 2 }, product.name),
33
+ react_1.default.createElement(Flex_1.default, { width: '100%', gap: 1, justify: 'space-between', alignItems: 'center' },
43
34
  react_1.default.createElement(Flex_1.default, { gap: 0.5, alignItems: 'center' },
44
- react_1.default.createElement("span", { className: "text-lg block" }, getDisplayPrice()),
35
+ react_1.default.createElement("span", { className: "block" }, getDisplayPrice()),
45
36
  hasDiscount && (react_1.default.createElement(Text_1.default, { size: 'xs', color: 'info', weight: 600 },
46
37
  discountPercent,
47
38
  "% Off"))),
48
39
  hasDiscount && (react_1.default.createElement(Text_1.default, { size: "sm", opacity: 4, textDecoration: 'line-through' },
49
40
  product.currency || currency,
50
- product.comparePrice.toFixed(2)))),
51
- !stockAvailable ? (react_1.default.createElement("span", { className: "funui_store_stock-info out text-xs" }, "Out of Stock")) : product.stock !== undefined && product.stock > 0 && product.stock < 10 ? (react_1.default.createElement("span", { className: "funui_store_stock-info low text-xs" },
52
- "Only ",
53
- product.stock,
54
- " left")) : stockAvailable && (react_1.default.createElement("span", { className: "funui_store_stock-info in text-xs" }, "In Stock"))))));
41
+ product.comparePrice.toFixed(2))))))));
55
42
  };
56
43
  exports.default = ProductCard;
@@ -57,8 +57,6 @@ var Text_1 = __importDefault(require("../text/Text"));
57
57
  var Flex_1 = __importDefault(require("../flex/Flex"));
58
58
  var Button_1 = __importDefault(require("../button/Button"));
59
59
  var RowFlex_1 = __importDefault(require("../specials/RowFlex"));
60
- var Input_1 = __importDefault(require("../input/Input"));
61
- var Circle_1 = __importDefault(require("../specials/Circle"));
62
60
  var Carousel_1 = __importDefault(require("../carousel/Carousel"));
63
61
  var Select_1 = __importDefault(require("../select/Select"));
64
62
  var io5_1 = require("react-icons/io5");
@@ -68,25 +66,43 @@ var ProductDetail = function (_a) {
68
66
  var _c = (0, react_1.useState)(0), selectedImageIndex = _c[0], setSelectedImageIndex = _c[1];
69
67
  var _d = (0, react_1.useState)(''), selectedColor = _d[0], setSelectedColor = _d[1];
70
68
  var _e = (0, react_1.useState)(''), selectedSize = _e[0], setSelectedSize = _e[1];
71
- var _f = (0, react_1.useState)(1), quantity = _f[0], setQuantity = _f[1];
72
- var _g = (0, react_1.useState)(false), showFullDescription = _g[0], setShowFullDescription = _g[1];
69
+ var _f = (0, react_1.useState)(false), showFullDescription = _f[0], setShowFullDescription = _f[1];
70
+ var _g = (0, react_1.useState)(false), canAddToCart = _g[0], setCanAddToCart = _g[1];
73
71
  var hasDiscount = product.comparePrice && product.comparePrice > product.price;
74
72
  var discountPercent = hasDiscount
75
73
  ? Math.round(((product.comparePrice - product.price) / product.comparePrice) * 100)
76
74
  : 0;
75
+ // Stock information logic
76
+ var stockAvailable = product.stock === undefined || product.stock > 0;
77
+ var lowStock = product.stock !== undefined && product.stock > 0 && product.stock < 10;
77
78
  var getDisplayPrice = function () {
78
79
  var price = product.price || 0;
79
80
  var productCurrency = product.currency || currency;
80
81
  return "".concat(productCurrency).concat(price.toFixed(2));
81
82
  };
82
83
  var handleAddToCart = function () {
83
- onAddToCart === null || onAddToCart === void 0 ? void 0 : onAddToCart(product, quantity, {
84
+ // Always add with quantity 1
85
+ onAddToCart === null || onAddToCart === void 0 ? void 0 : onAddToCart(product, 1, {
84
86
  color: selectedColor,
85
87
  size: selectedSize,
86
88
  });
87
89
  setOpen(false);
88
90
  };
89
- var totalPrice = ((product.price || 0) * quantity).toFixed(2);
91
+ // Validate if all required selections are made
92
+ (0, react_1.useEffect)(function () {
93
+ var isValid = true;
94
+ // Check if color selection is required and selected
95
+ if (product.colors && product.colors.length > 0) {
96
+ isValid = isValid && selectedColor !== '';
97
+ }
98
+ // Check if size selection is required and selected
99
+ if (product.sizes && product.sizes.length > 0) {
100
+ isValid = isValid && selectedSize !== '';
101
+ }
102
+ // Also check stock availability
103
+ isValid = isValid && stockAvailable;
104
+ setCanAddToCart(isValid);
105
+ }, [selectedColor, selectedSize, stockAvailable, product.colors, product.sizes]);
90
106
  // Function to safely process description
91
107
  var processDescription = function (description) {
92
108
  if (!description)
@@ -143,107 +159,130 @@ var ProductDetail = function (_a) {
143
159
  return (react_1.default.createElement(Modal_1.default, { animation: "SlideDown", open: open, setOpen: setOpen, maxWidth: '1000px', title: react_1.default.createElement(react_1.default.Fragment, null), body: react_1.default.createElement(Flex_1.default, { width: '100%', gap: 2 },
144
160
  react_1.default.createElement("div", { className: "w-400" }, product.images && product.images.length > 0 && (react_1.default.createElement(Div_1.default, { funcss: "margin-bottom-20" },
145
161
  react_1.default.createElement(Div_1.default, { funcss: "funui_products_main_image_container mb-3" },
146
- react_1.default.createElement(ImageScaler_1.default, { src: product.images[selectedImageIndex], size: "100%" })),
162
+ react_1.default.createElement(ImageScaler_1.default, { src: product.images[selectedImageIndex], size: "400px", funcss: 'round-edge' })),
147
163
  product.images.length > 1 && (react_1.default.createElement(Carousel_1.default, { gap: 1 }, product.images.map(function (image, index) { return (react_1.default.createElement(Div_1.default, { key: index, funcss: "funui_products_thumbnail rounde-edge ".concat(selectedImageIndex === index ? 'funui_products_thumbnail-active' : ''), onClick: function () { return setSelectedImageIndex(index); } },
148
- react_1.default.createElement(ImageScaler_1.default, { src: image, size: "100px" }))); })))))),
164
+ react_1.default.createElement(ImageScaler_1.default, { src: image, size: "100px", funcss: 'round-edge' }))); })))))),
149
165
  react_1.default.createElement("div", { className: "col" },
150
- react_1.default.createElement(Flex_1.default, { direction: 'column', gap: 2, alignItems: 'flex-start', justify: 'flex-start' },
151
- react_1.default.createElement("div", null,
152
- react_1.default.createElement(Text_1.default, { text: product.name, size: "2xl", block: true }),
166
+ react_1.default.createElement(Flex_1.default, { direction: 'column', gap: 2, alignItems: 'flex-start', justify: 'flex-start', width: '100%' },
167
+ react_1.default.createElement("div", { className: "w-full" },
153
168
  react_1.default.createElement(Flex_1.default, { justify: "space-between", alignItems: "center", width: '100%' },
154
- react_1.default.createElement(Text_1.default, { text: getDisplayPrice(), size: "xl" }),
155
- (hasDiscount || product.comparePrice) && (react_1.default.createElement(Text_1.default, { text: "".concat(product.currency || currency).concat(product.comparePrice.toFixed(2)), textDecoration: 'line-through' })))),
156
- ((product.colors && product.colors.length > 0) || (product.sizes && product.sizes.length > 0)) &&
157
- react_1.default.createElement(Flex_1.default, { width: '100%', gap: 1 },
158
- product.colors && product.colors.length > 0 && (react_1.default.createElement("div", { className: "col" },
159
- react_1.default.createElement(Select_1.default, { fullWidth: true, options: __spreadArray([
160
- { text: 'Select Color', value: '' }
161
- ], product.colors.map(function (color) { return ({
162
- text: color.name,
163
- value: color.name,
164
- prefix: react_1.default.createElement("div", { className: 'circle', style: { width: "20px", height: '20px', backgroundColor: color.code } })
165
- }); }), true), value: selectedColor, onChange: function (e) { return setSelectedColor(e); }, bordered: true }))),
166
- product.sizes && product.sizes.length > 0 && (react_1.default.createElement("div", { className: "col" },
167
- react_1.default.createElement(Select_1.default, { fullWidth: true, options: __spreadArray([
168
- { text: 'Select Size', value: '' }
169
- ], product.sizes.map(function (size) { return ({ text: size, value: size }); }), true), value: selectedSize, onChange: function (e) { return setSelectedSize(e); }, bordered: true })))),
170
- processedDescription && (react_1.default.createElement("div", null,
171
- react_1.default.createElement(Text_1.default, { text: "Description", size: "lg", funcss: "margin-bottom-1" }),
169
+ react_1.default.createElement(Flex_1.default, { gap: 1, alignItems: "center" },
170
+ product.category && (react_1.default.createElement(Text_1.default, { size: 'xs', opacity: 4, uppercase: true, weight: 500, color: "text-muted" }, product.category)),
171
+ product.isNew && (react_1.default.createElement(Div_1.default, { funcss: "badge-new" },
172
+ react_1.default.createElement(Text_1.default, { size: 'xs', color: 'white', weight: 600 }, "NEW"))),
173
+ product.isSale && (react_1.default.createElement(Div_1.default, { funcss: "badge-sale" },
174
+ react_1.default.createElement(Text_1.default, { size: 'xs', color: 'white', weight: 600 }, "SALE")))),
175
+ !stockAvailable ? (react_1.default.createElement(Text_1.default, { size: 'xs', color: 'error', weight: 600 }, "Out of Stock")) : lowStock ? (react_1.default.createElement(Text_1.default, { size: 'xs', color: 'warning', weight: 600 },
176
+ "Only ",
177
+ product.stock,
178
+ " left")) : (react_1.default.createElement(Text_1.default, { size: 'xs', color: 'success', weight: 600 }, "In Stock"))),
179
+ react_1.default.createElement(Text_1.default, { text: product.name, size: "2xl", block: true, weight: 600, funcss: "mb-3" }),
180
+ react_1.default.createElement(Flex_1.default, { justify: "space-between", alignItems: "center", width: '100%', funcss: "mb-3" },
181
+ react_1.default.createElement(Flex_1.default, { gap: 1, alignItems: "baseline" },
182
+ react_1.default.createElement(Text_1.default, { text: getDisplayPrice(), size: "xl", weight: 700, color: "primary" }),
183
+ hasDiscount && (react_1.default.createElement(Div_1.default, { funcss: "discount-percent" },
184
+ react_1.default.createElement(Text_1.default, { size: 'sm', color: 'white', weight: 600 },
185
+ "-",
186
+ discountPercent,
187
+ "%")))),
188
+ (hasDiscount || product.comparePrice) && (react_1.default.createElement(Text_1.default, { text: "".concat(product.currency || currency).concat(product.comparePrice.toFixed(2)), textDecoration: 'line-through', size: "sm", color: "text-muted" })))),
189
+ product.stock !== undefined && (react_1.default.createElement(Div_1.default, null,
190
+ react_1.default.createElement(Text_1.default, { size: 'xs', opacity: 4 },
191
+ product.stock,
192
+ " units available"))),
193
+ ((product.colors && product.colors.length > 0) || (product.sizes && product.sizes.length > 0)) && (react_1.default.createElement(Flex_1.default, { width: '100%', gap: 1, direction: "column" },
194
+ product.colors && product.colors.length > 0 && (react_1.default.createElement("div", { className: "col" },
195
+ react_1.default.createElement(Text_1.default, { size: "sm", weight: 500, funcss: "mb-1" },
196
+ "Color",
197
+ react_1.default.createElement(Text_1.default, { size: "xs", color: "error", funcss: "margin-left-1" }, "*")),
198
+ react_1.default.createElement(Select_1.default, { fullWidth: true, options: __spreadArray([
199
+ { text: 'Select Color', value: '' }
200
+ ], product.colors.map(function (color) { return ({
201
+ text: color.name,
202
+ value: color.name,
203
+ prefix: (react_1.default.createElement(Div_1.default, { funcss: "color-preview", customStyle: {
204
+ width: "20px",
205
+ height: "20px",
206
+ borderRadius: "50%",
207
+ backgroundColor: color.code,
208
+ border: selectedColor === color.name ? '2px solid var(--primary)' : '1px solid var(--border)'
209
+ } }))
210
+ }); }), true), value: selectedColor, onChange: function (e) { return setSelectedColor(e); }, bordered: true }),
211
+ selectedColor === '' && (react_1.default.createElement(Text_1.default, { size: "xs", color: "error", funcss: "margin-top-1" }, "Please select a color")))),
212
+ product.sizes && product.sizes.length > 0 && (react_1.default.createElement("div", { className: "col" },
213
+ react_1.default.createElement(Text_1.default, { size: "sm", weight: 500, funcss: "mb-1" },
214
+ "Size",
215
+ react_1.default.createElement(Text_1.default, { size: "xs", color: "error", funcss: "margin-left-1" }, "*")),
216
+ react_1.default.createElement(Select_1.default, { fullWidth: true, options: __spreadArray([
217
+ { text: 'Select Size', value: '' }
218
+ ], product.sizes.map(function (size) { return ({ text: size, value: size }); }), true), value: selectedSize, onChange: function (e) { return setSelectedSize(e); }, bordered: true }),
219
+ selectedSize === '' && (react_1.default.createElement(Text_1.default, { size: "xs", color: "error", funcss: "margin-top-1" }, "Please select a size")))))),
220
+ processedDescription && (react_1.default.createElement(Div_1.default, null,
221
+ react_1.default.createElement(Text_1.default, { text: "Description", size: "lg", weight: 600, funcss: "margin-bottom-1" }),
172
222
  react_1.default.createElement("div", { className: "article text-sm ".concat(hasHTML ? '' : 'whitespace-pre-wrap'), dangerouslySetInnerHTML: { __html: displayDescription } }),
173
- shouldTruncate && (react_1.default.createElement(Button_1.default, { text: showFullDescription ? 'Show Less' : 'Read More', onClick: function () { return setShowFullDescription(!showFullDescription); }, small: true, bg: 'lighter', startIcon: showFullDescription ? react_1.default.createElement(pi_1.PiCaretUp, null) : react_1.default.createElement(pi_1.PiCaretDown, null) })))),
174
- react_1.default.createElement("div", null,
223
+ shouldTruncate && (react_1.default.createElement(Button_1.default, { text: showFullDescription ? 'Show Less' : 'Read More', onClick: function () { return setShowFullDescription(!showFullDescription); }, small: true, bg: 'lighter', startIcon: showFullDescription ? react_1.default.createElement(pi_1.PiCaretUp, null) : react_1.default.createElement(pi_1.PiCaretDown, null), funcss: "mt-2" })))),
224
+ react_1.default.createElement(Div_1.default, { funcss: "product-details-grid" },
175
225
  react_1.default.createElement(Flex_1.default, { gap: 3, width: '100%' },
176
- product.warranty && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
177
- react_1.default.createElement("div", null,
178
- react_1.default.createElement(pi_1.PiShieldCheck, { className: 'text-primary' })),
179
- react_1.default.createElement("div", null,
180
- react_1.default.createElement(Text_1.default, { text: "Warranty", size: "xs", opacity: 4, block: true }),
181
- react_1.default.createElement(Text_1.default, { text: product.warranty, size: "sm", block: true, lineHeight: '1' })))),
182
- product.manufacturer && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
183
- react_1.default.createElement("div", null,
226
+ product.brand && (react_1.default.createElement(Flex_1.default, { gap: 0.3, funcss: "detail-item" },
227
+ react_1.default.createElement(Div_1.default, null,
228
+ react_1.default.createElement(si_1.SiBlackmagicdesign, { className: 'text-primary' })),
229
+ react_1.default.createElement(Div_1.default, null,
230
+ react_1.default.createElement(Text_1.default, { text: "Brand", size: "xs", opacity: 4, block: true }),
231
+ react_1.default.createElement(Text_1.default, { text: product.brand, size: "sm", block: true, lineHeight: '1', weight: 500 })))),
232
+ product.sku && (react_1.default.createElement(Flex_1.default, { gap: 0.3, funcss: "detail-item" },
233
+ react_1.default.createElement(Div_1.default, null,
234
+ react_1.default.createElement(pi_1.PiTag, { className: 'text-primary' })),
235
+ react_1.default.createElement(Div_1.default, null,
236
+ react_1.default.createElement(Text_1.default, { text: "SKU", size: "xs", opacity: 4, block: true }),
237
+ react_1.default.createElement(Text_1.default, { text: product.sku, size: "sm", block: true, lineHeight: '1', weight: 500 })))),
238
+ product.rating && (react_1.default.createElement(Flex_1.default, { gap: 0.3, funcss: "detail-item" },
239
+ react_1.default.createElement(Div_1.default, null,
240
+ react_1.default.createElement(tfi_1.TfiComments, { className: 'text-primary' })),
241
+ react_1.default.createElement(Div_1.default, null,
242
+ react_1.default.createElement(Text_1.default, { text: "Rating", size: "xs", opacity: 4, block: true }),
243
+ react_1.default.createElement(Text_1.default, { text: product.rating.toString(), size: "sm", block: true, lineHeight: '1', weight: 500 })))),
244
+ product.weight && (react_1.default.createElement(Flex_1.default, { gap: 0.3, funcss: "detail-item" },
245
+ react_1.default.createElement(Div_1.default, null,
246
+ react_1.default.createElement(pi_1.PiScales, { className: 'text-primary' })),
247
+ react_1.default.createElement(Div_1.default, null,
248
+ react_1.default.createElement(Text_1.default, { text: "Weight", size: "xs", opacity: 4, block: true }),
249
+ react_1.default.createElement(Text_1.default, { text: "".concat(product.weight, " ").concat(product.weightUnit || ''), size: "sm", block: true, lineHeight: '1', weight: 500 })))),
250
+ product.manufacturer && (react_1.default.createElement(Flex_1.default, { gap: 0.3, funcss: "detail-item" },
251
+ react_1.default.createElement(Div_1.default, null,
184
252
  react_1.default.createElement(pi_1.PiUser, { className: 'text-primary' })),
185
- react_1.default.createElement("div", null,
253
+ react_1.default.createElement(Div_1.default, null,
186
254
  react_1.default.createElement(Text_1.default, { text: "Manufacturer", size: "xs", opacity: 4, block: true }),
187
- react_1.default.createElement(Text_1.default, { text: product.manufacturer, size: "sm", block: true, lineHeight: '1' })))),
188
- product.countryOfOrigin && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
189
- react_1.default.createElement("div", null,
255
+ react_1.default.createElement(Text_1.default, { text: product.manufacturer, size: "sm", block: true, lineHeight: '1', weight: 500 })))),
256
+ product.countryOfOrigin && (react_1.default.createElement(Flex_1.default, { gap: 0.3, funcss: "detail-item" },
257
+ react_1.default.createElement(Div_1.default, null,
190
258
  react_1.default.createElement(pi_1.PiGlobe, { className: 'text-primary' })),
191
- react_1.default.createElement("div", null,
259
+ react_1.default.createElement(Div_1.default, null,
192
260
  react_1.default.createElement(Text_1.default, { text: "Country of Origin", size: "xs", opacity: 4, block: true }),
193
- react_1.default.createElement(Text_1.default, { text: product.countryOfOrigin, size: "sm", block: true, lineHeight: '1' })))),
194
- product.isFeatured && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
195
- react_1.default.createElement("div", null,
196
- react_1.default.createElement(pi_1.PiUsers, { className: 'text-primary' })),
197
- react_1.default.createElement("div", null,
198
- react_1.default.createElement(Text_1.default, { text: "Featured", size: "xs", opacity: 4, block: true }),
199
- react_1.default.createElement(Text_1.default, { text: "Yes", size: "sm", block: true, lineHeight: '1' })))),
200
- product.rating && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
201
- react_1.default.createElement("div", null,
202
- react_1.default.createElement(tfi_1.TfiComments, { className: 'text-primary' })),
203
- react_1.default.createElement("div", null,
204
- react_1.default.createElement(Text_1.default, { text: "Rating", size: "xs", opacity: 4, block: true }),
205
- react_1.default.createElement(Text_1.default, { text: product.rating, size: "sm", block: true, lineHeight: '1' })))),
206
- product.brand && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
207
- react_1.default.createElement("div", null,
208
- react_1.default.createElement(si_1.SiBlackmagicdesign, { className: 'text-primary' })),
209
- react_1.default.createElement("div", null,
210
- react_1.default.createElement(Text_1.default, { text: "Brand", size: "xs", opacity: 4, block: true }),
211
- react_1.default.createElement(Text_1.default, { text: product.brand, size: "sm", block: true, lineHeight: '1' })))),
212
- product.category && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
213
- react_1.default.createElement("div", null,
261
+ react_1.default.createElement(Text_1.default, { text: product.countryOfOrigin, size: "sm", block: true, lineHeight: '1', weight: 500 })))),
262
+ product.warranty && (react_1.default.createElement(Flex_1.default, { gap: 0.3, funcss: "detail-item" },
263
+ react_1.default.createElement(Div_1.default, null,
264
+ react_1.default.createElement(pi_1.PiShieldCheck, { className: 'text-primary' })),
265
+ react_1.default.createElement(Div_1.default, null,
266
+ react_1.default.createElement(Text_1.default, { text: "Warranty", size: "xs", opacity: 4, block: true }),
267
+ react_1.default.createElement(Text_1.default, { text: product.warranty, size: "sm", block: true, lineHeight: '1', weight: 500 })))),
268
+ product.category && (react_1.default.createElement(Flex_1.default, { gap: 0.3, funcss: "detail-item" },
269
+ react_1.default.createElement(Div_1.default, null,
214
270
  react_1.default.createElement(io5_1.IoLayersOutline, { className: 'text-primary' })),
215
- react_1.default.createElement("div", null,
271
+ react_1.default.createElement(Div_1.default, null,
216
272
  react_1.default.createElement(Text_1.default, { text: "Category", size: "xs", opacity: 4, block: true }),
217
- react_1.default.createElement(Text_1.default, { text: product.category, size: "sm", block: true, lineHeight: '1' })))),
218
- product.isNew && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
219
- react_1.default.createElement("div", null,
220
- react_1.default.createElement(pi_1.PiChecks, { className: 'text-primary' })),
221
- react_1.default.createElement("div", null,
222
- react_1.default.createElement(Text_1.default, { text: "New", size: "xs", opacity: 4, block: true }),
223
- react_1.default.createElement(Text_1.default, { text: "Yes", size: "sm", block: true, lineHeight: '1' })))),
224
- product.isSale && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
225
- react_1.default.createElement("div", null,
226
- react_1.default.createElement(pi_1.PiChecks, { className: 'text-primary' })),
227
- react_1.default.createElement("div", null,
228
- react_1.default.createElement(Text_1.default, { text: "On Sale", size: "xs", opacity: 4, block: true }),
229
- react_1.default.createElement(Text_1.default, { text: "Yes", size: "sm", block: true, lineHeight: '1' })))),
230
- product.weight && (react_1.default.createElement(Flex_1.default, { gap: 0.3 },
231
- react_1.default.createElement("div", null,
232
- react_1.default.createElement(pi_1.PiScales, { className: 'text-primary' })),
233
- react_1.default.createElement("div", null,
234
- react_1.default.createElement(Text_1.default, { text: "Weight", size: "xs", opacity: 4, block: true }),
235
- react_1.default.createElement(Text_1.default, { text: product.weight + " " + product.weightUnit, size: "sm", block: true, lineHeight: '1' }))))))))), footer: react_1.default.createElement(RowFlex_1.default, { gap: 1, justify: 'flex-end', funcss: 'pt' },
236
- react_1.default.createElement(RowFlex_1.default, { gap: 0.5, alignItems: "center" },
237
- react_1.default.createElement(Circle_1.default, { body: react_1.default.createElement(pi_1.PiMinus, null), onClick: function () { return setQuantity(Math.max(1, quantity - 1)); }, funcss: quantity <= 1 ? "disabled" : "" }),
238
- react_1.default.createElement("div", { className: "w-90" },
239
- react_1.default.createElement(Input_1.default, { type: "number", value: quantity, onChange: function (e) {
240
- var value = parseInt(e.target.value);
241
- if (!isNaN(value)) {
242
- setQuantity(Math.max(1, value));
243
- }
244
- }, funcss: "text-center", bordered: true })),
245
- react_1.default.createElement(Circle_1.default, { onClick: function () { return setQuantity(quantity + 1); }, bg: 'lighter' },
246
- react_1.default.createElement(pi_1.PiPlus, null))),
247
- react_1.default.createElement(Button_1.default, { text: "Add to Cart - ".concat(currency).concat(totalPrice), bg: "primary", raised: true, onClick: handleAddToCart })) }));
273
+ react_1.default.createElement(Text_1.default, { text: product.category, size: "sm", block: true, lineHeight: '1', weight: 500 })))),
274
+ product.brand && (react_1.default.createElement(Flex_1.default, { gap: 0.3, funcss: "detail-item" },
275
+ react_1.default.createElement(Div_1.default, null,
276
+ react_1.default.createElement(pi_1.PiStorefront, { className: 'text-primary' })),
277
+ react_1.default.createElement(Div_1.default, null,
278
+ react_1.default.createElement(Text_1.default, { text: "Store", size: "xs", opacity: 4, block: true }),
279
+ react_1.default.createElement(Text_1.default, { text: product.brand, size: "sm", block: true, lineHeight: '1', weight: 500 })))),
280
+ product.tags && product.tags.length > 0 && (react_1.default.createElement(Flex_1.default, { gap: 0.3, funcss: "detail-item" },
281
+ react_1.default.createElement(Div_1.default, null,
282
+ react_1.default.createElement(pi_1.PiTag, { className: 'text-primary' })),
283
+ react_1.default.createElement(Div_1.default, null,
284
+ react_1.default.createElement(Text_1.default, { text: "Tags", size: "xs", opacity: 4, block: true }),
285
+ react_1.default.createElement(Text_1.default, { text: product.tags.join(', '), size: "sm", block: true, lineHeight: '1', truncate: 1 }))))))))), footer: react_1.default.createElement(RowFlex_1.default, { gap: 1, justify: 'flex-end', funcss: 'pt' },
286
+ react_1.default.createElement(Button_1.default, { text: "Add to Cart", startIcon: react_1.default.createElement(pi_1.PiBag, null), bg: "primary", raised: true, onClick: handleAddToCart, disabled: !canAddToCart, funcss: !canAddToCart ? "opacity-6" : "" })) }));
248
287
  };
249
288
  exports.default = ProductDetail;
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const ProductLoader: () => React.JSX.Element;
3
+ export default ProductLoader;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ 'use client';
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ var react_1 = __importDefault(require("react"));
8
+ var Div_1 = __importDefault(require("../div/Div"));
9
+ var View_1 = __importDefault(require("../view/View"));
10
+ var ProductLoader = function () {
11
+ return (react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-card " },
12
+ react_1.default.createElement(Div_1.default, { funcss: "funui_store_image-container round-edge skeleton" }),
13
+ react_1.default.createElement(View_1.default, { funcss: 'skeleton round-edge', style: {
14
+ height: "1rem",
15
+ marginTop: "0.5rem"
16
+ } }),
17
+ react_1.default.createElement(View_1.default, { funcss: 'skeleton round-edge', style: {
18
+ height: "3rem",
19
+ marginTop: "0.5rem"
20
+ } })));
21
+ };
22
+ exports.default = ProductLoader;