@deneb-ui/ui 2.0.85 → 2.0.87
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/dist/EditableProductCard.d.ts +13 -0
- package/dist/EditableProductCard.js +37 -12
- package/dist/EditableProductDetail.js +5 -4
- package/dist/EditableProductGrid.js +36 -7
- package/dist/EditableProductShowcase.js +21 -10
- package/dist/PlatformProductDetail.js +6 -0
- package/dist/SiteDataProvider.d.ts +11 -0
- package/dist/SiteDataProvider.js +176 -45
- package/dist/cart/useCart.d.ts +1 -0
- package/dist/cart/useCart.js +12 -0
- package/package.json +2 -2
|
@@ -4,16 +4,29 @@ export interface ProductItem {
|
|
|
4
4
|
id?: string | number;
|
|
5
5
|
name?: string;
|
|
6
6
|
title?: string;
|
|
7
|
+
productName?: string;
|
|
8
|
+
itemTitle?: string;
|
|
7
9
|
brand?: string;
|
|
8
10
|
price?: string | number;
|
|
11
|
+
cost?: string | number;
|
|
12
|
+
amount?: string | number;
|
|
13
|
+
productPrice?: string | number;
|
|
14
|
+
compareAtPrice?: string | number;
|
|
9
15
|
originalPrice?: string | number;
|
|
10
16
|
currency?: string;
|
|
11
17
|
description?: string;
|
|
18
|
+
desc?: string;
|
|
19
|
+
details?: string;
|
|
12
20
|
category?: string;
|
|
13
21
|
imageUrl?: string;
|
|
14
22
|
image?: string;
|
|
23
|
+
photo?: string;
|
|
24
|
+
thumbnail?: string;
|
|
25
|
+
productImage?: string;
|
|
26
|
+
gallery?: string[];
|
|
15
27
|
images?: string[];
|
|
16
28
|
badge?: string;
|
|
29
|
+
tag?: string;
|
|
17
30
|
rating?: number | string;
|
|
18
31
|
reviewsCount?: number | string;
|
|
19
32
|
isNew?: boolean;
|
|
@@ -20,18 +20,43 @@ function CartIcon({ className = '', style = {} }) {
|
|
|
20
20
|
*/
|
|
21
21
|
function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass', imageFallback, as: Component = 'article', currency = 'LKR', showBrand = true, showPrice = true, showDescription = true, showCategory = true, whatsappNumber = '94770000000', storeName, showWhatsAppButton = true, showAddToCartButton = true, whatsappActionLabel = 'Inquire on WhatsApp', addToCartLabel = 'Add to Cart', actionSlot, actionLabel, actionLabelPath, onAddToCart, onWhatsAppClick, className = '', style, ...props }) {
|
|
22
22
|
const cart = (0, useCart_1.useOptionalCart)();
|
|
23
|
-
const
|
|
23
|
+
const titleKey = 'title' in (product || {}) && !('name' in (product || {}) && product.name)
|
|
24
|
+
? 'title'
|
|
25
|
+
: ('productName' in (product || {}) && !('name' in (product || {}) && product.name)
|
|
26
|
+
? 'productName'
|
|
27
|
+
: 'name');
|
|
28
|
+
const name = String(product?.name || product?.title || product?.productName || product?.itemTitle || 'Untitled Product');
|
|
24
29
|
const brand = String(product?.brand || '');
|
|
25
|
-
const
|
|
26
|
-
const
|
|
30
|
+
const rawPriceCandidate = product?.price ?? product?.cost ?? product?.amount ?? product?.productPrice;
|
|
31
|
+
const hasPrice = showPrice && rawPriceCandidate !== undefined && rawPriceCandidate !== null && String(rawPriceCandidate).trim() !== '';
|
|
32
|
+
const rawPrice = rawPriceCandidate;
|
|
27
33
|
const priceNum = typeof rawPrice === 'number' ? rawPrice : parseFloat(String(rawPrice || '').replace(/[^0-9.]/g, '')) || 0;
|
|
28
34
|
const formattedPrice = hasPrice ? (typeof rawPrice === 'string' && rawPrice.includes('LKR') ? rawPrice : (0, useCart_1.formatCurrency)(priceNum, currency)) : '';
|
|
29
|
-
const
|
|
30
|
-
|
|
35
|
+
const priceKey = 'cost' in (product || {}) && !('price' in (product || {}) && product.price !== undefined)
|
|
36
|
+
? 'cost'
|
|
37
|
+
: ('amount' in (product || {}) && !('price' in (product || {}) && product.price !== undefined)
|
|
38
|
+
? 'amount'
|
|
39
|
+
: 'price');
|
|
40
|
+
const rawOriginalPrice = product?.originalPrice ?? product?.compareAtPrice;
|
|
41
|
+
const originalPrice = rawOriginalPrice !== undefined && rawOriginalPrice !== null ? String(rawOriginalPrice) : '';
|
|
42
|
+
const originalPriceKey = 'compareAtPrice' in (product || {}) && !('originalPrice' in (product || {}) && product.originalPrice !== undefined)
|
|
43
|
+
? 'compareAtPrice'
|
|
44
|
+
: 'originalPrice';
|
|
45
|
+
const descriptionKey = 'desc' in (product || {}) && !('description' in (product || {}) && product.description)
|
|
46
|
+
? 'desc'
|
|
47
|
+
: 'description';
|
|
48
|
+
const description = String(product?.description || product?.desc || product?.details || '');
|
|
31
49
|
const category = String(product?.category || '');
|
|
32
|
-
const
|
|
50
|
+
const badgeKey = 'tag' in (product || {}) && !('badge' in (product || {}) && product.badge) ? 'tag' : 'badge';
|
|
51
|
+
const badge = String(product?.badge || product?.tag || '');
|
|
33
52
|
const fallbackImage = imageFallback || 'https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=800&q=80';
|
|
34
|
-
const
|
|
53
|
+
const rawImage = product?.imageUrl || product?.image || product?.photo || product?.thumbnail || product?.productImage || (Array.isArray(product?.gallery) && product.gallery[0]) || (Array.isArray(product?.images) && product.images[0]);
|
|
54
|
+
const imageUrl = String(rawImage || fallbackImage);
|
|
55
|
+
const imageKey = 'image' in (product || {}) && !('imageUrl' in (product || {}) && product.imageUrl)
|
|
56
|
+
? 'image'
|
|
57
|
+
: ('photo' in (product || {}) && !('imageUrl' in (product || {}) && product.imageUrl)
|
|
58
|
+
? 'photo'
|
|
59
|
+
: 'imageUrl');
|
|
35
60
|
// Resolved phone number for WhatsApp
|
|
36
61
|
const resolvedPhone = String(product?.whatsappNumber || whatsappNumber || '94770000000');
|
|
37
62
|
const resolvedWhatsAppText = String(product?.whatsappButtonText || whatsappActionLabel);
|
|
@@ -113,7 +138,7 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
|
|
|
113
138
|
overflow: 'hidden',
|
|
114
139
|
width: isHorizontal ? '40%' : '100%',
|
|
115
140
|
flexShrink: 0,
|
|
116
|
-
}, children: [(0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}
|
|
141
|
+
}, children: [(0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}.${imageKey}`, "data-preview-field-path": `${itemPath}.${imageKey}`, src: imageUrl, fallbackSrc: imageFallback, alt: name, aspectRatio: isHorizontal ? 'square' : '4/3', fit: "cover", hoverZoom: true, style: { width: '100%', height: '100%', display: 'block' } }), badge && ((0, jsx_runtime_1.jsx)("div", { style: { position: 'absolute', top: '10px', left: '10px', zIndex: 10 }, children: (0, jsx_runtime_1.jsx)(EditableText_2.EditableBadge, { id: `${itemPath}.${badgeKey}`, "data-preview-field-path": `${itemPath}.${badgeKey}`, defaultValue: badge, badgeVariant: "primary" }) }))] }), (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
117
142
|
padding: '1.25rem',
|
|
118
143
|
display: 'flex',
|
|
119
144
|
flexDirection: 'column',
|
|
@@ -135,13 +160,13 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
|
|
|
135
160
|
backgroundColor: 'var(--tag-bg, var(--color-secondary, rgba(241, 245, 249, 0.9)))',
|
|
136
161
|
padding: '2px 8px',
|
|
137
162
|
borderRadius: '6px',
|
|
138
|
-
} })) : null] }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: `${itemPath}
|
|
163
|
+
} })) : null] }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: `${itemPath}.${titleKey}`, "data-preview-field-path": `${itemPath}.${titleKey}`, defaultValue: name, style: {
|
|
139
164
|
fontSize: '1.125rem',
|
|
140
165
|
fontWeight: 700,
|
|
141
166
|
lineHeight: 1.35,
|
|
142
167
|
color: 'var(--heading-color, #ffffff)',
|
|
143
168
|
marginBottom: '0.375rem',
|
|
144
|
-
} }), showDescription && description ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: `${itemPath}
|
|
169
|
+
} }), showDescription && description ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: `${itemPath}.${descriptionKey}`, "data-preview-field-path": `${itemPath}.${descriptionKey}`, defaultValue: description, style: {
|
|
145
170
|
fontSize: '0.875rem',
|
|
146
171
|
color: 'var(--muted-text, #94a3b8)',
|
|
147
172
|
lineHeight: 1.5,
|
|
@@ -157,12 +182,12 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
|
|
|
157
182
|
display: 'flex',
|
|
158
183
|
flexDirection: 'column',
|
|
159
184
|
gap: '0.75rem',
|
|
160
|
-
}, children: [hasPrice ? ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'baseline', gap: '0.5rem', flexWrap: 'wrap' }, children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}
|
|
185
|
+
}, children: [hasPrice ? ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'baseline', gap: '0.5rem', flexWrap: 'wrap' }, children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.${priceKey}`, "data-preview-field-path": `${itemPath}.${priceKey}`, defaultValue: formattedPrice, style: {
|
|
161
186
|
fontSize: '1.3rem',
|
|
162
187
|
fontWeight: 800,
|
|
163
188
|
color: 'var(--brand-color, #ffffff)',
|
|
164
189
|
letterSpacing: '-0.02em',
|
|
165
|
-
} }), originalPrice ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}
|
|
190
|
+
} }), originalPrice ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.${originalPriceKey}`, "data-preview-field-path": `${itemPath}.${originalPriceKey}`, defaultValue: originalPrice, style: {
|
|
166
191
|
fontSize: '0.875rem',
|
|
167
192
|
textDecoration: 'line-through',
|
|
168
193
|
color: 'var(--muted-text, #94a3b8)',
|
|
@@ -29,9 +29,9 @@ function EditableProductDetail({ sectionPath = 'product', product, sizes, colors
|
|
|
29
29
|
? product.gallery
|
|
30
30
|
: (product.images && product.images.length > 0)
|
|
31
31
|
? product.images
|
|
32
|
-
: [product.featuredImage || product.imageUrl || product.image || '/products/vanta-aero-x.jpg'];
|
|
32
|
+
: [product.featuredImage || product.imageUrl || product.image || product.photo || product.thumbnail || '/products/vanta-aero-x.jpg'];
|
|
33
33
|
return rawList.filter(Boolean);
|
|
34
|
-
}, [product.gallery, product.images, product.featuredImage, product.imageUrl, product.image]);
|
|
34
|
+
}, [product.gallery, product.images, product.featuredImage, product.imageUrl, product.image, product.photo, product.thumbnail]);
|
|
35
35
|
// 2. Resolve Options (Sizes, Volumes, Weights, Counts)
|
|
36
36
|
const resolved = (0, productOptions_1.resolveProductOptions)(product);
|
|
37
37
|
const effectiveOptions = (0, react_1.useMemo)(() => {
|
|
@@ -106,8 +106,9 @@ function EditableProductDetail({ sectionPath = 'product', product, sizes, colors
|
|
|
106
106
|
setActiveImage(c.image);
|
|
107
107
|
}
|
|
108
108
|
};
|
|
109
|
-
const name = String(product.name || product.title || 'Product Title');
|
|
110
|
-
const
|
|
109
|
+
const name = String(product.name || product.title || product.productName || product.itemTitle || 'Product Title');
|
|
110
|
+
const rawPriceCandidate = product.price ?? product.cost ?? product.amount ?? product.productPrice;
|
|
111
|
+
const price = rawPriceCandidate !== undefined && rawPriceCandidate !== null ? String(rawPriceCandidate) : 'LKR 0';
|
|
111
112
|
const originalPrice = product.originalPrice ?? product.compareAtPrice;
|
|
112
113
|
const isAvailable = product.isAvailable !== false;
|
|
113
114
|
const description = String(product.description || '');
|
|
@@ -20,6 +20,33 @@ function EditableProductGrid({ sectionPath = 'home', listPath = 'products', titl
|
|
|
20
20
|
const siteApi = (0, SiteDataProvider_1.useSiteApi)();
|
|
21
21
|
const liveProducts = (0, SiteDataProvider_1.useProducts)();
|
|
22
22
|
const baseProducts = userProducts && userProducts.length > 0 ? userProducts : liveProducts;
|
|
23
|
+
const resolvedListPath = (0, react_1.useMemo)(() => {
|
|
24
|
+
if (listPath && listPath !== 'products') {
|
|
25
|
+
return listPath;
|
|
26
|
+
}
|
|
27
|
+
const content = (0, SiteDataProvider_1.isRecord)(siteData?.content) ? siteData.content : null;
|
|
28
|
+
if (!content)
|
|
29
|
+
return listPath || 'products';
|
|
30
|
+
if (Array.isArray(content.products) && content.products.length > 0)
|
|
31
|
+
return 'products';
|
|
32
|
+
if ((0, SiteDataProvider_1.isRecord)(content.shop) && Array.isArray(content.shop.products))
|
|
33
|
+
return 'shop.products';
|
|
34
|
+
if ((0, SiteDataProvider_1.isRecord)(content.home) && Array.isArray(content.home.products))
|
|
35
|
+
return 'home.products';
|
|
36
|
+
if ((0, SiteDataProvider_1.isRecord)(content.home) && Array.isArray(content.home.featuredProducts))
|
|
37
|
+
return 'home.featuredProducts';
|
|
38
|
+
if ((0, SiteDataProvider_1.isRecord)(content.catalog) && Array.isArray(content.catalog.products))
|
|
39
|
+
return 'catalog.products';
|
|
40
|
+
if ((0, SiteDataProvider_1.isRecord)(content.menu) && Array.isArray(content.menu.items))
|
|
41
|
+
return 'menu.items';
|
|
42
|
+
if ((0, SiteDataProvider_1.isRecord)(content.menu) && Array.isArray(content.menu.products))
|
|
43
|
+
return 'menu.products';
|
|
44
|
+
if ((0, SiteDataProvider_1.isRecord)(content.store) && Array.isArray(content.store.products))
|
|
45
|
+
return 'store.products';
|
|
46
|
+
if ((0, SiteDataProvider_1.isRecord)(content.shop) && Array.isArray(content.shop.items))
|
|
47
|
+
return 'shop.items';
|
|
48
|
+
return listPath || 'products';
|
|
49
|
+
}, [listPath, siteData]);
|
|
23
50
|
const [searchQuery, setSearchQuery] = (0, react_1.useState)('');
|
|
24
51
|
const [isSearchingBackend, setIsSearchingBackend] = (0, react_1.useState)(false);
|
|
25
52
|
const [backendProducts, setBackendProducts] = (0, react_1.useState)(null);
|
|
@@ -103,12 +130,13 @@ function EditableProductGrid({ sectionPath = 'home', listPath = 'products', titl
|
|
|
103
130
|
if (searchQuery.trim()) {
|
|
104
131
|
const q = searchQuery.trim().toLowerCase();
|
|
105
132
|
result = result.filter((p) => {
|
|
106
|
-
const name = String(p.name || p.title || '').toLowerCase();
|
|
107
|
-
const desc = String(p.description || '').toLowerCase();
|
|
133
|
+
const name = String(p.name || p.title || p.productName || p.itemTitle || '').toLowerCase();
|
|
134
|
+
const desc = String(p.description || p.desc || p.details || '').toLowerCase();
|
|
108
135
|
const brand = String(p.brand || '').toLowerCase();
|
|
109
136
|
const cat = String(p.category || '').toLowerCase();
|
|
110
137
|
const tags = Array.isArray(p.tags) ? p.tags.join(' ').toLowerCase() : '';
|
|
111
|
-
|
|
138
|
+
const badge = String(p.badge || p.tag || '').toLowerCase();
|
|
139
|
+
return name.includes(q) || desc.includes(q) || brand.includes(q) || cat.includes(q) || tags.includes(q) || badge.includes(q);
|
|
112
140
|
});
|
|
113
141
|
}
|
|
114
142
|
return result;
|
|
@@ -178,16 +206,17 @@ function EditableProductGrid({ sectionPath = 'home', listPath = 'products', titl
|
|
|
178
206
|
}, placeholder: searchPlaceholder, className: "w-full pl-10 pr-10 py-2.5 rounded-2xl text-sm bg-slate-100/90 dark:bg-slate-900/90 border border-slate-200 dark:border-slate-800 text-slate-900 dark:text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-lime-400 dark:focus:ring-lime-400 transition-all shadow-sm" }), searchQuery && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => {
|
|
179
207
|
setSearchQuery('');
|
|
180
208
|
onSearchChange?.('');
|
|
181
|
-
}, className: "absolute inset-y-0 right-0 pr-3.5 flex items-center text-slate-400 hover:text-slate-600 dark:hover:text-white transition-colors", title: "Clear search", children: (0, jsx_runtime_1.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3 text-xs text-slate-500 dark:text-slate-400", children: [isSearchingBackend && ((0, jsx_runtime_1.jsxs)("span", { className: "inline-flex items-center gap-1.5 text-emerald-600 dark:text-lime-400 font-medium animate-pulse", children: [(0, jsx_runtime_1.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-lime-400" }), "Searching live catalog..."] })), (0, jsx_runtime_1.jsxs)("span", { className: "font-semibold bg-slate-100 dark:bg-slate-900/80 px-3 py-1.5 rounded-xl border border-slate-200/80 dark:border-slate-800", children: ["Showing ", (0, jsx_runtime_1.jsx)("span", { className: "text-slate-900 dark:text-white font-bold", children: filteredProducts.length }), " of ", products.length, " products"] })] })] })), (0, jsx_runtime_1.jsx)("div", { ...(
|
|
209
|
+
}, className: "absolute inset-y-0 right-0 pr-3.5 flex items-center text-slate-400 hover:text-slate-600 dark:hover:text-white transition-colors", title: "Clear search", children: (0, jsx_runtime_1.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3 text-xs text-slate-500 dark:text-slate-400", children: [isSearchingBackend && ((0, jsx_runtime_1.jsxs)("span", { className: "inline-flex items-center gap-1.5 text-emerald-600 dark:text-lime-400 font-medium animate-pulse", children: [(0, jsx_runtime_1.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-lime-400" }), "Searching live catalog..."] })), (0, jsx_runtime_1.jsxs)("span", { className: "font-semibold bg-slate-100 dark:bg-slate-900/80 px-3 py-1.5 rounded-xl border border-slate-200/80 dark:border-slate-800", children: ["Showing ", (0, jsx_runtime_1.jsx)("span", { className: "text-slate-900 dark:text-white font-bold", children: filteredProducts.length }), " of ", products.length, " products"] })] })] })), (0, jsx_runtime_1.jsx)("div", { ...(resolvedListPath ? { 'data-preview-list-path': resolvedListPath } : {}), className: displayedProducts.length > 0
|
|
182
210
|
? `deneb-product-grid grid ${gridColClasses} gap-6 sm:gap-8`
|
|
183
211
|
: 'deneb-product-grid-empty w-full', children: displayedProducts.length > 0 ? (displayedProducts.map((product, idx) => {
|
|
184
212
|
// Determine true index in baseProducts for exact Fivora visual editing focus targeting
|
|
185
213
|
const baseIndex = baseProducts.findIndex((bp) => (bp.id && product.id ? String(bp.id) === String(product.id) : false) ||
|
|
186
214
|
(bp.name && product.name ? bp.name === product.name : false) ||
|
|
187
|
-
(bp.title && product.title ? bp.title === product.title : false)
|
|
215
|
+
(bp.title && product.title ? bp.title === product.title : false) ||
|
|
216
|
+
(bp.productName && product.productName ? bp.productName === product.productName : false));
|
|
188
217
|
const effectiveIndex = baseIndex !== -1 ? baseIndex : (activePage - 1) * activePageSize + idx;
|
|
189
|
-
const itemPath =
|
|
190
|
-
? `${
|
|
218
|
+
const itemPath = resolvedListPath
|
|
219
|
+
? `${resolvedListPath}[${effectiveIndex}]`
|
|
191
220
|
: `${sectionPath}.${cardPrefix}${effectiveIndex + 1}`;
|
|
192
221
|
return ((0, jsx_runtime_1.jsxs)("div", { "data-preview-item-path": itemPath, className: "relative group", children: [(0, jsx_runtime_1.jsx)(EditableProductCard_1.EditableProductCard, { itemPath: itemPath, product: product, cardVariant: cardVariant, className: "h-full" }), onQuickView && ((0, jsx_runtime_1.jsx)("div", { className: "absolute top-4 right-4 z-20 opacity-0 group-hover:opacity-100 transition-opacity duration-200", children: (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => onQuickView(product, itemPath), className: "p-2.5 rounded-xl bg-slate-950/80 backdrop-blur-md text-white hover:bg-lime-400 hover:text-slate-950 shadow-lg transition-all active:scale-95", title: "Quick View", "aria-label": `Quick View ${product.name || product.title}`, children: (0, jsx_runtime_1.jsxs)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }), (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" })] }) }) }))] }, product.id || idx));
|
|
193
222
|
})) : (
|
|
@@ -99,23 +99,34 @@ function EditableProductShowcase({ sectionPath = 'home', listPath = 'featuredPho
|
|
|
99
99
|
return { name: `Color ${cIdx + 1}`, hex: c };
|
|
100
100
|
return { name: c?.name || `Color ${cIdx + 1}`, hex: c?.hex || '#9d9890' };
|
|
101
101
|
});
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
const rawImage = item.image || item.imageUrl || item.photo || item.thumbnail || (Array.isArray(item.images) && item.images[0]);
|
|
103
|
+
const resolvedImage = typeof rawImage === 'string' && rawImage.trim() !== ''
|
|
104
|
+
? rawImage
|
|
105
|
+
: (def.image || '/images/showcase-phone.jpg');
|
|
106
|
+
const rawPrice = item.price ?? item.cost ?? item.amount ?? item.productPrice;
|
|
107
|
+
const parsedPrice = typeof rawPrice === 'number'
|
|
108
|
+
? rawPrice
|
|
109
|
+
: typeof rawPrice === 'string'
|
|
110
|
+
? parseFloat(rawPrice.replace(/[^0-9.]/g, ''))
|
|
111
|
+
: NaN;
|
|
112
|
+
const finalPrice = Number.isFinite(parsedPrice) ? parsedPrice : def.price;
|
|
113
|
+
const rawOrig = item.originalPrice ?? item.compareAtPrice;
|
|
114
|
+
const parsedOrig = typeof rawOrig === 'number'
|
|
115
|
+
? rawOrig
|
|
116
|
+
: typeof rawOrig === 'string'
|
|
117
|
+
? parseFloat(rawOrig.replace(/[^0-9.]/g, ''))
|
|
118
|
+
: NaN;
|
|
119
|
+
const finalOrig = Number.isFinite(parsedOrig) ? parsedOrig : def.originalPrice;
|
|
107
120
|
return {
|
|
108
121
|
...def,
|
|
109
122
|
...item,
|
|
110
123
|
_index: idx,
|
|
111
124
|
id: item.id || `product-${idx}`,
|
|
112
|
-
name: item.name || item.title || def.name,
|
|
125
|
+
name: item.name || item.title || item.productName || item.itemTitle || def.name,
|
|
113
126
|
brand: item.brand || item.category || def.brand || 'Store',
|
|
114
127
|
subtitle: item.subtitle || def.subtitle || '',
|
|
115
|
-
price:
|
|
116
|
-
originalPrice:
|
|
117
|
-
? Number(item.originalPrice)
|
|
118
|
-
: (item.compareAtPrice != null ? Number(item.compareAtPrice) : def.originalPrice),
|
|
128
|
+
price: finalPrice,
|
|
129
|
+
originalPrice: finalOrig,
|
|
119
130
|
condition: item.condition || def.condition || 'Brand New',
|
|
120
131
|
category: item.category || item.brand || def.category || 'All',
|
|
121
132
|
badge: item.badge || def.badge || '',
|
|
@@ -70,11 +70,16 @@ function normalizeProductForDetail(product, siteData) {
|
|
|
70
70
|
};
|
|
71
71
|
const name = (typeof mergedProduct.name === 'string' && mergedProduct.name) ||
|
|
72
72
|
(typeof mergedProduct.title === 'string' && mergedProduct.title) ||
|
|
73
|
+
(typeof mergedProduct.productName === 'string' && mergedProduct.productName) ||
|
|
74
|
+
(typeof mergedProduct.itemTitle === 'string' && mergedProduct.itemTitle) ||
|
|
73
75
|
undefined;
|
|
74
76
|
const image = (typeof mergedProduct.featuredImage === 'string' && mergedProduct.featuredImage) ||
|
|
75
77
|
(typeof mergedProduct.imageUrl === 'string' && mergedProduct.imageUrl) ||
|
|
76
78
|
(typeof mergedProduct.image === 'string' && mergedProduct.image) ||
|
|
79
|
+
(typeof mergedProduct.photo === 'string' && mergedProduct.photo) ||
|
|
80
|
+
(typeof mergedProduct.thumbnail === 'string' && mergedProduct.thumbnail) ||
|
|
77
81
|
undefined;
|
|
82
|
+
const price = mergedProduct.price ?? mergedProduct.cost ?? mergedProduct.amount ?? mergedProduct.productPrice;
|
|
78
83
|
const images = Array.isArray(mergedProduct.gallery)
|
|
79
84
|
? mergedProduct.gallery
|
|
80
85
|
: Array.isArray(mergedProduct.images)
|
|
@@ -103,6 +108,7 @@ function normalizeProductForDetail(product, siteData) {
|
|
|
103
108
|
...(image
|
|
104
109
|
? { featuredImage: image, imageUrl: image, image }
|
|
105
110
|
: {}),
|
|
111
|
+
...(price !== undefined ? { price } : {}),
|
|
106
112
|
...(images ? { gallery: images, images } : {}),
|
|
107
113
|
...(compareAtPrice !== undefined
|
|
108
114
|
? { compareAtPrice, originalPrice: compareAtPrice }
|
|
@@ -106,6 +106,17 @@ export type DenebData = SiteData;
|
|
|
106
106
|
* Hook to retrieve products cleanly from SiteData, supporting both
|
|
107
107
|
* top-level content.products and nested content.home.products.
|
|
108
108
|
*/
|
|
109
|
+
/**
|
|
110
|
+
* Universal Bidirectional Product Normalizer:
|
|
111
|
+
* Ensures every product object has both canonical and alias keys simultaneously populated
|
|
112
|
+
* with clean numbers and resolved image URLs, so any template component code works flawlessly
|
|
113
|
+
* regardless of whether the developer wrote .title or .name, .cost or .price, .image or .imageUrl.
|
|
114
|
+
*/
|
|
115
|
+
export declare function normalizeProductItem(p: unknown): ProductItem;
|
|
116
|
+
/**
|
|
117
|
+
* Universal Service Normalizer
|
|
118
|
+
*/
|
|
119
|
+
export declare function normalizeServiceItem(s: unknown): ServiceItem;
|
|
109
120
|
export declare function useProducts(fallback?: ProductItem[]): ProductItem[];
|
|
110
121
|
/**
|
|
111
122
|
* Hook to retrieve services cleanly from SiteData, supporting both
|
package/dist/SiteDataProvider.js
CHANGED
|
@@ -18,6 +18,8 @@ exports.contentNumber = contentNumber;
|
|
|
18
18
|
exports.parseFieldPath = parseFieldPath;
|
|
19
19
|
exports.getFieldStyle = getFieldStyle;
|
|
20
20
|
exports.useFieldStyle = useFieldStyle;
|
|
21
|
+
exports.normalizeProductItem = normalizeProductItem;
|
|
22
|
+
exports.normalizeServiceItem = normalizeServiceItem;
|
|
21
23
|
exports.useProducts = useProducts;
|
|
22
24
|
exports.useServices = useServices;
|
|
23
25
|
exports.useSiteApi = useSiteApi;
|
|
@@ -263,20 +265,8 @@ function SiteDataProvider({ children, initialSiteData, fallbackSiteData, liveCat
|
|
|
263
265
|
const currentCommon = isRecord(currentContent.common) ? currentContent.common : {};
|
|
264
266
|
const currentContact = isRecord(currentContent.contact) ? currentContent.contact : {};
|
|
265
267
|
const rawLiveProducts = Array.isArray(live.products) ? live.products : currentContent.products;
|
|
266
|
-
const nextProducts = Array.isArray(rawLiveProducts)
|
|
267
|
-
|
|
268
|
-
if (!isRecord(p))
|
|
269
|
-
return p;
|
|
270
|
-
const customData = isRecord(p.customData) ? p.customData : {};
|
|
271
|
-
return {
|
|
272
|
-
...customData,
|
|
273
|
-
...p,
|
|
274
|
-
};
|
|
275
|
-
})
|
|
276
|
-
: rawLiveProducts;
|
|
277
|
-
const nextServices = Array.isArray(live.services)
|
|
278
|
-
? live.services
|
|
279
|
-
: currentContent.services;
|
|
268
|
+
const nextProducts = Array.isArray(rawLiveProducts) ? rawLiveProducts.map(normalizeProductItem) : rawLiveProducts;
|
|
269
|
+
const nextServices = Array.isArray(live.services) ? live.services.map(normalizeServiceItem) : currentContent.services;
|
|
280
270
|
const nextReviews = Array.isArray(live.reviews)
|
|
281
271
|
? live.reviews
|
|
282
272
|
: null;
|
|
@@ -296,6 +286,7 @@ function SiteDataProvider({ children, initialSiteData, fallbackSiteData, liveCat
|
|
|
296
286
|
nextContact.phone = contact.phone;
|
|
297
287
|
nextContact.contactNumber = contact.phone;
|
|
298
288
|
nextCommon.contactNumber = contact.phone;
|
|
289
|
+
nextCommon.phone = contact.phone;
|
|
299
290
|
}
|
|
300
291
|
if (typeof contact.whatsapp === 'string' && contact.whatsapp.trim()) {
|
|
301
292
|
nextContact.whatsapp = contact.whatsapp;
|
|
@@ -304,6 +295,7 @@ function SiteDataProvider({ children, initialSiteData, fallbackSiteData, liveCat
|
|
|
304
295
|
if (cleanWa) {
|
|
305
296
|
nextContact.whatsappNumber = cleanWa;
|
|
306
297
|
nextCommon.whatsappNumber = cleanWa;
|
|
298
|
+
nextHome.whatsappNumber = cleanWa;
|
|
307
299
|
// Dynamically update any hardcoded or static wa.me URLs across home and common
|
|
308
300
|
const waRegex = /(https?:\/\/(?:wa\.me|api\.whatsapp\.com\/send\?phone=))\d+/gi;
|
|
309
301
|
for (const key of ['whatsappCtaUrl', 'whatsappOrderUrl', 'whatsappUrl']) {
|
|
@@ -341,6 +333,7 @@ function SiteDataProvider({ children, initialSiteData, fallbackSiteData, liveCat
|
|
|
341
333
|
nextContact.hours = live.shop.openingHours;
|
|
342
334
|
nextContact.openingHours = live.shop.openingHours;
|
|
343
335
|
nextCommon.openingHours = live.shop.openingHours;
|
|
336
|
+
nextCommon.hours = live.shop.openingHours;
|
|
344
337
|
nextHome.businessHours = live.shop.openingHours;
|
|
345
338
|
}
|
|
346
339
|
if (typeof live.shop.businessName === 'string' && live.shop.businessName.trim()) {
|
|
@@ -368,6 +361,18 @@ function SiteDataProvider({ children, initialSiteData, fallbackSiteData, liveCat
|
|
|
368
361
|
...(nextProducts !== undefined ? { products: nextProducts } : {}),
|
|
369
362
|
...(nextServices !== undefined ? { services: nextServices } : {}),
|
|
370
363
|
...(nextReviews !== null ? { reviews: nextReviews, testimonials: nextReviews, feedbacks: nextReviews } : {}),
|
|
364
|
+
...(currentContent?.shop && typeof currentContent.shop === 'object' && nextProducts !== undefined
|
|
365
|
+
? { shop: { ...currentContent.shop, products: nextProducts } }
|
|
366
|
+
: {}),
|
|
367
|
+
...(currentContent?.catalog && typeof currentContent.catalog === 'object' && nextProducts !== undefined
|
|
368
|
+
? { catalog: { ...currentContent.catalog, products: nextProducts } }
|
|
369
|
+
: {}),
|
|
370
|
+
...(currentContent?.menu && typeof currentContent.menu === 'object' && nextProducts !== undefined
|
|
371
|
+
? { menu: { ...currentContent.menu, items: nextProducts, products: nextProducts } }
|
|
372
|
+
: {}),
|
|
373
|
+
...(currentContent?.store && typeof currentContent.store === 'object' && nextProducts !== undefined
|
|
374
|
+
? { store: { ...currentContent.store, products: nextProducts } }
|
|
375
|
+
: {}),
|
|
371
376
|
...(currentHome || Object.keys(nextHome).length > 0
|
|
372
377
|
? {
|
|
373
378
|
home: {
|
|
@@ -681,37 +686,162 @@ exports.DenebDataContext = exports.SiteDataContext;
|
|
|
681
686
|
* Hook to retrieve products cleanly from SiteData, supporting both
|
|
682
687
|
* top-level content.products and nested content.home.products.
|
|
683
688
|
*/
|
|
689
|
+
/**
|
|
690
|
+
* Universal Bidirectional Product Normalizer:
|
|
691
|
+
* Ensures every product object has both canonical and alias keys simultaneously populated
|
|
692
|
+
* with clean numbers and resolved image URLs, so any template component code works flawlessly
|
|
693
|
+
* regardless of whether the developer wrote .title or .name, .cost or .price, .image or .imageUrl.
|
|
694
|
+
*/
|
|
695
|
+
function normalizeProductItem(p) {
|
|
696
|
+
if (!isRecord(p))
|
|
697
|
+
return p;
|
|
698
|
+
const customData = isRecord(p.customData) ? p.customData : {};
|
|
699
|
+
const nameCandidate = p.name ?? p.title ?? p.productName ?? p.itemTitle ?? p.heading ?? p.label;
|
|
700
|
+
const titleCandidate = p.title ?? p.name ?? p.itemTitle ?? p.productName ?? p.heading ?? p.label;
|
|
701
|
+
const rawPrice = p.price !== undefined
|
|
702
|
+
? p.price
|
|
703
|
+
: p.cost !== undefined
|
|
704
|
+
? p.cost
|
|
705
|
+
: p.amount !== undefined
|
|
706
|
+
? p.amount
|
|
707
|
+
: p.productPrice !== undefined
|
|
708
|
+
? p.productPrice
|
|
709
|
+
: p.currentPrice !== undefined
|
|
710
|
+
? p.currentPrice
|
|
711
|
+
: p.rate;
|
|
712
|
+
let numPrice = rawPrice;
|
|
713
|
+
if (typeof rawPrice === "string" && rawPrice.trim()) {
|
|
714
|
+
const match = rawPrice.match(/-?\d+(?:,\d{3})*(?:\.\d+)?|-?\d+(?:\.\d+)?/);
|
|
715
|
+
if (match) {
|
|
716
|
+
const parsed = parseFloat(match[0].replace(/,/g, ""));
|
|
717
|
+
if (!isNaN(parsed) && Number.isFinite(parsed)) {
|
|
718
|
+
numPrice = parsed;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
const rawCompare = p.compareAtPrice !== undefined
|
|
723
|
+
? p.compareAtPrice
|
|
724
|
+
: p.originalPrice !== undefined
|
|
725
|
+
? p.originalPrice
|
|
726
|
+
: p.oldPrice !== undefined
|
|
727
|
+
? p.oldPrice
|
|
728
|
+
: p.regularPrice !== undefined
|
|
729
|
+
? p.regularPrice
|
|
730
|
+
: p.strikePrice;
|
|
731
|
+
let numCompare = rawCompare;
|
|
732
|
+
if (typeof rawCompare === "string" && rawCompare.trim()) {
|
|
733
|
+
const match = rawCompare.match(/-?\d+(?:,\d{3})*(?:\.\d+)?|-?\d+(?:\.\d+)?/);
|
|
734
|
+
if (match) {
|
|
735
|
+
const parsed = parseFloat(match[0].replace(/,/g, ""));
|
|
736
|
+
if (!isNaN(parsed) && Number.isFinite(parsed)) {
|
|
737
|
+
numCompare = parsed;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
const imageCandidate = p.imageUrl ??
|
|
742
|
+
p.image ??
|
|
743
|
+
p.photo ??
|
|
744
|
+
p.thumbnail ??
|
|
745
|
+
p.picture ??
|
|
746
|
+
p.img ??
|
|
747
|
+
p.src ??
|
|
748
|
+
p.productImage ??
|
|
749
|
+
(Array.isArray(p.gallery) ? p.gallery[0] : undefined) ??
|
|
750
|
+
(Array.isArray(p.images) ? p.images[0] : undefined);
|
|
751
|
+
const badgeCandidate = p.badge ?? p.tag ?? p.label ?? p.badgeText ?? p.chip;
|
|
752
|
+
const descCandidate = p.description ?? p.desc ?? p.details ?? p.shortDescription ?? p.subtitle;
|
|
753
|
+
return {
|
|
754
|
+
...customData,
|
|
755
|
+
...p,
|
|
756
|
+
name: nameCandidate,
|
|
757
|
+
title: titleCandidate,
|
|
758
|
+
productName: (titleCandidate ?? nameCandidate),
|
|
759
|
+
itemTitle: (titleCandidate ?? nameCandidate),
|
|
760
|
+
...(numPrice !== undefined
|
|
761
|
+
? {
|
|
762
|
+
price: numPrice,
|
|
763
|
+
cost: numPrice,
|
|
764
|
+
amount: numPrice,
|
|
765
|
+
productPrice: numPrice,
|
|
766
|
+
}
|
|
767
|
+
: {}),
|
|
768
|
+
...(numCompare !== undefined
|
|
769
|
+
? {
|
|
770
|
+
compareAtPrice: numCompare,
|
|
771
|
+
originalPrice: numCompare,
|
|
772
|
+
}
|
|
773
|
+
: {}),
|
|
774
|
+
...(imageCandidate !== undefined
|
|
775
|
+
? {
|
|
776
|
+
imageUrl: imageCandidate,
|
|
777
|
+
image: imageCandidate,
|
|
778
|
+
photo: imageCandidate,
|
|
779
|
+
thumbnail: imageCandidate,
|
|
780
|
+
productImage: imageCandidate,
|
|
781
|
+
}
|
|
782
|
+
: {}),
|
|
783
|
+
...(badgeCandidate !== undefined
|
|
784
|
+
? {
|
|
785
|
+
badge: badgeCandidate,
|
|
786
|
+
tag: badgeCandidate,
|
|
787
|
+
}
|
|
788
|
+
: {}),
|
|
789
|
+
...(descCandidate !== undefined
|
|
790
|
+
? {
|
|
791
|
+
description: descCandidate,
|
|
792
|
+
desc: descCandidate,
|
|
793
|
+
details: descCandidate,
|
|
794
|
+
}
|
|
795
|
+
: {}),
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Universal Service Normalizer
|
|
800
|
+
*/
|
|
801
|
+
function normalizeServiceItem(s) {
|
|
802
|
+
if (!isRecord(s))
|
|
803
|
+
return s;
|
|
804
|
+
const customData = isRecord(s.customData) ? s.customData : {};
|
|
805
|
+
const nameCandidate = s.name ?? s.title ?? s.serviceName ?? s.heading;
|
|
806
|
+
const titleCandidate = s.title ?? s.name ?? s.serviceName ?? s.heading;
|
|
807
|
+
const descCandidate = s.description ?? s.desc ?? s.details ?? s.shortDescription;
|
|
808
|
+
const imageCandidate = s.imageUrl ?? s.image ?? s.photo ?? s.thumbnail ?? s.picture;
|
|
809
|
+
return {
|
|
810
|
+
...customData,
|
|
811
|
+
...s,
|
|
812
|
+
name: nameCandidate,
|
|
813
|
+
title: titleCandidate,
|
|
814
|
+
...(descCandidate !== undefined ? { description: descCandidate, desc: descCandidate, details: descCandidate } : {}),
|
|
815
|
+
...(imageCandidate !== undefined ? { imageUrl: imageCandidate, image: imageCandidate, photo: imageCandidate } : {}),
|
|
816
|
+
};
|
|
817
|
+
}
|
|
684
818
|
function useProducts(fallback = []) {
|
|
685
819
|
const siteData = useSiteData();
|
|
686
820
|
const content = isRecord(siteData?.content) ? siteData.content : null;
|
|
687
821
|
if (!content)
|
|
688
822
|
return fallback;
|
|
689
823
|
let rawList = null;
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
824
|
+
const candidates = [
|
|
825
|
+
content.products,
|
|
826
|
+
content.shop?.products,
|
|
827
|
+
content.home?.products,
|
|
828
|
+
content.home?.featuredProducts,
|
|
829
|
+
content.catalog?.products,
|
|
830
|
+
content.menu?.items,
|
|
831
|
+
content.menu?.products,
|
|
832
|
+
content.store?.products,
|
|
833
|
+
content.shop?.items,
|
|
834
|
+
siteData.shop?.products,
|
|
835
|
+
];
|
|
836
|
+
for (const candidate of candidates) {
|
|
837
|
+
if (Array.isArray(candidate) && candidate.length > 0) {
|
|
838
|
+
rawList = candidate;
|
|
839
|
+
break;
|
|
702
840
|
}
|
|
703
841
|
}
|
|
704
842
|
if (!rawList)
|
|
705
843
|
return fallback;
|
|
706
|
-
return rawList.map(
|
|
707
|
-
if (!isRecord(p))
|
|
708
|
-
return p;
|
|
709
|
-
const customData = isRecord(p.customData) ? p.customData : {};
|
|
710
|
-
return {
|
|
711
|
-
...customData,
|
|
712
|
-
...p,
|
|
713
|
-
};
|
|
714
|
-
});
|
|
844
|
+
return rawList.map(normalizeProductItem);
|
|
715
845
|
}
|
|
716
846
|
/**
|
|
717
847
|
* Hook to retrieve services cleanly from SiteData, supporting both
|
|
@@ -722,16 +852,17 @@ function useServices(fallback = []) {
|
|
|
722
852
|
const content = isRecord(siteData?.content) ? siteData.content : null;
|
|
723
853
|
if (!content)
|
|
724
854
|
return fallback;
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
855
|
+
const candidates = [
|
|
856
|
+
content.services,
|
|
857
|
+
content.servicesPage?.services,
|
|
858
|
+
content.home?.services,
|
|
859
|
+
content.home?.featuredServices,
|
|
860
|
+
content.company?.services,
|
|
861
|
+
content.business?.services,
|
|
862
|
+
];
|
|
863
|
+
for (const candidate of candidates) {
|
|
864
|
+
if (Array.isArray(candidate) && candidate.length > 0) {
|
|
865
|
+
return candidate.map(normalizeServiceItem);
|
|
735
866
|
}
|
|
736
867
|
}
|
|
737
868
|
return fallback;
|
package/dist/cart/useCart.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface CartItem {
|
|
|
12
12
|
sku?: string;
|
|
13
13
|
metadata?: Record<string, unknown>;
|
|
14
14
|
}
|
|
15
|
+
export declare function parseNumericPrice(value: unknown): number;
|
|
15
16
|
export declare function formatCurrency(amount: number, currency?: string): string;
|
|
16
17
|
export declare function getProductWhatsAppUrl(product: {
|
|
17
18
|
name?: string;
|
package/dist/cart/useCart.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
'use client';
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.parseNumericPrice = parseNumericPrice;
|
|
4
5
|
exports.formatCurrency = formatCurrency;
|
|
5
6
|
exports.getProductWhatsAppUrl = getProductWhatsAppUrl;
|
|
6
7
|
exports.CartProvider = CartProvider;
|
|
@@ -8,6 +9,17 @@ exports.useOptionalCart = useOptionalCart;
|
|
|
8
9
|
exports.useCart = useCart;
|
|
9
10
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
10
11
|
const react_1 = require("react");
|
|
12
|
+
function parseNumericPrice(value) {
|
|
13
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
14
|
+
return value;
|
|
15
|
+
if (typeof value !== "string" || !value.trim())
|
|
16
|
+
return 0;
|
|
17
|
+
const match = value.match(/-?\d+(?:,\d{3})*(?:\.\d+)?|-?\d+(?:\.\d+)?/);
|
|
18
|
+
if (!match)
|
|
19
|
+
return 0;
|
|
20
|
+
const parsed = parseFloat(match[0].replace(/,/g, ""));
|
|
21
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
22
|
+
}
|
|
11
23
|
function formatCurrency(amount, currency = 'LKR') {
|
|
12
24
|
const formatted = (amount || 0).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
13
25
|
if (currency === 'LKR' || currency === 'Rs.' || currency === 'Rs') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deneb-ui/ui",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.87",
|
|
4
4
|
"description": "Visual-first React component library for editable commerce storefronts. Built for Next.js and Fivora.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
],
|
|
51
51
|
"license": "MIT",
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@deneb-ui/core": "^2.0.
|
|
53
|
+
"@deneb-ui/core": "^2.0.87"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"react": "^18.0.0 || ^19.0.0",
|