@akinon/pz-virtual-try-on 1.119.0-rc.3 → 2.0.0-beta.13
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 +3 -75
- package/README.md +7 -403
- package/package.json +5 -6
- package/src/hooks/use-image-cropper.ts +8 -58
- package/src/hooks/use-virtual-try-on-async.ts +0 -1
- package/src/hooks/use-virtual-try-on.ts +4 -30
- package/src/index.ts +1 -26
- package/src/types/index.ts +0 -32
- package/src/utils/error-mapping.ts +1 -3
- package/src/utils/index.ts +0 -115
- package/src/views/basket-async-modal.tsx +2 -7
- package/src/views/main.tsx +1 -15
- package/src/views/virtual-try-on-upload-modal.tsx +44 -62
- package/src/components/barcode-scanner.tsx +0 -422
- package/src/data/barcode-endpoints.ts +0 -34
- package/src/hooks/use-barcode-search.ts +0 -172
- package/src/types/barcode.ts +0 -308
- package/src/views/barcode-scanner-button.tsx +0 -63
- package/src/views/barcode-scanner-modal.tsx +0 -632
- package/src/views/barcode-scanner-plugin.tsx +0 -232
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useState, useRef, useCallback } from 'react';
|
|
2
2
|
import 'react-image-crop/dist/ReactCrop.css';
|
|
3
|
-
import { validateAspectRatioFromDimensions } from '../utils';
|
|
4
3
|
|
|
5
4
|
type CropType = {
|
|
6
5
|
unit: 'px' | '%';
|
|
@@ -10,16 +9,10 @@ type CropType = {
|
|
|
10
9
|
height: number;
|
|
11
10
|
};
|
|
12
11
|
|
|
13
|
-
export interface CropResult {
|
|
14
|
-
success: boolean;
|
|
15
|
-
error?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
12
|
export function useImageCropper(
|
|
19
13
|
setIsLoading: (loading: boolean) => void,
|
|
20
14
|
processImage: (base64: string) => void,
|
|
21
|
-
clearError?: () => void
|
|
22
|
-
onAspectRatioError?: (error: string) => void
|
|
15
|
+
clearError?: () => void
|
|
23
16
|
) {
|
|
24
17
|
const [isCropping, setIsCropping] = useState(false);
|
|
25
18
|
const [crop, setCrop] = useState<CropType>({
|
|
@@ -71,12 +64,10 @@ export function useImageCropper(
|
|
|
71
64
|
}
|
|
72
65
|
};
|
|
73
66
|
|
|
74
|
-
const processCompletedCropImmediate = async (
|
|
75
|
-
crop: any
|
|
76
|
-
): Promise<CropResult> => {
|
|
67
|
+
const processCompletedCropImmediate = async (crop: any) => {
|
|
77
68
|
if (!imageRef.current || !crop?.width || !crop?.height) {
|
|
78
69
|
setIsLoading(false);
|
|
79
|
-
return
|
|
70
|
+
return;
|
|
80
71
|
}
|
|
81
72
|
|
|
82
73
|
if (clearError) {
|
|
@@ -91,28 +82,8 @@ export function useImageCropper(
|
|
|
91
82
|
const scaleX = image.naturalWidth / image.width;
|
|
92
83
|
const scaleY = image.naturalHeight / image.height;
|
|
93
84
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
// Validate aspect ratio before processing
|
|
98
|
-
const aspectRatioValidation = validateAspectRatioFromDimensions(
|
|
99
|
-
croppedWidth,
|
|
100
|
-
croppedHeight
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
if (!aspectRatioValidation.isValid) {
|
|
104
|
-
setIsLoading(false);
|
|
105
|
-
if (onAspectRatioError && aspectRatioValidation.error) {
|
|
106
|
-
onAspectRatioError(aspectRatioValidation.error);
|
|
107
|
-
}
|
|
108
|
-
return {
|
|
109
|
-
success: false,
|
|
110
|
-
error: aspectRatioValidation.error
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
canvas.width = croppedWidth;
|
|
115
|
-
canvas.height = croppedHeight;
|
|
85
|
+
canvas.width = crop.width * scaleX;
|
|
86
|
+
canvas.height = crop.height * scaleY;
|
|
116
87
|
|
|
117
88
|
const ctx = canvas.getContext('2d');
|
|
118
89
|
|
|
@@ -123,8 +94,8 @@ export function useImageCropper(
|
|
|
123
94
|
|
|
124
95
|
const sourceX = crop.x * scaleX;
|
|
125
96
|
const sourceY = crop.y * scaleY;
|
|
126
|
-
const sourceWidth =
|
|
127
|
-
const sourceHeight =
|
|
97
|
+
const sourceWidth = crop.width * scaleX;
|
|
98
|
+
const sourceHeight = crop.height * scaleY;
|
|
128
99
|
|
|
129
100
|
ctx.drawImage(
|
|
130
101
|
image,
|
|
@@ -144,11 +115,9 @@ export function useImageCropper(
|
|
|
144
115
|
setCropProcessed(true);
|
|
145
116
|
setLastSuccessfulCrop(crop);
|
|
146
117
|
setIsLoading(false);
|
|
147
|
-
return { success: true };
|
|
148
118
|
} catch (error) {
|
|
149
119
|
console.error('❌ processCompletedCrop failed:', error);
|
|
150
120
|
setIsLoading(false);
|
|
151
|
-
return { success: false, error: 'Failed to process crop' };
|
|
152
121
|
}
|
|
153
122
|
};
|
|
154
123
|
|
|
@@ -187,28 +156,10 @@ export function useImageCropper(
|
|
|
187
156
|
});
|
|
188
157
|
};
|
|
189
158
|
|
|
190
|
-
const closeCrop = () => {
|
|
191
|
-
if (debounceTimeoutRef.current) {
|
|
192
|
-
clearTimeout(debounceTimeoutRef.current);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
setIsCropping(false);
|
|
196
|
-
setCompletedCrop(null);
|
|
197
|
-
setCrop(undefined as any);
|
|
198
|
-
};
|
|
199
|
-
|
|
200
159
|
const confirmCrop = useCallback(async () => {
|
|
201
160
|
if (completedCrop) {
|
|
202
161
|
await processManualCrop(completedCrop);
|
|
203
162
|
setIsCropping(false);
|
|
204
|
-
setCompletedCrop(null);
|
|
205
|
-
setCrop({
|
|
206
|
-
unit: '%',
|
|
207
|
-
x: 25,
|
|
208
|
-
y: 25,
|
|
209
|
-
width: 50,
|
|
210
|
-
height: 50
|
|
211
|
-
});
|
|
212
163
|
}
|
|
213
164
|
}, [completedCrop, processManualCrop]);
|
|
214
165
|
|
|
@@ -224,7 +175,6 @@ export function useImageCropper(
|
|
|
224
175
|
processCompletedCrop,
|
|
225
176
|
processManualCrop,
|
|
226
177
|
confirmCrop,
|
|
227
|
-
resetCrop
|
|
228
|
-
closeCrop
|
|
178
|
+
resetCrop
|
|
229
179
|
};
|
|
230
180
|
}
|
|
@@ -15,8 +15,7 @@ import {
|
|
|
15
15
|
isVirtualTryOnEnabled,
|
|
16
16
|
VirtualTryOnCache,
|
|
17
17
|
compressImageToUnder1MB,
|
|
18
|
-
convertWebPToJPEG
|
|
19
|
-
validateImageAspectRatio
|
|
18
|
+
convertWebPToJPEG
|
|
20
19
|
} from '../utils';
|
|
21
20
|
import { useImageCropper } from './use-image-cropper';
|
|
22
21
|
import type { VirtualTryOnResponse } from '../types';
|
|
@@ -113,10 +112,7 @@ export function useVirtualTryOn(product: Product) {
|
|
|
113
112
|
(croppedBase64) => {
|
|
114
113
|
setUploadedImage(croppedBase64);
|
|
115
114
|
},
|
|
116
|
-
() => setFileError('')
|
|
117
|
-
(aspectRatioError) => {
|
|
118
|
-
setFileError(aspectRatioError);
|
|
119
|
-
}
|
|
115
|
+
() => setFileError('')
|
|
120
116
|
);
|
|
121
117
|
|
|
122
118
|
useEffect(() => {
|
|
@@ -182,14 +178,6 @@ export function useVirtualTryOn(product: Product) {
|
|
|
182
178
|
return;
|
|
183
179
|
}
|
|
184
180
|
|
|
185
|
-
const aspectRatioValidation = await validateImageAspectRatio(
|
|
186
|
-
processedFile
|
|
187
|
-
);
|
|
188
|
-
if (!aspectRatioValidation.isValid) {
|
|
189
|
-
setFileError(aspectRatioValidation.error || 'Invalid aspect ratio');
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
181
|
const base64Image = await fileToBase64(processedFile);
|
|
194
182
|
setUploadedImage(base64Image);
|
|
195
183
|
setOriginalImage(base64Image);
|
|
@@ -365,7 +353,6 @@ export function useVirtualTryOn(product: Product) {
|
|
|
365
353
|
data.error || data.result?.error || 'Processing failed';
|
|
366
354
|
setError(errorMsg);
|
|
367
355
|
setCurrentStep('processing');
|
|
368
|
-
cropperHook.closeCrop();
|
|
369
356
|
return;
|
|
370
357
|
}
|
|
371
358
|
} catch (pollError: any) {
|
|
@@ -383,7 +370,6 @@ export function useVirtualTryOn(product: Product) {
|
|
|
383
370
|
error?.message === 'Request aborted'
|
|
384
371
|
) {
|
|
385
372
|
setCurrentStep('upload');
|
|
386
|
-
cropperHook.closeCrop();
|
|
387
373
|
return;
|
|
388
374
|
}
|
|
389
375
|
|
|
@@ -392,23 +378,11 @@ export function useVirtualTryOn(product: Product) {
|
|
|
392
378
|
error?.message ||
|
|
393
379
|
'Virtual try-on processing failed'
|
|
394
380
|
);
|
|
395
|
-
|
|
396
|
-
error?.data?.message ||
|
|
397
|
-
error?.message ||
|
|
398
|
-
'Virtual try-on processing failed'
|
|
399
|
-
);
|
|
400
|
-
setCurrentStep('processing');
|
|
401
|
-
cropperHook.closeCrop();
|
|
381
|
+
setCurrentStep('upload');
|
|
402
382
|
} finally {
|
|
403
383
|
setAbortController(null);
|
|
404
384
|
}
|
|
405
|
-
}, [
|
|
406
|
-
uploadedImage,
|
|
407
|
-
product,
|
|
408
|
-
processVirtualTryOn,
|
|
409
|
-
abortController,
|
|
410
|
-
cropperHook
|
|
411
|
-
]);
|
|
385
|
+
}, [uploadedImage, product, processVirtualTryOn, abortController]);
|
|
412
386
|
|
|
413
387
|
const acceptLegalConsent = useCallback(() => {
|
|
414
388
|
setLegalConsentAccepted();
|
package/src/index.ts
CHANGED
|
@@ -9,16 +9,10 @@ export { VirtualTryOnProductSelector } from './views/virtual-try-on-product-sele
|
|
|
9
9
|
export { VirtualTryOnAsyncModal } from './views/virtual-try-on-async-modal';
|
|
10
10
|
export { BasketAsyncModal } from './views/basket-async-modal';
|
|
11
11
|
|
|
12
|
-
export { BarcodeScannerPlugin } from './views/barcode-scanner-plugin';
|
|
13
|
-
export { BarcodeScannerModal } from './views/barcode-scanner-modal';
|
|
14
|
-
export { BarcodeScannerButton } from './views/barcode-scanner-button';
|
|
15
|
-
export { BarcodeScanner } from './components/barcode-scanner';
|
|
16
|
-
|
|
17
12
|
export { ProcessingSpinner } from './components/processing-spinner';
|
|
18
13
|
|
|
19
14
|
export { useVirtualTryOn } from './hooks/use-virtual-try-on';
|
|
20
15
|
export { useImageCropper } from './hooks/use-image-cropper';
|
|
21
|
-
export { useBarcodeSearch } from './hooks/use-barcode-search';
|
|
22
16
|
|
|
23
17
|
export { useVirtualTryOnAsync } from './hooks/use-virtual-try-on-async';
|
|
24
18
|
|
|
@@ -30,11 +24,6 @@ export {
|
|
|
30
24
|
useSubmitVirtualTryOnFeedbackMutation
|
|
31
25
|
} from './data/endpoints';
|
|
32
26
|
|
|
33
|
-
export {
|
|
34
|
-
useSearchProductByBarcodeQuery,
|
|
35
|
-
useLazySearchProductByBarcodeQuery
|
|
36
|
-
} from './data/barcode-endpoints';
|
|
37
|
-
|
|
38
27
|
export type {
|
|
39
28
|
VirtualTryOnResponse,
|
|
40
29
|
VirtualTryOnModalProps,
|
|
@@ -49,21 +38,7 @@ export type {
|
|
|
49
38
|
VirtualTryOnMultipleResult,
|
|
50
39
|
VirtualTryOnCompatibilityError,
|
|
51
40
|
BasketProduct,
|
|
52
|
-
VirtualTryOnMultipleModalProps
|
|
53
|
-
BarcodeFormat,
|
|
54
|
-
BarcodeScanResult,
|
|
55
|
-
BarcodeSearchResponse,
|
|
56
|
-
BarcodeSearchRequest,
|
|
57
|
-
BarcodeScannerState,
|
|
58
|
-
ScannedProductState,
|
|
59
|
-
BarcodeScannerButtonProps,
|
|
60
|
-
BarcodeScannerModalProps,
|
|
61
|
-
BarcodeScannerProps,
|
|
62
|
-
ScannedProductCardProps,
|
|
63
|
-
BarcodeScannerSettings,
|
|
64
|
-
BarcodeScannerTheme,
|
|
65
|
-
BarcodeScannerCustomStyles,
|
|
66
|
-
BarcodeScannerCustomRenderers
|
|
41
|
+
VirtualTryOnMultipleModalProps
|
|
67
42
|
} from './types';
|
|
68
43
|
|
|
69
44
|
export * from './utils';
|
package/src/types/index.ts
CHANGED
|
@@ -2,9 +2,6 @@ import React from 'react';
|
|
|
2
2
|
import { Product } from '@akinon/next/types';
|
|
3
3
|
import { useVirtualTryOn } from '../hooks/use-virtual-try-on';
|
|
4
4
|
|
|
5
|
-
// Re-export barcode types
|
|
6
|
-
export * from './barcode';
|
|
7
|
-
|
|
8
5
|
export interface VirtualTryOnResponse {
|
|
9
6
|
reference: string;
|
|
10
7
|
generated: string;
|
|
@@ -564,32 +561,6 @@ export interface CustomRendererProps {
|
|
|
564
561
|
};
|
|
565
562
|
}
|
|
566
563
|
|
|
567
|
-
export interface VirtualTryOnModalImages {
|
|
568
|
-
ruleGoodExample?: string;
|
|
569
|
-
ruleBadExample1?: string;
|
|
570
|
-
ruleBadExample2?: string;
|
|
571
|
-
ruleBadExample3?: string;
|
|
572
|
-
ruleBadExample4?: string;
|
|
573
|
-
uploadIcon?: string;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
export interface VirtualTryOnModalTexts {
|
|
577
|
-
title?: string;
|
|
578
|
-
editPhotoTitle?: string;
|
|
579
|
-
uploadPrompt?: string;
|
|
580
|
-
uploadRequirements?: string;
|
|
581
|
-
uploadInfo?: string;
|
|
582
|
-
rule1?: string;
|
|
583
|
-
rule2?: string;
|
|
584
|
-
rule3?: string;
|
|
585
|
-
rule4?: string;
|
|
586
|
-
rule5?: string;
|
|
587
|
-
rule6?: string;
|
|
588
|
-
processingTitle?: string;
|
|
589
|
-
processingMessage?: string;
|
|
590
|
-
retryUpload?: string;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
564
|
export interface VirtualTryOnPluginSettings {
|
|
594
565
|
maxFileSize?: number;
|
|
595
566
|
allowedFormats?: string[];
|
|
@@ -600,7 +571,6 @@ export interface VirtualTryOnPluginSettings {
|
|
|
600
571
|
buttonSize?: 'sm' | 'md' | 'lg';
|
|
601
572
|
legal_text?: string;
|
|
602
573
|
instructions?: string;
|
|
603
|
-
|
|
604
574
|
customStyles?: {
|
|
605
575
|
plugin?: string;
|
|
606
576
|
button?: string;
|
|
@@ -639,8 +609,6 @@ export interface VirtualTryOnPluginSettings {
|
|
|
639
609
|
uploadRequirements?: string;
|
|
640
610
|
uploadRequirementsError?: string;
|
|
641
611
|
uploadButton?: string;
|
|
642
|
-
uploadModalImages?: VirtualTryOnModalImages;
|
|
643
|
-
uploadModalTexts?: VirtualTryOnModalTexts;
|
|
644
612
|
fileInput?: string;
|
|
645
613
|
|
|
646
614
|
rulesInfoText?: string;
|
|
@@ -11,9 +11,7 @@ export const ERROR_MESSAGES: Record<string, string> = {
|
|
|
11
11
|
background: 'Görüntü arka planı uygun değil.',
|
|
12
12
|
political: 'Siyasi içerik tespit edildi.',
|
|
13
13
|
others: 'Görüntü uygun değil.',
|
|
14
|
-
empty: 'Görüntüde insan tespit edilemedi.'
|
|
15
|
-
aspect_ratio_too_tall: `Görsel çok uzun. Dikey görseller için izin verilen maksimum oran 9:16'dır. Lütfen kırpın veya farklı bir görsel seçin.`,
|
|
16
|
-
aspect_ratio_too_wide: `Görsel çok geniş. Yatay görseller için izin verilen maksimum oran 21:9'dur. Lütfen kırpın veya farklı bir görsel seçin.`
|
|
14
|
+
empty: 'Görüntüde insan tespit edilemedi.'
|
|
17
15
|
};
|
|
18
16
|
|
|
19
17
|
export function getErrorMessage(
|
package/src/utils/index.ts
CHANGED
|
@@ -1,120 +1,5 @@
|
|
|
1
1
|
export { parseVirtualTryOnError } from './error-parser';
|
|
2
2
|
|
|
3
|
-
export const ASPECT_RATIO_LIMITS = {
|
|
4
|
-
MIN_RATIO: 9 / 16,
|
|
5
|
-
MAX_RATIO: 21 / 9
|
|
6
|
-
} as const;
|
|
7
|
-
|
|
8
|
-
export interface AspectRatioValidation {
|
|
9
|
-
isValid: boolean;
|
|
10
|
-
error?: string;
|
|
11
|
-
ratio?: number;
|
|
12
|
-
width?: number;
|
|
13
|
-
height?: number;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const getImageDimensions = (
|
|
17
|
-
source: string | File
|
|
18
|
-
): Promise<{ width: number; height: number }> => {
|
|
19
|
-
return new Promise((resolve, reject) => {
|
|
20
|
-
const img = new Image();
|
|
21
|
-
|
|
22
|
-
img.onload = () => {
|
|
23
|
-
resolve({
|
|
24
|
-
width: img.naturalWidth,
|
|
25
|
-
height: img.naturalHeight
|
|
26
|
-
});
|
|
27
|
-
URL.revokeObjectURL(img.src);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
img.onerror = () => {
|
|
31
|
-
reject(new Error('Failed to load image for dimension check'));
|
|
32
|
-
URL.revokeObjectURL(img.src);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
if (typeof source === 'string') {
|
|
36
|
-
img.src = source;
|
|
37
|
-
} else {
|
|
38
|
-
img.src = URL.createObjectURL(source);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const validateImageAspectRatio = async (
|
|
44
|
-
source: string | File
|
|
45
|
-
): Promise<AspectRatioValidation> => {
|
|
46
|
-
try {
|
|
47
|
-
const { width, height } = await getImageDimensions(source);
|
|
48
|
-
const ratio = width / height;
|
|
49
|
-
|
|
50
|
-
if (ratio < ASPECT_RATIO_LIMITS.MIN_RATIO) {
|
|
51
|
-
return {
|
|
52
|
-
isValid: false,
|
|
53
|
-
error: 'aspect_ratio_too_tall',
|
|
54
|
-
ratio,
|
|
55
|
-
width,
|
|
56
|
-
height
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (ratio > ASPECT_RATIO_LIMITS.MAX_RATIO) {
|
|
61
|
-
return {
|
|
62
|
-
isValid: false,
|
|
63
|
-
error: 'aspect_ratio_too_wide',
|
|
64
|
-
ratio,
|
|
65
|
-
width,
|
|
66
|
-
height
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
isValid: true,
|
|
72
|
-
ratio,
|
|
73
|
-
width,
|
|
74
|
-
height
|
|
75
|
-
};
|
|
76
|
-
} catch (error) {
|
|
77
|
-
return {
|
|
78
|
-
isValid: false,
|
|
79
|
-
error: 'Failed to validate image dimensions'
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export const validateAspectRatioFromDimensions = (
|
|
85
|
-
width: number,
|
|
86
|
-
height: number
|
|
87
|
-
): AspectRatioValidation => {
|
|
88
|
-
const ratio = width / height;
|
|
89
|
-
|
|
90
|
-
if (ratio < ASPECT_RATIO_LIMITS.MIN_RATIO) {
|
|
91
|
-
return {
|
|
92
|
-
isValid: false,
|
|
93
|
-
error: 'aspect_ratio_too_tall',
|
|
94
|
-
ratio,
|
|
95
|
-
width,
|
|
96
|
-
height
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (ratio > ASPECT_RATIO_LIMITS.MAX_RATIO) {
|
|
101
|
-
return {
|
|
102
|
-
isValid: false,
|
|
103
|
-
error: 'aspect_ratio_too_wide',
|
|
104
|
-
ratio,
|
|
105
|
-
width,
|
|
106
|
-
height
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
isValid: true,
|
|
112
|
-
ratio,
|
|
113
|
-
width,
|
|
114
|
-
height
|
|
115
|
-
};
|
|
116
|
-
};
|
|
117
|
-
|
|
118
3
|
export const validateImageFile = (
|
|
119
4
|
file: File
|
|
120
5
|
): { isValid: boolean; error?: string } => {
|
|
@@ -17,8 +17,6 @@ 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';
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
type ModalStep = 'processing' | 'results' | 'detail';
|
|
@@ -30,8 +28,7 @@ export function BasketAsyncModal({
|
|
|
30
28
|
onComplete,
|
|
31
29
|
hookData,
|
|
32
30
|
onRetryUpload,
|
|
33
|
-
settings
|
|
34
|
-
source = 'basket'
|
|
31
|
+
settings
|
|
35
32
|
}: BasketAsyncModalProps) {
|
|
36
33
|
const { t } = useLocalization();
|
|
37
34
|
const [currentStep, setCurrentStep] = useState<ModalStep>('processing');
|
|
@@ -519,9 +516,7 @@ export function BasketAsyncModal({
|
|
|
519
516
|
settings?.customStyles?.basketAsyncModalBackButton
|
|
520
517
|
)}
|
|
521
518
|
>
|
|
522
|
-
{
|
|
523
|
-
? t('product.virtual_try_on.close_button')
|
|
524
|
-
: t('product.virtual_try_on.back_to_basket')}
|
|
519
|
+
{t('product.virtual_try_on.back_to_basket')}
|
|
525
520
|
</button>
|
|
526
521
|
</div>
|
|
527
522
|
</div>
|
package/src/views/main.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React, { useState, useMemo
|
|
3
|
+
import React, { useState, useMemo } from 'react';
|
|
4
4
|
import { Product } from '@akinon/next/types';
|
|
5
5
|
import { twMerge } from 'tailwind-merge';
|
|
6
6
|
import { VirtualTryOnModal } from './virtual-try-on-modal';
|
|
@@ -30,18 +30,6 @@ export function VirtualTryOnPlugin({
|
|
|
30
30
|
const [isModalLoading, setIsModalLoading] = useState(false);
|
|
31
31
|
const { isEnabled } = useVirtualTryOn(product);
|
|
32
32
|
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
return () => {
|
|
35
|
-
document.documentElement.style.overflow = '';
|
|
36
|
-
};
|
|
37
|
-
}, []);
|
|
38
|
-
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
if (!isModalOpen && !isModalLoading) {
|
|
41
|
-
document.documentElement.style.overflow = '';
|
|
42
|
-
}
|
|
43
|
-
}, [isModalOpen, isModalLoading]);
|
|
44
|
-
|
|
45
33
|
const cssVariables = useMemo(() => {
|
|
46
34
|
if (!settings?.cssVariables && !settings?.theme) return {};
|
|
47
35
|
|
|
@@ -110,12 +98,10 @@ export function VirtualTryOnPlugin({
|
|
|
110
98
|
setTimeout(() => {
|
|
111
99
|
setIsModalLoading(false);
|
|
112
100
|
setIsModalOpen(true);
|
|
113
|
-
document.documentElement.style.overflow = 'hidden';
|
|
114
101
|
}, 500);
|
|
115
102
|
};
|
|
116
103
|
|
|
117
104
|
const handleCloseModal = () => {
|
|
118
|
-
document.documentElement.style.overflow = '';
|
|
119
105
|
setIsModalOpen(false);
|
|
120
106
|
setIsModalLoading(false);
|
|
121
107
|
};
|