@akinon/pz-virtual-try-on 2.0.0-beta.16 → 2.0.0-beta.18
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 +29 -0
- package/README.md +403 -7
- package/package.json +4 -3
- package/src/components/barcode-scanner.tsx +422 -0
- package/src/data/barcode-endpoints.ts +34 -0
- package/src/hooks/use-barcode-search.ts +172 -0
- package/src/hooks/use-image-cropper.ts +38 -7
- package/src/hooks/use-virtual-try-on-async.ts +1 -0
- package/src/hooks/use-virtual-try-on.ts +14 -2
- package/src/index.ts +26 -1
- package/src/types/barcode.ts +308 -0
- package/src/types/index.ts +32 -0
- package/src/utils/error-mapping.ts +3 -1
- package/src/utils/index.ts +115 -0
- package/src/views/barcode-scanner-button.tsx +63 -0
- package/src/views/barcode-scanner-modal.tsx +632 -0
- package/src/views/barcode-scanner-plugin.tsx +232 -0
- package/src/views/basket-async-modal.tsx +7 -2
- package/src/views/virtual-try-on-upload-modal.tsx +47 -41
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
|
4
|
+
import { Product } from '@akinon/next/types';
|
|
5
|
+
import { BarcodeScannerButton } from './barcode-scanner-button';
|
|
6
|
+
import { BarcodeScannerModal } from './barcode-scanner-modal';
|
|
7
|
+
import { VirtualTryOnProductSelector } from './virtual-try-on-product-selector';
|
|
8
|
+
import { VirtualTryOnUploadModal } from './virtual-try-on-upload-modal';
|
|
9
|
+
import { BasketAsyncModal } from './basket-async-modal';
|
|
10
|
+
import { useVirtualTryOnAsync } from '../hooks/use-virtual-try-on-async';
|
|
11
|
+
import { getVirtualTryOnEnabled } from '../utils';
|
|
12
|
+
import type {
|
|
13
|
+
BarcodeScannerSettings,
|
|
14
|
+
VirtualTryOnPluginSettings,
|
|
15
|
+
BasketProduct
|
|
16
|
+
} from '../types';
|
|
17
|
+
|
|
18
|
+
export interface BarcodeScannerPluginProps {
|
|
19
|
+
className?: string;
|
|
20
|
+
barcodeScannerSettings?: BarcodeScannerSettings;
|
|
21
|
+
vtoSettings?: VirtualTryOnPluginSettings;
|
|
22
|
+
|
|
23
|
+
settings?: {
|
|
24
|
+
barcodeScanner?: BarcodeScannerSettings;
|
|
25
|
+
vto?: VirtualTryOnPluginSettings;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
onProductsScanned?: (products: Product[]) => void;
|
|
29
|
+
onVTOComplete?: (result: any) => void;
|
|
30
|
+
|
|
31
|
+
showVTOContinue?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function BarcodeScannerPlugin({
|
|
35
|
+
className,
|
|
36
|
+
barcodeScannerSettings,
|
|
37
|
+
vtoSettings,
|
|
38
|
+
settings,
|
|
39
|
+
onProductsScanned,
|
|
40
|
+
onVTOComplete,
|
|
41
|
+
showVTOContinue = true
|
|
42
|
+
}: BarcodeScannerPluginProps) {
|
|
43
|
+
// Check if virtual try-on is enabled
|
|
44
|
+
const [isEnabled, setIsEnabled] = useState(false);
|
|
45
|
+
|
|
46
|
+
// Merge settings from props and PluginModule settings
|
|
47
|
+
const finalBarcodeScannerSettings =
|
|
48
|
+
barcodeScannerSettings || settings?.barcodeScanner;
|
|
49
|
+
const finalVtoSettings = vtoSettings || settings?.vto;
|
|
50
|
+
|
|
51
|
+
const [isScannerModalOpen, setIsScannerModalOpen] = useState(false);
|
|
52
|
+
const [isSelectorOpen, setIsSelectorOpen] = useState(false);
|
|
53
|
+
const [showUploadModal, setShowUploadModal] = useState(false);
|
|
54
|
+
const [showAsyncModal, setShowAsyncModal] = useState(false);
|
|
55
|
+
const [scannedProducts, setScannedProducts] = useState<BasketProduct[]>([]);
|
|
56
|
+
const [selectedProducts, setSelectedProducts] = useState<BasketProduct[]>([]);
|
|
57
|
+
const [categoryMapping, setCategoryMapping] = useState<
|
|
58
|
+
Record<string, number[]>
|
|
59
|
+
>({});
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
setIsEnabled(getVirtualTryOnEnabled());
|
|
63
|
+
}, []);
|
|
64
|
+
|
|
65
|
+
// Fetch categories when products are selected
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (selectedProducts.length === 0) {
|
|
68
|
+
setCategoryMapping({});
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const fetchCategories = async () => {
|
|
73
|
+
try {
|
|
74
|
+
const pks = selectedProducts.map((item) => item.pk).join(',');
|
|
75
|
+
const response = await fetch(`/api/product-categories?pks=${pks}`);
|
|
76
|
+
|
|
77
|
+
if (response.ok) {
|
|
78
|
+
const mapping = await response.json();
|
|
79
|
+
setCategoryMapping(mapping);
|
|
80
|
+
}
|
|
81
|
+
} catch (error) {}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
fetchCategories();
|
|
85
|
+
}, [selectedProducts]);
|
|
86
|
+
|
|
87
|
+
const hookData = useVirtualTryOnAsync(
|
|
88
|
+
selectedProducts.length > 0
|
|
89
|
+
? selectedProducts
|
|
90
|
+
: [{ pk: 0, sku: '', name: '', productimage_set: [], attributes: {} }],
|
|
91
|
+
categoryMapping
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const handleOpenScanner = useCallback(() => {
|
|
95
|
+
setIsScannerModalOpen(true);
|
|
96
|
+
}, []);
|
|
97
|
+
|
|
98
|
+
const handleCloseScannerModal = useCallback(() => {
|
|
99
|
+
setIsScannerModalOpen(false);
|
|
100
|
+
setScannedProducts([]);
|
|
101
|
+
}, []);
|
|
102
|
+
|
|
103
|
+
const handleProductsFound = useCallback(
|
|
104
|
+
(products: Product[]) => {
|
|
105
|
+
onProductsScanned?.(products);
|
|
106
|
+
},
|
|
107
|
+
[onProductsScanned]
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const handleContinueToVTO = useCallback((products: Product[]) => {
|
|
111
|
+
if (products.length === 0) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const basketProducts: BasketProduct[] = products.map((product) => ({
|
|
116
|
+
pk: product.pk,
|
|
117
|
+
sku: product.sku || '',
|
|
118
|
+
name: product.name,
|
|
119
|
+
productimage_set: product.productimage_set,
|
|
120
|
+
attributes: product.attributes,
|
|
121
|
+
category: (product as any).category
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
setIsScannerModalOpen(false);
|
|
125
|
+
setScannedProducts(basketProducts);
|
|
126
|
+
|
|
127
|
+
if (basketProducts.length === 1) {
|
|
128
|
+
setSelectedProducts(basketProducts);
|
|
129
|
+
setShowUploadModal(true);
|
|
130
|
+
} else {
|
|
131
|
+
setIsSelectorOpen(true);
|
|
132
|
+
}
|
|
133
|
+
}, []);
|
|
134
|
+
|
|
135
|
+
const handleProductsSelected = useCallback((products: BasketProduct[]) => {
|
|
136
|
+
setSelectedProducts(products);
|
|
137
|
+
setIsSelectorOpen(false);
|
|
138
|
+
setShowUploadModal(true);
|
|
139
|
+
}, []);
|
|
140
|
+
|
|
141
|
+
const handleSelectorClose = useCallback(() => {
|
|
142
|
+
setIsSelectorOpen(false);
|
|
143
|
+
setScannedProducts([]);
|
|
144
|
+
}, []);
|
|
145
|
+
|
|
146
|
+
const handleUploadModalClose = useCallback(() => {
|
|
147
|
+
hookData.cancelTryOn?.();
|
|
148
|
+
setShowUploadModal(false);
|
|
149
|
+
setSelectedProducts([]);
|
|
150
|
+
setScannedProducts([]);
|
|
151
|
+
setCategoryMapping({});
|
|
152
|
+
}, [hookData]);
|
|
153
|
+
|
|
154
|
+
const handleAsyncModalClose = useCallback(() => {
|
|
155
|
+
hookData.cancelTryOn?.();
|
|
156
|
+
setShowAsyncModal(false);
|
|
157
|
+
setSelectedProducts([]);
|
|
158
|
+
setScannedProducts([]);
|
|
159
|
+
setCategoryMapping({});
|
|
160
|
+
hookData.reset();
|
|
161
|
+
}, [hookData]);
|
|
162
|
+
|
|
163
|
+
const handleProcessingStart = useCallback(() => {
|
|
164
|
+
setShowUploadModal(false);
|
|
165
|
+
setShowAsyncModal(true);
|
|
166
|
+
}, []);
|
|
167
|
+
|
|
168
|
+
const mergedBarcodeSettings = useMemo(
|
|
169
|
+
(): BarcodeScannerSettings => ({
|
|
170
|
+
...finalBarcodeScannerSettings,
|
|
171
|
+
showContinueToVTO: showVTOContinue
|
|
172
|
+
}),
|
|
173
|
+
[finalBarcodeScannerSettings, showVTOContinue]
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
if (!isEnabled) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<>
|
|
182
|
+
<BarcodeScannerButton
|
|
183
|
+
onClick={handleOpenScanner}
|
|
184
|
+
className={className}
|
|
185
|
+
settings={mergedBarcodeSettings}
|
|
186
|
+
/>
|
|
187
|
+
|
|
188
|
+
<BarcodeScannerModal
|
|
189
|
+
isOpen={isScannerModalOpen}
|
|
190
|
+
onClose={handleCloseScannerModal}
|
|
191
|
+
onProductFound={handleProductsFound}
|
|
192
|
+
onContinueToVTO={handleContinueToVTO}
|
|
193
|
+
settings={mergedBarcodeSettings}
|
|
194
|
+
/>
|
|
195
|
+
|
|
196
|
+
{isSelectorOpen && scannedProducts.length > 0 && (
|
|
197
|
+
<VirtualTryOnProductSelector
|
|
198
|
+
isOpen={true}
|
|
199
|
+
onClose={handleSelectorClose}
|
|
200
|
+
products={scannedProducts}
|
|
201
|
+
maxSelection={3}
|
|
202
|
+
onConfirm={handleProductsSelected}
|
|
203
|
+
settings={finalVtoSettings}
|
|
204
|
+
/>
|
|
205
|
+
)}
|
|
206
|
+
|
|
207
|
+
{showUploadModal && selectedProducts.length > 0 && (
|
|
208
|
+
<VirtualTryOnUploadModal
|
|
209
|
+
isOpen={true}
|
|
210
|
+
onClose={handleUploadModalClose}
|
|
211
|
+
hookData={hookData}
|
|
212
|
+
onProcessingStart={handleProcessingStart}
|
|
213
|
+
settings={finalVtoSettings}
|
|
214
|
+
/>
|
|
215
|
+
)}
|
|
216
|
+
|
|
217
|
+
{showAsyncModal && selectedProducts.length > 0 && (
|
|
218
|
+
<BasketAsyncModal
|
|
219
|
+
isOpen={true}
|
|
220
|
+
onClose={handleAsyncModalClose}
|
|
221
|
+
hookData={hookData}
|
|
222
|
+
products={selectedProducts}
|
|
223
|
+
onComplete={onVTOComplete}
|
|
224
|
+
settings={finalVtoSettings}
|
|
225
|
+
source="barcode"
|
|
226
|
+
/>
|
|
227
|
+
)}
|
|
228
|
+
</>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export default BarcodeScannerPlugin;
|
|
@@ -17,6 +17,8 @@ export interface BasketAsyncModalProps {
|
|
|
17
17
|
hookData: ReturnType<typeof useVirtualTryOnAsync>;
|
|
18
18
|
onRetryUpload?: () => void;
|
|
19
19
|
settings?: VirtualTryOnPluginSettings;
|
|
20
|
+
/** Source of the modal - affects button text */
|
|
21
|
+
source?: 'basket' | 'barcode';
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
type ModalStep = 'processing' | 'results' | 'detail';
|
|
@@ -28,7 +30,8 @@ export function BasketAsyncModal({
|
|
|
28
30
|
onComplete,
|
|
29
31
|
hookData,
|
|
30
32
|
onRetryUpload,
|
|
31
|
-
settings
|
|
33
|
+
settings,
|
|
34
|
+
source = 'basket'
|
|
32
35
|
}: BasketAsyncModalProps) {
|
|
33
36
|
const { t } = useLocalization();
|
|
34
37
|
const [currentStep, setCurrentStep] = useState<ModalStep>('processing');
|
|
@@ -516,7 +519,9 @@ export function BasketAsyncModal({
|
|
|
516
519
|
settings?.customStyles?.basketAsyncModalBackButton
|
|
517
520
|
)}
|
|
518
521
|
>
|
|
519
|
-
{
|
|
522
|
+
{source === 'barcode'
|
|
523
|
+
? t('product.virtual_try_on.close_button')
|
|
524
|
+
: t('product.virtual_try_on.back_to_basket')}
|
|
520
525
|
</button>
|
|
521
526
|
</div>
|
|
522
527
|
</div>
|
|
@@ -122,6 +122,23 @@ export function VirtualTryOnUploadModal({
|
|
|
122
122
|
const localHookData = product ? useVirtualTryOn(product) : null;
|
|
123
123
|
const activeHookData = hookData || localHookData;
|
|
124
124
|
|
|
125
|
+
|
|
126
|
+
const getImageSrc = (
|
|
127
|
+
settingsImage: string | undefined,
|
|
128
|
+
defaultImage: string | { src: string }
|
|
129
|
+
): string => {
|
|
130
|
+
if (settingsImage) return settingsImage;
|
|
131
|
+
return typeof defaultImage === 'string' ? defaultImage : defaultImage.src;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const getText = (
|
|
135
|
+
settingsText: string | undefined,
|
|
136
|
+
localizationKey: string
|
|
137
|
+
): string => {
|
|
138
|
+
if (settingsText) return settingsText;
|
|
139
|
+
return t(localizationKey);
|
|
140
|
+
};
|
|
141
|
+
|
|
125
142
|
const {
|
|
126
143
|
uploadedImage,
|
|
127
144
|
originalImage,
|
|
@@ -424,8 +441,8 @@ export function VirtualTryOnUploadModal({
|
|
|
424
441
|
)}
|
|
425
442
|
>
|
|
426
443
|
{uploadedImage
|
|
427
|
-
?
|
|
428
|
-
:
|
|
444
|
+
? getText(settings?.customStyles?.uploadModalTexts?.editPhotoTitle, 'product.virtual_try_on.edit_photo')
|
|
445
|
+
: getText(settings?.customStyles?.uploadModalTexts?.title, 'product.virtual_try_on.title')}
|
|
429
446
|
</h3>
|
|
430
447
|
<button
|
|
431
448
|
type="button"
|
|
@@ -498,7 +515,7 @@ export function VirtualTryOnUploadModal({
|
|
|
498
515
|
)
|
|
499
516
|
)}
|
|
500
517
|
>
|
|
501
|
-
{
|
|
518
|
+
{getText(settings?.customStyles?.uploadModalTexts?.uploadPrompt, 'product.virtual_try_on.upload_prompt')}
|
|
502
519
|
</p>
|
|
503
520
|
<p
|
|
504
521
|
className={twMerge(
|
|
@@ -515,7 +532,7 @@ export function VirtualTryOnUploadModal({
|
|
|
515
532
|
)
|
|
516
533
|
)}
|
|
517
534
|
>
|
|
518
|
-
{
|
|
535
|
+
{getText(settings?.customStyles?.uploadRequirements, 'product.virtual_try_on.upload_requirements')}
|
|
519
536
|
</p>
|
|
520
537
|
</div>
|
|
521
538
|
<input
|
|
@@ -542,8 +559,7 @@ export function VirtualTryOnUploadModal({
|
|
|
542
559
|
settings?.customStyles?.rulesInfoText
|
|
543
560
|
)}
|
|
544
561
|
>
|
|
545
|
-
{
|
|
546
|
-
'Uygulamaya uygun fotoğraf yüklemeniz çok önemlidir.'}
|
|
562
|
+
{getText(settings?.customStyles?.uploadModalTexts?.uploadInfo, 'product.virtual_try_on.upload_info')}
|
|
547
563
|
</p>
|
|
548
564
|
</div>
|
|
549
565
|
|
|
@@ -567,11 +583,7 @@ export function VirtualTryOnUploadModal({
|
|
|
567
583
|
)}
|
|
568
584
|
>
|
|
569
585
|
<img
|
|
570
|
-
src={
|
|
571
|
-
typeof rule1Image === 'string'
|
|
572
|
-
? rule1Image
|
|
573
|
-
: rule1Image.src
|
|
574
|
-
}
|
|
586
|
+
src={getImageSrc(settings?.customStyles?.uploadModalImages?.ruleGoodExample, rule1Image)}
|
|
575
587
|
alt="Example"
|
|
576
588
|
className={twMerge(
|
|
577
589
|
'w-full h-full',
|
|
@@ -587,10 +599,10 @@ export function VirtualTryOnUploadModal({
|
|
|
587
599
|
)}
|
|
588
600
|
>
|
|
589
601
|
{[
|
|
590
|
-
{ img: rule2Image, num: 2 },
|
|
591
|
-
{ img: rule3Image, num: 3 },
|
|
592
|
-
{ img: rule4Image, num: 4 },
|
|
593
|
-
{ img: rule5Image, num: 5 }
|
|
602
|
+
{ img: getImageSrc(settings?.customStyles?.uploadModalImages?.ruleBadExample1, rule2Image), num: 2 },
|
|
603
|
+
{ img: getImageSrc(settings?.customStyles?.uploadModalImages?.ruleBadExample2, rule3Image), num: 3 },
|
|
604
|
+
{ img: getImageSrc(settings?.customStyles?.uploadModalImages?.ruleBadExample3, rule4Image), num: 4 },
|
|
605
|
+
{ img: getImageSrc(settings?.customStyles?.uploadModalImages?.ruleBadExample4, rule5Image), num: 5 }
|
|
594
606
|
].map(({ img, num }) => (
|
|
595
607
|
<div
|
|
596
608
|
key={num}
|
|
@@ -601,7 +613,7 @@ export function VirtualTryOnUploadModal({
|
|
|
601
613
|
)}
|
|
602
614
|
>
|
|
603
615
|
<img
|
|
604
|
-
src={
|
|
616
|
+
src={img}
|
|
605
617
|
alt={`Bad example ${num}`}
|
|
606
618
|
className={twMerge(
|
|
607
619
|
'w-full h-full',
|
|
@@ -644,7 +656,7 @@ export function VirtualTryOnUploadModal({
|
|
|
644
656
|
settings?.customStyles?.rulesListItemText
|
|
645
657
|
}
|
|
646
658
|
>
|
|
647
|
-
{
|
|
659
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule1, 'product.virtual_try_on.rule_1')}
|
|
648
660
|
</span>
|
|
649
661
|
</li>
|
|
650
662
|
<li
|
|
@@ -666,7 +678,7 @@ export function VirtualTryOnUploadModal({
|
|
|
666
678
|
settings?.customStyles?.rulesListItemText
|
|
667
679
|
}
|
|
668
680
|
>
|
|
669
|
-
{
|
|
681
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule2, 'product.virtual_try_on.rule_2')}
|
|
670
682
|
</span>
|
|
671
683
|
</li>
|
|
672
684
|
<li
|
|
@@ -688,7 +700,7 @@ export function VirtualTryOnUploadModal({
|
|
|
688
700
|
settings?.customStyles?.rulesListItemText
|
|
689
701
|
}
|
|
690
702
|
>
|
|
691
|
-
{
|
|
703
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule3, 'product.virtual_try_on.rule_3')}
|
|
692
704
|
</span>
|
|
693
705
|
</li>
|
|
694
706
|
<li
|
|
@@ -710,7 +722,7 @@ export function VirtualTryOnUploadModal({
|
|
|
710
722
|
settings?.customStyles?.rulesListItemText
|
|
711
723
|
}
|
|
712
724
|
>
|
|
713
|
-
{
|
|
725
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule4, 'product.virtual_try_on.rule_4')}
|
|
714
726
|
</span>
|
|
715
727
|
</li>
|
|
716
728
|
<li
|
|
@@ -732,7 +744,7 @@ export function VirtualTryOnUploadModal({
|
|
|
732
744
|
settings?.customStyles?.rulesListItemText
|
|
733
745
|
}
|
|
734
746
|
>
|
|
735
|
-
{
|
|
747
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule5, 'product.virtual_try_on.rule_5')}
|
|
736
748
|
</span>
|
|
737
749
|
</li>
|
|
738
750
|
<li
|
|
@@ -754,7 +766,7 @@ export function VirtualTryOnUploadModal({
|
|
|
754
766
|
settings?.customStyles?.rulesListItemText
|
|
755
767
|
}
|
|
756
768
|
>
|
|
757
|
-
{
|
|
769
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule6, 'product.virtual_try_on.rule_6')}
|
|
758
770
|
</span>
|
|
759
771
|
</li>
|
|
760
772
|
</ul>
|
|
@@ -780,11 +792,7 @@ export function VirtualTryOnUploadModal({
|
|
|
780
792
|
)}
|
|
781
793
|
>
|
|
782
794
|
<img
|
|
783
|
-
src={
|
|
784
|
-
typeof rule1Image === 'string'
|
|
785
|
-
? rule1Image
|
|
786
|
-
: rule1Image.src
|
|
787
|
-
}
|
|
795
|
+
src={getImageSrc(settings?.customStyles?.uploadModalImages?.ruleGoodExample, rule1Image)}
|
|
788
796
|
alt="Example"
|
|
789
797
|
className={twMerge(
|
|
790
798
|
'relative w-full',
|
|
@@ -803,10 +811,10 @@ export function VirtualTryOnUploadModal({
|
|
|
803
811
|
)}
|
|
804
812
|
>
|
|
805
813
|
{[
|
|
806
|
-
{ img: rule2Image, num: 2 },
|
|
807
|
-
{ img: rule3Image, num: 3 },
|
|
808
|
-
{ img: rule4Image, num: 4 },
|
|
809
|
-
{ img: rule5Image, num: 5 }
|
|
814
|
+
{ img: getImageSrc(settings?.customStyles?.uploadModalImages?.ruleBadExample1, rule2Image), num: 2 },
|
|
815
|
+
{ img: getImageSrc(settings?.customStyles?.uploadModalImages?.ruleBadExample2, rule3Image), num: 3 },
|
|
816
|
+
{ img: getImageSrc(settings?.customStyles?.uploadModalImages?.ruleBadExample3, rule4Image), num: 4 },
|
|
817
|
+
{ img: getImageSrc(settings?.customStyles?.uploadModalImages?.ruleBadExample4, rule5Image), num: 5 }
|
|
810
818
|
].map(({ img, num }) => (
|
|
811
819
|
<div
|
|
812
820
|
key={num}
|
|
@@ -817,9 +825,7 @@ export function VirtualTryOnUploadModal({
|
|
|
817
825
|
)}
|
|
818
826
|
>
|
|
819
827
|
<img
|
|
820
|
-
src={
|
|
821
|
-
typeof img === 'string' ? img : img.src
|
|
822
|
-
}
|
|
828
|
+
src={img}
|
|
823
829
|
alt={`Bad example ${num}`}
|
|
824
830
|
className={twMerge(
|
|
825
831
|
'w-full h-full',
|
|
@@ -844,7 +850,7 @@ export function VirtualTryOnUploadModal({
|
|
|
844
850
|
settings?.customStyles?.rulesInfoTextDesktop
|
|
845
851
|
)}
|
|
846
852
|
>
|
|
847
|
-
{
|
|
853
|
+
{getText(settings?.customStyles?.uploadModalTexts?.uploadInfo, 'product.virtual_try_on.upload_info')}
|
|
848
854
|
</p>
|
|
849
855
|
<ul
|
|
850
856
|
className={twMerge(
|
|
@@ -872,7 +878,7 @@ export function VirtualTryOnUploadModal({
|
|
|
872
878
|
settings?.customStyles?.rulesListItemText
|
|
873
879
|
}
|
|
874
880
|
>
|
|
875
|
-
{
|
|
881
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule1, 'product.virtual_try_on.rule_1')}
|
|
876
882
|
</span>
|
|
877
883
|
</li>
|
|
878
884
|
<li
|
|
@@ -895,7 +901,7 @@ export function VirtualTryOnUploadModal({
|
|
|
895
901
|
settings?.customStyles?.rulesListItemText
|
|
896
902
|
}
|
|
897
903
|
>
|
|
898
|
-
{
|
|
904
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule2, 'product.virtual_try_on.rule_2')}
|
|
899
905
|
</span>
|
|
900
906
|
</li>
|
|
901
907
|
<li
|
|
@@ -918,7 +924,7 @@ export function VirtualTryOnUploadModal({
|
|
|
918
924
|
settings?.customStyles?.rulesListItemText
|
|
919
925
|
}
|
|
920
926
|
>
|
|
921
|
-
{
|
|
927
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule3, 'product.virtual_try_on.rule_3')}
|
|
922
928
|
</span>
|
|
923
929
|
</li>
|
|
924
930
|
<li
|
|
@@ -941,7 +947,7 @@ export function VirtualTryOnUploadModal({
|
|
|
941
947
|
settings?.customStyles?.rulesListItemText
|
|
942
948
|
}
|
|
943
949
|
>
|
|
944
|
-
{
|
|
950
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule4, 'product.virtual_try_on.rule_4')}
|
|
945
951
|
</span>
|
|
946
952
|
</li>
|
|
947
953
|
<li
|
|
@@ -964,7 +970,7 @@ export function VirtualTryOnUploadModal({
|
|
|
964
970
|
settings?.customStyles?.rulesListItemText
|
|
965
971
|
}
|
|
966
972
|
>
|
|
967
|
-
{
|
|
973
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule5, 'product.virtual_try_on.rule_5')}
|
|
968
974
|
</span>
|
|
969
975
|
</li>
|
|
970
976
|
<li
|
|
@@ -987,7 +993,7 @@ export function VirtualTryOnUploadModal({
|
|
|
987
993
|
settings?.customStyles?.rulesListItemText
|
|
988
994
|
}
|
|
989
995
|
>
|
|
990
|
-
{
|
|
996
|
+
{getText(settings?.customStyles?.uploadModalTexts?.rule6, 'product.virtual_try_on.rule_6')}
|
|
991
997
|
</span>
|
|
992
998
|
</li>
|
|
993
999
|
</ul>
|