@akinon/pz-similar-products 1.92.0-rc.26 → 1.92.0-snapshot-ZERO-3457-20250627111231
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/CHANGELOG.md +2 -34
- package/README.md +3 -30
- package/package.json +1 -1
- package/src/hooks/use-similar-products.ts +0 -9
- package/src/types/index.ts +0 -15
- package/src/views/filters.tsx +646 -690
- package/src/views/image-search.tsx +86 -98
- package/src/views/main.tsx +3 -11
- package/src/views/results.tsx +5 -7
- package/src/views/search-modal.tsx +0 -4
package/src/views/filters.tsx
CHANGED
|
@@ -167,786 +167,742 @@ export function SimilarProductsFilterSidebar({
|
|
|
167
167
|
);
|
|
168
168
|
|
|
169
169
|
return (
|
|
170
|
-
|
|
171
|
-
{
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
170
|
+
<div
|
|
171
|
+
className={sidebarClassName}
|
|
172
|
+
style={{
|
|
173
|
+
maxHeight: 'calc(100vh - 120px)'
|
|
174
|
+
}}
|
|
175
|
+
>
|
|
176
|
+
{(() => {
|
|
177
|
+
if (
|
|
178
|
+
settings?.customRenderers?.render?.filterSidebar?.renderMobileHeader
|
|
179
|
+
) {
|
|
180
|
+
return settings.customRenderers.render.filterSidebar.renderMobileHeader(
|
|
181
|
+
{
|
|
182
|
+
title: t('common.product.filters'),
|
|
183
|
+
itemCount: searchResults?.pagination?.total_count || 0,
|
|
184
|
+
onClose: () => setIsFilterMenuOpen(false)
|
|
185
|
+
}
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const mobileHeaderClassName = twMerge(
|
|
190
|
+
'flex justify-between mb-6 md:hidden',
|
|
191
|
+
settings?.customStyles?.filterSidebarMobileHeader
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<>
|
|
196
|
+
<div className={mobileHeaderClassName}>
|
|
197
|
+
<h3
|
|
198
|
+
className={twMerge(
|
|
199
|
+
'text-2xl font-bold',
|
|
200
|
+
settings?.customStyles?.filterSidebarMobileTitle
|
|
201
|
+
)}
|
|
202
|
+
>
|
|
203
|
+
{t('common.product.filters')}
|
|
204
|
+
</h3>
|
|
205
|
+
<Button
|
|
206
|
+
appearance="ghost"
|
|
207
|
+
size="sm"
|
|
208
|
+
onClick={() => setIsFilterMenuOpen(false)}
|
|
209
|
+
className={twMerge(
|
|
210
|
+
'hover:bg-gray-200 rounded-full p-0 w-6 h-6',
|
|
211
|
+
settings?.customStyles?.filterSidebarMobileCloseButton
|
|
212
|
+
)}
|
|
213
|
+
>
|
|
214
|
+
<Icon name="close" size={16} />
|
|
215
|
+
</Button>
|
|
216
|
+
</div>
|
|
217
|
+
<div
|
|
218
|
+
className={twMerge(
|
|
219
|
+
'flex justify-between items-center mb-6 md:hidden',
|
|
220
|
+
settings?.customStyles?.filterSidebarMobileCounter
|
|
221
|
+
)}
|
|
222
|
+
>
|
|
223
|
+
<span
|
|
224
|
+
className={twMerge(
|
|
225
|
+
'text-sm',
|
|
226
|
+
settings?.customStyles?.filterSidebarMobileCounterText
|
|
227
|
+
)}
|
|
228
|
+
>
|
|
229
|
+
{searchResults?.pagination?.total_count || 0} items
|
|
230
|
+
</span>
|
|
231
|
+
</div>
|
|
232
|
+
</>
|
|
233
|
+
);
|
|
234
|
+
})()}
|
|
235
|
+
|
|
236
|
+
{(() => {
|
|
237
|
+
if (
|
|
238
|
+
settings?.customRenderers?.render?.filterSidebar?.renderImageSection
|
|
239
|
+
) {
|
|
240
|
+
return settings.customRenderers.render.filterSidebar.renderImageSection(
|
|
241
|
+
{
|
|
242
|
+
currentImageUrl,
|
|
243
|
+
isCropping,
|
|
244
|
+
onToggleCrop: handleToggleCropMode,
|
|
245
|
+
onFileUpload: handleFileChangeWithCropReset,
|
|
246
|
+
onResetToOriginal: handleResetToOriginal,
|
|
247
|
+
fileError,
|
|
248
|
+
isLoading
|
|
249
|
+
}
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const imageSectionClassName = twMerge(
|
|
254
|
+
'relative mb-2 md:mb-6 mt-4',
|
|
255
|
+
settings?.customStyles?.imageSection
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
const imageContainerClassName = twMerge(
|
|
259
|
+
'relative bg-white overflow-hidden flex items-center justify-center transition-all duration-300 ease-in-out',
|
|
260
|
+
isCropping ? 'border-2 border-dashed border-gray-300' : '',
|
|
261
|
+
settings?.customStyles?.imageContainer
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
const cropButtonClassName = twMerge(
|
|
265
|
+
`absolute z-10 bottom-3 left-3 p-2 rounded-full bg-white shadow-md w-10 h-10 ${
|
|
266
|
+
isCropping ? 'text-red-500' : 'text-gray-700'
|
|
267
|
+
} ${isLoading ? 'opacity-50 cursor-not-allowed' : ''}`,
|
|
268
|
+
settings?.customStyles?.cropButton
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const renderCropButton = () => {
|
|
272
|
+
if (!settings?.enableCropping || settings.enableCropping === false)
|
|
273
|
+
return null;
|
|
274
|
+
|
|
188
275
|
if (
|
|
189
|
-
settings?.customRenderers?.render?.filterSidebar?.
|
|
276
|
+
settings?.customRenderers?.render?.filterSidebar?.renderCropButton
|
|
190
277
|
) {
|
|
191
|
-
return settings.customRenderers.render.filterSidebar.
|
|
278
|
+
return settings.customRenderers.render.filterSidebar.renderCropButton(
|
|
192
279
|
{
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
280
|
+
isCropping,
|
|
281
|
+
onClick: handleToggleCropMode,
|
|
282
|
+
disabled: isLoading
|
|
196
283
|
}
|
|
197
284
|
);
|
|
198
285
|
}
|
|
199
286
|
|
|
200
|
-
const mobileHeaderClassName = twMerge(
|
|
201
|
-
'flex justify-between mb-6 md:hidden',
|
|
202
|
-
settings?.customStyles?.filterSidebarMobileHeader
|
|
203
|
-
);
|
|
204
|
-
|
|
205
287
|
return (
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
288
|
+
<Button
|
|
289
|
+
appearance="ghost"
|
|
290
|
+
size="sm"
|
|
291
|
+
onClick={handleToggleCropMode}
|
|
292
|
+
disabled={isLoading}
|
|
293
|
+
className={cropButtonClassName}
|
|
294
|
+
>
|
|
295
|
+
{isLoading ? (
|
|
296
|
+
<LoaderSpinner className="w-5 h-5" />
|
|
297
|
+
) : isCropping ? (
|
|
298
|
+
<svg
|
|
299
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
300
|
+
width="20"
|
|
301
|
+
height="20"
|
|
302
|
+
viewBox="0 0 24 24"
|
|
303
|
+
fill="none"
|
|
304
|
+
stroke="currentColor"
|
|
305
|
+
strokeWidth="2"
|
|
306
|
+
strokeLinecap="round"
|
|
307
|
+
strokeLinejoin="round"
|
|
213
308
|
>
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
309
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
310
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
311
|
+
</svg>
|
|
312
|
+
) : (
|
|
313
|
+
<svg
|
|
314
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
315
|
+
width="20"
|
|
316
|
+
height="20"
|
|
317
|
+
viewBox="0 0 24 24"
|
|
318
|
+
fill="none"
|
|
319
|
+
stroke="currentColor"
|
|
320
|
+
strokeWidth="2"
|
|
321
|
+
strokeLinecap="round"
|
|
322
|
+
strokeLinejoin="round"
|
|
224
323
|
>
|
|
225
|
-
<
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
'flex justify-between items-center mb-6 md:hidden',
|
|
231
|
-
settings?.customStyles?.filterSidebarMobileCounter
|
|
232
|
-
)}
|
|
233
|
-
>
|
|
234
|
-
<span
|
|
235
|
-
className={twMerge(
|
|
236
|
-
'text-sm',
|
|
237
|
-
settings?.customStyles?.filterSidebarMobileCounterText
|
|
238
|
-
)}
|
|
239
|
-
>
|
|
240
|
-
{searchResults?.pagination?.total_count || 0} items
|
|
241
|
-
</span>
|
|
242
|
-
</div>
|
|
243
|
-
</>
|
|
324
|
+
<path d="M6 2v14a2 2 0 0 0 2 2h14"></path>
|
|
325
|
+
<path d="M18 22V8a2 2 0 0 0-2-2H2"></path>
|
|
326
|
+
</svg>
|
|
327
|
+
)}
|
|
328
|
+
</Button>
|
|
244
329
|
);
|
|
245
|
-
}
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const renderTickButton = () => {
|
|
333
|
+
if (!settings?.enableCropping || settings.enableCropping === false)
|
|
334
|
+
return null;
|
|
335
|
+
if (
|
|
336
|
+
!isCropping ||
|
|
337
|
+
!completedCrop ||
|
|
338
|
+
completedCrop.width <= 10 ||
|
|
339
|
+
completedCrop.height <= 10
|
|
340
|
+
)
|
|
341
|
+
return null;
|
|
246
342
|
|
|
247
|
-
{(() => {
|
|
248
343
|
if (
|
|
249
|
-
settings?.customRenderers?.render?.filterSidebar?.
|
|
344
|
+
settings?.customRenderers?.render?.filterSidebar?.renderTickButton
|
|
250
345
|
) {
|
|
251
|
-
return settings.customRenderers.render.filterSidebar.
|
|
346
|
+
return settings.customRenderers.render.filterSidebar.renderTickButton(
|
|
252
347
|
{
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
onToggleCrop: handleToggleCropMode,
|
|
256
|
-
onFileUpload: handleFileChangeWithCropReset,
|
|
257
|
-
onResetToOriginal: handleResetToOriginal,
|
|
258
|
-
fileError,
|
|
259
|
-
isLoading
|
|
348
|
+
onClick: () => handleSafeProcessCrop(completedCrop),
|
|
349
|
+
disabled: isLoading
|
|
260
350
|
}
|
|
261
351
|
);
|
|
262
352
|
}
|
|
263
353
|
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
354
|
+
const tickButtonClassName = twMerge(
|
|
355
|
+
`absolute z-10 bottom-3 right-3 p-2 rounded-full bg-white shadow-md w-10 h-10 text-green-600 ${
|
|
356
|
+
isLoading ? 'opacity-50 cursor-not-allowed' : ''
|
|
357
|
+
}`,
|
|
358
|
+
settings?.customStyles?.tickButton
|
|
267
359
|
);
|
|
268
360
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
361
|
+
return (
|
|
362
|
+
<Button
|
|
363
|
+
appearance="ghost"
|
|
364
|
+
size="sm"
|
|
365
|
+
onClick={() => {
|
|
366
|
+
if (!isLoading) {
|
|
367
|
+
handleSafeProcessCrop(completedCrop);
|
|
368
|
+
}
|
|
369
|
+
}}
|
|
370
|
+
disabled={isLoading}
|
|
371
|
+
className={tickButtonClassName}
|
|
372
|
+
>
|
|
373
|
+
{isLoading ? (
|
|
374
|
+
<LoaderSpinner className="w-5 h-5" />
|
|
375
|
+
) : (
|
|
376
|
+
<svg
|
|
377
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
378
|
+
width="20"
|
|
379
|
+
height="20"
|
|
380
|
+
viewBox="0 0 24 24"
|
|
381
|
+
fill="none"
|
|
382
|
+
stroke="currentColor"
|
|
383
|
+
strokeWidth="2"
|
|
384
|
+
strokeLinecap="round"
|
|
385
|
+
strokeLinejoin="round"
|
|
386
|
+
>
|
|
387
|
+
<polyline points="20,6 9,17 4,12"></polyline>
|
|
388
|
+
</svg>
|
|
389
|
+
)}
|
|
390
|
+
</Button>
|
|
280
391
|
);
|
|
392
|
+
};
|
|
281
393
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
394
|
+
return (
|
|
395
|
+
<div className={imageSectionClassName}>
|
|
396
|
+
<div className={imageContainerClassName}>
|
|
397
|
+
{renderCropButton()}
|
|
398
|
+
{renderTickButton()}
|
|
285
399
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
{
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
400
|
+
{(() => {
|
|
401
|
+
if (
|
|
402
|
+
settings?.customRenderers?.render?.filterSidebar
|
|
403
|
+
?.renderImageContainer
|
|
404
|
+
) {
|
|
405
|
+
return settings.customRenderers.render.filterSidebar.renderImageContainer(
|
|
406
|
+
{
|
|
407
|
+
imageUrl: currentImageUrl || '',
|
|
408
|
+
productName: product?.name || 'Product image',
|
|
409
|
+
isCropping
|
|
410
|
+
}
|
|
411
|
+
);
|
|
294
412
|
}
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
413
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
onClick={handleToggleCropMode}
|
|
303
|
-
disabled={isLoading}
|
|
304
|
-
className={cropButtonClassName}
|
|
305
|
-
>
|
|
306
|
-
{isLoading ? (
|
|
307
|
-
<LoaderSpinner className="w-5 h-5" />
|
|
308
|
-
) : isCropping ? (
|
|
309
|
-
<svg
|
|
310
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
311
|
-
width="20"
|
|
312
|
-
height="20"
|
|
313
|
-
viewBox="0 0 24 24"
|
|
314
|
-
fill="none"
|
|
315
|
-
stroke="currentColor"
|
|
316
|
-
strokeWidth="2"
|
|
317
|
-
strokeLinecap="round"
|
|
318
|
-
strokeLinejoin="round"
|
|
319
|
-
>
|
|
320
|
-
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
321
|
-
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
322
|
-
</svg>
|
|
323
|
-
) : (
|
|
324
|
-
<svg
|
|
325
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
326
|
-
width="20"
|
|
327
|
-
height="20"
|
|
328
|
-
viewBox="0 0 24 24"
|
|
329
|
-
fill="none"
|
|
330
|
-
stroke="currentColor"
|
|
331
|
-
strokeWidth="2"
|
|
332
|
-
strokeLinecap="round"
|
|
333
|
-
strokeLinejoin="round"
|
|
334
|
-
>
|
|
335
|
-
<path d="M6 2v14a2 2 0 0 0 2 2h14"></path>
|
|
336
|
-
<path d="M18 22V8a2 2 0 0 0-2-2H2"></path>
|
|
337
|
-
</svg>
|
|
338
|
-
)}
|
|
339
|
-
</Button>
|
|
340
|
-
);
|
|
341
|
-
};
|
|
414
|
+
const imageWrapperClassName = twMerge(
|
|
415
|
+
'w-full h-full flex items-center justify-center',
|
|
416
|
+
settings?.customStyles?.imageWrapper
|
|
417
|
+
);
|
|
342
418
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
419
|
+
return (
|
|
420
|
+
<div className={imageWrapperClassName}>
|
|
421
|
+
{isCropping ? (
|
|
422
|
+
<ReactCrop
|
|
423
|
+
crop={crop}
|
|
424
|
+
onChange={(newCrop) => {
|
|
425
|
+
if (!isLoading) {
|
|
426
|
+
setCrop(newCrop);
|
|
427
|
+
if (newCrop?.width > 10 && newCrop?.height > 10) {
|
|
428
|
+
setCompletedCrop(newCrop);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}}
|
|
432
|
+
onComplete={handleCropComplete}
|
|
433
|
+
onDragStart={() => {}}
|
|
434
|
+
onDragEnd={() => {}}
|
|
435
|
+
ruleOfThirds={false}
|
|
436
|
+
aspect={settings?.cropAspectRatio}
|
|
437
|
+
className="slider-crop"
|
|
438
|
+
disabled={isLoading}
|
|
439
|
+
keepSelection={true}
|
|
440
|
+
>
|
|
441
|
+
<img
|
|
442
|
+
ref={imageRef}
|
|
443
|
+
src={currentImageUrl || ''}
|
|
444
|
+
alt={product?.name || 'Product image'}
|
|
445
|
+
className="max-w-full max-h-[200px] md:max-h-[280px]"
|
|
446
|
+
style={{ transform: `scale(1) rotate(0deg)` }}
|
|
447
|
+
/>
|
|
448
|
+
</ReactCrop>
|
|
449
|
+
) : (
|
|
450
|
+
<div className="relative w-full h-full flex items-center justify-center">
|
|
451
|
+
<img
|
|
452
|
+
ref={imageRef}
|
|
453
|
+
src={currentImageUrl || ''}
|
|
454
|
+
alt={product?.name || 'Product image'}
|
|
455
|
+
className="max-w-full max-h-[200px] md:max-h-[280px] object-contain"
|
|
456
|
+
/>
|
|
457
|
+
{!isCropping && completedCrop && (
|
|
458
|
+
<div className="hidden md:block absolute inset-0 bg-black bg-opacity-50 transition-opacity duration-300 ease-in-out">
|
|
459
|
+
<div
|
|
460
|
+
className="absolute transition-all duration-300 ease-in-out"
|
|
461
|
+
style={{
|
|
462
|
+
width: `${completedCrop.width}px`,
|
|
463
|
+
height: `${completedCrop.height}px`,
|
|
464
|
+
left: `${completedCrop.x}px`,
|
|
465
|
+
top: `${completedCrop.y}px`,
|
|
466
|
+
boxShadow: '0 0 0 9999px rgba(0, 0, 0, 0.5)',
|
|
467
|
+
border: '2px solid white'
|
|
468
|
+
}}
|
|
469
|
+
></div>
|
|
470
|
+
</div>
|
|
471
|
+
)}
|
|
472
|
+
</div>
|
|
473
|
+
)}
|
|
474
|
+
</div>
|
|
475
|
+
);
|
|
476
|
+
})()}
|
|
477
|
+
</div>
|
|
353
478
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
479
|
+
{!isCropping && (
|
|
480
|
+
<div
|
|
481
|
+
className={twMerge(
|
|
482
|
+
'flex flex-col md:flex-row justify-center mt-3 gap-2',
|
|
483
|
+
settings?.customStyles?.cropControls
|
|
484
|
+
)}
|
|
485
|
+
>
|
|
486
|
+
{settings?.enableFileUpload !== false && (
|
|
487
|
+
<>
|
|
488
|
+
<input
|
|
489
|
+
type="file"
|
|
490
|
+
accept="image/*"
|
|
491
|
+
ref={fileInputRef}
|
|
492
|
+
onChange={handleFileChangeWithCropReset}
|
|
493
|
+
className="hidden"
|
|
494
|
+
/>
|
|
495
|
+
{(() => {
|
|
496
|
+
if (
|
|
497
|
+
settings?.customRenderers?.render?.filterSidebar
|
|
498
|
+
?.renderUploadButton
|
|
499
|
+
) {
|
|
500
|
+
return settings.customRenderers.render.filterSidebar.renderUploadButton(
|
|
501
|
+
{
|
|
502
|
+
onClick: handleNewImageClick,
|
|
503
|
+
disabled: isLoading
|
|
504
|
+
}
|
|
505
|
+
);
|
|
506
|
+
}
|
|
364
507
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
508
|
+
const uploadButtonClassName = twMerge(
|
|
509
|
+
`flex items-center gap-2 text-xs md:text-sm justify-center bg-gray-100 hover:bg-gray-200 border-gray-200 ${
|
|
510
|
+
isLoading ? 'opacity-50 cursor-not-allowed' : ''
|
|
511
|
+
}`,
|
|
512
|
+
settings?.customStyles?.uploadButton
|
|
513
|
+
);
|
|
371
514
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
515
|
+
return (
|
|
516
|
+
<Button
|
|
517
|
+
appearance="outlined"
|
|
518
|
+
size="sm"
|
|
519
|
+
onClick={handleNewImageClick}
|
|
520
|
+
disabled={isLoading}
|
|
521
|
+
className={uploadButtonClassName}
|
|
522
|
+
>
|
|
523
|
+
<svg
|
|
524
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
525
|
+
width="20"
|
|
526
|
+
height="20"
|
|
527
|
+
viewBox="0 0 24 24"
|
|
528
|
+
fill="none"
|
|
529
|
+
stroke="currentColor"
|
|
530
|
+
strokeWidth="2"
|
|
531
|
+
strokeLinecap="round"
|
|
532
|
+
strokeLinejoin="round"
|
|
533
|
+
className="text-gray-500"
|
|
534
|
+
>
|
|
535
|
+
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path>
|
|
536
|
+
<circle cx="12" cy="13" r="4"></circle>
|
|
537
|
+
</svg>
|
|
538
|
+
{t('common.product.new_image')}
|
|
539
|
+
</Button>
|
|
540
|
+
);
|
|
541
|
+
})()}
|
|
542
|
+
</>
|
|
400
543
|
)}
|
|
401
|
-
</Button>
|
|
402
|
-
);
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
return (
|
|
406
|
-
<div className={imageSectionClassName}>
|
|
407
|
-
<div className={imageContainerClassName}>
|
|
408
|
-
{renderCropButton()}
|
|
409
|
-
{renderTickButton()}
|
|
410
544
|
|
|
411
545
|
{(() => {
|
|
412
546
|
if (
|
|
413
547
|
settings?.customRenderers?.render?.filterSidebar
|
|
414
|
-
?.
|
|
548
|
+
?.renderResetButton
|
|
415
549
|
) {
|
|
416
|
-
return settings.customRenderers.render.filterSidebar.
|
|
550
|
+
return settings.customRenderers.render.filterSidebar.renderResetButton(
|
|
417
551
|
{
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
552
|
+
onClick: handleResetToOriginal,
|
|
553
|
+
disabled: isLoading,
|
|
554
|
+
showButton:
|
|
555
|
+
showResetButton && (hasUploadedImage || completedCrop)
|
|
421
556
|
}
|
|
422
557
|
);
|
|
423
558
|
}
|
|
424
559
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
560
|
+
if (!showResetButton || (!hasUploadedImage && !completedCrop))
|
|
561
|
+
return null;
|
|
562
|
+
|
|
563
|
+
const resetButtonClassName = twMerge(
|
|
564
|
+
`flex items-center gap-2 text-xs md:text-sm justify-center bg-blue-100 hover:bg-blue-200 border-blue-200 text-blue-600 ${
|
|
565
|
+
isLoading ? 'opacity-50 cursor-not-allowed' : ''
|
|
566
|
+
}`,
|
|
567
|
+
settings?.customStyles?.resetButton
|
|
428
568
|
);
|
|
429
569
|
|
|
430
570
|
return (
|
|
431
|
-
<
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
src={currentImageUrl || ''}
|
|
458
|
-
alt={product?.name || 'Product image'}
|
|
459
|
-
className={twMerge(
|
|
460
|
-
'max-w-full max-h-[200px] md:max-h-[280px]',
|
|
461
|
-
settings?.customStyles?.cropImage,
|
|
462
|
-
settings?.customStyles?.cropImageActive
|
|
463
|
-
)}
|
|
464
|
-
style={{ transform: `scale(1) rotate(0deg)` }}
|
|
465
|
-
/>
|
|
466
|
-
</ReactCrop>
|
|
467
|
-
) : (
|
|
468
|
-
<div
|
|
469
|
-
className={twMerge(
|
|
470
|
-
'relative w-full h-full flex items-center justify-center',
|
|
471
|
-
settings?.customStyles?.cropImageContainer
|
|
472
|
-
)}
|
|
473
|
-
>
|
|
474
|
-
<img
|
|
475
|
-
ref={imageRef}
|
|
476
|
-
src={currentImageUrl || ''}
|
|
477
|
-
alt={product?.name || 'Product image'}
|
|
478
|
-
className={twMerge(
|
|
479
|
-
'max-w-full max-h-[200px] md:max-h-[280px] object-contain',
|
|
480
|
-
settings?.customStyles?.cropImage,
|
|
481
|
-
settings?.customStyles?.cropImageNonCropping
|
|
482
|
-
)}
|
|
483
|
-
/>
|
|
484
|
-
{!isCropping && completedCrop && (
|
|
485
|
-
<div
|
|
486
|
-
className={twMerge(
|
|
487
|
-
'hidden md:block absolute inset-0 bg-black bg-opacity-50 transition-opacity duration-300 ease-in-out',
|
|
488
|
-
settings?.customStyles?.cropOverlay,
|
|
489
|
-
settings?.customStyles?.cropOverlayBackground
|
|
490
|
-
)}
|
|
491
|
-
>
|
|
492
|
-
<div
|
|
493
|
-
className={twMerge(
|
|
494
|
-
'absolute transition-all duration-300 ease-in-out',
|
|
495
|
-
settings?.customStyles?.cropSelection,
|
|
496
|
-
settings?.customStyles?.cropSelectionHighlight
|
|
497
|
-
)}
|
|
498
|
-
style={{
|
|
499
|
-
width: `${completedCrop.width}px`,
|
|
500
|
-
height: `${completedCrop.height}px`,
|
|
501
|
-
left: `${completedCrop.x}px`,
|
|
502
|
-
top: `${completedCrop.y}px`,
|
|
503
|
-
boxShadow: '0 0 0 9999px rgba(0, 0, 0, 0.5)',
|
|
504
|
-
border: '2px solid white'
|
|
505
|
-
}}
|
|
506
|
-
></div>
|
|
507
|
-
</div>
|
|
508
|
-
)}
|
|
509
|
-
</div>
|
|
510
|
-
)}
|
|
511
|
-
</div>
|
|
571
|
+
<Button
|
|
572
|
+
appearance="outlined"
|
|
573
|
+
size="sm"
|
|
574
|
+
onClick={handleResetToOriginal}
|
|
575
|
+
disabled={isLoading}
|
|
576
|
+
className={resetButtonClassName}
|
|
577
|
+
>
|
|
578
|
+
<svg
|
|
579
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
580
|
+
width="20"
|
|
581
|
+
height="20"
|
|
582
|
+
viewBox="0 0 24 24"
|
|
583
|
+
fill="none"
|
|
584
|
+
stroke="currentColor"
|
|
585
|
+
strokeWidth="2"
|
|
586
|
+
strokeLinecap="round"
|
|
587
|
+
strokeLinejoin="round"
|
|
588
|
+
className="text-blue-600"
|
|
589
|
+
>
|
|
590
|
+
<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path>
|
|
591
|
+
<path d="M21 3v5h-5"></path>
|
|
592
|
+
<path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"></path>
|
|
593
|
+
<path d="M3 21v-5h5"></path>
|
|
594
|
+
</svg>
|
|
595
|
+
{t('common.product.reset_to_original')}
|
|
596
|
+
</Button>
|
|
512
597
|
);
|
|
513
598
|
})()}
|
|
514
599
|
</div>
|
|
600
|
+
)}
|
|
515
601
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
type="file"
|
|
527
|
-
accept="image/*"
|
|
528
|
-
ref={fileInputRef}
|
|
529
|
-
onChange={handleFileChangeWithCropReset}
|
|
530
|
-
className="hidden"
|
|
531
|
-
/>
|
|
532
|
-
{(() => {
|
|
533
|
-
if (
|
|
534
|
-
settings?.customRenderers?.render?.filterSidebar
|
|
535
|
-
?.renderUploadButton
|
|
536
|
-
) {
|
|
537
|
-
return settings.customRenderers.render.filterSidebar.renderUploadButton(
|
|
538
|
-
{
|
|
539
|
-
onClick: handleNewImageClick,
|
|
540
|
-
disabled: isLoading
|
|
541
|
-
}
|
|
542
|
-
);
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
const uploadButtonClassName = twMerge(
|
|
546
|
-
`flex items-center gap-2 text-xs md:text-sm justify-center bg-gray-100 hover:bg-gray-200 border-gray-200 ${
|
|
547
|
-
isLoading ? 'opacity-50 cursor-not-allowed' : ''
|
|
548
|
-
}`,
|
|
549
|
-
settings?.customStyles?.uploadButton
|
|
550
|
-
);
|
|
551
|
-
|
|
552
|
-
return (
|
|
553
|
-
<Button
|
|
554
|
-
appearance="outlined"
|
|
555
|
-
size="sm"
|
|
556
|
-
onClick={handleNewImageClick}
|
|
557
|
-
disabled={isLoading}
|
|
558
|
-
className={uploadButtonClassName}
|
|
559
|
-
>
|
|
560
|
-
<svg
|
|
561
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
562
|
-
width="20"
|
|
563
|
-
height="20"
|
|
564
|
-
viewBox="0 0 24 24"
|
|
565
|
-
fill="none"
|
|
566
|
-
stroke="currentColor"
|
|
567
|
-
strokeWidth="2"
|
|
568
|
-
strokeLinecap="round"
|
|
569
|
-
strokeLinejoin="round"
|
|
570
|
-
className="text-gray-500"
|
|
571
|
-
>
|
|
572
|
-
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path>
|
|
573
|
-
<circle cx="12" cy="13" r="4"></circle>
|
|
574
|
-
</svg>
|
|
575
|
-
{t('common.product.new_image')}
|
|
576
|
-
</Button>
|
|
577
|
-
);
|
|
578
|
-
})()}
|
|
579
|
-
</>
|
|
580
|
-
)}
|
|
581
|
-
|
|
582
|
-
{(() => {
|
|
583
|
-
if (
|
|
584
|
-
settings?.customRenderers?.render?.filterSidebar
|
|
585
|
-
?.renderResetButton
|
|
586
|
-
) {
|
|
587
|
-
return settings.customRenderers.render.filterSidebar.renderResetButton(
|
|
588
|
-
{
|
|
589
|
-
onClick: handleResetToOriginal,
|
|
590
|
-
disabled: isLoading,
|
|
591
|
-
showButton:
|
|
592
|
-
showResetButton &&
|
|
593
|
-
(hasUploadedImage || completedCrop)
|
|
594
|
-
}
|
|
595
|
-
);
|
|
602
|
+
{fileError &&
|
|
603
|
+
!isCropping &&
|
|
604
|
+
(() => {
|
|
605
|
+
if (
|
|
606
|
+
settings?.customRenderers?.render?.filterSidebar
|
|
607
|
+
?.renderErrorMessage
|
|
608
|
+
) {
|
|
609
|
+
return settings.customRenderers.render.filterSidebar.renderErrorMessage(
|
|
610
|
+
{
|
|
611
|
+
error: fileError
|
|
596
612
|
}
|
|
613
|
+
);
|
|
614
|
+
}
|
|
597
615
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
return null;
|
|
616
|
+
const errorClassName = twMerge(
|
|
617
|
+
'mt-2 px-3 py-2 bg-red-50 border border-red-100 rounded-md',
|
|
618
|
+
settings?.customStyles?.errorMessage
|
|
619
|
+
);
|
|
603
620
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
|
|
621
|
+
return (
|
|
622
|
+
<div className={errorClassName}>
|
|
623
|
+
<p className="text-xs text-red-600 font-medium">
|
|
624
|
+
{fileError}
|
|
625
|
+
</p>
|
|
626
|
+
</div>
|
|
627
|
+
);
|
|
628
|
+
})()}
|
|
629
|
+
</div>
|
|
630
|
+
);
|
|
631
|
+
})()}
|
|
632
|
+
|
|
633
|
+
{/* Filters */}
|
|
634
|
+
<div className="space-y-2 md:space-y-4">
|
|
635
|
+
{searchResults?.facets
|
|
636
|
+
?.filter((facet) => facet.key !== 'category_ids')
|
|
637
|
+
?.map((facet) => {
|
|
638
|
+
if (
|
|
639
|
+
settings?.customRenderers?.render?.filterSidebar
|
|
640
|
+
?.renderFilterGroup
|
|
641
|
+
) {
|
|
642
|
+
return settings.customRenderers.render.filterSidebar.renderFilterGroup(
|
|
643
|
+
{
|
|
644
|
+
facet,
|
|
645
|
+
onFacetChange: handleFacetChange,
|
|
646
|
+
isLoading
|
|
647
|
+
}
|
|
648
|
+
);
|
|
649
|
+
}
|
|
610
650
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
disabled={isLoading}
|
|
617
|
-
className={resetButtonClassName}
|
|
618
|
-
>
|
|
619
|
-
<svg
|
|
620
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
621
|
-
width="20"
|
|
622
|
-
height="20"
|
|
623
|
-
viewBox="0 0 24 24"
|
|
624
|
-
fill="none"
|
|
625
|
-
stroke="currentColor"
|
|
626
|
-
strokeWidth="2"
|
|
627
|
-
strokeLinecap="round"
|
|
628
|
-
strokeLinejoin="round"
|
|
629
|
-
className="text-blue-600"
|
|
630
|
-
>
|
|
631
|
-
<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path>
|
|
632
|
-
<path d="M21 3v5h-5"></path>
|
|
633
|
-
<path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"></path>
|
|
634
|
-
<path d="M3 21v-5h5"></path>
|
|
635
|
-
</svg>
|
|
636
|
-
{t('common.product.reset_to_original')}
|
|
637
|
-
</Button>
|
|
638
|
-
);
|
|
639
|
-
})()}
|
|
640
|
-
</div>
|
|
641
|
-
)}
|
|
651
|
+
const Component = getComponentByWidgetType(
|
|
652
|
+
facet.widget_type,
|
|
653
|
+
facet.key
|
|
654
|
+
);
|
|
655
|
+
const choices = facet.data.choices || [];
|
|
642
656
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
return settings.customRenderers.render.filterSidebar.renderErrorMessage(
|
|
651
|
-
{
|
|
652
|
-
error: fileError
|
|
653
|
-
}
|
|
654
|
-
);
|
|
655
|
-
}
|
|
657
|
+
if (!Component) {
|
|
658
|
+
console.warn(
|
|
659
|
+
'Component not found for widget type:',
|
|
660
|
+
facet.widget_type
|
|
661
|
+
);
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
656
664
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
665
|
+
const filterGroupClassName = twMerge(
|
|
666
|
+
'filter-group',
|
|
667
|
+
settings?.customStyles?.filterGroup
|
|
668
|
+
);
|
|
661
669
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
})()}
|
|
670
|
-
</div>
|
|
671
|
-
);
|
|
672
|
-
})()}
|
|
670
|
+
const filterGroupContentClassName = twMerge(
|
|
671
|
+
clsx('flex gap-4', {
|
|
672
|
+
'flex-wrap flex-row': facet.key === sizeKey,
|
|
673
|
+
'flex-col': facet.key !== sizeKey
|
|
674
|
+
}),
|
|
675
|
+
settings?.customStyles?.filterGroupContent
|
|
676
|
+
);
|
|
673
677
|
|
|
674
|
-
|
|
675
|
-
<div className="space-y-2 md:space-y-4">
|
|
676
|
-
{searchResults?.facets
|
|
677
|
-
?.filter((facet) => facet.key !== 'category_ids')
|
|
678
|
-
?.map((facet) => {
|
|
678
|
+
const renderFilterGroupTitle = () => {
|
|
679
679
|
if (
|
|
680
680
|
settings?.customRenderers?.render?.filterSidebar
|
|
681
|
-
?.
|
|
681
|
+
?.renderFilterGroupTitle
|
|
682
682
|
) {
|
|
683
|
-
return settings.customRenderers.render.filterSidebar.
|
|
683
|
+
return settings.customRenderers.render.filterSidebar.renderFilterGroupTitle(
|
|
684
684
|
{
|
|
685
|
-
facet,
|
|
686
|
-
|
|
687
|
-
|
|
685
|
+
title: facet.name,
|
|
686
|
+
isCollapsed: choices.some((choice) => choice.is_selected),
|
|
687
|
+
onToggle: () => {}
|
|
688
688
|
}
|
|
689
689
|
);
|
|
690
690
|
}
|
|
691
|
+
return null;
|
|
692
|
+
};
|
|
691
693
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
694
|
+
const renderFilterItem = (choice: any, index: number) => {
|
|
695
|
+
if (
|
|
696
|
+
settings?.customRenderers?.render?.filterSidebar
|
|
697
|
+
?.renderFilterItem
|
|
698
|
+
) {
|
|
699
|
+
return settings.customRenderers.render.filterSidebar.renderFilterItem(
|
|
700
|
+
{
|
|
701
|
+
choice,
|
|
702
|
+
facetKey: facet.key,
|
|
703
|
+
onFacetChange: handleFacetChange,
|
|
704
|
+
isLoading,
|
|
705
|
+
isSelected: choice.is_selected
|
|
706
|
+
}
|
|
702
707
|
);
|
|
703
|
-
return null;
|
|
704
708
|
}
|
|
705
709
|
|
|
706
|
-
const
|
|
707
|
-
'filter-
|
|
708
|
-
settings?.customStyles?.
|
|
710
|
+
const filterItemClassName = twMerge(
|
|
711
|
+
'filter-item',
|
|
712
|
+
settings?.customStyles?.filterItem
|
|
709
713
|
);
|
|
710
714
|
|
|
711
|
-
const
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
'flex-col': facet.key !== sizeKey
|
|
715
|
-
}),
|
|
716
|
-
settings?.customStyles?.filterGroupContent
|
|
715
|
+
const filterItemInputClassName = twMerge(
|
|
716
|
+
'filter-item-input',
|
|
717
|
+
settings?.customStyles?.filterItemInput
|
|
717
718
|
);
|
|
718
719
|
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
) {
|
|
724
|
-
return settings.customRenderers.render.filterSidebar.renderFilterGroupTitle(
|
|
725
|
-
{
|
|
726
|
-
title: facet.name,
|
|
727
|
-
isCollapsed: choices.some((choice) => choice.is_selected),
|
|
728
|
-
onToggle: () => {}
|
|
729
|
-
}
|
|
730
|
-
);
|
|
731
|
-
}
|
|
732
|
-
return null;
|
|
733
|
-
};
|
|
734
|
-
|
|
735
|
-
const renderFilterItem = (choice: any, index: number) => {
|
|
736
|
-
if (
|
|
737
|
-
settings?.customRenderers?.render?.filterSidebar
|
|
738
|
-
?.renderFilterItem
|
|
739
|
-
) {
|
|
740
|
-
return settings.customRenderers.render.filterSidebar.renderFilterItem(
|
|
741
|
-
{
|
|
742
|
-
choice,
|
|
743
|
-
facetKey: facet.key,
|
|
744
|
-
onFacetChange: handleFacetChange,
|
|
745
|
-
isLoading,
|
|
746
|
-
isSelected: choice.is_selected
|
|
747
|
-
}
|
|
748
|
-
);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
const filterItemClassName = twMerge(
|
|
752
|
-
'filter-item',
|
|
753
|
-
settings?.customStyles?.filterItem
|
|
754
|
-
);
|
|
755
|
-
|
|
756
|
-
const filterItemInputClassName = twMerge(
|
|
757
|
-
'filter-item-input',
|
|
758
|
-
settings?.customStyles?.filterItemInput
|
|
759
|
-
);
|
|
760
|
-
|
|
761
|
-
const filterItemLabelClassName = twMerge(
|
|
762
|
-
'filter-item-label',
|
|
763
|
-
settings?.customStyles?.filterItemLabel
|
|
764
|
-
);
|
|
765
|
-
|
|
766
|
-
const filterItemCountClassName = twMerge(
|
|
767
|
-
'filter-item-count',
|
|
768
|
-
settings?.customStyles?.filterItemCount
|
|
769
|
-
);
|
|
720
|
+
const filterItemLabelClassName = twMerge(
|
|
721
|
+
'filter-item-label',
|
|
722
|
+
settings?.customStyles?.filterItemLabel
|
|
723
|
+
);
|
|
770
724
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
value={choice.value}
|
|
776
|
-
label={choice.label}
|
|
777
|
-
name={facet.key}
|
|
778
|
-
onChange={() => {
|
|
779
|
-
if (!isLoading) {
|
|
780
|
-
handleFacetChange(facet.key, choice.value);
|
|
781
|
-
}
|
|
782
|
-
}}
|
|
783
|
-
onClick={() => {
|
|
784
|
-
if (!isLoading && facet.key === sizeKey) {
|
|
785
|
-
handleFacetChange(facet.key, choice.value);
|
|
786
|
-
}
|
|
787
|
-
}}
|
|
788
|
-
checked={choice.is_selected}
|
|
789
|
-
data-testid={`${choice.label.trim()}`}
|
|
790
|
-
disabled={isLoading}
|
|
791
|
-
className={filterItemInputClassName}
|
|
792
|
-
>
|
|
793
|
-
<span className={filterItemLabelClassName}>
|
|
794
|
-
{choice.label}
|
|
795
|
-
</span>{' '}
|
|
796
|
-
(
|
|
797
|
-
<span
|
|
798
|
-
data-testid={`filter-count-${facet.name.toLowerCase()}-${index}`}
|
|
799
|
-
className={filterItemCountClassName}
|
|
800
|
-
>
|
|
801
|
-
{choice.quantity}
|
|
802
|
-
</span>
|
|
803
|
-
)
|
|
804
|
-
</Component>
|
|
805
|
-
</div>
|
|
806
|
-
);
|
|
807
|
-
};
|
|
725
|
+
const filterItemCountClassName = twMerge(
|
|
726
|
+
'filter-item-count',
|
|
727
|
+
settings?.customStyles?.filterItemCount
|
|
728
|
+
);
|
|
808
729
|
|
|
809
730
|
return (
|
|
810
|
-
<div key={
|
|
811
|
-
<
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
731
|
+
<div key={choice.value} className={filterItemClassName}>
|
|
732
|
+
<Component
|
|
733
|
+
key={choice.label}
|
|
734
|
+
value={choice.value}
|
|
735
|
+
label={choice.label}
|
|
736
|
+
name={facet.key}
|
|
737
|
+
onChange={() => {
|
|
738
|
+
if (!isLoading) {
|
|
739
|
+
handleFacetChange(facet.key, choice.value);
|
|
740
|
+
}
|
|
741
|
+
}}
|
|
742
|
+
onClick={() => {
|
|
743
|
+
if (!isLoading && facet.key === sizeKey) {
|
|
744
|
+
handleFacetChange(facet.key, choice.value);
|
|
745
|
+
}
|
|
746
|
+
}}
|
|
747
|
+
checked={choice.is_selected}
|
|
748
|
+
data-testid={`${choice.label.trim()}`}
|
|
749
|
+
disabled={isLoading}
|
|
750
|
+
className={filterItemInputClassName}
|
|
815
751
|
>
|
|
816
|
-
<
|
|
817
|
-
{
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
752
|
+
<span className={filterItemLabelClassName}>
|
|
753
|
+
{choice.label}
|
|
754
|
+
</span>{' '}
|
|
755
|
+
(
|
|
756
|
+
<span
|
|
757
|
+
data-testid={`filter-count-${facet.name.toLowerCase()}-${index}`}
|
|
758
|
+
className={filterItemCountClassName}
|
|
759
|
+
>
|
|
760
|
+
{choice.quantity}
|
|
761
|
+
</span>
|
|
762
|
+
)
|
|
763
|
+
</Component>
|
|
824
764
|
</div>
|
|
825
765
|
);
|
|
826
|
-
}
|
|
827
|
-
</div>
|
|
828
|
-
|
|
829
|
-
{/* Mobile Active Filters and Clear Button */}
|
|
830
|
-
{(() => {
|
|
831
|
-
const hasActiveFilters = searchResults?.facets
|
|
832
|
-
?.filter((facet) => facet.key !== 'category_ids')
|
|
833
|
-
?.some((facet) =>
|
|
834
|
-
facet.data.choices?.some((choice) => choice.is_selected)
|
|
835
|
-
);
|
|
836
|
-
|
|
837
|
-
if (!hasActiveFilters) return null;
|
|
766
|
+
};
|
|
838
767
|
|
|
839
|
-
const activeFilters = searchResults.facets
|
|
840
|
-
.filter((facet) => facet.key !== 'category_ids')
|
|
841
|
-
.flatMap(
|
|
842
|
-
(facet) =>
|
|
843
|
-
facet.data.choices
|
|
844
|
-
?.filter((choice) => choice.is_selected)
|
|
845
|
-
.map((choice) => ({
|
|
846
|
-
key: facet.key,
|
|
847
|
-
value: choice.value.toString(),
|
|
848
|
-
label: choice.label
|
|
849
|
-
})) || []
|
|
850
|
-
);
|
|
851
|
-
|
|
852
|
-
const handleClearAll = () => {
|
|
853
|
-
if (!isLoading) {
|
|
854
|
-
const facetsToRemove = [];
|
|
855
|
-
searchResults?.facets
|
|
856
|
-
?.filter((facet) => facet.key !== 'category_ids')
|
|
857
|
-
?.forEach((facet) => {
|
|
858
|
-
facet.data.choices
|
|
859
|
-
?.filter((choice) => choice.is_selected)
|
|
860
|
-
.forEach((choice) => {
|
|
861
|
-
facetsToRemove.push({
|
|
862
|
-
facetKey: facet.key,
|
|
863
|
-
choiceValue: choice.value
|
|
864
|
-
});
|
|
865
|
-
});
|
|
866
|
-
});
|
|
867
|
-
|
|
868
|
-
facetsToRemove.forEach(({ facetKey, choiceValue }) => {
|
|
869
|
-
removeFacetFilter(facetKey, choiceValue);
|
|
870
|
-
});
|
|
871
|
-
}
|
|
872
|
-
};
|
|
873
|
-
|
|
874
|
-
if (
|
|
875
|
-
settings?.customRenderers?.render?.filterSidebar
|
|
876
|
-
?.renderMobileActiveFilters
|
|
877
|
-
) {
|
|
878
768
|
return (
|
|
879
|
-
<div className=
|
|
880
|
-
|
|
881
|
-
{
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
769
|
+
<div key={facet.key} className={filterGroupClassName}>
|
|
770
|
+
<Accordion
|
|
771
|
+
title={renderFilterGroupTitle() || facet.name}
|
|
772
|
+
isCollapse={choices.some((choice) => choice.is_selected)}
|
|
773
|
+
dataTestId={`filter-${facet.name}`}
|
|
774
|
+
>
|
|
775
|
+
<div className={filterGroupContentClassName}>
|
|
776
|
+
{choices
|
|
777
|
+
.slice(0, 10)
|
|
778
|
+
.map((choice, index) => renderFilterItem(choice, index))}
|
|
779
|
+
</div>
|
|
780
|
+
</Accordion>
|
|
888
781
|
</div>
|
|
889
782
|
);
|
|
890
|
-
}
|
|
783
|
+
})}
|
|
784
|
+
</div>
|
|
891
785
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
786
|
+
{/* Mobile Active Filters and Clear Button */}
|
|
787
|
+
{(() => {
|
|
788
|
+
const hasActiveFilters = searchResults?.facets
|
|
789
|
+
?.filter((facet) => facet.key !== 'category_ids')
|
|
790
|
+
?.some((facet) =>
|
|
791
|
+
facet.data.choices?.some((choice) => choice.is_selected)
|
|
895
792
|
);
|
|
896
793
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
794
|
+
if (!hasActiveFilters) return null;
|
|
795
|
+
|
|
796
|
+
const activeFilters = searchResults.facets
|
|
797
|
+
.filter((facet) => facet.key !== 'category_ids')
|
|
798
|
+
.flatMap(
|
|
799
|
+
(facet) =>
|
|
800
|
+
facet.data.choices
|
|
801
|
+
?.filter((choice) => choice.is_selected)
|
|
802
|
+
.map((choice) => ({
|
|
803
|
+
key: facet.key,
|
|
804
|
+
value: choice.value.toString(),
|
|
805
|
+
label: choice.label
|
|
806
|
+
})) || []
|
|
900
807
|
);
|
|
901
808
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
809
|
+
const handleClearAll = () => {
|
|
810
|
+
if (!isLoading) {
|
|
811
|
+
const facetsToRemove = [];
|
|
812
|
+
searchResults?.facets
|
|
813
|
+
?.filter((facet) => facet.key !== 'category_ids')
|
|
814
|
+
?.forEach((facet) => {
|
|
815
|
+
facet.data.choices
|
|
816
|
+
?.filter((choice) => choice.is_selected)
|
|
817
|
+
.forEach((choice) => {
|
|
818
|
+
facetsToRemove.push({
|
|
819
|
+
facetKey: facet.key,
|
|
820
|
+
choiceValue: choice.value
|
|
821
|
+
});
|
|
822
|
+
});
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
facetsToRemove.forEach(({ facetKey, choiceValue }) => {
|
|
826
|
+
removeFacetFilter(facetKey, choiceValue);
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
};
|
|
906
830
|
|
|
831
|
+
if (
|
|
832
|
+
settings?.customRenderers?.render?.filterSidebar
|
|
833
|
+
?.renderMobileActiveFilters
|
|
834
|
+
) {
|
|
907
835
|
return (
|
|
908
|
-
<div className=
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
836
|
+
<div className="md:hidden mt-6">
|
|
837
|
+
{settings.customRenderers.render.filterSidebar.renderMobileActiveFilters(
|
|
838
|
+
{
|
|
839
|
+
filters: activeFilters,
|
|
840
|
+
onRemove: handleFacetChange,
|
|
841
|
+
onClearAll: handleClearAll,
|
|
842
|
+
isLoading
|
|
843
|
+
}
|
|
844
|
+
)}
|
|
845
|
+
</div>
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
const mobileActiveFiltersClassName = twMerge(
|
|
850
|
+
'md:hidden mt-6',
|
|
851
|
+
settings?.customStyles?.mobileActiveFilters
|
|
852
|
+
);
|
|
853
|
+
|
|
854
|
+
const mobileActiveFilterTagClassName = twMerge(
|
|
855
|
+
'flex items-center gap-1 px-2 py-1 bg-gray-100 rounded-full text-xs',
|
|
856
|
+
settings?.customStyles?.mobileActiveFilterTag
|
|
857
|
+
);
|
|
858
|
+
|
|
859
|
+
const mobileClearAllButtonClassName = twMerge(
|
|
860
|
+
'w-full',
|
|
861
|
+
settings?.customStyles?.mobileClearAllButton
|
|
862
|
+
);
|
|
863
|
+
|
|
864
|
+
return (
|
|
865
|
+
<div className={mobileActiveFiltersClassName}>
|
|
866
|
+
<div className="mb-4">
|
|
867
|
+
<h4 className="text-sm font-medium mb-2">
|
|
868
|
+
{t('common.product.active_filters')}
|
|
869
|
+
</h4>
|
|
870
|
+
<div className="flex flex-wrap gap-2">
|
|
871
|
+
{activeFilters.map((filter) => (
|
|
872
|
+
<div
|
|
873
|
+
key={`${filter.key}-${filter.value}`}
|
|
874
|
+
className={mobileActiveFilterTagClassName}
|
|
875
|
+
>
|
|
876
|
+
<span>{filter.label}</span>
|
|
877
|
+
<Button
|
|
878
|
+
appearance="ghost"
|
|
879
|
+
size="sm"
|
|
880
|
+
onClick={() => {
|
|
881
|
+
if (!isLoading) {
|
|
882
|
+
handleFacetChange(filter.key, filter.value);
|
|
883
|
+
}
|
|
884
|
+
}}
|
|
885
|
+
disabled={isLoading}
|
|
886
|
+
className="hover:bg-gray-200 rounded-full p-0 w-5 h-5 disabled:opacity-50 disabled:cursor-not-allowed ml-1"
|
|
918
887
|
>
|
|
919
|
-
<
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
onClick={() => {
|
|
924
|
-
if (!isLoading) {
|
|
925
|
-
handleFacetChange(filter.key, filter.value);
|
|
926
|
-
}
|
|
927
|
-
}}
|
|
928
|
-
disabled={isLoading}
|
|
929
|
-
className="hover:bg-gray-200 rounded-full p-0 w-5 h-5 disabled:opacity-50 disabled:cursor-not-allowed ml-1"
|
|
930
|
-
>
|
|
931
|
-
<Icon name="close" size={10} />
|
|
932
|
-
</Button>
|
|
933
|
-
</div>
|
|
934
|
-
))}
|
|
935
|
-
</div>
|
|
888
|
+
<Icon name="close" size={10} />
|
|
889
|
+
</Button>
|
|
890
|
+
</div>
|
|
891
|
+
))}
|
|
936
892
|
</div>
|
|
937
|
-
|
|
938
|
-
<Button
|
|
939
|
-
appearance="outlined"
|
|
940
|
-
className={mobileClearAllButtonClassName}
|
|
941
|
-
onClick={handleClearAll}
|
|
942
|
-
disabled={isLoading}
|
|
943
|
-
>
|
|
944
|
-
{t('common.product.clear_all_filters')}
|
|
945
|
-
</Button>
|
|
946
893
|
</div>
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
894
|
+
|
|
895
|
+
<Button
|
|
896
|
+
appearance="outlined"
|
|
897
|
+
className={mobileClearAllButtonClassName}
|
|
898
|
+
onClick={handleClearAll}
|
|
899
|
+
disabled={isLoading}
|
|
900
|
+
>
|
|
901
|
+
{t('common.product.clear_all_filters')}
|
|
902
|
+
</Button>
|
|
903
|
+
</div>
|
|
904
|
+
);
|
|
905
|
+
})()}
|
|
906
|
+
</div>
|
|
951
907
|
);
|
|
952
908
|
}
|