@nyris/nyris-webapp 0.3.90 → 0.3.92
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.5ea01690.css +4 -0
- package/build/static/css/main.5ea01690.css.map +1 -0
- package/build/static/js/main.36b77705.js +3 -0
- package/build/static/js/{main.cede3ae1.js.map → main.36b77705.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/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 +124 -91
- 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 +198 -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 +3 -7
- 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.cede3ae1.js +0 -3
- package/src/utils/addAssets.ts +0 -40
- /package/build/static/js/{main.cede3ae1.js.LICENSE.txt → main.36b77705.js.LICENSE.txt} +0 -0
|
@@ -1,25 +1,31 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffectiveGroundingResults } from 'hooks/useEffectiveGroundingResults';
|
|
2
|
+
import { useGroundedSearch } from 'hooks/useGroundedSearch';
|
|
3
|
+
import React, { useEffect, useMemo } from 'react';
|
|
2
4
|
import { find } from 'services/visualSearch';
|
|
3
5
|
import useRequestStore from 'stores/request/requestStore';
|
|
4
6
|
import useResultStore from 'stores/result/resultStore';
|
|
7
|
+
import useUiStore from 'stores/ui/uiStore';
|
|
5
8
|
import { twMerge } from 'tailwind-merge';
|
|
6
9
|
|
|
7
10
|
const MatchNotificationBanner = ({ className }: { className?: string }) => {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
const goBack = useUiStore(state => state.bannerGoBack);
|
|
12
|
+
const setGoBack = useUiStore(state => state.setBannerGoBack);
|
|
13
|
+
const textSearch = useUiStore(state => state.bannerTextSearch);
|
|
14
|
+
const setTextSearch = useUiStore(state => state.setBannerTextSearch);
|
|
12
15
|
|
|
13
|
-
const [prevResult, setPrevResult] = useState<any[]>([]);
|
|
16
|
+
const [prevResult, setPrevResult] = React.useState<any[]>([]);
|
|
14
17
|
|
|
15
18
|
const productsFromFindApi = useResultStore(
|
|
16
19
|
state => state.productsFromFindApi,
|
|
17
20
|
);
|
|
21
|
+
const groundingError = useResultStore(state => state.groundingError);
|
|
18
22
|
|
|
19
23
|
const groundingFilterResult = useResultStore(
|
|
20
24
|
state => state.groundingFilterResult,
|
|
21
25
|
);
|
|
22
26
|
|
|
27
|
+
const { groundedSearch } = useGroundedSearch();
|
|
28
|
+
|
|
23
29
|
const showBanner = useMemo(() => {
|
|
24
30
|
if (groundingFilterResult.length !== productsFromFindApi.length) {
|
|
25
31
|
return true;
|
|
@@ -36,11 +42,6 @@ const MatchNotificationBanner = ({ className }: { className?: string }) => {
|
|
|
36
42
|
return false;
|
|
37
43
|
}, [groundingFilterResult, productsFromFindApi]);
|
|
38
44
|
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
setGoBack(false);
|
|
41
|
-
setTextSearch('pending');
|
|
42
|
-
}, []);
|
|
43
|
-
|
|
44
45
|
useEffect(() => {
|
|
45
46
|
if (textSearch === 'pending') {
|
|
46
47
|
setPrevResult(productsFromFindApi || []);
|
|
@@ -54,10 +55,46 @@ const MatchNotificationBanner = ({ className }: { className?: string }) => {
|
|
|
54
55
|
state => state.showingGroundingFilterResult,
|
|
55
56
|
);
|
|
56
57
|
|
|
58
|
+
const effectiveGroundingResults = useEffectiveGroundingResults();
|
|
59
|
+
|
|
57
60
|
const groundingQuery = useRequestStore(state => state.groundingQuery);
|
|
58
61
|
if (goBack) {
|
|
59
62
|
return <></>;
|
|
60
63
|
}
|
|
64
|
+
|
|
65
|
+
if (groundingError) {
|
|
66
|
+
return (
|
|
67
|
+
<div
|
|
68
|
+
className={twMerge([
|
|
69
|
+
'flex items-center justify-between w-full bg-[#FFF8FB] rounded-[16px] p-2 pl-2 shadow-sm',
|
|
70
|
+
className,
|
|
71
|
+
])}
|
|
72
|
+
>
|
|
73
|
+
{/* Left Section: Icon and Text */}
|
|
74
|
+
<div className="flex items-center gap-3">
|
|
75
|
+
<div className="h-2.5 w-2.5 rounded-full bg-[#E31B5D]" />
|
|
76
|
+
<p className="text-[#4a5568] text-sm md:text-base">
|
|
77
|
+
No results from web search.
|
|
78
|
+
</p>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
{/* Right Section: Action Button */}
|
|
82
|
+
<button
|
|
83
|
+
className="bg-[#373b53] hover:bg-[#2d3145] text-white px-6 py-3 rounded-lg text-xs font-semibold transition-colors duration-200"
|
|
84
|
+
onClick={() => {
|
|
85
|
+
const requestImages = useRequestStore.getState().requestImages;
|
|
86
|
+
const requestImage = requestImages?.[0];
|
|
87
|
+
const findApiProducts =
|
|
88
|
+
useResultStore.getState().productsFromFindApi;
|
|
89
|
+
groundedSearch(requestImage, findApiProducts || []);
|
|
90
|
+
}}
|
|
91
|
+
>
|
|
92
|
+
Search again
|
|
93
|
+
</button>
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
61
98
|
if (
|
|
62
99
|
(!groundingFilterResult || groundingFilterResult?.length === 0) &&
|
|
63
100
|
!groundingQuery
|
|
@@ -79,13 +116,13 @@ const MatchNotificationBanner = ({ className }: { className?: string }) => {
|
|
|
79
116
|
<div className="h-2.5 w-2.5 rounded-full bg-[#10b981]" />
|
|
80
117
|
{textSearch === 'resolved' && (
|
|
81
118
|
<p className="text-[#4a5568] text-sm md:text-base">
|
|
82
|
-
Didn't find
|
|
119
|
+
Didn't find what you're looking for?
|
|
83
120
|
</p>
|
|
84
121
|
)}
|
|
85
122
|
{textSearch !== 'resolved' && (
|
|
86
123
|
<p className="text-[#4a5568] text-sm md:text-base">
|
|
87
|
-
Are you looking for
|
|
88
|
-
<span className="font-bold">{groundingQuery}</span>
|
|
124
|
+
Are you looking for
|
|
125
|
+
<span className="font-bold px-0.5">{groundingQuery}</span> ?
|
|
89
126
|
</p>
|
|
90
127
|
)}
|
|
91
128
|
</div>
|
|
@@ -99,7 +136,7 @@ const MatchNotificationBanner = ({ className }: { className?: string }) => {
|
|
|
99
136
|
useResultStore.getState().setFindApiProducts(prevResult);
|
|
100
137
|
}}
|
|
101
138
|
>
|
|
102
|
-
Show
|
|
139
|
+
Show original results
|
|
103
140
|
</button>
|
|
104
141
|
)}
|
|
105
142
|
|
|
@@ -108,16 +145,22 @@ const MatchNotificationBanner = ({ className }: { className?: string }) => {
|
|
|
108
145
|
className="bg-[#373b53] hover:bg-[#2d3145] text-white px-6 py-3 rounded-lg text-xs font-semibold transition-colors duration-200"
|
|
109
146
|
onClick={() => {
|
|
110
147
|
setTextSearch('loading');
|
|
148
|
+
useUiStore.getState().setIsFindApiLoading(true);
|
|
149
|
+
|
|
111
150
|
find({
|
|
112
151
|
settings: window.settings,
|
|
113
152
|
text: groundingQuery,
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
153
|
+
})
|
|
154
|
+
.then(res => {
|
|
155
|
+
useResultStore.getState().setFindApiProducts(res?.results);
|
|
156
|
+
setTextSearch('resolved');
|
|
157
|
+
})
|
|
158
|
+
.finally(() => {
|
|
159
|
+
useUiStore.getState().setIsFindApiLoading(false);
|
|
160
|
+
});
|
|
118
161
|
}}
|
|
119
162
|
>
|
|
120
|
-
Search
|
|
163
|
+
Search catalog
|
|
121
164
|
</button>
|
|
122
165
|
)}
|
|
123
166
|
</div>
|
|
@@ -131,7 +174,7 @@ const MatchNotificationBanner = ({ className }: { className?: string }) => {
|
|
|
131
174
|
return (
|
|
132
175
|
<div
|
|
133
176
|
className={twMerge([
|
|
134
|
-
'flex items-center justify-between w-full bg-[#F2FBF3] rounded-[16px] p-2 pl-2 shadow-sm',
|
|
177
|
+
'flex items-center justify-between w-full bg-[#F2FBF3] rounded-[16px] p-2 pl-2 shadow-sm min-h-[56px]',
|
|
135
178
|
className,
|
|
136
179
|
])}
|
|
137
180
|
>
|
|
@@ -139,25 +182,36 @@ const MatchNotificationBanner = ({ className }: { className?: string }) => {
|
|
|
139
182
|
<div className="flex items-center gap-3">
|
|
140
183
|
<div className="h-2.5 w-2.5 rounded-full bg-[#10b981]" />
|
|
141
184
|
<p className="text-[#4a5568] text-sm md:text-base">
|
|
142
|
-
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
185
|
+
{effectiveGroundingResults.length === 0 && (
|
|
186
|
+
<span>Matched 0 results from Internet search</span>
|
|
187
|
+
)}
|
|
188
|
+
{effectiveGroundingResults.length > 0 && (
|
|
189
|
+
<>
|
|
190
|
+
{showingGroundingFilterResult ? 'Showing' : 'Found'}{' '}
|
|
191
|
+
<span className="font-bold text-slate-900 pr-0.5">
|
|
192
|
+
{effectiveGroundingResults.length}
|
|
193
|
+
</span>
|
|
194
|
+
{showingGroundingFilterResult
|
|
195
|
+
? 'result from Internet search'
|
|
196
|
+
: ' matching result from Internet search'}
|
|
197
|
+
</>
|
|
198
|
+
)}
|
|
147
199
|
</p>
|
|
148
200
|
</div>
|
|
149
201
|
|
|
150
202
|
{/* Right Section: Action Button */}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
203
|
+
{effectiveGroundingResults.length > 0 && (
|
|
204
|
+
<button
|
|
205
|
+
className="bg-[#373b53] hover:bg-[#2d3145] text-white px-6 py-3 rounded-lg text-xs font-semibold transition-colors duration-200"
|
|
206
|
+
onClick={() => {
|
|
207
|
+
useResultStore.getState().setShowingGroundingFilterResult();
|
|
208
|
+
}}
|
|
209
|
+
>
|
|
210
|
+
{showingGroundingFilterResult
|
|
211
|
+
? 'Show original results'
|
|
212
|
+
: 'Show matched results'}
|
|
213
|
+
</button>
|
|
214
|
+
)}
|
|
161
215
|
</div>
|
|
162
216
|
);
|
|
163
217
|
};
|
|
@@ -5,7 +5,7 @@ export default function PoweredBy({ className }: { className?: string }) {
|
|
|
5
5
|
return (
|
|
6
6
|
<div className={twMerge(className)}>
|
|
7
7
|
<Icon
|
|
8
|
-
className="fill-
|
|
8
|
+
className="fill-[#989BB7] group-hover:fill-[url(#powered_by_nyris_colored_svg__gradient)] hover:fill-[url(#powered_by_nyris_colored_svg__gradient)] cursor-pointer w-[110px] h-5"
|
|
9
9
|
name="powered_by_nyris"
|
|
10
10
|
onClick={() => {
|
|
11
11
|
window.open('https://www.nyris.io', '_blank');
|
|
@@ -9,7 +9,6 @@ import useRequestStore from 'stores/request/requestStore';
|
|
|
9
9
|
import { truncateString } from 'utils/truncateString';
|
|
10
10
|
import { twMerge } from 'tailwind-merge';
|
|
11
11
|
import Tooltip from 'components/Tooltip/TooltipComponent';
|
|
12
|
-
import { useNavigate } from 'react-router';
|
|
13
12
|
import useResultStore from '../../stores/result/resultStore';
|
|
14
13
|
|
|
15
14
|
interface Props {
|
|
@@ -41,11 +40,11 @@ const PreFilterComponent = (props: Props) => {
|
|
|
41
40
|
const specification = useRequestStore(state => state.specifications);
|
|
42
41
|
const setSpecifications = useRequestStore(state => state.setSpecifications);
|
|
43
42
|
const setImageAnalysis = useResultStore(state => state.setImageAnalysis);
|
|
43
|
+
const regions = useRequestStore(state => state.regions);
|
|
44
44
|
|
|
45
45
|
const [keyFilter, setKeyFilter] = useState<Record<string, boolean>>(
|
|
46
46
|
keyFilterState || {},
|
|
47
47
|
);
|
|
48
|
-
const navigate = useNavigate();
|
|
49
48
|
|
|
50
49
|
const selectedFilter = useMemo(
|
|
51
50
|
() =>
|
|
@@ -158,6 +157,18 @@ const PreFilterComponent = (props: Props) => {
|
|
|
158
157
|
}
|
|
159
158
|
|
|
160
159
|
handleClose();
|
|
160
|
+
const query = useRequestStore.getState().query;
|
|
161
|
+
if (!window.settings?.algolia.enabled && requestImages.length === 0) {
|
|
162
|
+
singleImageSearch({
|
|
163
|
+
image: requestImages[0],
|
|
164
|
+
imageRegion: regions[0],
|
|
165
|
+
text: query,
|
|
166
|
+
settings,
|
|
167
|
+
showFeedback: false,
|
|
168
|
+
newSearch: false,
|
|
169
|
+
preFilterParams: preFilter,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
161
172
|
|
|
162
173
|
if (requestImages.length === 0) {
|
|
163
174
|
return;
|
|
@@ -170,7 +181,7 @@ const PreFilterComponent = (props: Props) => {
|
|
|
170
181
|
imageRegion: imageRegions[0],
|
|
171
182
|
preFilterParams: preFilter,
|
|
172
183
|
compress: false,
|
|
173
|
-
}).then(
|
|
184
|
+
}).then(() => {});
|
|
174
185
|
} else {
|
|
175
186
|
}
|
|
176
187
|
};
|
|
@@ -80,7 +80,7 @@ function Product(props: Props) {
|
|
|
80
80
|
img.src = url;
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
-
const handlerToggleModal = (
|
|
83
|
+
const handlerToggleModal = (_item?: any) => {
|
|
84
84
|
setOpenDetailedView('image');
|
|
85
85
|
};
|
|
86
86
|
|
|
@@ -123,10 +123,18 @@ function Product(props: Props) {
|
|
|
123
123
|
onSearchImage={onSearchImage}
|
|
124
124
|
openDetailedView={openDetailedView}
|
|
125
125
|
setOpenDetailedView={setOpenDetailedView}
|
|
126
|
-
main_image_link={main_image_link}
|
|
127
126
|
onAddToCart={onAddToCart}
|
|
128
127
|
/>
|
|
129
|
-
<div
|
|
128
|
+
<div
|
|
129
|
+
className={twMerge(
|
|
130
|
+
'wrap-main-item-result',
|
|
131
|
+
'max-w-[190px] w-[180px] desktop:w-[190px]',
|
|
132
|
+
'border border-solid border-[#E7E8F1]',
|
|
133
|
+
'scroll-pt-5',
|
|
134
|
+
'shadow-ds-1',
|
|
135
|
+
'rounded-2xl',
|
|
136
|
+
)}
|
|
137
|
+
>
|
|
130
138
|
<div className="relative h-fit">
|
|
131
139
|
{!isHover && main_image_link && !settings.noSimilarSearch && (
|
|
132
140
|
<div
|
|
@@ -434,7 +442,7 @@ function Product(props: Props) {
|
|
|
434
442
|
? 8
|
|
435
443
|
: 0,
|
|
436
444
|
gridGap: 8,
|
|
437
|
-
color: '#
|
|
445
|
+
color: '#3B3E5F',
|
|
438
446
|
}}
|
|
439
447
|
>
|
|
440
448
|
{settings.attributes?.attributeOneValue && (
|
|
@@ -445,7 +453,6 @@ function Product(props: Props) {
|
|
|
445
453
|
settings.attributes?.attributeOneValue || '',
|
|
446
454
|
)}
|
|
447
455
|
padding={'4px 8px'}
|
|
448
|
-
backgroundColor={'#E0E0E0'}
|
|
449
456
|
isTitleVisible={
|
|
450
457
|
!!settings.attributes?.attributeOneLabelValue
|
|
451
458
|
}
|
|
@@ -459,7 +466,6 @@ function Product(props: Props) {
|
|
|
459
466
|
settings.attributes?.attributeTwoValue || '',
|
|
460
467
|
)}
|
|
461
468
|
padding={'4px 8px'}
|
|
462
|
-
backgroundColor={'#E0E0E0'}
|
|
463
469
|
isTitleVisible={
|
|
464
470
|
!!settings.attributes?.attributeTwoLabelValue
|
|
465
471
|
}
|
|
@@ -473,7 +479,6 @@ function Product(props: Props) {
|
|
|
473
479
|
settings.attributes?.attributeThreeValue || '',
|
|
474
480
|
)}
|
|
475
481
|
padding={'4px 8px'}
|
|
476
|
-
backgroundColor={'#E0E0E0'}
|
|
477
482
|
isTitleVisible={
|
|
478
483
|
!!settings.attributes?.attributeThreeLabelValue
|
|
479
484
|
}
|
|
@@ -488,7 +493,6 @@ function Product(props: Props) {
|
|
|
488
493
|
settings.attributes?.attributeFourValue || '',
|
|
489
494
|
)}
|
|
490
495
|
padding={'4px 8px'}
|
|
491
|
-
backgroundColor={'#E0E0E0'}
|
|
492
496
|
isTitleVisible={
|
|
493
497
|
!!settings.attributes?.attributeFourLabelValue
|
|
494
498
|
}
|
|
@@ -507,7 +511,7 @@ function Product(props: Props) {
|
|
|
507
511
|
background:
|
|
508
512
|
settings.secondaryCTAButton?.secondaryCTAButtonColor ||
|
|
509
513
|
'#2B2C46',
|
|
510
|
-
borderRadius:
|
|
514
|
+
borderRadius: 6,
|
|
511
515
|
paddingLeft: '8px',
|
|
512
516
|
marginBottom: settings.CTAButton?.CTAButton ? 8 : 0,
|
|
513
517
|
display: 'flex',
|
|
@@ -591,7 +595,7 @@ function Product(props: Props) {
|
|
|
591
595
|
background:
|
|
592
596
|
settings.CTAButton?.CTAButtonColor ||
|
|
593
597
|
settings.theme?.primaryColor,
|
|
594
|
-
borderRadius:
|
|
598
|
+
borderRadius: 6,
|
|
595
599
|
paddingLeft: '8px',
|
|
596
600
|
display: 'flex',
|
|
597
601
|
justifyItems: 'center',
|
|
@@ -677,7 +681,7 @@ function Product(props: Props) {
|
|
|
677
681
|
background:
|
|
678
682
|
settings.CTAButton?.CTAButtonColor ||
|
|
679
683
|
settings.theme?.primaryColor,
|
|
680
|
-
borderRadius:
|
|
684
|
+
borderRadius: 6,
|
|
681
685
|
paddingLeft: '8px',
|
|
682
686
|
display: 'flex',
|
|
683
687
|
justifyItems: 'center',
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import Tooltip from 'components/Tooltip/TooltipComponent';
|
|
2
|
-
import React from 'react';
|
|
3
2
|
|
|
4
3
|
interface Props {
|
|
5
4
|
title: any;
|
|
@@ -26,16 +25,16 @@ function ProductAttribute(props: Props) {
|
|
|
26
25
|
display: 'flex',
|
|
27
26
|
flexDirection: 'column',
|
|
28
27
|
justifyContent: 'center',
|
|
29
|
-
borderRadius:
|
|
28
|
+
borderRadius: 6,
|
|
30
29
|
height: '36px',
|
|
31
|
-
backgroundColor: props.backgroundColor || '#
|
|
30
|
+
backgroundColor: props.backgroundColor || '#F3F3F5',
|
|
32
31
|
padding: padding,
|
|
33
32
|
}}
|
|
34
33
|
>
|
|
35
34
|
{isTitleVisible ? (
|
|
36
35
|
<div
|
|
37
36
|
style={{
|
|
38
|
-
color: '#
|
|
37
|
+
color: '#3B3E5F',
|
|
39
38
|
overflow: 'hidden',
|
|
40
39
|
textOverflow: 'ellipsis',
|
|
41
40
|
whiteSpace: 'nowrap',
|
|
@@ -51,7 +50,7 @@ function ProductAttribute(props: Props) {
|
|
|
51
50
|
<Tooltip content={value} disabled={!value} sideOffset={10}>
|
|
52
51
|
<div
|
|
53
52
|
style={{
|
|
54
|
-
color: '#
|
|
53
|
+
color: '#3B3E5F',
|
|
55
54
|
overflow: 'hidden',
|
|
56
55
|
textOverflow: 'ellipsis',
|
|
57
56
|
whiteSpace: 'nowrap',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
2
|
import { Dialog, DialogContent, DialogTitle } from 'components/Modal/Dialog';
|
|
3
3
|
import ProductDetailView from './ProductDetailView';
|
|
4
4
|
|
|
@@ -8,7 +8,6 @@ function ProductDetailViewModal({
|
|
|
8
8
|
dataItem,
|
|
9
9
|
handlerFeedback,
|
|
10
10
|
onSearchImage,
|
|
11
|
-
main_image_link,
|
|
12
11
|
onAddToCart,
|
|
13
12
|
}: {
|
|
14
13
|
openDetailedView: '3d' | 'image' | undefined;
|
|
@@ -16,7 +15,6 @@ function ProductDetailViewModal({
|
|
|
16
15
|
dataItem: any;
|
|
17
16
|
handlerFeedback: (value: string) => void;
|
|
18
17
|
onSearchImage: (url: string) => void;
|
|
19
|
-
main_image_link: string;
|
|
20
18
|
onAddToCart: (item: any) => void;
|
|
21
19
|
}) {
|
|
22
20
|
useEffect(() => {
|
|
@@ -35,7 +33,7 @@ function ProductDetailViewModal({
|
|
|
35
33
|
return (
|
|
36
34
|
<Dialog
|
|
37
35
|
open={openDetailedView === '3d' || openDetailedView === 'image'}
|
|
38
|
-
onOpenChange={(
|
|
36
|
+
onOpenChange={() => {
|
|
39
37
|
setOpenDetailedView(undefined);
|
|
40
38
|
}}
|
|
41
39
|
modal={true}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
1
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
2
2
|
import useResultStore from 'stores/result/resultStore';
|
|
3
3
|
import Product from './Product';
|
|
4
4
|
import { useImageSearch } from 'hooks/useImageSearch';
|
|
@@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
8
8
|
import { twMerge } from 'tailwind-merge';
|
|
9
9
|
import { filterProducts } from 'utils/specificationFilter';
|
|
10
10
|
import { filterProductsByText } from 'utils/textSearchFilter';
|
|
11
|
+
import { useEffectiveGroundingResults } from 'hooks/useEffectiveGroundingResults';
|
|
11
12
|
|
|
12
13
|
interface Props {
|
|
13
14
|
sendFeedBackAction?: any;
|
|
@@ -25,16 +26,17 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
25
26
|
state => state.productsFromFindApi,
|
|
26
27
|
);
|
|
27
28
|
|
|
28
|
-
const groundingFilterResult = useResultStore(
|
|
29
|
-
state => state.groundingFilterResult,
|
|
30
|
-
);
|
|
31
|
-
|
|
32
29
|
const showingGroundingFilterResult = useResultStore(
|
|
33
30
|
state => state.showingGroundingFilterResult,
|
|
34
31
|
);
|
|
35
32
|
|
|
33
|
+
const effectiveGroundingResults = useEffectiveGroundingResults();
|
|
34
|
+
|
|
36
35
|
const isAlgoliaLoading = useUiStore(state => state.isAlgoliaLoading);
|
|
37
36
|
const isFindApiLoading = useUiStore(state => state.isFindApiLoading);
|
|
37
|
+
const isAiModeOpen = useUiStore(state => state.isAiModeOpen);
|
|
38
|
+
|
|
39
|
+
const [products, setProducts] = useState<any[]>([]);
|
|
38
40
|
|
|
39
41
|
const setQuery = useRequestStore(state => state.setQuery);
|
|
40
42
|
const query = useRequestStore(state => state.query);
|
|
@@ -96,7 +98,8 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
96
98
|
}).then(() => {});
|
|
97
99
|
};
|
|
98
100
|
const isAlgoliaEnabled = window.settings?.algolia?.enabled;
|
|
99
|
-
|
|
101
|
+
|
|
102
|
+
const baseProducts = useMemo(() => {
|
|
100
103
|
const filter = Object.values(specificationFilter || {})[0];
|
|
101
104
|
const baseFindApiProducts = postFilteredProducts;
|
|
102
105
|
|
|
@@ -124,22 +127,27 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
124
127
|
postFilteredProducts,
|
|
125
128
|
]);
|
|
126
129
|
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
setProducts(baseProducts || []);
|
|
132
|
+
}, [baseProducts, specificationFilter]);
|
|
133
|
+
|
|
127
134
|
const groundedFilteredProducts = useMemo(() => {
|
|
128
|
-
if (
|
|
135
|
+
if (effectiveGroundingResults && effectiveGroundingResults.length > 0) {
|
|
129
136
|
const filtered = products.filter((product: any) =>
|
|
130
|
-
|
|
137
|
+
effectiveGroundingResults.some(
|
|
138
|
+
(result: any) => product.sku === result.sku,
|
|
139
|
+
),
|
|
131
140
|
);
|
|
132
141
|
if (filtered.length > 0) {
|
|
133
142
|
return filtered;
|
|
134
143
|
}
|
|
135
144
|
return products;
|
|
136
145
|
}
|
|
137
|
-
return
|
|
138
|
-
|
|
139
|
-
}, [groundingFilterResult]);
|
|
146
|
+
return products;
|
|
147
|
+
}, [effectiveGroundingResults, products]);
|
|
140
148
|
|
|
141
149
|
const renderItem = useMemo(() => {
|
|
142
|
-
const productsToRender =
|
|
150
|
+
const productsToRender: any[] =
|
|
143
151
|
groundedFilteredProducts &&
|
|
144
152
|
groundedFilteredProducts.length > 0 &&
|
|
145
153
|
showingGroundingFilterResult
|
|
@@ -185,7 +193,12 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
185
193
|
</div>
|
|
186
194
|
);
|
|
187
195
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
188
|
-
}, [
|
|
196
|
+
}, [
|
|
197
|
+
products,
|
|
198
|
+
groundedFilteredProducts,
|
|
199
|
+
showingGroundingFilterResult,
|
|
200
|
+
isAiModeOpen,
|
|
201
|
+
]);
|
|
189
202
|
|
|
190
203
|
if (
|
|
191
204
|
products?.length === 0 &&
|