funuicss 3.7.16 → 3.8.1
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.
- package/css/fun.css +324 -202
- package/demo/theme.tsx +1311 -0
- package/index.d.ts +2 -0
- package/index.js +5 -1
- package/package.json +1 -1
- package/ui/button/Button.d.ts +2 -1
- package/ui/button/Button.js +3 -3
- package/ui/components/ImageScaler.d.ts +6 -0
- package/ui/components/ImageScaler.js +17 -0
- package/ui/div/Div.d.ts +3 -1
- package/ui/div/Div.js +2 -2
- package/ui/empty/Empty.d.ts +17 -0
- package/ui/empty/Empty.js +66 -0
- package/ui/flex/Flex.d.ts +2 -1
- package/ui/flex/Flex.js +3 -3
- package/ui/modal/Modal.d.ts +1 -1
- package/ui/products/CartModal.d.ts +20 -0
- package/ui/products/CartModal.js +85 -0
- package/ui/products/ProductCard.d.ts +13 -0
- package/ui/products/ProductCard.js +56 -0
- package/ui/products/ProductDetail.d.ts +14 -0
- package/ui/products/ProductDetail.js +249 -0
- package/ui/products/ProductDetailModal.d.ts +17 -0
- package/ui/products/ProductDetailModal.js +99 -0
- package/ui/products/Products.d.ts +60 -0
- package/ui/products/Products.js +312 -0
- package/ui/products/Store.d.ts +99 -0
- package/ui/products/Store.js +515 -0
- package/ui/sidebar/SideBar.d.ts +3 -1
- package/ui/sidebar/SideBar.js +50 -11
- package/ui/specials/Circle.d.ts +2 -1
- package/ui/specials/Circle.js +2 -2
- package/ui/table/Table.d.ts +15 -1
- package/ui/table/Table.js +158 -31
- package/ui/theme/theme.d.ts +90 -0
- package/ui/theme/theme.js +440 -545
- package/utils/Buckets.d.ts +0 -0
- package/utils/Buckets.js +1 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Products.tsx
|
|
3
|
+
'use client';
|
|
4
|
+
var __assign = (this && this.__assign) || function () {
|
|
5
|
+
__assign = Object.assign || function(t) {
|
|
6
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
7
|
+
s = arguments[i];
|
|
8
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
9
|
+
t[p] = s[p];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
return __assign.apply(this, arguments);
|
|
14
|
+
};
|
|
15
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
18
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
19
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
20
|
+
}
|
|
21
|
+
Object.defineProperty(o, k2, desc);
|
|
22
|
+
}) : (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
o[k2] = m[k];
|
|
25
|
+
}));
|
|
26
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
27
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
28
|
+
}) : function(o, v) {
|
|
29
|
+
o["default"] = v;
|
|
30
|
+
});
|
|
31
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
32
|
+
var ownKeys = function(o) {
|
|
33
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
34
|
+
var ar = [];
|
|
35
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
36
|
+
return ar;
|
|
37
|
+
};
|
|
38
|
+
return ownKeys(o);
|
|
39
|
+
};
|
|
40
|
+
return function (mod) {
|
|
41
|
+
if (mod && mod.__esModule) return mod;
|
|
42
|
+
var result = {};
|
|
43
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
44
|
+
__setModuleDefault(result, mod);
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
})();
|
|
48
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
49
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
50
|
+
if (ar || !(i in from)) {
|
|
51
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
52
|
+
ar[i] = from[i];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
56
|
+
};
|
|
57
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
58
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
59
|
+
};
|
|
60
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
61
|
+
var react_1 = __importStar(require("react"));
|
|
62
|
+
var pi_1 = require("react-icons/pi");
|
|
63
|
+
var Button_1 = __importDefault(require("../button/Button"));
|
|
64
|
+
var RowFlex_1 = __importDefault(require("../specials/RowFlex"));
|
|
65
|
+
var Text_1 = __importDefault(require("../text/Text"));
|
|
66
|
+
var Input_1 = __importDefault(require("../input/Input"));
|
|
67
|
+
var Div_1 = __importDefault(require("../div/Div"));
|
|
68
|
+
var Carousel_1 = __importDefault(require("../carousel/Carousel"));
|
|
69
|
+
// Constants
|
|
70
|
+
var EMPTY_IMAGE_SVG = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="%23f5f7fa"><rect width="100" height="100"/><text x="50" y="55" text-anchor="middle" fill="%236b7280" font-size="12" font-family="system-ui">No Image</text></svg>';
|
|
71
|
+
var THUMBNAIL_EMPTY_SVG = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="%23f3f4f6"><rect width="100" height="100"/></svg>';
|
|
72
|
+
var DETAIL_EMPTY_SVG = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="%23f3f4f6"><rect width="100" height="100"/><text x="50" y="55" text-anchor="middle" fill="%239ca3af" font-size="12">No Image</text></svg>';
|
|
73
|
+
// Styles - moved outside to avoid recreation
|
|
74
|
+
var PRODUCT_CARD_STYLE = { cursor: 'pointer' };
|
|
75
|
+
var IMAGE_STYLE = { width: '100%', height: '100%', objectFit: 'cover' };
|
|
76
|
+
var THUMBNAIL_STYLE = {
|
|
77
|
+
width: '80px',
|
|
78
|
+
height: '80px',
|
|
79
|
+
borderRadius: '0.5rem',
|
|
80
|
+
overflow: 'hidden',
|
|
81
|
+
cursor: 'pointer'
|
|
82
|
+
};
|
|
83
|
+
// Lazy load modals for better performance
|
|
84
|
+
var CartModal = (0, react_1.lazy)(function () { return Promise.resolve().then(function () { return __importStar(require('./CartModal')); }); });
|
|
85
|
+
var ProductDetailModal = (0, react_1.lazy)(function () { return Promise.resolve().then(function () { return __importStar(require('./ProductDetailModal')); }); });
|
|
86
|
+
// Memoized Product Card Component
|
|
87
|
+
var ProductCard = (0, react_1.memo)(function (_a) {
|
|
88
|
+
var _b;
|
|
89
|
+
var product = _a.product, openProductModal = _a.openProductModal, rounded = _a.rounded, raised = _a.raised;
|
|
90
|
+
var productData = (0, react_1.useMemo)(function () {
|
|
91
|
+
var hasDiscount = product.comparePrice && product.comparePrice > product.price;
|
|
92
|
+
var discountPercent = hasDiscount
|
|
93
|
+
? Math.round(((product.comparePrice - product.price) / product.comparePrice) * 100)
|
|
94
|
+
: 0;
|
|
95
|
+
var stockAvailable = product.stock === undefined || product.stock > 0;
|
|
96
|
+
return { hasDiscount: hasDiscount, discountPercent: discountPercent, stockAvailable: stockAvailable };
|
|
97
|
+
}, [product]);
|
|
98
|
+
return (react_1.default.createElement(Div_1.default, { key: product.id, funcss: "funui_store_product-card ".concat(rounded ? 'round-edge' : '', " ").concat(raised ? 'card' : ''), onClick: function () { return openProductModal(product); }, customStyle: PRODUCT_CARD_STYLE },
|
|
99
|
+
react_1.default.createElement(Div_1.default, { funcss: "funui_store_image-container" },
|
|
100
|
+
((_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", onError: function (e) {
|
|
101
|
+
e.target.src = EMPTY_IMAGE_SVG;
|
|
102
|
+
} })) : (react_1.default.createElement(Div_1.default, { funcss: "funui_store_no-image" },
|
|
103
|
+
react_1.default.createElement(Text_1.default, { text: "No Image", color: "text-muted", size: "small" }))),
|
|
104
|
+
react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-badges" },
|
|
105
|
+
product.isNew && (react_1.default.createElement("span", { className: "funui_store_badge new" }, "New")),
|
|
106
|
+
product.isSale && (react_1.default.createElement("span", { className: "funui_store_badge sale" }, "Sale")),
|
|
107
|
+
productData.hasDiscount && (react_1.default.createElement("span", { className: "funui_store_badge discount" },
|
|
108
|
+
"-",
|
|
109
|
+
productData.discountPercent,
|
|
110
|
+
"%")))),
|
|
111
|
+
react_1.default.createElement(Div_1.default, { funcss: "funui_store_product-info" },
|
|
112
|
+
product.category && (react_1.default.createElement("span", { className: "funui_store_product-category" }, product.category)),
|
|
113
|
+
react_1.default.createElement(Text_1.default, { block: true, size: 'lg', truncate: 2 }, product.name),
|
|
114
|
+
react_1.default.createElement(Div_1.default, { funcss: "funui_store_price-container" },
|
|
115
|
+
react_1.default.createElement("span", { className: "funui_store_price" },
|
|
116
|
+
"$",
|
|
117
|
+
product.price.toFixed(2)),
|
|
118
|
+
productData.hasDiscount && (react_1.default.createElement("span", { className: "funui_store_old-price" },
|
|
119
|
+
"$",
|
|
120
|
+
product.comparePrice.toFixed(2)))),
|
|
121
|
+
!productData.stockAvailable ? (react_1.default.createElement("span", { className: "funui_store_stock-info out" }, "Out of Stock")) : product.stock !== undefined && product.stock > 0 && product.stock < 10 ? (react_1.default.createElement("span", { className: "funui_store_stock-info low" },
|
|
122
|
+
"Only ",
|
|
123
|
+
product.stock,
|
|
124
|
+
" left")) : productData.stockAvailable && (react_1.default.createElement("span", { className: "funui_store_stock-info in" }, "In Stock")))));
|
|
125
|
+
});
|
|
126
|
+
ProductCard.displayName = 'ProductCard';
|
|
127
|
+
// Products Component
|
|
128
|
+
var Products = function (_a) {
|
|
129
|
+
var _b = _a.products, products = _b === void 0 ? [] : _b, _c = _a.title, title = _c === void 0 ? 'Products' : _c, _d = _a.showHeader, showHeader = _d === void 0 ? true : _d, _e = _a.showSearch, showSearch = _e === void 0 ? true : _e, _f = _a.showFilters, showFilters = _f === void 0 ? true : _f, _g = _a.showCart, showCart = _g === void 0 ? true : _g, _h = _a.cartIcon, cartIcon = _h === void 0 ? react_1.default.createElement(pi_1.PiShoppingCart, null) : _h, _j = _a.cartBadgeColor, cartBadgeColor = _j === void 0 ? 'error' : _j, cartBadgeText = _a.cartBadgeText, _k = _a.checkoutText, checkoutText = _k === void 0 ? 'Checkout' : _k, checkoutIcon = _a.checkoutIcon, onAddToCart = _a.onAddToCart, onRemoveFromCart = _a.onRemoveFromCart, onUpdateQuantity = _a.onUpdateQuantity, onCheckout = _a.onCheckout, onProductClick = _a.onProductClick, _l = _a.className, className = _l === void 0 ? '' : _l, _m = _a.gridClassName, gridClassName = _m === void 0 ? '' : _m, children = _a.children, style = _a.style, id = _a.id, _o = _a.funcss, funcss = _o === void 0 ? '' : _o, bg = _a.bg, color = _a.color, _p = _a.rounded, rounded = _p === void 0 ? false : _p, _q = _a.raised, raised = _q === void 0 ? false : _q, _r = _a.fullWidth, fullWidth = _r === void 0 ? false : _r, _s = _a.small, small = _s === void 0 ? false : _s, _t = _a.big, big = _t === void 0 ? false : _t;
|
|
130
|
+
// Parse products once (can be array or JSON string)
|
|
131
|
+
var parsedProducts = (0, react_1.useMemo)(function () {
|
|
132
|
+
if (typeof products === 'string') {
|
|
133
|
+
try {
|
|
134
|
+
var parsed = JSON.parse(products);
|
|
135
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
console.error('Error parsing products JSON:', error);
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return products || [];
|
|
143
|
+
}, [products]);
|
|
144
|
+
// Get unique categories with proper dependencies
|
|
145
|
+
var categories = (0, react_1.useMemo)(function () {
|
|
146
|
+
var allCategories = parsedProducts
|
|
147
|
+
.map(function (p) { return p.category; })
|
|
148
|
+
.filter(function (cat) { return typeof cat === 'string' && cat.trim() !== ''; });
|
|
149
|
+
var uniqueCategories = Array.from(new Set(allCategories));
|
|
150
|
+
return __spreadArray(['all'], uniqueCategories, true);
|
|
151
|
+
}, [parsedProducts]);
|
|
152
|
+
// States
|
|
153
|
+
var _u = (0, react_1.useState)([]), cart = _u[0], setCart = _u[1];
|
|
154
|
+
var _v = (0, react_1.useState)(false), isCartOpen = _v[0], setIsCartOpen = _v[1];
|
|
155
|
+
var _w = (0, react_1.useState)(false), isProductModalOpen = _w[0], setIsProductModalOpen = _w[1];
|
|
156
|
+
var _x = (0, react_1.useState)(null), selectedProduct = _x[0], setSelectedProduct = _x[1];
|
|
157
|
+
var _y = (0, react_1.useState)(''), searchQuery = _y[0], setSearchQuery = _y[1];
|
|
158
|
+
var _z = (0, react_1.useState)('all'), selectedCategory = _z[0], setSelectedCategory = _z[1];
|
|
159
|
+
var _0 = (0, react_1.useState)(''), selectedColor = _0[0], setSelectedColor = _0[1];
|
|
160
|
+
var _1 = (0, react_1.useState)(1), quantity = _1[0], setQuantity = _1[1];
|
|
161
|
+
var _2 = (0, react_1.useState)(0), selectedImageIndex = _2[0], setSelectedImageIndex = _2[1];
|
|
162
|
+
// Deferred search for better performance
|
|
163
|
+
var deferredSearchQuery = (0, react_1.useDeferredValue)(searchQuery);
|
|
164
|
+
// Filter products with memoization
|
|
165
|
+
var filteredProducts = (0, react_1.useMemo)(function () {
|
|
166
|
+
var filtered = __spreadArray([], parsedProducts, true);
|
|
167
|
+
if (deferredSearchQuery.trim()) {
|
|
168
|
+
var query_1 = deferredSearchQuery.toLowerCase();
|
|
169
|
+
filtered = filtered.filter(function (p) {
|
|
170
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
171
|
+
var nameMatch = (_b = (_a = p.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(query_1)) !== null && _b !== void 0 ? _b : false;
|
|
172
|
+
var descMatch = (_d = (_c = p.description) === null || _c === void 0 ? void 0 : _c.toLowerCase().includes(query_1)) !== null && _d !== void 0 ? _d : false;
|
|
173
|
+
var brandMatch = (_f = (_e = p.brand) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes(query_1)) !== null && _f !== void 0 ? _f : false;
|
|
174
|
+
var tagMatch = (_h = (_g = p.tags) === null || _g === void 0 ? void 0 : _g.some(function (tag) { return tag.toLowerCase().includes(query_1); })) !== null && _h !== void 0 ? _h : false;
|
|
175
|
+
return nameMatch || descMatch || brandMatch || tagMatch;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
if (selectedCategory !== 'all') {
|
|
179
|
+
filtered = filtered.filter(function (p) { return p.category === selectedCategory; });
|
|
180
|
+
}
|
|
181
|
+
return filtered;
|
|
182
|
+
}, [parsedProducts, deferredSearchQuery, selectedCategory]);
|
|
183
|
+
// Cart calculations
|
|
184
|
+
var cartCalculations = (0, react_1.useMemo)(function () {
|
|
185
|
+
var totalItems = cart.reduce(function (sum, item) { return sum + item.quantity; }, 0);
|
|
186
|
+
var subtotal = cart.reduce(function (sum, item) { return sum + (item.product.price * item.quantity); }, 0);
|
|
187
|
+
return { totalItems: totalItems, subtotal: subtotal };
|
|
188
|
+
}, [cart]);
|
|
189
|
+
var totalItems = cartCalculations.totalItems, subtotal = cartCalculations.subtotal;
|
|
190
|
+
// Memoized cart functions
|
|
191
|
+
var addToCart = (0, react_1.useCallback)(function (product, color) {
|
|
192
|
+
var existingItem = cart.find(function (item) {
|
|
193
|
+
return item.product.id === product.id &&
|
|
194
|
+
item.selectedColor === color;
|
|
195
|
+
});
|
|
196
|
+
var updatedCart;
|
|
197
|
+
if (existingItem) {
|
|
198
|
+
updatedCart = cart.map(function (item) {
|
|
199
|
+
return item.product.id === existingItem.product.id &&
|
|
200
|
+
item.selectedColor === existingItem.selectedColor
|
|
201
|
+
? __assign(__assign({}, item), { quantity: item.quantity + 1 }) : item;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
updatedCart = __spreadArray(__spreadArray([], cart, true), [{
|
|
206
|
+
product: product,
|
|
207
|
+
quantity: 1,
|
|
208
|
+
selectedColor: color,
|
|
209
|
+
}], false);
|
|
210
|
+
}
|
|
211
|
+
setCart(updatedCart);
|
|
212
|
+
// Call callback
|
|
213
|
+
if (existingItem) {
|
|
214
|
+
onUpdateQuantity === null || onUpdateQuantity === void 0 ? void 0 : onUpdateQuantity(product.id, existingItem.quantity + 1);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
var newItem = updatedCart.find(function (item) {
|
|
218
|
+
return item.product.id === product.id &&
|
|
219
|
+
item.selectedColor === color;
|
|
220
|
+
});
|
|
221
|
+
if (newItem) {
|
|
222
|
+
onAddToCart === null || onAddToCart === void 0 ? void 0 : onAddToCart(newItem);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}, [cart, onUpdateQuantity, onAddToCart]);
|
|
226
|
+
var updateQuantity = (0, react_1.useCallback)(function (productId, newQuantity) {
|
|
227
|
+
if (newQuantity < 1) {
|
|
228
|
+
removeFromCart(productId);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
var updatedCart = cart.map(function (item) {
|
|
232
|
+
return item.product.id === productId
|
|
233
|
+
? __assign(__assign({}, item), { quantity: newQuantity }) : item;
|
|
234
|
+
});
|
|
235
|
+
setCart(updatedCart);
|
|
236
|
+
onUpdateQuantity === null || onUpdateQuantity === void 0 ? void 0 : onUpdateQuantity(productId, newQuantity);
|
|
237
|
+
}, [cart, onUpdateQuantity]);
|
|
238
|
+
var removeFromCart = (0, react_1.useCallback)(function (productId) {
|
|
239
|
+
var updatedCart = cart.filter(function (item) { return item.product.id !== productId; });
|
|
240
|
+
setCart(updatedCart);
|
|
241
|
+
onRemoveFromCart === null || onRemoveFromCart === void 0 ? void 0 : onRemoveFromCart(productId);
|
|
242
|
+
}, [cart, onRemoveFromCart]);
|
|
243
|
+
var handleCheckout = (0, react_1.useCallback)(function () {
|
|
244
|
+
if (onCheckout) {
|
|
245
|
+
onCheckout(cart, subtotal);
|
|
246
|
+
}
|
|
247
|
+
setIsCartOpen(false);
|
|
248
|
+
}, [onCheckout, cart, subtotal]);
|
|
249
|
+
// Memoized product modal function
|
|
250
|
+
var openProductModal = (0, react_1.useCallback)(function (product) {
|
|
251
|
+
if (onProductClick) {
|
|
252
|
+
onProductClick(product);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
setSelectedProduct(product);
|
|
256
|
+
setSelectedColor('');
|
|
257
|
+
setQuantity(1);
|
|
258
|
+
setSelectedImageIndex(0);
|
|
259
|
+
setIsProductModalOpen(true);
|
|
260
|
+
}, [onProductClick]);
|
|
261
|
+
var handleAddFromModal = (0, react_1.useCallback)(function () {
|
|
262
|
+
if (selectedProduct) {
|
|
263
|
+
for (var i = 0; i < quantity; i++) {
|
|
264
|
+
addToCart(selectedProduct, selectedColor || undefined);
|
|
265
|
+
}
|
|
266
|
+
setIsProductModalOpen(false);
|
|
267
|
+
}
|
|
268
|
+
}, [selectedProduct, quantity, selectedColor, addToCart]);
|
|
269
|
+
// Debounced search handler
|
|
270
|
+
var handleSearchChange = (0, react_1.useCallback)(function (value) {
|
|
271
|
+
setSearchQuery(value);
|
|
272
|
+
}, []);
|
|
273
|
+
// Memoized render functions
|
|
274
|
+
var renderHeader = (0, react_1.useMemo)(function () {
|
|
275
|
+
if (!showHeader)
|
|
276
|
+
return null;
|
|
277
|
+
return (react_1.default.createElement(RowFlex_1.default, { justify: "space-between", alignItems: "center", funcss: "mb-5" },
|
|
278
|
+
react_1.default.createElement(Text_1.default, { text: title, size: "h1", funcss: "text-bold" })));
|
|
279
|
+
}, [showHeader, title]);
|
|
280
|
+
var renderSearchAndFilters = (0, react_1.useMemo)(function () {
|
|
281
|
+
if (!showSearch && !showFilters)
|
|
282
|
+
return null;
|
|
283
|
+
return (react_1.default.createElement(Div_1.default, { funcss: "" },
|
|
284
|
+
showSearch && (react_1.default.createElement(RowFlex_1.default, { gap: 1, alignItems: "center", justify: 'space-between' },
|
|
285
|
+
react_1.default.createElement(Input_1.default, { label: "Search products...", value: searchQuery, onChange: function (e) { return handleSearchChange(e.target.value); }, bordered: true, fullWidth: fullWidth, startIcon: react_1.default.createElement(pi_1.PiMagnifyingGlass, null) }),
|
|
286
|
+
showCart && (react_1.default.createElement("button", { onClick: function () { return setIsCartOpen(true); }, className: "cart-icon", type: "button", "aria-label": "Shopping cart (".concat(totalItems, " items)") },
|
|
287
|
+
react_1.default.createElement(pi_1.PiShoppingCart, { size: 30 }),
|
|
288
|
+
totalItems > 0 && (react_1.default.createElement("div", { className: "cart-badge" }, totalItems > 99 ? '99+' : totalItems)))))),
|
|
289
|
+
showFilters && categories.length > 1 && (react_1.default.createElement(Carousel_1.default, { funcss: 'section' },
|
|
290
|
+
react_1.default.createElement(Button_1.default, { text: "All", onClick: function () { return setSelectedCategory('all'); }, bg: selectedCategory === 'all' ? 'primary' : undefined, color: selectedCategory === 'all' ? 'white' : 'text', outlined: selectedCategory !== 'all', small: true }),
|
|
291
|
+
categories
|
|
292
|
+
.filter(function (c) { return c !== 'all'; })
|
|
293
|
+
.map(function (category) { return (react_1.default.createElement(Button_1.default, { key: category, text: category, onClick: function () { return setSelectedCategory(category); }, bg: selectedCategory === category ? 'primary' : "lighter", color: selectedCategory === category ? 'white' : 'text', outlined: selectedCategory !== category, small: true })); })))));
|
|
294
|
+
}, [showSearch, showFilters, showCart, searchQuery, handleSearchChange, fullWidth, totalItems, categories, selectedCategory]);
|
|
295
|
+
var renderProductsGrid = (0, react_1.useMemo)(function () {
|
|
296
|
+
if (filteredProducts.length === 0) {
|
|
297
|
+
return (react_1.default.createElement(Div_1.default, { funcss: "funui_products_empty flex-center padding-40" },
|
|
298
|
+
react_1.default.createElement(Text_1.default, { text: "No products found", color: "text-light", size: "large" })));
|
|
299
|
+
}
|
|
300
|
+
return (react_1.default.createElement(Div_1.default, { funcss: "funui_products_grid grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 ".concat(gridClassName) }, filteredProducts.map(function (product) { return (react_1.default.createElement(ProductCard, { key: product.id, product: product, openProductModal: openProductModal, rounded: rounded, raised: raised })); })));
|
|
301
|
+
}, [filteredProducts, gridClassName, openProductModal, rounded, raised]);
|
|
302
|
+
return (react_1.default.createElement(Div_1.default, { funcss: "funui_products_classname ".concat(className, " ").concat(funcss).trim(), id: id, customStyle: style },
|
|
303
|
+
renderHeader,
|
|
304
|
+
renderSearchAndFilters,
|
|
305
|
+
renderProductsGrid,
|
|
306
|
+
children,
|
|
307
|
+
showCart && (react_1.default.createElement(react_1.Suspense, { fallback: react_1.default.createElement("div", null, "Loading cart...") },
|
|
308
|
+
react_1.default.createElement(CartModal, { isOpen: isCartOpen, setIsOpen: setIsCartOpen, cart: cart, subtotal: subtotal, totalItems: totalItems, updateQuantity: updateQuantity, removeFromCart: removeFromCart, handleCheckout: handleCheckout, checkoutText: checkoutText, checkoutIcon: checkoutIcon, small: small, big: big }))),
|
|
309
|
+
selectedProduct && (react_1.default.createElement(react_1.Suspense, { fallback: react_1.default.createElement("div", null, "Loading product details...") },
|
|
310
|
+
react_1.default.createElement(ProductDetailModal, { isOpen: isProductModalOpen, setIsOpen: setIsProductModalOpen, selectedProduct: selectedProduct, selectedImageIndex: selectedImageIndex, setSelectedImageIndex: setSelectedImageIndex, selectedColor: selectedColor, setSelectedColor: setSelectedColor, quantity: quantity, setQuantity: setQuantity, handleAddFromModal: handleAddFromModal, small: small, big: big })))));
|
|
311
|
+
};
|
|
312
|
+
exports.default = Products;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type WeightUnit = 'g' | 'kg' | 'oz' | 'lb';
|
|
3
|
+
export type DimensionUnit = 'cm' | 'm' | 'in' | 'ft';
|
|
4
|
+
export interface ProductVariant {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
sku?: string;
|
|
8
|
+
price: number;
|
|
9
|
+
comparePrice?: number;
|
|
10
|
+
currency?: string;
|
|
11
|
+
weight?: number;
|
|
12
|
+
weightUnit?: WeightUnit;
|
|
13
|
+
stock?: number;
|
|
14
|
+
images?: string[];
|
|
15
|
+
color?: string;
|
|
16
|
+
size?: string;
|
|
17
|
+
discount?: number;
|
|
18
|
+
}
|
|
19
|
+
export type Product = {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
price: number;
|
|
23
|
+
comparePrice?: number;
|
|
24
|
+
currency?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
images?: string[];
|
|
27
|
+
category?: string;
|
|
28
|
+
brand?: string;
|
|
29
|
+
tags?: string[];
|
|
30
|
+
colors?: {
|
|
31
|
+
name: string;
|
|
32
|
+
code: string;
|
|
33
|
+
}[];
|
|
34
|
+
sizes?: string[];
|
|
35
|
+
weight?: number;
|
|
36
|
+
weightUnit?: WeightUnit;
|
|
37
|
+
sku?: string;
|
|
38
|
+
stock?: number;
|
|
39
|
+
rating?: number;
|
|
40
|
+
isNew?: boolean;
|
|
41
|
+
isSale?: boolean;
|
|
42
|
+
variants?: ProductVariant[];
|
|
43
|
+
manufacturer: string | '';
|
|
44
|
+
countryOfOrigin: string | '';
|
|
45
|
+
warranty: string | '';
|
|
46
|
+
isFeatured: string | '';
|
|
47
|
+
discount?: number;
|
|
48
|
+
};
|
|
49
|
+
export type CartItem = {
|
|
50
|
+
product: Product;
|
|
51
|
+
variant?: ProductVariant;
|
|
52
|
+
quantity: number;
|
|
53
|
+
selectedColor?: string;
|
|
54
|
+
selectedSize?: string;
|
|
55
|
+
addedAt: number;
|
|
56
|
+
originalPrice?: number;
|
|
57
|
+
};
|
|
58
|
+
export type CartStorage = {
|
|
59
|
+
items: CartItem[];
|
|
60
|
+
updatedAt: number;
|
|
61
|
+
};
|
|
62
|
+
type ProductsPageProps = {
|
|
63
|
+
products?: Product[] | string;
|
|
64
|
+
bucket?: string;
|
|
65
|
+
bucketPage?: number;
|
|
66
|
+
bucketSize?: number;
|
|
67
|
+
title?: string;
|
|
68
|
+
showHeader?: boolean;
|
|
69
|
+
showSearch?: boolean;
|
|
70
|
+
showFilters?: boolean;
|
|
71
|
+
showCart?: boolean;
|
|
72
|
+
cartIcon?: string | React.ReactNode;
|
|
73
|
+
cartBadgeColor?: string;
|
|
74
|
+
cartBadgeText?: string;
|
|
75
|
+
checkoutText?: string;
|
|
76
|
+
checkoutIcon?: string | React.ReactNode;
|
|
77
|
+
currency?: string;
|
|
78
|
+
persistCart?: boolean;
|
|
79
|
+
storageKey?: string;
|
|
80
|
+
onAddToCart?: (item: CartItem) => void;
|
|
81
|
+
onRemoveFromCart?: (itemId: string) => void;
|
|
82
|
+
onUpdateQuantity?: (itemId: string, quantity: number) => void;
|
|
83
|
+
onCheckout?: (cartItems: CartItem[], totalAmount: number) => void;
|
|
84
|
+
onProductClick?: (product: Product) => void;
|
|
85
|
+
className?: string;
|
|
86
|
+
gridClassName?: string;
|
|
87
|
+
children?: React.ReactNode;
|
|
88
|
+
id?: string;
|
|
89
|
+
funcss?: string;
|
|
90
|
+
bg?: string;
|
|
91
|
+
color?: string;
|
|
92
|
+
fullWidth?: boolean;
|
|
93
|
+
small?: boolean;
|
|
94
|
+
big?: boolean;
|
|
95
|
+
itemsPerPage?: number;
|
|
96
|
+
variant?: string;
|
|
97
|
+
};
|
|
98
|
+
declare const Store: React.FC<ProductsPageProps>;
|
|
99
|
+
export default Store;
|