@o2vend/theme-cli 1.0.35 → 1.0.36
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/lib/lib/dev-server.js +352 -421
- package/lib/lib/liquid-engine.js +88 -65
- package/lib/lib/liquid-filters.js +10 -29
- package/lib/lib/mock-api-server.js +58 -144
- package/lib/lib/mock-data.js +126 -78
- package/lib/lib/widget-service.js +49 -0
- package/package.json +1 -1
package/lib/lib/mock-data.js
CHANGED
|
@@ -10,29 +10,41 @@
|
|
|
10
10
|
function generateMockData() {
|
|
11
11
|
return {
|
|
12
12
|
store: {
|
|
13
|
-
id:
|
|
13
|
+
id: 1,
|
|
14
|
+
identifier: 'mock-store',
|
|
14
15
|
name: 'My O2VEND Store',
|
|
15
|
-
description: 'A beautiful e-commerce store powered by O2VEND',
|
|
16
16
|
domain: 'localhost:3000',
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
city: 'New York',
|
|
22
|
-
state: 'NY',
|
|
23
|
-
zip: '10001',
|
|
24
|
-
country: 'US'
|
|
25
|
-
},
|
|
17
|
+
companyName: 'My O2VEND Store',
|
|
18
|
+
companyAddress: '123 Main Street, New York, NY 10001',
|
|
19
|
+
companyPhoneNumber: '+1234567890',
|
|
20
|
+
companyEmail: 'store@example.com',
|
|
26
21
|
currency: 'USD',
|
|
27
22
|
currencySymbol: '$',
|
|
28
|
-
locale: 'en-US',
|
|
29
23
|
timezone: 'America/New_York',
|
|
24
|
+
language: 'en',
|
|
25
|
+
logoUrl: '/assets/logo.png',
|
|
26
|
+
favouriteIconUrl: '/favicon.ico',
|
|
30
27
|
settings: {
|
|
28
|
+
currency: 'USD',
|
|
31
29
|
currencySymbol: '$',
|
|
32
30
|
currencyFormat: '#,##0.00',
|
|
33
31
|
currencyDecimalDigits: 2,
|
|
34
32
|
currencyGroupSeparator: ',',
|
|
35
|
-
currencyDecimalSeparator: '.'
|
|
33
|
+
currencyDecimalSeparator: '.',
|
|
34
|
+
currencyGroupSizes: [3],
|
|
35
|
+
deliveryZoneSupport: false,
|
|
36
|
+
deliveryZoneSelection: 0,
|
|
37
|
+
defaultDeliveryZoneZipCode: null,
|
|
38
|
+
loginTypes: null,
|
|
39
|
+
zipcodeSearchEnabled: false,
|
|
40
|
+
referEnabled: false,
|
|
41
|
+
shoppingCartIconType: null,
|
|
42
|
+
timezone: 'America/New_York',
|
|
43
|
+
language: 'en',
|
|
44
|
+
logo: '/assets/logo.png',
|
|
45
|
+
favicon: '/favicon.ico',
|
|
46
|
+
countries: [],
|
|
47
|
+
states: {}
|
|
36
48
|
}
|
|
37
49
|
},
|
|
38
50
|
|
|
@@ -50,8 +62,10 @@ function generateMockData() {
|
|
|
50
62
|
id: 'mock-cart-1',
|
|
51
63
|
items: [],
|
|
52
64
|
total: 0,
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
subTotal: 0,
|
|
66
|
+
taxAmount: 0,
|
|
67
|
+
shippingAmount: 0,
|
|
68
|
+
itemCount: 0
|
|
55
69
|
}
|
|
56
70
|
};
|
|
57
71
|
}
|
|
@@ -67,21 +81,21 @@ function generateMockProducts(count = 20) {
|
|
|
67
81
|
|
|
68
82
|
// Category mapping - map category names to category IDs (matching generateMockCategories order)
|
|
69
83
|
const categoryMap = {
|
|
70
|
-
'Electronics':
|
|
71
|
-
'Clothing':
|
|
72
|
-
'Accessories':
|
|
73
|
-
'Home & Garden':
|
|
74
|
-
'Home':
|
|
75
|
-
'Sports & Fitness':
|
|
76
|
-
'Sports':
|
|
77
|
-
'Books & Media':
|
|
78
|
-
'Toys & Games':
|
|
79
|
-
'Beauty & Health':
|
|
80
|
-
'Automotive':
|
|
81
|
-
'Food & Beverages':
|
|
82
|
-
'Furniture':
|
|
83
|
-
'Office':
|
|
84
|
-
'Footwear':
|
|
84
|
+
'Electronics': 1,
|
|
85
|
+
'Clothing': 2,
|
|
86
|
+
'Accessories': 3,
|
|
87
|
+
'Home & Garden': 4,
|
|
88
|
+
'Home': 4,
|
|
89
|
+
'Sports & Fitness': 5,
|
|
90
|
+
'Sports': 5,
|
|
91
|
+
'Books & Media': 6,
|
|
92
|
+
'Toys & Games': 7,
|
|
93
|
+
'Beauty & Health': 8,
|
|
94
|
+
'Automotive': 9,
|
|
95
|
+
'Food & Beverages': 10,
|
|
96
|
+
'Furniture': 4,
|
|
97
|
+
'Office': 6,
|
|
98
|
+
'Footwear': 2
|
|
85
99
|
};
|
|
86
100
|
|
|
87
101
|
// Product data with images from picsum.photos (reliable placeholder service)
|
|
@@ -140,7 +154,7 @@ function generateMockProducts(count = 20) {
|
|
|
140
154
|
const productImageId = productTemplate.imageId;
|
|
141
155
|
|
|
142
156
|
// Get categoryId from category name using categoryMap
|
|
143
|
-
const categoryId = categoryMap[productCategory] ||
|
|
157
|
+
const categoryId = categoryMap[productCategory] || 1;
|
|
144
158
|
|
|
145
159
|
// Determine stock quantity - mix of low stock, high stock, and out of stock
|
|
146
160
|
const stockType = i % 5;
|
|
@@ -179,10 +193,10 @@ function generateMockProducts(count = 20) {
|
|
|
179
193
|
const variantPrice = basePrice + (variantIndex % 3 === 0 ? 500 : 0); // Some variants slightly more expensive
|
|
180
194
|
const variantMrp = Math.round(variantPrice * 1.5);
|
|
181
195
|
const variantStock = Math.floor(Math.random() * stock) + (stock > 0 ? 1 : 0);
|
|
182
|
-
const variantProductId = (i + 1) * 1000 + variantIndex;
|
|
196
|
+
const variantProductId = (i + 1) * 1000 + variantIndex;
|
|
183
197
|
variants.push({
|
|
184
198
|
id: `variant-${i + 1}-${variantIndex}`,
|
|
185
|
-
productId: variantProductId,
|
|
199
|
+
productId: variantProductId,
|
|
186
200
|
title: `${size} / ${color}`,
|
|
187
201
|
option1: size,
|
|
188
202
|
option2: color,
|
|
@@ -190,14 +204,15 @@ function generateMockProducts(count = 20) {
|
|
|
190
204
|
option2Name: 'Color',
|
|
191
205
|
price: variantPrice,
|
|
192
206
|
compareAtPrice: variantMrp,
|
|
193
|
-
// prices object required by product-card template
|
|
194
207
|
prices: {
|
|
195
208
|
price: variantPrice,
|
|
196
209
|
mrp: variantMrp
|
|
197
210
|
},
|
|
198
211
|
sku: `SKU-${i + 1}-${size}-${color}`,
|
|
199
212
|
inStock: variantStock > 0,
|
|
200
|
-
|
|
213
|
+
stockQuantity: variantStock,
|
|
214
|
+
stockTrackingIsEnabled: true,
|
|
215
|
+
isAllowToOrder: false,
|
|
201
216
|
available: variantStock > 0
|
|
202
217
|
});
|
|
203
218
|
variantIndex++;
|
|
@@ -206,7 +221,7 @@ function generateMockProducts(count = 20) {
|
|
|
206
221
|
} else if (hasSizeVariations) {
|
|
207
222
|
// Product with size variations only
|
|
208
223
|
sizes.slice(0, 5).forEach((size, idx) => {
|
|
209
|
-
const variantPrice = basePrice + (idx * 200);
|
|
224
|
+
const variantPrice = basePrice + (idx * 200);
|
|
210
225
|
const variantMrp = Math.round(variantPrice * 1.5);
|
|
211
226
|
const variantStock = Math.floor(Math.random() * stock) + (stock > 0 ? 1 : 0);
|
|
212
227
|
const variantProductId = (i + 1) * 1000 + idx + 1;
|
|
@@ -224,14 +239,16 @@ function generateMockProducts(count = 20) {
|
|
|
224
239
|
},
|
|
225
240
|
sku: `SKU-${i + 1}-${size}`,
|
|
226
241
|
inStock: variantStock > 0,
|
|
227
|
-
|
|
242
|
+
stockQuantity: variantStock,
|
|
243
|
+
stockTrackingIsEnabled: true,
|
|
244
|
+
isAllowToOrder: false,
|
|
228
245
|
available: variantStock > 0
|
|
229
246
|
});
|
|
230
247
|
});
|
|
231
248
|
} else if (hasColorVariations) {
|
|
232
249
|
// Product with color variations only
|
|
233
250
|
colors.slice(0, 4).forEach((color, idx) => {
|
|
234
|
-
const variantPrice = basePrice + (idx % 2 === 0 ? 300 : 0);
|
|
251
|
+
const variantPrice = basePrice + (idx % 2 === 0 ? 300 : 0);
|
|
235
252
|
const variantMrp = Math.round(variantPrice * 1.5);
|
|
236
253
|
const variantStock = Math.floor(Math.random() * stock) + (stock > 0 ? 1 : 0);
|
|
237
254
|
const variantProductId = (i + 1) * 1000 + idx + 1;
|
|
@@ -249,7 +266,9 @@ function generateMockProducts(count = 20) {
|
|
|
249
266
|
},
|
|
250
267
|
sku: `SKU-${i + 1}-${color}`,
|
|
251
268
|
inStock: variantStock > 0,
|
|
252
|
-
|
|
269
|
+
stockQuantity: variantStock,
|
|
270
|
+
stockTrackingIsEnabled: true,
|
|
271
|
+
isAllowToOrder: false,
|
|
253
272
|
available: variantStock > 0
|
|
254
273
|
});
|
|
255
274
|
});
|
|
@@ -268,49 +287,44 @@ function generateMockProducts(count = 20) {
|
|
|
268
287
|
},
|
|
269
288
|
sku: `SKU-${i + 1}`,
|
|
270
289
|
inStock: inStock,
|
|
271
|
-
|
|
290
|
+
stockQuantity: stock,
|
|
291
|
+
stockTrackingIsEnabled: true,
|
|
292
|
+
isAllowToOrder: false,
|
|
272
293
|
available: inStock
|
|
273
294
|
});
|
|
274
295
|
}
|
|
275
296
|
|
|
276
|
-
|
|
277
|
-
const totalStock = variants.reduce((sum, v) => sum + (v.stock || 0), 0);
|
|
297
|
+
const totalStock = variants.reduce((sum, v) => sum + (v.stockQuantity || 0), 0);
|
|
278
298
|
const hasAnyStock = variants.some(v => v.inStock || v.available);
|
|
279
299
|
|
|
280
|
-
const productHandle =
|
|
300
|
+
const productHandle = productName.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '') + (i > 0 ? `-${i + 1}` : '');
|
|
301
|
+
const productTitle = productName + (i > 0 ? ` ${i + 1}` : '');
|
|
281
302
|
products.push({
|
|
282
|
-
id:
|
|
283
|
-
productId: i + 1,
|
|
284
|
-
title:
|
|
285
|
-
name:
|
|
303
|
+
id: i + 1,
|
|
304
|
+
productId: i + 1,
|
|
305
|
+
title: productTitle,
|
|
306
|
+
name: productTitle,
|
|
286
307
|
handle: productHandle,
|
|
287
308
|
slug: productHandle,
|
|
288
|
-
url:
|
|
289
|
-
link:
|
|
309
|
+
url: productHandle,
|
|
310
|
+
link: productHandle,
|
|
290
311
|
description: `Description for ${productName}. High quality product with excellent features.${hasVariations ? ' Available in multiple options.' : ''}`,
|
|
291
312
|
price: basePrice,
|
|
292
313
|
compareAtPrice: comparePrice,
|
|
293
|
-
// Prices object used by product-card snippet
|
|
294
314
|
prices: {
|
|
295
315
|
price: basePrice,
|
|
296
|
-
mrp: comparePrice
|
|
297
|
-
currency: 'USD'
|
|
316
|
+
mrp: comparePrice
|
|
298
317
|
},
|
|
299
|
-
discountPercentage: Math.floor(((comparePrice - basePrice) / comparePrice) * 100),
|
|
300
|
-
currency: 'USD',
|
|
301
318
|
inStock: hasAnyStock,
|
|
302
|
-
available: hasAnyStock,
|
|
303
|
-
|
|
304
|
-
|
|
319
|
+
available: hasAnyStock,
|
|
320
|
+
stockQuantity: totalStock,
|
|
321
|
+
stockTrackingIsEnabled: true,
|
|
322
|
+
isAllowToOrder: false,
|
|
305
323
|
sku: `SKU-${i + 1}`,
|
|
306
|
-
categoryId: categoryId,
|
|
307
|
-
category:
|
|
308
|
-
brandId:
|
|
309
|
-
|
|
310
|
-
thumbnailImage1: {
|
|
311
|
-
url: `https://picsum.photos/seed/${productImageId}/800/800`,
|
|
312
|
-
altText: productName
|
|
313
|
-
},
|
|
324
|
+
categoryId: categoryId,
|
|
325
|
+
category: { id: categoryId, name: productCategory },
|
|
326
|
+
brandId: (i % 8) + 1,
|
|
327
|
+
thumbnailImage: `https://picsum.photos/seed/${productImageId}/800/800`,
|
|
314
328
|
imageUrl: `https://picsum.photos/seed/${productImageId}/800/800`,
|
|
315
329
|
images: [
|
|
316
330
|
{
|
|
@@ -351,23 +365,19 @@ function generateMockProducts(count = 20) {
|
|
|
351
365
|
: [],
|
|
352
366
|
tags: ['featured', 'new', 'sale'],
|
|
353
367
|
createdAt: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000).toISOString(),
|
|
354
|
-
|
|
355
|
-
productType: 0, // 0 = simple product, 1 = variable, 2 = subscription
|
|
356
|
-
// additionalData uses | default:null without | json, so we use string 'null'
|
|
357
|
-
// This outputs as literal null in JSON (without quotes)
|
|
368
|
+
productType: 0,
|
|
358
369
|
additionalData: 'null',
|
|
359
|
-
// These fields use | json filter, so they should be actual arrays
|
|
360
370
|
combinations: [],
|
|
361
371
|
subscriptions: [],
|
|
362
372
|
shippingMethods: [],
|
|
363
|
-
variations: variants
|
|
373
|
+
variations: variants
|
|
364
374
|
});
|
|
365
375
|
}
|
|
366
376
|
|
|
367
377
|
// Log summary
|
|
368
378
|
const productsWithVariations = products.filter(p => (p.variants?.length || 0) > 1).length;
|
|
369
379
|
const productsWithOptions = products.filter(p => (p.options?.length || 0) > 0).length;
|
|
370
|
-
const outOfStock = products.filter(p => !p.inStock || (p.
|
|
380
|
+
const outOfStock = products.filter(p => !p.inStock || (p.stockQuantity || 0) === 0).length;
|
|
371
381
|
|
|
372
382
|
// Log category distribution
|
|
373
383
|
const categoryDistribution = {};
|
|
@@ -410,14 +420,24 @@ function generateMockCategories(count = 10) {
|
|
|
410
420
|
|
|
411
421
|
for (let i = 0; i < count; i++) {
|
|
412
422
|
const catData = categoryData[i] || { name: `Category ${i + 1}`, imageId: 60 + i, description: `Products in Category ${i + 1}` };
|
|
423
|
+
const catHandle = catData.name.toLowerCase().replace(/\s+/g, '-').replace(/&/g, 'and');
|
|
424
|
+
const catImageUrl = `https://picsum.photos/seed/cat${catData.imageId}/400/300`;
|
|
413
425
|
categories.push({
|
|
414
|
-
id:
|
|
426
|
+
id: i + 1,
|
|
427
|
+
categoryId: i + 1,
|
|
415
428
|
name: catData.name,
|
|
416
|
-
|
|
429
|
+
displayName: catData.name,
|
|
430
|
+
handle: catHandle,
|
|
431
|
+
slug: catHandle,
|
|
417
432
|
description: catData.description,
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
433
|
+
thumbnailImage: { url: catImageUrl },
|
|
434
|
+
bannerImage: { url: catImageUrl },
|
|
435
|
+
menuImage: { url: catImageUrl },
|
|
436
|
+
displayOrder: i + 1,
|
|
437
|
+
parentCategoryId: i > 5 ? Math.floor(Math.random() * 5) + 1 : null,
|
|
438
|
+
parentName: i > 5 ? categoryData[Math.floor(Math.random() * 5)]?.name || null : null,
|
|
439
|
+
products: [],
|
|
440
|
+
productsCount: Math.floor(Math.random() * 50) + 5
|
|
421
441
|
});
|
|
422
442
|
}
|
|
423
443
|
|
|
@@ -447,9 +467,11 @@ function generateMockBrands(count = 10) {
|
|
|
447
467
|
for (let i = 0; i < count; i++) {
|
|
448
468
|
const brand = brandData[i] || { name: `Brand ${i + 1}`, tagline: 'Quality Products', imageId: 80 + i };
|
|
449
469
|
brands.push({
|
|
450
|
-
id:
|
|
470
|
+
id: i + 1,
|
|
471
|
+
brandId: i + 1,
|
|
451
472
|
name: brand.name,
|
|
452
473
|
handle: brand.name.toLowerCase().replace(/\s+/g, '-'),
|
|
474
|
+
slug: brand.name.toLowerCase().replace(/\s+/g, '-'),
|
|
453
475
|
description: `${brand.tagline}. Premium products from ${brand.name}`,
|
|
454
476
|
logo: `https://picsum.photos/seed/brand${brand.imageId}/200/100`,
|
|
455
477
|
image: `https://picsum.photos/seed/brand${brand.imageId}/400/200`,
|
|
@@ -473,6 +495,7 @@ function generateMockWidgets() {
|
|
|
473
495
|
type: 'Header',
|
|
474
496
|
section: 'header',
|
|
475
497
|
sectionName: 'header',
|
|
498
|
+
pageId: 'all',
|
|
476
499
|
status: 'active',
|
|
477
500
|
Position: 1,
|
|
478
501
|
settings: {
|
|
@@ -494,6 +517,7 @@ function generateMockWidgets() {
|
|
|
494
517
|
type: 'HeaderMenu',
|
|
495
518
|
section: 'header',
|
|
496
519
|
sectionName: 'header',
|
|
520
|
+
pageId: 'all',
|
|
497
521
|
status: 'active',
|
|
498
522
|
Position: 2,
|
|
499
523
|
settings: {
|
|
@@ -514,6 +538,7 @@ function generateMockWidgets() {
|
|
|
514
538
|
type: 'Carousel',
|
|
515
539
|
section: 'hero',
|
|
516
540
|
sectionName: 'hero',
|
|
541
|
+
pageId: 'home',
|
|
517
542
|
status: 'active',
|
|
518
543
|
Position: 1,
|
|
519
544
|
settings: {
|
|
@@ -584,6 +609,7 @@ function generateMockWidgets() {
|
|
|
584
609
|
type: 'SpaceBar',
|
|
585
610
|
section: 'hero',
|
|
586
611
|
sectionName: 'hero',
|
|
612
|
+
pageId: 'home',
|
|
587
613
|
status: 'active',
|
|
588
614
|
Position: 2,
|
|
589
615
|
settings: {
|
|
@@ -654,6 +680,7 @@ function generateMockWidgets() {
|
|
|
654
680
|
type: 'CategoryList',
|
|
655
681
|
section: 'content',
|
|
656
682
|
sectionName: 'content',
|
|
683
|
+
pageId: 'home',
|
|
657
684
|
status: 'active',
|
|
658
685
|
Position: 1,
|
|
659
686
|
Title: 'Shop by Category',
|
|
@@ -701,6 +728,7 @@ function generateMockWidgets() {
|
|
|
701
728
|
type: 'ProductCarousel',
|
|
702
729
|
section: 'content',
|
|
703
730
|
sectionName: 'content',
|
|
731
|
+
pageId: 'home',
|
|
704
732
|
status: 'active',
|
|
705
733
|
Position: 2,
|
|
706
734
|
Title: 'Featured Products',
|
|
@@ -739,6 +767,7 @@ function generateMockWidgets() {
|
|
|
739
767
|
type: 'ProductCarousel',
|
|
740
768
|
section: 'content',
|
|
741
769
|
sectionName: 'content',
|
|
770
|
+
pageId: 'home',
|
|
742
771
|
status: 'active',
|
|
743
772
|
Position: 3,
|
|
744
773
|
Title: 'Best Sellers',
|
|
@@ -775,6 +804,7 @@ function generateMockWidgets() {
|
|
|
775
804
|
type: 'ProductCarousel',
|
|
776
805
|
section: 'content',
|
|
777
806
|
sectionName: 'content',
|
|
807
|
+
pageId: 'home',
|
|
778
808
|
status: 'active',
|
|
779
809
|
Position: 4,
|
|
780
810
|
Title: 'New Arrivals',
|
|
@@ -810,6 +840,7 @@ function generateMockWidgets() {
|
|
|
810
840
|
type: 'ProductCarousel',
|
|
811
841
|
section: 'content',
|
|
812
842
|
sectionName: 'content',
|
|
843
|
+
pageId: 'home',
|
|
813
844
|
status: 'active',
|
|
814
845
|
Position: 5,
|
|
815
846
|
Title: 'On Sale',
|
|
@@ -847,6 +878,7 @@ function generateMockWidgets() {
|
|
|
847
878
|
type: 'ProductCarousel',
|
|
848
879
|
section: 'content',
|
|
849
880
|
sectionName: 'content',
|
|
881
|
+
pageId: 'home',
|
|
850
882
|
status: 'active',
|
|
851
883
|
Position: 6,
|
|
852
884
|
Title: 'Trending Now',
|
|
@@ -882,6 +914,7 @@ function generateMockWidgets() {
|
|
|
882
914
|
type: 'ProductCarousel',
|
|
883
915
|
section: 'content',
|
|
884
916
|
sectionName: 'content',
|
|
917
|
+
pageId: 'home',
|
|
885
918
|
status: 'active',
|
|
886
919
|
Position: 7,
|
|
887
920
|
Title: 'Electronics',
|
|
@@ -918,6 +951,7 @@ function generateMockWidgets() {
|
|
|
918
951
|
type: 'ProductCarousel',
|
|
919
952
|
section: 'content',
|
|
920
953
|
sectionName: 'content',
|
|
954
|
+
pageId: 'home',
|
|
921
955
|
status: 'active',
|
|
922
956
|
Position: 8,
|
|
923
957
|
Title: 'Fashion',
|
|
@@ -954,6 +988,7 @@ function generateMockWidgets() {
|
|
|
954
988
|
type: 'ProductCarousel',
|
|
955
989
|
section: 'content',
|
|
956
990
|
sectionName: 'content',
|
|
991
|
+
pageId: 'product',
|
|
957
992
|
status: 'active',
|
|
958
993
|
Position: 9,
|
|
959
994
|
Title: 'You May Also Like',
|
|
@@ -988,6 +1023,7 @@ function generateMockWidgets() {
|
|
|
988
1023
|
type: 'ProductCarousel',
|
|
989
1024
|
section: 'content',
|
|
990
1025
|
sectionName: 'content',
|
|
1026
|
+
pageId: 'product',
|
|
991
1027
|
status: 'active',
|
|
992
1028
|
Position: 10,
|
|
993
1029
|
Title: 'Frequently Bought Together',
|
|
@@ -1023,6 +1059,7 @@ function generateMockWidgets() {
|
|
|
1023
1059
|
type: 'ProductCarousel',
|
|
1024
1060
|
section: 'content',
|
|
1025
1061
|
sectionName: 'content',
|
|
1062
|
+
pageId: 'home',
|
|
1026
1063
|
status: 'active',
|
|
1027
1064
|
Position: 11,
|
|
1028
1065
|
Title: "Editor's Choice",
|
|
@@ -1060,6 +1097,7 @@ function generateMockWidgets() {
|
|
|
1060
1097
|
type: 'ProductGrid',
|
|
1061
1098
|
section: 'content',
|
|
1062
1099
|
sectionName: 'content',
|
|
1100
|
+
pageId: 'home',
|
|
1063
1101
|
status: 'active',
|
|
1064
1102
|
Position: 12,
|
|
1065
1103
|
Title: 'Shop All Products',
|
|
@@ -1096,6 +1134,7 @@ function generateMockWidgets() {
|
|
|
1096
1134
|
type: 'ProductGrid',
|
|
1097
1135
|
section: 'content',
|
|
1098
1136
|
sectionName: 'content',
|
|
1137
|
+
pageId: 'home',
|
|
1099
1138
|
status: 'active',
|
|
1100
1139
|
Position: 13,
|
|
1101
1140
|
Title: 'Featured Collection',
|
|
@@ -1133,6 +1172,7 @@ function generateMockWidgets() {
|
|
|
1133
1172
|
type: 'Banner',
|
|
1134
1173
|
section: 'content',
|
|
1135
1174
|
sectionName: 'content',
|
|
1175
|
+
pageId: 'home',
|
|
1136
1176
|
status: 'active',
|
|
1137
1177
|
Position: 4,
|
|
1138
1178
|
Title: 'Special Offers',
|
|
@@ -1171,6 +1211,7 @@ function generateMockWidgets() {
|
|
|
1171
1211
|
type: 'SimpleProduct',
|
|
1172
1212
|
section: 'content',
|
|
1173
1213
|
sectionName: 'content',
|
|
1214
|
+
pageId: 'home',
|
|
1174
1215
|
status: 'active',
|
|
1175
1216
|
Position: 5,
|
|
1176
1217
|
Title: 'Best Sellers',
|
|
@@ -1195,6 +1236,7 @@ function generateMockWidgets() {
|
|
|
1195
1236
|
type: 'SingleProduct',
|
|
1196
1237
|
section: 'content',
|
|
1197
1238
|
sectionName: 'content',
|
|
1239
|
+
pageId: 'home',
|
|
1198
1240
|
status: 'active',
|
|
1199
1241
|
Position: 6,
|
|
1200
1242
|
Title: 'Deal of the Day',
|
|
@@ -1217,6 +1259,7 @@ function generateMockWidgets() {
|
|
|
1217
1259
|
type: 'RecentlyViewed',
|
|
1218
1260
|
section: 'content',
|
|
1219
1261
|
sectionName: 'content',
|
|
1262
|
+
pageId: 'product',
|
|
1220
1263
|
status: 'active',
|
|
1221
1264
|
Position: 7,
|
|
1222
1265
|
Title: 'Recently Viewed',
|
|
@@ -1238,6 +1281,7 @@ function generateMockWidgets() {
|
|
|
1238
1281
|
type: 'BrandCarousel',
|
|
1239
1282
|
section: 'content',
|
|
1240
1283
|
sectionName: 'content',
|
|
1284
|
+
pageId: 'home',
|
|
1241
1285
|
status: 'active',
|
|
1242
1286
|
Position: 8,
|
|
1243
1287
|
Title: 'Our Brands',
|
|
@@ -1283,6 +1327,7 @@ function generateMockWidgets() {
|
|
|
1283
1327
|
type: 'Gallery',
|
|
1284
1328
|
section: 'content',
|
|
1285
1329
|
sectionName: 'content',
|
|
1330
|
+
pageId: 'home',
|
|
1286
1331
|
status: 'active',
|
|
1287
1332
|
Position: 4,
|
|
1288
1333
|
Title: 'Instagram Gallery',
|
|
@@ -1323,6 +1368,7 @@ function generateMockWidgets() {
|
|
|
1323
1368
|
type: 'TestimonialCarousel',
|
|
1324
1369
|
section: 'content',
|
|
1325
1370
|
sectionName: 'content',
|
|
1371
|
+
pageId: 'home',
|
|
1326
1372
|
status: 'active',
|
|
1327
1373
|
Position: 5,
|
|
1328
1374
|
Title: 'What Our Customers Say',
|
|
@@ -1408,6 +1454,7 @@ function generateMockWidgets() {
|
|
|
1408
1454
|
type: 'Footer',
|
|
1409
1455
|
section: 'footer',
|
|
1410
1456
|
sectionName: 'footer',
|
|
1457
|
+
pageId: 'all',
|
|
1411
1458
|
status: 'active',
|
|
1412
1459
|
Position: 1,
|
|
1413
1460
|
settings: {
|
|
@@ -1475,6 +1522,7 @@ function generateMockWidgets() {
|
|
|
1475
1522
|
type: 'FooterMenu',
|
|
1476
1523
|
section: 'footer',
|
|
1477
1524
|
sectionName: 'footer',
|
|
1525
|
+
pageId: 'all',
|
|
1478
1526
|
status: 'active',
|
|
1479
1527
|
Position: 2,
|
|
1480
1528
|
settings: {
|
|
@@ -305,6 +305,55 @@ class WidgetService {
|
|
|
305
305
|
}
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Get widgets for a specific page and section.
|
|
310
|
+
* Matches production API: POST /pages/{pageId}/sections/{section}/widgets
|
|
311
|
+
* @param {string} pageId - Page ID (home, product, category, products, categories, brand, checkout)
|
|
312
|
+
* @param {string} section - Section name (header, hero, content, footer)
|
|
313
|
+
* @returns {Promise<Array>} Array of normalized widgets sorted by Position
|
|
314
|
+
*/
|
|
315
|
+
async getPageSectionWidgets(pageId, section) {
|
|
316
|
+
try {
|
|
317
|
+
if (!this.apiClient) return [];
|
|
318
|
+
|
|
319
|
+
const response = await this.apiClient.post(`/pages/${pageId}/sections/${section}/widgets`, { status: 'active' });
|
|
320
|
+
const widgets = Array.isArray(response) ? response : (response.widgets || []);
|
|
321
|
+
return this.normalizeWidgetArray(widgets);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
console.warn(`[WidgetService] Error fetching widgets for page=${pageId} section=${section}:`, error.message);
|
|
324
|
+
return [];
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Fetch all widgets for a page, organized by section.
|
|
330
|
+
* Mirrors the production fetchPageWidgets() helper.
|
|
331
|
+
* @param {string} pageId - Page ID
|
|
332
|
+
* @returns {Promise<Object>} Widgets organized by section { header:[], hero:[], content:[], footer:[] }
|
|
333
|
+
*/
|
|
334
|
+
async fetchPageWidgets(pageId) {
|
|
335
|
+
const validPageIds = ['home', 'product', 'category', 'products', 'categories', 'brand', 'checkout'];
|
|
336
|
+
if (!pageId || !validPageIds.includes(pageId)) {
|
|
337
|
+
console.warn(`[WidgetService] Invalid pageId: ${pageId}, returning empty widgets`);
|
|
338
|
+
return { header: [], hero: [], content: [], footer: [] };
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const sections = ['header', 'hero', 'content', 'footer'];
|
|
342
|
+
const results = await Promise.allSettled(
|
|
343
|
+
sections.map(section => this.getPageSectionWidgets(pageId, section))
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
const organized = {};
|
|
347
|
+
sections.forEach((section, index) => {
|
|
348
|
+
const result = results[index];
|
|
349
|
+
organized[section] = (result.status === 'fulfilled' && Array.isArray(result.value)) ? result.value : [];
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const counts = sections.map(s => `${s}:${organized[s].length}`).join(', ');
|
|
353
|
+
console.log(`[WidgetService] fetchPageWidgets(${pageId}): ${counts}`);
|
|
354
|
+
return organized;
|
|
355
|
+
}
|
|
356
|
+
|
|
308
357
|
/**
|
|
309
358
|
* Check if widget template exists in theme
|
|
310
359
|
* @param {string} widgetType - Widget type
|