@nyris/nyris-webapp 0.3.57 → 0.3.59
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/build/asset-manifest.json +15 -16
- package/build/index.html +1 -1
- package/build/js/settings.example.js +1 -0
- package/build/static/css/main.cb6e2cfd.css +4 -0
- package/build/static/css/main.cb6e2cfd.css.map +1 -0
- package/build/static/js/main.a1e24447.js +3 -0
- package/build/static/js/{main.5143aa56.js.LICENSE.txt → main.a1e24447.js.LICENSE.txt} +55 -0
- package/build/static/js/main.a1e24447.js.map +1 -0
- package/build/static/media/camera_simple.bff4194954bbb5f4bc33bd99014a93e8.svg +3 -0
- package/build/static/media/collpase.50dae91fff891c46b10dfc281344d0ef.svg +6 -0
- package/build/static/media/crop.0676ebbbdc1375ed67e32bba890ce941.svg +3 -0
- package/build/static/media/{download.8007f7c72e2080a9ffa96fa63d480dcf.svg → download.a8452bc23334e9f8e53fe1225742d216.svg} +1 -1
- package/build/static/media/gallery.15d1f3308921480a8c9d96d9a77c9966.svg +3 -0
- package/build/static/media/{logout.b544fcd2969edf431a1e998333119834.svg → logout.bab56bd407f25eb34d6eff401a436ce1.svg} +1 -1
- package/build/static/media/next-arrow.b13263d05d107ceb5e99bc4fabb41279.svg +3 -0
- package/build/static/media/plus.329672cb2feb55345490589e91481b88.svg +3 -0
- package/package.json +8 -5
- package/public/index.html +0 -3
- package/public/js/settings.example.js +1 -0
- package/src/Router.tsx +2 -2
- package/src/Store/Store.ts +2 -0
- package/src/Store/requestStore.ts +70 -0
- package/src/Store/resultStore.ts +25 -0
- package/src/Store/search/Search.ts +2 -33
- package/src/Store/search/search.initialState.ts +1 -4
- package/src/Store/search/types.ts +0 -5
- package/src/common/assets/icons/arrow_enter.svg +3 -0
- package/src/common/assets/icons/camera_simple.svg +3 -0
- package/src/common/assets/icons/collpase.svg +6 -0
- package/src/common/assets/icons/crop.svg +3 -0
- package/src/common/assets/icons/download.svg +1 -1
- package/src/common/assets/icons/gallery.svg +3 -0
- package/src/common/assets/icons/logout.svg +1 -1
- package/src/common/assets/icons/next-arrow.svg +3 -0
- package/src/common/assets/icons/plus.svg +3 -0
- package/src/components/CadenasWebViewer.tsx +1 -1
- package/src/components/DragDropFile.tsx +17 -77
- package/src/components/Experience-visual-search/ExperienceVisualSearch.tsx +47 -71
- package/src/components/Feedback.tsx +23 -9
- package/src/components/GoBackButton.tsx +15 -18
- package/src/components/HeaderMobile.tsx +342 -246
- package/src/components/ImageCaptureHelpModal.tsx +63 -65
- package/src/components/ImagePreview.tsx +564 -0
- package/src/components/Inquiry/InquiryBanner.tsx +1 -1
- package/src/components/Inquiry/InquiryModal.tsx +4 -7
- package/src/components/Layout.tsx +9 -18
- package/src/components/MobileLayout.tsx +51 -0
- package/src/components/MobilePostFilter.tsx +9 -3
- package/src/components/PanelResult/PostFilterAlgolia.tsx +4 -32
- package/src/components/PanelResult/expandable-panel.tsx +3 -16
- package/src/components/PanelResult/virtual-state-results.ts +17 -22
- package/src/components/ProductDetailView.tsx +1 -1
- package/src/components/SidePanel.tsx +7 -97
- package/src/components/UploadDisclaimer.tsx +85 -0
- package/src/components/appMobile.scss +2 -2
- package/src/components/common.scss +57 -27
- package/src/components/drawer/cameraCustom.tsx +389 -231
- package/src/components/icon-label/icon-label.tsx +1 -1
- package/src/components/input/inputSearch.tsx +197 -338
- package/src/components/pre-filter/index.tsx +70 -72
- package/src/components/results/ItemResult.tsx +34 -17
- package/src/components/rfq/RfqBanner.tsx +1 -4
- package/src/components/rfq/RfqModal.tsx +10 -10
- package/src/hooks/useFilteredRegions.ts +1 -1
- package/src/hooks/useImageSearch.ts +189 -0
- package/src/hooks/useSearchOrRedirect.ts +84 -0
- package/src/index.css +4 -0
- package/src/page/landingPage/Home.tsx +49 -0
- package/src/page/landingPage/{AppMD.tsx → HomeDesktop.tsx} +7 -34
- package/src/page/landingPage/{AppMobile.tsx → HomeMobile.tsx} +8 -37
- package/src/page/landingPage/common.scss +9 -1
- package/src/page/result/index.tsx +118 -232
- package/src/services/Feedback.ts +4 -5
- package/src/services/image.ts +19 -0
- package/src/types.ts +9 -7
- package/src/utils.ts +44 -0
- package/tailwind.config.js +54 -0
- package/build/static/css/main.67965609.css +0 -2
- package/build/static/css/main.67965609.css.map +0 -1
- package/build/static/js/main.5143aa56.js +0 -3
- package/build/static/js/main.5143aa56.js.map +0 -1
- package/build/static/media/arrow_down.f417689ce292978a8292a7f00407fdd5.svg +0 -3
- package/build/static/media/arrow_left.73d03a534eaf9b99ab196e0fb67da602.svg +0 -3
- package/build/static/media/arrow_right.59a4594a3a1657037537dbae1eee0251.svg +0 -3
- package/build/static/media/arrow_up.85dbe70bc51ec32c8894a06499330f14.svg +0 -3
- package/build/static/media/home.9ffb65a9c0be8fc5a502ba05cf5f719c.svg +0 -3
- package/build/static/media/icon_camera_mobile.6772053c4dfef487255649d2a05cc9d4.svg +0 -3
- package/build/static/media/reverse_camera.cee0200b151941cc83c182167a85d667.svg +0 -5
- package/src/App.tsx +0 -18
- package/src/components/AppMobile.tsx +0 -117
- package/src/components/FooterMobile.tsx +0 -230
- package/src/components/ImagePreviewMobile.tsx +0 -237
- /package/build/static/media/{add.2b72cedb98c4c89c954266d2356c166c.svg → add-rounded.2b72cedb98c4c89c954266d2356c166c.svg} +0 -0
- /package/src/common/assets/icons/{add.svg → add-rounded.svg} +0 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
import { useCallback, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import cx from 'classnames';
|
|
4
|
+
|
|
5
|
+
import { RectCoords } from '@nyris/nyris-api';
|
|
6
|
+
import { Preview } from '@nyris/nyris-react-components';
|
|
7
|
+
import { DEFAULT_REGION } from '../constants';
|
|
8
|
+
import { useTranslation } from 'react-i18next';
|
|
9
|
+
import { useAppDispatch, useAppSelector } from 'Store/Store';
|
|
10
|
+
import { ReactComponent as PlusIcon } from 'common/assets/icons/plus.svg';
|
|
11
|
+
import { ReactComponent as CropIcon } from 'common/assets/icons/crop.svg';
|
|
12
|
+
import { ReactComponent as CollapseIcon } from 'common/assets/icons/collpase.svg';
|
|
13
|
+
import { ReactComponent as TrashIcon } from 'common/assets/icons/trash.svg';
|
|
14
|
+
|
|
15
|
+
import { ReactComponent as DownloadIcon } from 'common/assets/icons/download.svg';
|
|
16
|
+
import { ReactComponent as IconInfo } from 'common/assets/icons/info-tooltip.svg';
|
|
17
|
+
|
|
18
|
+
import { useQuery } from 'hooks/useQuery';
|
|
19
|
+
import {
|
|
20
|
+
loadingActionResults,
|
|
21
|
+
reset,
|
|
22
|
+
setSearchResults,
|
|
23
|
+
updateResultChangePosition,
|
|
24
|
+
updateStatusLoading,
|
|
25
|
+
} from 'Store/search/Search';
|
|
26
|
+
import { useHistory } from 'react-router-dom';
|
|
27
|
+
import { createImage, find } from 'services/image';
|
|
28
|
+
import { debounce, isEmpty, isUndefined } from 'lodash';
|
|
29
|
+
import useRequestStore from 'Store/requestStore';
|
|
30
|
+
import CameraCustom from './drawer/cameraCustom';
|
|
31
|
+
import useFilteredRegions from 'hooks/useFilteredRegions';
|
|
32
|
+
import useResultStore from 'Store/resultStore';
|
|
33
|
+
import { useDropzone } from 'react-dropzone';
|
|
34
|
+
import { useImageSearch } from 'hooks/useImageSearch';
|
|
35
|
+
import { compressImage } from 'utils';
|
|
36
|
+
import React from 'react';
|
|
37
|
+
|
|
38
|
+
function ImagePreviewComponent({
|
|
39
|
+
showAdjustInfo = false,
|
|
40
|
+
isExpanded,
|
|
41
|
+
isCameraUploadEnabled = true,
|
|
42
|
+
}: {
|
|
43
|
+
requestImage?: any;
|
|
44
|
+
imageSelection?: any;
|
|
45
|
+
filteredRegions?: any;
|
|
46
|
+
showAdjustInfo?: any;
|
|
47
|
+
isCameraUploadEnabled?: boolean;
|
|
48
|
+
isExpanded?: boolean;
|
|
49
|
+
}) {
|
|
50
|
+
const [showAdjustInfoBasedOnConfidence, setShowAdjustInfoBasedOnConfidence] =
|
|
51
|
+
useState(false);
|
|
52
|
+
|
|
53
|
+
const { t } = useTranslation();
|
|
54
|
+
const settings = useAppSelector(state => state.settings);
|
|
55
|
+
const preFilter = useAppSelector(state => state.search.preFilter);
|
|
56
|
+
const isAlgoliaEnabled = settings.algolia?.enabled;
|
|
57
|
+
const isMultiImageSearchEnabled = settings.multiImageSearch;
|
|
58
|
+
|
|
59
|
+
const query = useQuery();
|
|
60
|
+
const dispatch = useAppDispatch();
|
|
61
|
+
const history = useHistory();
|
|
62
|
+
|
|
63
|
+
const {
|
|
64
|
+
setRequestImages,
|
|
65
|
+
resetRegions,
|
|
66
|
+
requestImages,
|
|
67
|
+
addRequestImage,
|
|
68
|
+
regions,
|
|
69
|
+
updateRegion,
|
|
70
|
+
imageRegions,
|
|
71
|
+
} = useRequestStore(state => ({
|
|
72
|
+
requestImages: state.requestImages,
|
|
73
|
+
regions: state.regions,
|
|
74
|
+
addRequestImage: state.addRequestImage,
|
|
75
|
+
updateRegion: state.updateRegion,
|
|
76
|
+
imageRegions: state.regions,
|
|
77
|
+
resetRegions: state.resetRegions,
|
|
78
|
+
setRequestImages: state.setRequestImages,
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
const { detectedObject } = useResultStore(state => ({
|
|
82
|
+
detectedObject: state.detectedObject,
|
|
83
|
+
}));
|
|
84
|
+
|
|
85
|
+
const { multiImageSearch, singleImageSearch } = useImageSearch();
|
|
86
|
+
|
|
87
|
+
const [showCamera, setShowCamera] = useState(false);
|
|
88
|
+
const [currentIndex, setCurrentIndex] = useState(requestImages.length - 1);
|
|
89
|
+
const [isVisible, setIsVisible] = useState(true);
|
|
90
|
+
const [zIndex, setZIndex] = useState<number>(0);
|
|
91
|
+
|
|
92
|
+
const previewWrapperRef = useRef<any>(null);
|
|
93
|
+
|
|
94
|
+
const searchQuery = query.get('query') || '';
|
|
95
|
+
|
|
96
|
+
const onImageRemove = () => {
|
|
97
|
+
dispatch(reset(''));
|
|
98
|
+
resetRegions();
|
|
99
|
+
setRequestImages([]);
|
|
100
|
+
if (!searchQuery) {
|
|
101
|
+
history.push('/');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!isAlgoliaEnabled) {
|
|
105
|
+
let payload: any;
|
|
106
|
+
let filters: any[] = [];
|
|
107
|
+
const preFilterValues = [
|
|
108
|
+
{
|
|
109
|
+
key: settings.visualSearchFilterKey,
|
|
110
|
+
values: Object.keys(preFilter),
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
if (searchQuery || requestImages.length > 0) {
|
|
114
|
+
dispatch(updateStatusLoading(true));
|
|
115
|
+
find({
|
|
116
|
+
settings,
|
|
117
|
+
filters: !isEmpty(preFilter) ? preFilterValues : undefined,
|
|
118
|
+
text: searchQuery,
|
|
119
|
+
})
|
|
120
|
+
.then((res: any) => {
|
|
121
|
+
res?.results.forEach((item: any) => {
|
|
122
|
+
filters.push({
|
|
123
|
+
sku: item.sku,
|
|
124
|
+
score: item.score,
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
payload = {
|
|
128
|
+
...res,
|
|
129
|
+
filters,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
dispatch(setSearchResults(payload));
|
|
133
|
+
dispatch(updateStatusLoading(false));
|
|
134
|
+
})
|
|
135
|
+
.catch((e: any) => {
|
|
136
|
+
dispatch(updateStatusLoading(false));
|
|
137
|
+
});
|
|
138
|
+
} else {
|
|
139
|
+
dispatch(setSearchResults([]));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const handleExpand = () => {
|
|
145
|
+
if (isVisible) {
|
|
146
|
+
setTimeout(() => {
|
|
147
|
+
setZIndex(-1);
|
|
148
|
+
}, 300);
|
|
149
|
+
} else {
|
|
150
|
+
setZIndex(0);
|
|
151
|
+
}
|
|
152
|
+
setIsVisible(s => !s);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const filteredRegions = useFilteredRegions(
|
|
156
|
+
detectedObject[currentIndex],
|
|
157
|
+
regions[currentIndex],
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const { getInputProps } = useDropzone({
|
|
161
|
+
onDrop: async (fs: File[]) => {
|
|
162
|
+
if (!fs[0]) return;
|
|
163
|
+
|
|
164
|
+
dispatch(updateStatusLoading(true));
|
|
165
|
+
dispatch(loadingActionResults());
|
|
166
|
+
|
|
167
|
+
const compressedBase64 = await compressImage(fs[0]);
|
|
168
|
+
let image = await createImage(compressedBase64);
|
|
169
|
+
|
|
170
|
+
multiImageSearch({
|
|
171
|
+
images: [...requestImages, image],
|
|
172
|
+
regions: regions,
|
|
173
|
+
settings,
|
|
174
|
+
}).then(() => {
|
|
175
|
+
dispatch(updateStatusLoading(false));
|
|
176
|
+
});
|
|
177
|
+
addRequestImage(image);
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
182
|
+
const findItemsInSelection = useCallback(
|
|
183
|
+
debounce(async (r: RectCoords, image: HTMLCanvasElement) => {
|
|
184
|
+
dispatch(updateStatusLoading(true));
|
|
185
|
+
singleImageSearch({
|
|
186
|
+
image: image,
|
|
187
|
+
settings,
|
|
188
|
+
imageRegion: r,
|
|
189
|
+
showFeedback: true,
|
|
190
|
+
}).then((res: any) => {
|
|
191
|
+
dispatch(updateStatusLoading(false));
|
|
192
|
+
|
|
193
|
+
dispatch(updateResultChangePosition(res));
|
|
194
|
+
const highConfidence = res.results.find(
|
|
195
|
+
(data: { score: number }) => data.score >= 0.65,
|
|
196
|
+
);
|
|
197
|
+
if (!highConfidence) {
|
|
198
|
+
setShowAdjustInfoBasedOnConfidence(true);
|
|
199
|
+
}
|
|
200
|
+
setTimeout(() => {
|
|
201
|
+
setShowAdjustInfoBasedOnConfidence(false);
|
|
202
|
+
}, 2000);
|
|
203
|
+
});
|
|
204
|
+
return;
|
|
205
|
+
}, 250),
|
|
206
|
+
[dispatch, settings, singleImageSearch],
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const multiImageSearchOnRegionChange = useCallback(
|
|
210
|
+
(r: RectCoords, index: number) => {
|
|
211
|
+
dispatch(updateStatusLoading(true));
|
|
212
|
+
dispatch(loadingActionResults());
|
|
213
|
+
let modifiedRegions = [...imageRegions];
|
|
214
|
+
modifiedRegions[index] = r;
|
|
215
|
+
multiImageSearch({
|
|
216
|
+
images: requestImages,
|
|
217
|
+
regions: modifiedRegions,
|
|
218
|
+
settings,
|
|
219
|
+
}).then(() => {
|
|
220
|
+
dispatch(updateStatusLoading(false));
|
|
221
|
+
});
|
|
222
|
+
},
|
|
223
|
+
[dispatch, imageRegions, multiImageSearch, requestImages, settings],
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
227
|
+
const debouncedOnImageSelectionChange = useCallback(
|
|
228
|
+
debounce((r: RectCoords, index?: number) => {
|
|
229
|
+
if (requestImages.length > 1 && !isUndefined(index)) {
|
|
230
|
+
updateRegion(r, index);
|
|
231
|
+
multiImageSearchOnRegionChange(r, index);
|
|
232
|
+
} else {
|
|
233
|
+
updateRegion(r, 0);
|
|
234
|
+
findItemsInSelection(r, requestImages[0]);
|
|
235
|
+
}
|
|
236
|
+
}, 50),
|
|
237
|
+
[
|
|
238
|
+
findItemsInSelection,
|
|
239
|
+
multiImageSearchOnRegionChange,
|
|
240
|
+
requestImages,
|
|
241
|
+
updateRegion,
|
|
242
|
+
],
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const [editActive, setEditActive] = useState(false);
|
|
246
|
+
return (
|
|
247
|
+
<>
|
|
248
|
+
{/* Image preview Desktop, To-do: Remove and use same code as Image preview for Mobile */}
|
|
249
|
+
<div
|
|
250
|
+
ref={previewWrapperRef}
|
|
251
|
+
className={cx([
|
|
252
|
+
'bg-primary',
|
|
253
|
+
'justify-center',
|
|
254
|
+
isVisible ? (!isMultiImageSearchEnabled ? 'py-5' : 'pt-6') : '',
|
|
255
|
+
'px-7',
|
|
256
|
+
'w-full',
|
|
257
|
+
'desktop:px-5',
|
|
258
|
+
'relative',
|
|
259
|
+
'hidden',
|
|
260
|
+
'desktop:flex',
|
|
261
|
+
])}
|
|
262
|
+
// style={{
|
|
263
|
+
// height: '100%',
|
|
264
|
+
// maxHeight: isVisible ? '800px' : 0,
|
|
265
|
+
// overflow: 'hidden',
|
|
266
|
+
// zIndex: zIndex,
|
|
267
|
+
// }}
|
|
268
|
+
style={{
|
|
269
|
+
// transform: isVisible ? 'translateY(0)' : `translateY(-100%)`,
|
|
270
|
+
// opacity: isVisible ? 1 : 0,
|
|
271
|
+
marginTop: isVisible ? '0px' : 'calc(-100% + 30px)',
|
|
272
|
+
transition: isVisible ? 'margin-top 0.4s linear' : '',
|
|
273
|
+
zIndex: zIndex,
|
|
274
|
+
}}
|
|
275
|
+
>
|
|
276
|
+
<div className="w-full bg-[#55566b] aspect-square flex just items-center">
|
|
277
|
+
<Preview
|
|
278
|
+
onSelectionChange={(r: RectCoords) => {
|
|
279
|
+
debouncedOnImageSelectionChange(r, currentIndex);
|
|
280
|
+
}}
|
|
281
|
+
image={requestImages[currentIndex]}
|
|
282
|
+
selection={regions[currentIndex] || DEFAULT_REGION}
|
|
283
|
+
regions={filteredRegions || []}
|
|
284
|
+
dotColor={'#FBD914'}
|
|
285
|
+
minCropWidth={30}
|
|
286
|
+
minCropHeight={30}
|
|
287
|
+
rounded={true}
|
|
288
|
+
/>
|
|
289
|
+
</div>
|
|
290
|
+
{(showAdjustInfoBasedOnConfidence || showAdjustInfo) && (
|
|
291
|
+
<div
|
|
292
|
+
style={{
|
|
293
|
+
backgroundColor: '#3E36DC',
|
|
294
|
+
display: 'flex',
|
|
295
|
+
columnGap: '6px',
|
|
296
|
+
padding: '5px',
|
|
297
|
+
width: 'fit-content',
|
|
298
|
+
marginTop: 'auto',
|
|
299
|
+
position: 'absolute',
|
|
300
|
+
bottom: -20,
|
|
301
|
+
borderRadius: '16px',
|
|
302
|
+
zIndex: 1000,
|
|
303
|
+
height: 'fit-content',
|
|
304
|
+
}}
|
|
305
|
+
>
|
|
306
|
+
<IconInfo color="white" />
|
|
307
|
+
<p
|
|
308
|
+
style={{
|
|
309
|
+
fontSize: 12,
|
|
310
|
+
color: '#fff',
|
|
311
|
+
paddingRight: '4px',
|
|
312
|
+
}}
|
|
313
|
+
>
|
|
314
|
+
{showAdjustInfo
|
|
315
|
+
? t('Crop the image for better results')
|
|
316
|
+
: 'Crop the image for better results'}
|
|
317
|
+
</p>
|
|
318
|
+
</div>
|
|
319
|
+
)}
|
|
320
|
+
<div
|
|
321
|
+
onClick={() => onImageRemove()}
|
|
322
|
+
className={`absolute left-2 top-2 flex justify-center items-center cursor-pointer`}
|
|
323
|
+
>
|
|
324
|
+
<div className="rounded-full bg-white/50 hover:bg-white w-6 h-6 flex justify-center items-center">
|
|
325
|
+
<TrashIcon className="text-primary" />
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
</div>
|
|
329
|
+
{/* Image preview Mobile*/}
|
|
330
|
+
<div
|
|
331
|
+
className={cx([
|
|
332
|
+
'bg-primary',
|
|
333
|
+
'justify-center',
|
|
334
|
+
'p-5',
|
|
335
|
+
!editActive ? 'py-2' : '',
|
|
336
|
+
'w-full',
|
|
337
|
+
'relative',
|
|
338
|
+
'flex',
|
|
339
|
+
'desktop:hidden',
|
|
340
|
+
])}
|
|
341
|
+
>
|
|
342
|
+
<div
|
|
343
|
+
className={`w-full ${
|
|
344
|
+
editActive ? 'bg-[#55566b] ' : ''
|
|
345
|
+
} flex just items-center`}
|
|
346
|
+
>
|
|
347
|
+
<Preview
|
|
348
|
+
onSelectionChange={(r: RectCoords) => {
|
|
349
|
+
debouncedOnImageSelectionChange(r, currentIndex);
|
|
350
|
+
}}
|
|
351
|
+
image={requestImages[currentIndex]}
|
|
352
|
+
selection={regions[currentIndex] || DEFAULT_REGION}
|
|
353
|
+
regions={filteredRegions || []}
|
|
354
|
+
minWidth={Math.min(
|
|
355
|
+
80 *
|
|
356
|
+
(requestImages[currentIndex]?.width /
|
|
357
|
+
requestImages[currentIndex]?.height),
|
|
358
|
+
200,
|
|
359
|
+
)}
|
|
360
|
+
minHeight={80}
|
|
361
|
+
dotColor={editActive ? '#FBD914' : ''}
|
|
362
|
+
minCropWidth={editActive ? 30 : 5}
|
|
363
|
+
minCropHeight={editActive ? 30 : 5}
|
|
364
|
+
rounded={false}
|
|
365
|
+
expandAnimation={editActive}
|
|
366
|
+
shrinkAnimation={!editActive}
|
|
367
|
+
onExpand={() => {
|
|
368
|
+
setEditActive(true);
|
|
369
|
+
}}
|
|
370
|
+
showGrip={editActive}
|
|
371
|
+
draggable={editActive ? true : false}
|
|
372
|
+
/>
|
|
373
|
+
</div>
|
|
374
|
+
{(showAdjustInfoBasedOnConfidence || showAdjustInfo) && (
|
|
375
|
+
<div
|
|
376
|
+
style={{
|
|
377
|
+
backgroundColor: '#3E36DC',
|
|
378
|
+
display: 'flex',
|
|
379
|
+
columnGap: '6px',
|
|
380
|
+
padding: '5px',
|
|
381
|
+
width: 'fit-content',
|
|
382
|
+
marginTop: 'auto',
|
|
383
|
+
position: 'absolute',
|
|
384
|
+
bottom: -16,
|
|
385
|
+
borderRadius: '16px',
|
|
386
|
+
zIndex: 1000,
|
|
387
|
+
height: 'fit-content',
|
|
388
|
+
}}
|
|
389
|
+
>
|
|
390
|
+
<IconInfo color="white" />
|
|
391
|
+
<p
|
|
392
|
+
style={{
|
|
393
|
+
fontSize: 12,
|
|
394
|
+
color: '#fff',
|
|
395
|
+
paddingRight: '4px',
|
|
396
|
+
}}
|
|
397
|
+
>
|
|
398
|
+
{showAdjustInfo
|
|
399
|
+
? t('Crop the image for better results')
|
|
400
|
+
: 'Crop the image for better results'}
|
|
401
|
+
</p>
|
|
402
|
+
</div>
|
|
403
|
+
)}
|
|
404
|
+
<div
|
|
405
|
+
onClick={() => setEditActive(s => !s)}
|
|
406
|
+
className={`absolute right-1 ${
|
|
407
|
+
editActive ? 'bottom-1' : 'bottom-8'
|
|
408
|
+
} flex justify-center items-center desktop:hidden p-1`}
|
|
409
|
+
>
|
|
410
|
+
<div className="rounded-full bg-white w-6 h-6 flex justify-center items-center desktop:hidden">
|
|
411
|
+
{editActive && <CollapseIcon className="text-primary" />}
|
|
412
|
+
{!editActive && <CropIcon className="text-primary" />}
|
|
413
|
+
</div>
|
|
414
|
+
</div>
|
|
415
|
+
|
|
416
|
+
<div
|
|
417
|
+
onClick={() => onImageRemove()}
|
|
418
|
+
className={`absolute left-1 ${
|
|
419
|
+
editActive ? 'top-1' : 'top-8'
|
|
420
|
+
} flex justify-center items-center desktop:hidden p-1`}
|
|
421
|
+
>
|
|
422
|
+
<div className="rounded-full bg-white w-6 h-6 flex justify-center items-center desktop:hidden">
|
|
423
|
+
<TrashIcon className="text-primary" />
|
|
424
|
+
</div>
|
|
425
|
+
</div>
|
|
426
|
+
</div>
|
|
427
|
+
|
|
428
|
+
<div className={cx([!isMultiImageSearchEnabled && 'hidden'])}>
|
|
429
|
+
<div
|
|
430
|
+
className={cx([
|
|
431
|
+
'flex',
|
|
432
|
+
'items-center',
|
|
433
|
+
'gap-x-2',
|
|
434
|
+
'h-28',
|
|
435
|
+
'w-full',
|
|
436
|
+
'bg-primary',
|
|
437
|
+
'justify-center',
|
|
438
|
+
'relative',
|
|
439
|
+
'py-4',
|
|
440
|
+
'desktop:pt-7 desktop:pb-5',
|
|
441
|
+
])}
|
|
442
|
+
>
|
|
443
|
+
{requestImages.map((image, index) => {
|
|
444
|
+
return (
|
|
445
|
+
<div
|
|
446
|
+
key={index}
|
|
447
|
+
className={cx([
|
|
448
|
+
'rounded-md',
|
|
449
|
+
'relative',
|
|
450
|
+
'p-1',
|
|
451
|
+
currentIndex === index && isVisible
|
|
452
|
+
? ' bg-white'
|
|
453
|
+
: 'bg-transparent',
|
|
454
|
+
])}
|
|
455
|
+
>
|
|
456
|
+
<img
|
|
457
|
+
className={cx([
|
|
458
|
+
'w-[70px]',
|
|
459
|
+
'h-[70px]',
|
|
460
|
+
'desktop:w-[52px]',
|
|
461
|
+
'desktop:h-[52px]',
|
|
462
|
+
'rounded-md',
|
|
463
|
+
'object-cover',
|
|
464
|
+
'shadow-inner',
|
|
465
|
+
])}
|
|
466
|
+
src={image.toDataURL()}
|
|
467
|
+
alt=""
|
|
468
|
+
onClick={() => {
|
|
469
|
+
setCurrentIndex(index);
|
|
470
|
+
if (!isVisible) {
|
|
471
|
+
handleExpand();
|
|
472
|
+
}
|
|
473
|
+
}}
|
|
474
|
+
/>
|
|
475
|
+
{currentIndex === index && (
|
|
476
|
+
<div
|
|
477
|
+
className={cx([
|
|
478
|
+
'absolute',
|
|
479
|
+
'w-[70px]',
|
|
480
|
+
'h-[70px]',
|
|
481
|
+
'desktop:w-[52px]',
|
|
482
|
+
'desktop:h-[52px]',
|
|
483
|
+
'rounded-md',
|
|
484
|
+
'top-1',
|
|
485
|
+
'bg-black/15',
|
|
486
|
+
])}
|
|
487
|
+
onClick={() => {
|
|
488
|
+
setCurrentIndex(index);
|
|
489
|
+
if (!isVisible) {
|
|
490
|
+
handleExpand();
|
|
491
|
+
}
|
|
492
|
+
}}
|
|
493
|
+
/>
|
|
494
|
+
)}
|
|
495
|
+
</div>
|
|
496
|
+
);
|
|
497
|
+
})}
|
|
498
|
+
{requestImages.length < 3 && isMultiImageSearchEnabled && (
|
|
499
|
+
<label
|
|
500
|
+
className={cx([
|
|
501
|
+
'w-[70px]',
|
|
502
|
+
'h-[70px]',
|
|
503
|
+
'desktop:w-[52px]',
|
|
504
|
+
'desktop:h-[52px]',
|
|
505
|
+
'bg-[#55566B]/50',
|
|
506
|
+
'flex',
|
|
507
|
+
'justify-center',
|
|
508
|
+
'items-center',
|
|
509
|
+
'border',
|
|
510
|
+
'border-dashed',
|
|
511
|
+
'border-[#AAABB5]',
|
|
512
|
+
'rounded-md',
|
|
513
|
+
'cursor-pointer',
|
|
514
|
+
])}
|
|
515
|
+
onClick={() => {
|
|
516
|
+
if (isCameraUploadEnabled) {
|
|
517
|
+
setShowCamera(true);
|
|
518
|
+
}
|
|
519
|
+
}}
|
|
520
|
+
htmlFor={isCameraUploadEnabled ? '' : 'icon-add-image'}
|
|
521
|
+
>
|
|
522
|
+
<input
|
|
523
|
+
accept="image/*"
|
|
524
|
+
id="icon-add-image"
|
|
525
|
+
type="file"
|
|
526
|
+
style={{ display: 'none' }}
|
|
527
|
+
{...getInputProps({
|
|
528
|
+
onClick: e => {
|
|
529
|
+
e.currentTarget.value = '';
|
|
530
|
+
e.stopPropagation();
|
|
531
|
+
},
|
|
532
|
+
})}
|
|
533
|
+
/>
|
|
534
|
+
<PlusIcon className={cx(['text-[#AAABB5] desktop:hidden'])} />
|
|
535
|
+
<div className="hidden desktop:block">
|
|
536
|
+
<DownloadIcon className={cx(['text-[#AAABB5]'])} />
|
|
537
|
+
</div>
|
|
538
|
+
</label>
|
|
539
|
+
)}
|
|
540
|
+
<div
|
|
541
|
+
onClick={() => handleExpand()}
|
|
542
|
+
className="absolute right-5 flex justify-center items-center desktop:hidden p-2"
|
|
543
|
+
>
|
|
544
|
+
<div className="rounded-full bg-white w-6 h-6 flex justify-center items-center desktop:hidden">
|
|
545
|
+
<CropIcon className="text-primary" />
|
|
546
|
+
</div>
|
|
547
|
+
</div>
|
|
548
|
+
|
|
549
|
+
<CameraCustom
|
|
550
|
+
show={showCamera}
|
|
551
|
+
onClose={() => setShowCamera(false)}
|
|
552
|
+
/>
|
|
553
|
+
</div>
|
|
554
|
+
{requestImages.length < 3 && isMultiImageSearchEnabled && (
|
|
555
|
+
<p className="text-[10px] pb-4 w-full text-center bg-primary text-white -mt-[1px]">
|
|
556
|
+
Add up to three photos for a more accurate visual search.
|
|
557
|
+
</p>
|
|
558
|
+
)}
|
|
559
|
+
</div>
|
|
560
|
+
</>
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
const ImagePreview = React.memo(ImagePreviewComponent);
|
|
564
|
+
export default ImagePreview;
|
|
@@ -70,9 +70,9 @@ export default function InquiryModal({
|
|
|
70
70
|
|
|
71
71
|
const handleInquiry = async (e: { preventDefault: () => void }) => {
|
|
72
72
|
e.preventDefault();
|
|
73
|
-
|
|
74
|
-
const croppedImage =
|
|
75
|
-
? getCroppedCanvas(
|
|
73
|
+
|
|
74
|
+
const croppedImage = requestImage
|
|
75
|
+
? getCroppedCanvas(requestImage, selectedRegion)
|
|
76
76
|
: null;
|
|
77
77
|
const serviceId = 'service_zfsxshi';
|
|
78
78
|
setIsInquiryModalOpen(false);
|
|
@@ -200,10 +200,7 @@ export default function InquiryModal({
|
|
|
200
200
|
}}
|
|
201
201
|
>
|
|
202
202
|
<img
|
|
203
|
-
src={getCroppedCanvas(
|
|
204
|
-
requestImage?.canvas,
|
|
205
|
-
selectedRegion,
|
|
206
|
-
)?.toDataURL()}
|
|
203
|
+
src={getCroppedCanvas(requestImage, selectedRegion)?.toDataURL()}
|
|
207
204
|
alt="request_image"
|
|
208
205
|
style={{ maxHeight: '200px' }}
|
|
209
206
|
/>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'components/common';
|
|
2
|
-
import React, { memo, useEffect
|
|
2
|
+
import React, { memo, useEffect } from 'react';
|
|
3
3
|
import { useMediaQuery } from 'react-responsive';
|
|
4
4
|
import { useHistory } from 'react-router-dom';
|
|
5
5
|
import {
|
|
@@ -11,11 +11,9 @@ import { useAppDispatch, useAppSelector } from 'Store/Store';
|
|
|
11
11
|
import { AppState } from '../types';
|
|
12
12
|
import './appMobile.scss';
|
|
13
13
|
import './common.scss';
|
|
14
|
-
import FooterMobile from './FooterMobile';
|
|
15
14
|
import HeaderMobile from './HeaderMobile';
|
|
16
15
|
import Header from './Header';
|
|
17
|
-
import
|
|
18
|
-
import AppMobile from './AppMobile';
|
|
16
|
+
import MobileLayout from './MobileLayout';
|
|
19
17
|
import jQuery from 'jquery';
|
|
20
18
|
import Loading from './Loading';
|
|
21
19
|
import i18n from 'i18next';
|
|
@@ -26,6 +24,8 @@ import InstantSearchProvider from './Provider/InstantSearchProvider';
|
|
|
26
24
|
import PoweredByNyris from './PoweredByNyris';
|
|
27
25
|
import { useQuery } from 'hooks/useQuery';
|
|
28
26
|
|
|
27
|
+
import packageJson from '../../package.json';
|
|
28
|
+
|
|
29
29
|
declare var psol: any;
|
|
30
30
|
|
|
31
31
|
jQuery(document).ready(function () {
|
|
@@ -65,7 +65,6 @@ function Layout({ children }: ReactNode): JSX.Element {
|
|
|
65
65
|
const { settings, search } = useAppSelector<AppState>((state: any) => state);
|
|
66
66
|
const { loadingSearchAlgolia } = search;
|
|
67
67
|
const isMobile = useMediaQuery({ query: '(max-width: 776px)' });
|
|
68
|
-
const [isOpenFilter, setOpenFilter] = useState<boolean>(false);
|
|
69
68
|
const history = useHistory();
|
|
70
69
|
const query = useQuery();
|
|
71
70
|
const searchQuery = query.get('query') || '';
|
|
@@ -96,11 +95,9 @@ function Layout({ children }: ReactNode): JSX.Element {
|
|
|
96
95
|
}, [user, dispatch, settings.shouldUseUserMetadata]);
|
|
97
96
|
|
|
98
97
|
let HeaderApp: any;
|
|
99
|
-
let FooterApp: any;
|
|
100
98
|
let classNameBoxVersion: string = 'newVersion';
|
|
101
99
|
if (isMobile) {
|
|
102
100
|
classNameBoxVersion = 'mobile';
|
|
103
|
-
FooterApp = FooterMobile;
|
|
104
101
|
HeaderApp = HeaderMobile;
|
|
105
102
|
} else {
|
|
106
103
|
HeaderApp = Header;
|
|
@@ -112,6 +109,8 @@ function Layout({ children }: ReactNode): JSX.Element {
|
|
|
112
109
|
document.documentElement.style.setProperty('--vh', `${vh}px`);
|
|
113
110
|
|
|
114
111
|
useEffect(() => {
|
|
112
|
+
console.log('App version:', packageJson.version);
|
|
113
|
+
|
|
115
114
|
const handleResize = () => {
|
|
116
115
|
let vh = window.innerHeight * 0.01;
|
|
117
116
|
document.documentElement.style.setProperty('--vh', `${vh}px`);
|
|
@@ -142,7 +141,7 @@ function Layout({ children }: ReactNode): JSX.Element {
|
|
|
142
141
|
</div>
|
|
143
142
|
)}
|
|
144
143
|
<InstantSearchProvider>
|
|
145
|
-
{isMobile && showApp && <
|
|
144
|
+
{isMobile && showApp && <MobileLayout>{children}</MobileLayout>}
|
|
146
145
|
{!isMobile && showApp && (
|
|
147
146
|
<div className={`layout-main-${classNameBoxVersion}`}>
|
|
148
147
|
<div
|
|
@@ -159,21 +158,13 @@ function Layout({ children }: ReactNode): JSX.Element {
|
|
|
159
158
|
: {}),
|
|
160
159
|
}}
|
|
161
160
|
>
|
|
162
|
-
<HeaderApp
|
|
163
|
-
onToggleFilterMobile={(show: boolean) => {
|
|
164
|
-
setOpenFilter(isUndefined(show) ? !isOpenFilter : show);
|
|
165
|
-
}}
|
|
166
|
-
/>
|
|
161
|
+
<HeaderApp />
|
|
167
162
|
</div>
|
|
168
163
|
|
|
169
164
|
<div className={`box-body-${classNameBoxVersion}-wrap-main`}>
|
|
170
165
|
{children}
|
|
171
166
|
</div>
|
|
172
|
-
|
|
173
|
-
<div className="footer-wrap-main">
|
|
174
|
-
<FooterApp />
|
|
175
|
-
</div>
|
|
176
|
-
)}
|
|
167
|
+
|
|
177
168
|
{showPoweredByNyris && <PoweredByNyris />}
|
|
178
169
|
</div>
|
|
179
170
|
)}
|