@nyris/nyris-webapp 0.3.91 → 0.3.93
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 +6 -6
- package/build/data/related-parts.json +83 -0
- package/build/index.html +1 -1
- package/build/js/settings.example.js +3 -0
- package/build/static/css/main.fed38059.css +4 -0
- package/build/static/css/main.fed38059.css.map +1 -0
- package/build/static/js/main.c9bbbcb9.js +3 -0
- package/build/static/js/{main.f2255597.js.map → main.c9bbbcb9.js.map} +1 -1
- package/package.json +4 -3
- package/public/data/related-parts.json +83 -0
- package/public/js/settings.example.js +3 -0
- package/src/App.test.tsx +0 -1
- package/src/App.tsx +0 -1
- package/src/assets/arrow_down_expanded.svg +3 -0
- package/src/assets/arrow_enter.svg +3 -0
- package/src/assets/camera.svg +3 -0
- package/src/assets/close.svg +3 -0
- package/src/assets/enter.svg +3 -0
- package/src/assets/refresh.svg +3 -0
- package/src/assets/vizo_avatar.svg +16 -0
- package/src/components/Cadenas/CadenasWebViewer.tsx +1 -1
- package/src/components/Cart.tsx +48 -36
- package/src/components/ChatAssistant/ChatAssistant.tsx +289 -0
- package/src/components/ChatAssistant/MobileChatAssistant.tsx +291 -0
- package/src/components/ChatAssistant/OptionChip.tsx +78 -0
- package/src/components/ChatAssistant/index.ts +3 -0
- package/src/components/ChatAssistant/useChatAssistantLogic.ts +745 -0
- package/src/components/CurrentRefinements.tsx +2 -2
- package/src/components/CustomCameraDrawer.tsx +56 -13
- package/src/components/DragDropFile.tsx +5 -5
- package/src/components/ExperienceVisualSearch/ExperienceVisualSearch.tsx +1 -1
- package/src/components/Header.tsx +116 -96
- package/src/components/Hint.tsx +1 -2
- package/src/components/HitsPerPage.tsx +9 -3
- package/src/components/IdentifiedAttributes.tsx +159 -0
- package/src/components/ImagePreview.tsx +32 -17
- package/src/components/ImageUpload.tsx +16 -8
- package/src/components/Inquiry/InquiryBanner.tsx +1 -1
- package/src/components/Inquiry/InquiryModal.tsx +35 -29
- package/src/components/ItemSpecification.tsx +58 -126
- package/src/components/LocationInfoPopup.tsx +33 -33
- package/src/components/MatchNotificationBanner.tsx +90 -36
- package/src/components/PostFilter/PostFilter.tsx +1 -1
- package/src/components/PostFilter/PostFilterComponent.tsx +0 -1
- package/src/components/PostFilter/PostFilterFindApi.tsx +0 -1
- package/src/components/PoweredBy.tsx +1 -1
- package/src/components/PreFilter/PreFilter.tsx +14 -3
- package/src/components/PreFilter/PreFilterModal.tsx +0 -1
- package/src/components/Product/Product.tsx +15 -11
- package/src/components/Product/ProductAttribute.tsx +4 -5
- package/src/components/Product/ProductDetailViewModal.tsx +2 -4
- package/src/components/Product/ProductList.tsx +26 -13
- package/src/components/Rfq/RfqModal.tsx +1 -1
- package/src/components/SidePanel.tsx +128 -46
- package/src/components/SmartFilter.tsx +320 -0
- package/src/components/TextSearch.tsx +134 -70
- package/src/components/UploadDisclaimer.tsx +1 -1
- package/src/hooks/useBadResultsRecovery.ts +407 -0
- package/src/hooks/useEffectiveGroundingResults.ts +54 -0
- package/src/hooks/useGoodResultsChat.ts +651 -0
- package/src/hooks/useGroundedSearch.ts +88 -0
- package/src/hooks/useImageSearch.ts +139 -187
- package/src/hooks/useResultEvaluator.ts +417 -0
- package/src/index.css +1 -1
- package/src/index.tsx +0 -1
- package/src/layouts/AppLayout.tsx +53 -2
- package/src/pages/Home.tsx +11 -52
- package/src/pages/Login.tsx +1 -2
- package/src/pages/Logout.tsx +1 -1
- package/src/pages/Result.tsx +254 -200
- package/src/providers/AuthProvider.tsx +0 -1
- package/src/services/Feedback.ts +1 -1
- package/src/services/visualSearch.ts +0 -21
- package/src/services/vizo.ts +192 -4
- package/src/stores/chat/chatStore.ts +150 -0
- package/src/stores/chat/conversationStore.ts +300 -0
- package/src/stores/request/Misc/misc.slice.ts +2 -2
- package/src/stores/request/filter/filter.slice.ts +8 -8
- package/src/stores/request/query/query.slice.ts +2 -2
- package/src/stores/request/requestImage/requestImage.slice.ts +6 -6
- package/src/stores/request/specifications/specifications.slice.ts +10 -7
- package/src/stores/result/detectedRegions/detectedRegions.slice.ts +1 -1
- package/src/stores/result/prodcuts/products.initialState.ts +12 -0
- package/src/stores/result/prodcuts/products.slice.ts +28 -8
- package/src/stores/result/session/session.slice.ts +2 -2
- package/src/stores/smartFilters/smartFiltersStore.ts +270 -0
- package/src/stores/types.ts +41 -0
- package/src/stores/ui/ai/ai.initialState.ts +5 -0
- package/src/stores/ui/ai/ai.slice.ts +15 -0
- package/src/stores/ui/banner/banner.initialState.ts +6 -0
- package/src/stores/ui/banner/banner.slice.ts +14 -0
- package/src/stores/ui/feedback/feedback.slice.ts +1 -1
- package/src/stores/ui/loading/loading.slice.ts +4 -4
- package/src/stores/ui/uiStore.ts +7 -1
- package/src/styles/product.scss +0 -2
- package/src/types.ts +4 -8
- package/src/utils/cropImageToBase64.ts +32 -0
- package/src/utils/fetchProductImage.ts +109 -0
- package/src/utils/imageConverters.ts +124 -0
- package/src/utils/relatedParts.ts +35 -0
- package/src/utils/specificationFilter.ts +1 -5
- package/tailwind.config.js +3 -2
- package/build/static/css/main.734b52e1.css +0 -4
- package/build/static/css/main.734b52e1.css.map +0 -1
- package/build/static/js/main.f2255597.js +0 -3
- package/src/utils/addAssets.ts +0 -40
- /package/build/static/js/{main.f2255597.js.LICENSE.txt → main.c9bbbcb9.js.LICENSE.txt} +0 -0
|
@@ -30,7 +30,7 @@ function CurrentRefinements({ className }: { className?: string }) {
|
|
|
30
30
|
key={value}
|
|
31
31
|
className="h-6 pl-2 pr-0.5 py-0.5 bg-[#f3f3f5] rounded-[1px] border border-solid border-[#e0e0e0] justify-start items-center gap-2 inline-flex"
|
|
32
32
|
>
|
|
33
|
-
<div className="text-[#
|
|
33
|
+
<div className="text-[#3B3E5F] text-xs font-normal ">{value}</div>
|
|
34
34
|
<div className="w-5 h-5 rounded-sm justify-center items-center flex cursor-pointer">
|
|
35
35
|
<Icon
|
|
36
36
|
name="close"
|
|
@@ -60,7 +60,7 @@ function CurrentRefinements({ className }: { className?: string }) {
|
|
|
60
60
|
key={refinement.label}
|
|
61
61
|
className="h-6 pl-2 pr-0.5 py-0.5 bg-[#f3f3f5] rounded-[1px] border border-solid border-[#e0e0e0] justify-start items-center gap-2 inline-flex"
|
|
62
62
|
>
|
|
63
|
-
<div className="text-[#
|
|
63
|
+
<div className="text-[#3B3E5F] text-xs font-normal ">
|
|
64
64
|
{refinement.label}
|
|
65
65
|
</div>
|
|
66
66
|
<div className="w-5 h-5 rounded-sm justify-center items-center flex cursor-pointer">
|
|
@@ -25,12 +25,18 @@ interface Props {
|
|
|
25
25
|
show: boolean;
|
|
26
26
|
onClose: any;
|
|
27
27
|
newSearch?: boolean;
|
|
28
|
+
handleImageUpload?: (image: any) => void;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
const FACING_MODE_USER = 'environment';
|
|
31
32
|
|
|
32
33
|
function CustomCamera(props: Props) {
|
|
33
|
-
const {
|
|
34
|
+
const {
|
|
35
|
+
show: isToggle,
|
|
36
|
+
onClose: onToggleModal,
|
|
37
|
+
newSearch,
|
|
38
|
+
handleImageUpload,
|
|
39
|
+
} = props;
|
|
34
40
|
const settings = window.settings;
|
|
35
41
|
const webcamRef: any = useRef(null);
|
|
36
42
|
const navigate = useNavigate();
|
|
@@ -44,12 +50,16 @@ function CustomCamera(props: Props) {
|
|
|
44
50
|
const specifications = useRequestStore(state => state.specifications);
|
|
45
51
|
const setSpecifications = useRequestStore(state => state.setSpecifications);
|
|
46
52
|
const setRequestImages = useRequestStore(state => state.setRequestImages);
|
|
47
|
-
const setNameplateNotificationText = useRequestStore(
|
|
53
|
+
const setNameplateNotificationText = useRequestStore(
|
|
54
|
+
state => state.setNameplateNotificationText,
|
|
55
|
+
);
|
|
48
56
|
const setAlgoliaFilter = useRequestStore(state => state.setAlgoliaFilter);
|
|
49
57
|
const setPreFilter = useRequestStore(state => state.setPreFilter);
|
|
50
58
|
const setShowLoading = useRequestStore(state => state.setShowLoading);
|
|
51
59
|
const setNameplateImage = useRequestStore(state => state.setNameplateImage);
|
|
52
|
-
const setShowNotMatchedError = useRequestStore(
|
|
60
|
+
const setShowNotMatchedError = useRequestStore(
|
|
61
|
+
state => state.setShowNotMatchedError,
|
|
62
|
+
);
|
|
53
63
|
const [capturedImages, setCapturedImages] = useState<HTMLCanvasElement[]>([]);
|
|
54
64
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
55
65
|
const [imageCaptureHelpModal, setImageCaptureHelpModal] = useState(false);
|
|
@@ -60,6 +70,12 @@ function CustomCamera(props: Props) {
|
|
|
60
70
|
};
|
|
61
71
|
|
|
62
72
|
const handlerFindImage = async (image: any) => {
|
|
73
|
+
if (handleImageUpload) {
|
|
74
|
+
handleImageUpload(image);
|
|
75
|
+
handleClose();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
63
79
|
if (location.pathname !== '/result') {
|
|
64
80
|
navigate('/result');
|
|
65
81
|
}
|
|
@@ -77,35 +93,62 @@ function CustomCamera(props: Props) {
|
|
|
77
93
|
settings,
|
|
78
94
|
newSearch,
|
|
79
95
|
showFeedback: true,
|
|
80
|
-
}).then(
|
|
81
|
-
const specificationPrefilter =
|
|
82
|
-
|
|
96
|
+
}).then(singleImageResp => {
|
|
97
|
+
const specificationPrefilter =
|
|
98
|
+
singleImageResp.image_analysis?.specification?.prefilter_value || null;
|
|
99
|
+
|
|
100
|
+
const hasPrefilter = preFilterList.filter((filter: any) =>
|
|
101
|
+
filter.values.includes(specificationPrefilter),
|
|
102
|
+
);
|
|
83
103
|
if (specificationPrefilter) {
|
|
84
104
|
setRequestImages([]);
|
|
85
105
|
setShowNotMatchedError(false);
|
|
86
106
|
if (hasPrefilter.length) {
|
|
87
|
-
setSpecifications(
|
|
107
|
+
setSpecifications(
|
|
108
|
+
clone(singleImageResp.image_analysis.specification),
|
|
109
|
+
);
|
|
88
110
|
setNameplateImage(image);
|
|
89
|
-
setPreFilter({
|
|
90
|
-
|
|
111
|
+
setPreFilter({
|
|
112
|
+
[singleImageResp.image_analysis?.specification?.prefilter_value]:
|
|
113
|
+
true,
|
|
114
|
+
});
|
|
115
|
+
setAlgoliaFilter(
|
|
116
|
+
`${settings.alogoliaFilterField}:'${singleImageResp.image_analysis?.specification?.prefilter_value}'`,
|
|
117
|
+
);
|
|
91
118
|
|
|
92
119
|
setShowLoading(false);
|
|
93
120
|
handleClose();
|
|
94
121
|
|
|
95
|
-
setNameplateNotificationText(
|
|
122
|
+
setNameplateNotificationText(
|
|
123
|
+
t('We have successfully defined the search criteria', {
|
|
124
|
+
prefilter_value: specificationPrefilter,
|
|
125
|
+
preFilterTitle:
|
|
126
|
+
window.settings.preFilterTitle?.toLocaleLowerCase(),
|
|
127
|
+
}),
|
|
128
|
+
);
|
|
96
129
|
setTimeout(() => {
|
|
97
130
|
setNameplateNotificationText('');
|
|
98
131
|
}, 5000);
|
|
99
132
|
}
|
|
100
133
|
if (!hasPrefilter.length && window.settings.preFilterOption) {
|
|
101
|
-
setSpecifications(
|
|
134
|
+
setSpecifications(
|
|
135
|
+
clone({
|
|
136
|
+
...singleImageResp.image_analysis.specification,
|
|
137
|
+
specificationPrefilter,
|
|
138
|
+
}),
|
|
139
|
+
);
|
|
102
140
|
setPreFilter({});
|
|
103
141
|
setAlgoliaFilter('');
|
|
104
142
|
setShowLoading(false);
|
|
105
143
|
handleClose();
|
|
106
144
|
setShowNotMatchedError(true);
|
|
107
145
|
setTimeout(() => {
|
|
108
|
-
setNameplateNotificationText(
|
|
146
|
+
setNameplateNotificationText(
|
|
147
|
+
t('Extracted details from the nameplate could not be matched', {
|
|
148
|
+
preFilterTitle:
|
|
149
|
+
window.settings.preFilterTitle?.toLocaleLowerCase(),
|
|
150
|
+
}),
|
|
151
|
+
);
|
|
109
152
|
}, 1000);
|
|
110
153
|
setTimeout(() => {
|
|
111
154
|
setNameplateNotificationText('');
|
|
@@ -113,7 +156,7 @@ function CustomCamera(props: Props) {
|
|
|
113
156
|
}
|
|
114
157
|
} else {
|
|
115
158
|
if (!specifications?.is_nameplate) {
|
|
116
|
-
setSpecifications({...specifications, is_nameplate: false});
|
|
159
|
+
setSpecifications({ ...specifications, is_nameplate: false });
|
|
117
160
|
}
|
|
118
161
|
setShowLoading(false);
|
|
119
162
|
handleClose();
|
|
@@ -46,7 +46,7 @@ function DragDropFile(props: Props) {
|
|
|
46
46
|
file: file,
|
|
47
47
|
settings: window.settings,
|
|
48
48
|
newSearch: true,
|
|
49
|
-
}).then(
|
|
49
|
+
}).then(() => {});
|
|
50
50
|
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
@@ -61,7 +61,7 @@ function DragDropFile(props: Props) {
|
|
|
61
61
|
newSearch: true,
|
|
62
62
|
}).then(singleImageResp => {
|
|
63
63
|
const specificationPrefilter =
|
|
64
|
-
singleImageResp
|
|
64
|
+
singleImageResp?.image_analysis?.specification?.prefilter_value || null;
|
|
65
65
|
const hasPrefilter = preFilterList.filter((filter: any) =>
|
|
66
66
|
filter.values.includes(specificationPrefilter),
|
|
67
67
|
);
|
|
@@ -154,9 +154,9 @@ function DragDropFile(props: Props) {
|
|
|
154
154
|
<div
|
|
155
155
|
className={twMerge([
|
|
156
156
|
'drag-n-drop-inner',
|
|
157
|
-
'flex flex-col items-center w-full cursor-pointer
|
|
158
|
-
'text-[#
|
|
159
|
-
'border-2 border-dashed border-
|
|
157
|
+
'flex flex-col items-center w-full cursor-pointer py-10 rounded-[12px]',
|
|
158
|
+
'text-[#767A9F] hover:text-primary',
|
|
159
|
+
'border-2 border-dashed border-[#BBBDCF]',
|
|
160
160
|
isDragging && 'text-primary border-[#e0e0e0]',
|
|
161
161
|
])}
|
|
162
162
|
>
|
|
@@ -51,7 +51,7 @@ function ExperienceVisualSearch({
|
|
|
51
51
|
Start your visual search by selecting an image below.
|
|
52
52
|
</div>
|
|
53
53
|
<div className="custom-modal-body-content experience-visual-search-images">
|
|
54
|
-
{new Array(4).fill(1).map((
|
|
54
|
+
{new Array(4).fill(1).map((_val, index) => {
|
|
55
55
|
let itemImage: any;
|
|
56
56
|
|
|
57
57
|
if (index <= experienceVisualSearchBlobs.length - 1) {
|
|
@@ -9,18 +9,20 @@ import TextSearch from './TextSearch';
|
|
|
9
9
|
import useRequestStore from 'stores/request/requestStore';
|
|
10
10
|
import { useState } from 'react';
|
|
11
11
|
import LogoutModal from './LogoutModal';
|
|
12
|
-
import { Popover, PopoverContent, PopoverTrigger } from './popover';
|
|
13
12
|
import useResultStore from 'stores/result/resultStore';
|
|
14
13
|
import Cart from './Cart';
|
|
14
|
+
import useUiStore from 'stores/ui/uiStore';
|
|
15
15
|
|
|
16
16
|
function Header() {
|
|
17
17
|
const { theme, auth0 } = window.settings;
|
|
18
|
-
const { isAuthenticated
|
|
18
|
+
const { isAuthenticated } = useAuth0();
|
|
19
19
|
let location = useLocation();
|
|
20
20
|
|
|
21
21
|
const reset = useRequestStore(state => state.reset);
|
|
22
22
|
const resetResultStore = useResultStore(state => state.reset);
|
|
23
23
|
const setSpecifications = useRequestStore(state => state.setSpecifications);
|
|
24
|
+
const showSidePanel = useUiStore(state => state.showSidePanel);
|
|
25
|
+
const setShowSidePanel = useUiStore(state => state.setShowSidePanel);
|
|
24
26
|
|
|
25
27
|
const showSearchBar = location?.pathname === '/result';
|
|
26
28
|
|
|
@@ -29,124 +31,142 @@ function Header() {
|
|
|
29
31
|
return (
|
|
30
32
|
<div
|
|
31
33
|
className={twMerge([
|
|
32
|
-
'h-
|
|
33
|
-
'desktop:h-[
|
|
34
|
-
'desktop:min-h-[
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
'desktop:border-solid desktop:border-b desktop:border-[#E0E0E0]',
|
|
38
|
-
'pr-6',
|
|
39
|
-
'pl-4',
|
|
34
|
+
'h-[56px]',
|
|
35
|
+
'desktop:h-[68px]',
|
|
36
|
+
'desktop:min-h-[68px]',
|
|
37
|
+
'px-2',
|
|
38
|
+
'desktop:px-4',
|
|
40
39
|
'w-full',
|
|
41
40
|
'flex-shrink-0',
|
|
41
|
+
'bg-transparent',
|
|
42
|
+
'mt-2',
|
|
43
|
+
'desktop:mt-4',
|
|
44
|
+
'mb-4',
|
|
45
|
+
'desktop:mb-2',
|
|
46
|
+
'flex',
|
|
47
|
+
'gap-2',
|
|
48
|
+
'justify-between',
|
|
49
|
+
'desktop:items-start',
|
|
42
50
|
])}
|
|
43
|
-
style={{ background: theme?.headerColor }}
|
|
44
51
|
>
|
|
52
|
+
{location?.pathname === '/result' && (
|
|
53
|
+
<div
|
|
54
|
+
className={twMerge(
|
|
55
|
+
'hidden desktop:flex',
|
|
56
|
+
'h-[56px] min-w-[56px]',
|
|
57
|
+
'desktop:min-w-[68px] desktop:h-[68px]',
|
|
58
|
+
'border border-solid border-[#DDDEE7] items-center justify-center cursor-pointer bg-white',
|
|
59
|
+
'rounded-2xl',
|
|
60
|
+
'shadow-ds-1',
|
|
61
|
+
)}
|
|
62
|
+
onClick={() => {
|
|
63
|
+
setShowSidePanel(!showSidePanel);
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
<Icon name={showSidePanel ? 'close' : 'hamburger'} />
|
|
67
|
+
</div>
|
|
68
|
+
)}
|
|
69
|
+
|
|
45
70
|
<div
|
|
46
|
-
className={twMerge(
|
|
47
|
-
|
|
71
|
+
className={twMerge(
|
|
72
|
+
'h-[56px]',
|
|
73
|
+
'min-w-[268px] desktop:h-[68px] flex items-center justify-between',
|
|
74
|
+
'border border-solid border-[#DDDEE7]',
|
|
75
|
+
'bg-white',
|
|
76
|
+
'rounded-2xl',
|
|
77
|
+
'shadow-ds-1',
|
|
78
|
+
location?.pathname === '/result' && 'flex-grow',
|
|
79
|
+
)}
|
|
48
80
|
>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
81
|
+
<NavLink
|
|
82
|
+
to="/"
|
|
83
|
+
style={{ lineHeight: 0 }}
|
|
84
|
+
onClick={() => {
|
|
85
|
+
reset();
|
|
86
|
+
resetResultStore();
|
|
87
|
+
setSpecifications(null);
|
|
88
|
+
}}
|
|
89
|
+
className="pl-6"
|
|
53
90
|
>
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
91
|
+
<img
|
|
92
|
+
src={theme?.appBarLogoUrl}
|
|
93
|
+
alt="logo"
|
|
94
|
+
style={{
|
|
95
|
+
aspectRatio: 1,
|
|
96
|
+
width: theme?.logoWidth,
|
|
97
|
+
height: theme?.logoHeight,
|
|
61
98
|
}}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
alt="logo"
|
|
66
|
-
style={{
|
|
67
|
-
aspectRatio: 1,
|
|
68
|
-
width: theme?.logoWidth,
|
|
69
|
-
height: theme?.logoHeight,
|
|
70
|
-
}}
|
|
71
|
-
/>
|
|
72
|
-
</NavLink>
|
|
73
|
-
</div>
|
|
74
|
-
{/* Center: Search bar */}
|
|
75
|
-
<div className="flex-1 flex justify-center items-center min-w-0">
|
|
76
|
-
<div
|
|
77
|
-
className={twMerge(['hidden', showSearchBar && 'desktop:block'])}
|
|
78
|
-
>
|
|
79
|
-
<TextSearch />
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
{/* Right: Cart and user actions */}
|
|
99
|
+
/>
|
|
100
|
+
</NavLink>
|
|
101
|
+
|
|
83
102
|
<div
|
|
84
|
-
className=
|
|
85
|
-
|
|
103
|
+
className={twMerge([
|
|
104
|
+
'hidden',
|
|
105
|
+
showSearchBar && 'desktop:flex',
|
|
106
|
+
'flex-1',
|
|
107
|
+
'justify-center',
|
|
108
|
+
'min-w-0',
|
|
109
|
+
])}
|
|
86
110
|
>
|
|
87
|
-
|
|
111
|
+
<TextSearch className="w-full max-w-[531px] min-w-0" aiMode={true} />
|
|
112
|
+
</div>
|
|
88
113
|
|
|
89
|
-
|
|
114
|
+
{auth0.enabled &&
|
|
115
|
+
isAuthenticated &&
|
|
116
|
+
location?.pathname === '/result' && (
|
|
90
117
|
<>
|
|
91
118
|
<div
|
|
92
|
-
className=
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
<PopoverTrigger>
|
|
97
|
-
<div
|
|
98
|
-
style={{
|
|
99
|
-
display: 'flex',
|
|
100
|
-
columnGap: '16px',
|
|
101
|
-
alignItems: 'center',
|
|
102
|
-
cursor: 'pointer',
|
|
103
|
-
}}
|
|
104
|
-
>
|
|
105
|
-
<p style={{ color: '#2B2C46' }}>{user?.email}</p>
|
|
106
|
-
<Icon name="avatar" />
|
|
107
|
-
</div>
|
|
108
|
-
</PopoverTrigger>
|
|
109
|
-
<PopoverContent className="w-[152px] bg-white p-2 shadow-outer">
|
|
110
|
-
<div
|
|
111
|
-
className={twMerge([
|
|
112
|
-
'flex',
|
|
113
|
-
'w-[75px]',
|
|
114
|
-
'h-[24px]',
|
|
115
|
-
'px-2',
|
|
116
|
-
'items-center',
|
|
117
|
-
'bg-[#2B2C46]',
|
|
118
|
-
'text-white',
|
|
119
|
-
'text-[10px]',
|
|
120
|
-
'cursor-pointer',
|
|
121
|
-
])}
|
|
122
|
-
onClick={() => {
|
|
123
|
-
logout({
|
|
124
|
-
logoutParams: { returnTo: window.location.origin },
|
|
125
|
-
});
|
|
126
|
-
}}
|
|
127
|
-
>
|
|
128
|
-
Sign out
|
|
129
|
-
</div>
|
|
130
|
-
</PopoverContent>
|
|
131
|
-
</Popover>
|
|
132
|
-
</div>
|
|
133
|
-
<div
|
|
134
|
-
className="block desktop:hidden cursor-pointer"
|
|
119
|
+
className={twMerge(
|
|
120
|
+
'cursor-pointer w-10 h-10 rounded-full bg-[#FAFAFA] flex items-center justify-center',
|
|
121
|
+
'mr-3.5',
|
|
122
|
+
)}
|
|
135
123
|
onClick={() => {
|
|
136
124
|
setShowLogoutModal(true);
|
|
137
125
|
}}
|
|
138
126
|
>
|
|
139
127
|
<Icon
|
|
140
128
|
name="logout"
|
|
141
|
-
className="text-
|
|
142
|
-
width={
|
|
143
|
-
height={
|
|
129
|
+
className="text-black"
|
|
130
|
+
width={16}
|
|
131
|
+
height={16}
|
|
144
132
|
/>
|
|
145
133
|
</div>
|
|
146
134
|
</>
|
|
147
135
|
)}
|
|
148
|
-
</div>
|
|
149
136
|
</div>
|
|
137
|
+
<div className="flex gap-2">
|
|
138
|
+
{auth0.enabled &&
|
|
139
|
+
isAuthenticated &&
|
|
140
|
+
location?.pathname !== '/result' && (
|
|
141
|
+
<>
|
|
142
|
+
<div
|
|
143
|
+
className={twMerge(
|
|
144
|
+
'h-[56px] min-w-[56px]',
|
|
145
|
+
'desktop:min-w-[68px] desktop:h-[68px] bg-white rounded-2xl flex items-center justify-center ',
|
|
146
|
+
'border border-solid border-[#DDDEE7]',
|
|
147
|
+
'shadow-ds-1',
|
|
148
|
+
)}
|
|
149
|
+
>
|
|
150
|
+
<button
|
|
151
|
+
className={twMerge(
|
|
152
|
+
'relative flex items-center justify-center rounded-2xl',
|
|
153
|
+
'h-10 w-10',
|
|
154
|
+
)}
|
|
155
|
+
style={{
|
|
156
|
+
backgroundColor: '#FAFAFA',
|
|
157
|
+
}}
|
|
158
|
+
onClick={() => {
|
|
159
|
+
setShowLogoutModal(true);
|
|
160
|
+
}}
|
|
161
|
+
>
|
|
162
|
+
<Icon name="logout" className={twMerge('text-[#BBBDCF]')} />
|
|
163
|
+
</button>
|
|
164
|
+
</div>
|
|
165
|
+
</>
|
|
166
|
+
)}
|
|
167
|
+
{window.settings.cart && <Cart />}
|
|
168
|
+
</div>
|
|
169
|
+
|
|
150
170
|
<LogoutModal
|
|
151
171
|
setShowLogoutModal={setShowLogoutModal}
|
|
152
172
|
showModal={showLogoutModal}
|
package/src/components/Hint.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useTranslation } from 'react-i18next';
|
|
2
2
|
import { useHitsPerPage, UseHitsPerPageProps } from 'react-instantsearch';
|
|
3
3
|
import PoweredBy from './PoweredBy';
|
|
4
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
5
|
|
|
5
6
|
export const HitsPerPage = (props: UseHitsPerPageProps) => {
|
|
6
7
|
const { items, refine } = useHitsPerPage(props);
|
|
@@ -11,9 +12,14 @@ export const HitsPerPage = (props: UseHitsPerPageProps) => {
|
|
|
11
12
|
|
|
12
13
|
return (
|
|
13
14
|
<>
|
|
14
|
-
<div
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
<div
|
|
16
|
+
className={twMerge(
|
|
17
|
+
'w-full min-h-10 bg-[#FFFFFF] border border-solid border-[#DDDEE7] items-center hidden desktop:inline-flex rounded-3xl justify-between pr-4',
|
|
18
|
+
'shadow-ds-1',
|
|
19
|
+
)}
|
|
20
|
+
>
|
|
21
|
+
<div className="self-stretch pl-4 pr-6 border-r border-solid border-[#DDDEE7] justify-center items-center gap-1 flex">
|
|
22
|
+
<div className="text-[#3B3E5F] text-[13px] font-normal font-['Source Sans 3'] leading-none tracking-tight">
|
|
17
23
|
{t('Items per page')}:
|
|
18
24
|
</div>
|
|
19
25
|
<select
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { useRefinementList } from 'react-instantsearch';
|
|
2
|
+
import Tooltip from './Tooltip/TooltipComponent';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
import useRequestStore from '../stores/request/requestStore';
|
|
5
|
+
import useResultStore from '../stores/result/resultStore';
|
|
6
|
+
import { Icon } from '@nyris/nyris-react-components';
|
|
7
|
+
import { useMediaQuery } from 'react-responsive';
|
|
8
|
+
|
|
9
|
+
const IdentifiedAttributes = ({
|
|
10
|
+
attr,
|
|
11
|
+
value,
|
|
12
|
+
specificationFilter,
|
|
13
|
+
imageAnalysis,
|
|
14
|
+
}: any) => {
|
|
15
|
+
const refinement = window.settings.refinements.filter((ref: any) => {
|
|
16
|
+
return ref.header?.toLocaleLowerCase() === attr?.toLocaleLowerCase();
|
|
17
|
+
});
|
|
18
|
+
const attribute = refinement?.length ? refinement[0].attribute : 'none';
|
|
19
|
+
const isMobile = useMediaQuery({ query: '(max-width: 776px)' });
|
|
20
|
+
const { refine } = useRefinementList({
|
|
21
|
+
attribute,
|
|
22
|
+
operator: 'or',
|
|
23
|
+
showMore: false,
|
|
24
|
+
limit: 1,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return isMobile ? (
|
|
28
|
+
<>
|
|
29
|
+
<div className="inline-flex justify-center items-start gap-2 " key={attr}>
|
|
30
|
+
<div className="pl-1 inline-flex justify-center items-center gap-2.5">
|
|
31
|
+
<div className="justify-start text-[#3B3E5F] text-sm font-semibold">
|
|
32
|
+
{attr}
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<div
|
|
36
|
+
className={twMerge(
|
|
37
|
+
`p-1 bg-[#e4e3ff] rounded-lg inline-flex justify-center items-center gap-1.5`,
|
|
38
|
+
'text-[#3e36dc]',
|
|
39
|
+
specificationFilter[attr]
|
|
40
|
+
? 'border-[#3E36DC] bg-[#3E36DC] text-white'
|
|
41
|
+
: '',
|
|
42
|
+
)}
|
|
43
|
+
onClick={() => {
|
|
44
|
+
if (!value) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (attribute !== 'none') {
|
|
48
|
+
refine(value);
|
|
49
|
+
} else {
|
|
50
|
+
const setSpecificationFilter =
|
|
51
|
+
useRequestStore.getState().setSpecificationFilter;
|
|
52
|
+
|
|
53
|
+
const setSpecificationFilteredProducts =
|
|
54
|
+
useResultStore.getState().setSpecificationFilteredProducts;
|
|
55
|
+
|
|
56
|
+
if (specificationFilter[attr]) {
|
|
57
|
+
setSpecificationFilter({});
|
|
58
|
+
setSpecificationFilteredProducts([]);
|
|
59
|
+
// setProducts(results);
|
|
60
|
+
} else {
|
|
61
|
+
setSpecificationFilter({
|
|
62
|
+
[attr]: value,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
<div className="justify-start items-center text-sm font-medium leading-none flex gap-2">
|
|
69
|
+
{imageAnalysis?.specification[attr] || 'N/A'}
|
|
70
|
+
<Icon
|
|
71
|
+
name="close"
|
|
72
|
+
className={twMerge(
|
|
73
|
+
'w-3 h-3 text-white',
|
|
74
|
+
specificationFilter[attr] ? 'block' : 'hidden',
|
|
75
|
+
)}
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</>
|
|
81
|
+
) : (
|
|
82
|
+
<div key={attr} className="flex justify-between w-full gap-2 items-center">
|
|
83
|
+
<div className="self-stretch inline-flex justify-start items-center gap-1.5">
|
|
84
|
+
<div className="justify-start text-[#3B3E5F] text-xs font-semibold">
|
|
85
|
+
{attr}:
|
|
86
|
+
</div>
|
|
87
|
+
<Tooltip
|
|
88
|
+
content={
|
|
89
|
+
specificationFilter[attr]
|
|
90
|
+
? 'Filter applied. Clear to choose a different value.'
|
|
91
|
+
: 'Click to apply as a search filter.'
|
|
92
|
+
}
|
|
93
|
+
delayDuration={1000}
|
|
94
|
+
disabled={!value}
|
|
95
|
+
>
|
|
96
|
+
<div
|
|
97
|
+
className={twMerge(
|
|
98
|
+
`px-1 py-1 bg-[#e4e3ff] rounded-[1px] flex justify-center items-center gap-1.5`,
|
|
99
|
+
'border border-solid border-transparent hover:border-[#3E36DC]',
|
|
100
|
+
'cursor-pointer',
|
|
101
|
+
specificationFilter[attr] ? 'border-[#3E36DC] bg-[#3E36DC] ' : '',
|
|
102
|
+
)}
|
|
103
|
+
onClick={() => {
|
|
104
|
+
if (!value) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (attribute !== 'none') {
|
|
108
|
+
refine(value);
|
|
109
|
+
} else {
|
|
110
|
+
const setSpecificationFilter =
|
|
111
|
+
useRequestStore.getState().setSpecificationFilter;
|
|
112
|
+
|
|
113
|
+
const setSpecificationFilteredProducts =
|
|
114
|
+
useResultStore.getState().setSpecificationFilteredProducts;
|
|
115
|
+
|
|
116
|
+
if (specificationFilter[attr]) {
|
|
117
|
+
setSpecificationFilter({});
|
|
118
|
+
setSpecificationFilteredProducts([]);
|
|
119
|
+
// setProducts(results);
|
|
120
|
+
} else {
|
|
121
|
+
setSpecificationFilter({
|
|
122
|
+
[attr]: value,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
<div
|
|
129
|
+
className={twMerge(
|
|
130
|
+
'justify-start text-[#3e36dc] text-[10px] leading-none px-0.5',
|
|
131
|
+
'font-normal hover:font-bold hover:px-0',
|
|
132
|
+
specificationFilter[attr]
|
|
133
|
+
? 'font-bold text-white hover:px-0.5'
|
|
134
|
+
: '',
|
|
135
|
+
'max-line-1',
|
|
136
|
+
)}
|
|
137
|
+
>
|
|
138
|
+
{imageAnalysis?.specification[attr] || 'N/A'}
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</Tooltip>
|
|
142
|
+
</div>
|
|
143
|
+
<div
|
|
144
|
+
onClick={() => {
|
|
145
|
+
navigator.clipboard.writeText(
|
|
146
|
+
imageAnalysis?.specification[attr] || '',
|
|
147
|
+
);
|
|
148
|
+
}}
|
|
149
|
+
>
|
|
150
|
+
<Icon
|
|
151
|
+
name="copy"
|
|
152
|
+
className="text-[#AAABB5] w-[12px] h-[12px] hover:text-[#3E36DC] cursor-pointer"
|
|
153
|
+
/>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export default IdentifiedAttributes;
|