@nyris/nyris-webapp 0.3.97 → 0.3.99
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 +7 -6
- package/build/index.html +1 -1
- package/build/js/settings.example.js +41 -0
- package/build/static/css/main.5cb72c09.css +4 -0
- package/build/static/css/main.5cb72c09.css.map +1 -0
- package/build/static/js/main.2339271b.js +3 -0
- package/build/static/js/{main.9e7fb38a.js.map → main.2339271b.js.map} +1 -1
- package/build/static/media/plate_info.6beaea36d35053be3a45.png +0 -0
- package/package.json +3 -3
- package/public/js/settings.example.js +41 -0
- package/src/common/assets/images/plate_info.png +0 -0
- package/src/components/AuthApiKeySync.tsx +34 -0
- package/src/components/Cart.tsx +41 -0
- package/src/components/ChatAssistant/useChatAssistantLogic.ts +3 -2
- package/src/components/GoBackButton.tsx +29 -2
- package/src/components/Header.tsx +3 -0
- package/src/components/HitsPerPage.tsx +55 -18
- package/src/components/ImagePreview.tsx +31 -1
- package/src/components/ImageUpload.tsx +14 -3
- package/src/components/Inquiry/InquiryModal.tsx +3 -0
- package/src/components/LogoutModal.tsx +2 -0
- package/src/components/Pagination.tsx +33 -6
- package/src/components/PostFilter/PostFilter.tsx +8 -1
- package/src/components/PostFilter/PostFilterComponent.tsx +8 -22
- package/src/components/PostFilter/PostFilterFindApi.test.tsx +249 -0
- package/src/components/PostFilter/PostFilterFindApi.tsx +128 -52
- package/src/components/PreFilter/PreFilter.tsx +10 -2
- package/src/components/Product/Product.tsx +60 -10
- package/src/components/Product/ProductDetailView.tsx +23 -1
- package/src/components/Product/ProductDetailViewModal.tsx +5 -1
- package/src/components/Product/ProductList.tsx +51 -16
- package/src/components/Rfq/RfqModal.tsx +3 -0
- package/src/components/ScopeSelect/ScopeSelectForm.tsx +514 -0
- package/src/components/ScopeSelect/ScopeSelectImageActions.tsx +62 -0
- package/src/components/ScopeSelect/ScopeSelectImagePreview.tsx +141 -0
- package/src/components/ScopeSelect/ScopeSelectInfo.tsx +68 -0
- package/src/components/ScopeSelect/ScopeSelectInput.tsx +123 -0
- package/src/components/ScopeSelect/ScopeSelectModal.tsx +310 -0
- package/src/components/ScopeSelect/identifyTypePlateImage.test.ts +129 -0
- package/src/components/ScopeSelect/identifyTypePlateImage.ts +83 -0
- package/src/components/ScopeSelect/parseScopeIdResponse.test.ts +103 -0
- package/src/components/ScopeSelect/parseScopeIdResponse.ts +72 -0
- package/src/components/ScopeSelect/scopeSelectHelpers.ts +54 -0
- package/src/components/SidePanel.tsx +43 -0
- package/src/components/TextSearch.tsx +80 -14
- package/src/components/Tooltip/TooltipComponent.tsx +12 -4
- package/src/components/TypePlateUpload.tsx +132 -0
- package/src/hooks/useEffectiveGroundingResults.ts +8 -6
- package/src/hooks/useGoodResultsChat.ts +8 -22
- package/src/hooks/useImageSearch.ts +325 -20
- package/src/hooks/useMachinePartsListingPagination.ts +95 -0
- package/src/hooks/useResultEvaluator.ts +43 -19
- package/src/index.css +1 -1
- package/src/index.tsx +4 -0
- package/src/layouts/AppLayout.tsx +95 -9
- package/src/pages/Home.tsx +60 -14
- package/src/pages/Logout.tsx +2 -0
- package/src/pages/Result.tsx +206 -20
- package/src/providers/AuthProvider.tsx +5 -0
- package/src/services/Feedback.ts +224 -35
- package/src/services/feedbackSubtypes.ts +63 -0
- package/src/services/filter.ts +4 -3
- package/src/services/initialMachinePartsText.payload.test.ts +61 -0
- package/src/services/initialMachinePartsText.test.ts +33 -0
- package/src/services/initialMachinePartsText.ts +11 -0
- package/src/services/machinePartsPage.test.ts +74 -0
- package/src/services/machinePartsPage.ts +120 -0
- package/src/services/normalizeChatResponse.ts +26 -0
- package/src/services/scopeLookup.test.ts +67 -0
- package/src/services/scopeLookup.ts +39 -0
- package/src/services/visualSearch.listingOptions.test.ts +79 -0
- package/src/services/visualSearch.ts +76 -7
- package/src/services/vizo.ts +17 -5
- package/src/stores/machinePartsListing/machinePartsListingStore.ts +35 -0
- package/src/stores/request/filter/filter.initialState.ts +1 -0
- package/src/stores/request/filter/filter.slice.ts +2 -0
- package/src/stores/result/prodcuts/products.initialState.ts +1 -0
- package/src/stores/result/prodcuts/products.slice.ts +4 -0
- package/src/stores/scope/scopeStore.ts +67 -4
- package/src/stores/types.ts +19 -14
- package/src/translations.ts +213 -0
- package/src/types.ts +40 -0
- package/src/utils/derivePostFilterFacets.ts +68 -0
- package/src/utils/fetchProductImage.ts +1 -0
- package/src/utils/normalizeChatAssistantResponse.ts +227 -0
- package/src/utils/nyrisApiKey.ts +115 -0
- package/src/utils/productCardImageUrl.test.ts +41 -0
- package/src/utils/productCardImageUrl.ts +49 -0
- package/src/utils/textSearchFilter.test.ts +41 -0
- package/src/utils/textSearchFilter.ts +13 -6
- package/build/static/css/main.7c7f5447.css +0 -4
- package/build/static/css/main.7c7f5447.css.map +0 -1
- package/build/static/js/main.9e7fb38a.js +0 -3
- /package/build/static/js/{main.9e7fb38a.js.LICENSE.txt → main.2339271b.js.LICENSE.txt} +0 -0
|
@@ -13,6 +13,10 @@ import { twMerge } from 'tailwind-merge';
|
|
|
13
13
|
import NoImage from '../../common/assets/images/no-image.svg';
|
|
14
14
|
import ProductDetailViewModal from './ProductDetailViewModal';
|
|
15
15
|
import Tooltip from 'components/Tooltip/TooltipComponent';
|
|
16
|
+
import { trackClick, trackConversion } from 'services/Feedback';
|
|
17
|
+
import { CLICK_SUBTYPE, CONVERSION_SUBTYPE } from 'services/feedbackSubtypes';
|
|
18
|
+
import useResultStore from 'stores/result/resultStore';
|
|
19
|
+
import { productCardImageUrl } from 'utils/productCardImageUrl';
|
|
16
20
|
|
|
17
21
|
interface Props {
|
|
18
22
|
dataItem: any;
|
|
@@ -35,8 +39,15 @@ function Product(props: Props) {
|
|
|
35
39
|
onSearchImage,
|
|
36
40
|
handlerFeedback,
|
|
37
41
|
main_image_link,
|
|
42
|
+
indexItem,
|
|
38
43
|
} = props;
|
|
44
|
+
const productRef = { sku: dataItem?.sku, position: indexItem };
|
|
39
45
|
const [urlImage, setUrlImage] = useState<string>('');
|
|
46
|
+
const [showOriginalImage, setShowOriginalImage] = useState(false);
|
|
47
|
+
const cardImageUrl =
|
|
48
|
+
typeof main_image_link === 'string' && main_image_link
|
|
49
|
+
? productCardImageUrl(main_image_link)
|
|
50
|
+
: '';
|
|
40
51
|
const settings = window.settings;
|
|
41
52
|
const [copiedKey, setCopiedKey] = useState<'main' | 'secondary' | null>(null);
|
|
42
53
|
const copyTimeoutRef = useRef<number | undefined>(undefined);
|
|
@@ -46,8 +57,9 @@ function Product(props: Props) {
|
|
|
46
57
|
>();
|
|
47
58
|
|
|
48
59
|
useEffect(() => {
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
setShowOriginalImage(false);
|
|
61
|
+
if (typeof main_image_link === 'string' && main_image_link) {
|
|
62
|
+
handlerCheckUrlImage(productCardImageUrl(main_image_link));
|
|
51
63
|
}
|
|
52
64
|
}, [main_image_link]);
|
|
53
65
|
|
|
@@ -81,17 +93,26 @@ function Product(props: Props) {
|
|
|
81
93
|
};
|
|
82
94
|
|
|
83
95
|
const handlerToggleModal = (_item?: any) => {
|
|
96
|
+
trackClick(CLICK_SUBTYPE.RESULT_CARD, productRef);
|
|
84
97
|
setOpenDetailedView('image');
|
|
85
98
|
};
|
|
86
99
|
|
|
87
|
-
const onAddToCart = (part: any): void => {
|
|
100
|
+
const onAddToCart = (part: any, position: number = indexItem): void => {
|
|
88
101
|
// Get current cart from sessionStorage
|
|
89
102
|
const cart = JSON.parse(sessionStorage.getItem('cart') || '[]');
|
|
90
103
|
// Find if part already exists in cart
|
|
91
104
|
const partIndex = cart.findIndex((p: any) => p.sku === part.sku);
|
|
92
105
|
if (partIndex === -1) {
|
|
93
|
-
// Add new part with quantity 1
|
|
94
|
-
cart
|
|
106
|
+
// Add new part with quantity 1; remember which search it came from so
|
|
107
|
+
// cart conversions can be tied back to the originating request.
|
|
108
|
+
const { requestId, sessionId } = useResultStore.getState();
|
|
109
|
+
cart.push({
|
|
110
|
+
...part,
|
|
111
|
+
quantity: 1,
|
|
112
|
+
feedbackRequestId: requestId,
|
|
113
|
+
feedbackSessionId: sessionId,
|
|
114
|
+
feedbackPosition: position,
|
|
115
|
+
});
|
|
95
116
|
} else {
|
|
96
117
|
// Increment quantity
|
|
97
118
|
cart[partIndex] = {
|
|
@@ -102,10 +123,16 @@ function Product(props: Props) {
|
|
|
102
123
|
sessionStorage.setItem('cart', JSON.stringify(cart));
|
|
103
124
|
window.dispatchEvent(new Event('cart-updated'));
|
|
104
125
|
ToastHelper.success('Product added');
|
|
126
|
+
trackConversion(CONVERSION_SUBTYPE.ADD_TO_CART, {
|
|
127
|
+
skus: [part?.sku],
|
|
128
|
+
positions: [position],
|
|
129
|
+
quantity: 1,
|
|
130
|
+
});
|
|
105
131
|
};
|
|
106
132
|
|
|
107
133
|
const handleCopy = (value: string, key: 'main' | 'secondary') => {
|
|
108
134
|
navigator.clipboard.writeText(value);
|
|
135
|
+
trackClick(CLICK_SUBTYPE.COPY_DETAILS, productRef);
|
|
109
136
|
setCopiedKey(key);
|
|
110
137
|
if (copyTimeoutRef.current) {
|
|
111
138
|
window.clearTimeout(copyTimeoutRef.current);
|
|
@@ -124,6 +151,7 @@ function Product(props: Props) {
|
|
|
124
151
|
openDetailedView={openDetailedView}
|
|
125
152
|
setOpenDetailedView={setOpenDetailedView}
|
|
126
153
|
onAddToCart={onAddToCart}
|
|
154
|
+
indexItem={indexItem}
|
|
127
155
|
/>
|
|
128
156
|
<div
|
|
129
157
|
className={twMerge(
|
|
@@ -141,6 +169,7 @@ function Product(props: Props) {
|
|
|
141
169
|
className="box-icon-modal"
|
|
142
170
|
onClick={() => {
|
|
143
171
|
if (urlImage.length > 1) {
|
|
172
|
+
trackClick(CLICK_SUBTYPE.SIMILAR_PART_SEARCH, productRef);
|
|
144
173
|
onSearchImage(main_image_link);
|
|
145
174
|
}
|
|
146
175
|
}}
|
|
@@ -157,6 +186,7 @@ function Product(props: Props) {
|
|
|
157
186
|
<div
|
|
158
187
|
className="box-icon-modal-3d"
|
|
159
188
|
onClick={() => {
|
|
189
|
+
trackClick(CLICK_SUBTYPE.EXPAND_DETAILS, productRef);
|
|
160
190
|
setOpenDetailedView('3d');
|
|
161
191
|
}}
|
|
162
192
|
>
|
|
@@ -189,7 +219,11 @@ function Product(props: Props) {
|
|
|
189
219
|
>
|
|
190
220
|
{main_image_link && (
|
|
191
221
|
<img
|
|
192
|
-
src={
|
|
222
|
+
src={
|
|
223
|
+
showOriginalImage || !cardImageUrl
|
|
224
|
+
? main_image_link
|
|
225
|
+
: cardImageUrl
|
|
226
|
+
}
|
|
193
227
|
key={main_image_link}
|
|
194
228
|
alt=""
|
|
195
229
|
className="img-style product-image"
|
|
@@ -198,6 +232,13 @@ function Product(props: Props) {
|
|
|
198
232
|
height: '100%',
|
|
199
233
|
objectFit: 'contain',
|
|
200
234
|
}}
|
|
235
|
+
onError={() => {
|
|
236
|
+
if (showOriginalImage || cardImageUrl === main_image_link) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
setShowOriginalImage(true);
|
|
240
|
+
handlerCheckUrlImage(main_image_link);
|
|
241
|
+
}}
|
|
201
242
|
/>
|
|
202
243
|
)}
|
|
203
244
|
|
|
@@ -265,7 +306,10 @@ function Product(props: Props) {
|
|
|
265
306
|
}}
|
|
266
307
|
onClick={() => {
|
|
267
308
|
if (settings.CTAButton?.CTALinkField) {
|
|
268
|
-
|
|
309
|
+
trackConversion(undefined, {
|
|
310
|
+
skus: [dataItem?.sku],
|
|
311
|
+
positions: [indexItem],
|
|
312
|
+
});
|
|
269
313
|
window.open(
|
|
270
314
|
`${get(dataItem, settings.CTAButton?.CTALinkField)}`,
|
|
271
315
|
'_blank',
|
|
@@ -533,7 +577,10 @@ function Product(props: Props) {
|
|
|
533
577
|
}}
|
|
534
578
|
onClick={() => {
|
|
535
579
|
if (settings.secondaryCTAButton?.secondaryCTALinkField) {
|
|
536
|
-
|
|
580
|
+
trackConversion(undefined, {
|
|
581
|
+
skus: [dataItem?.sku],
|
|
582
|
+
positions: [indexItem],
|
|
583
|
+
});
|
|
537
584
|
window.open(
|
|
538
585
|
`${get(
|
|
539
586
|
dataItem,
|
|
@@ -616,7 +663,10 @@ function Product(props: Props) {
|
|
|
616
663
|
}}
|
|
617
664
|
onClick={() => {
|
|
618
665
|
if (settings.CTAButton?.CTALinkField) {
|
|
619
|
-
|
|
666
|
+
trackConversion(undefined, {
|
|
667
|
+
skus: [dataItem?.sku],
|
|
668
|
+
positions: [indexItem],
|
|
669
|
+
});
|
|
620
670
|
window.open(
|
|
621
671
|
`${get(dataItem, settings.CTAButton?.CTALinkField)}`,
|
|
622
672
|
'_blank',
|
|
@@ -700,7 +750,7 @@ function Product(props: Props) {
|
|
|
700
750
|
cursor: 'pointer',
|
|
701
751
|
}}
|
|
702
752
|
onClick={() => {
|
|
703
|
-
onAddToCart(dataItem);
|
|
753
|
+
onAddToCart(dataItem, indexItem);
|
|
704
754
|
}}
|
|
705
755
|
>
|
|
706
756
|
<div
|
|
@@ -20,6 +20,8 @@ import {
|
|
|
20
20
|
AccordionTrigger,
|
|
21
21
|
} from 'components/Accordion';
|
|
22
22
|
import Tooltip from 'components/Tooltip/TooltipComponent';
|
|
23
|
+
import { trackClick, trackConversion } from 'services/Feedback';
|
|
24
|
+
import { CLICK_SUBTYPE } from 'services/feedbackSubtypes';
|
|
23
25
|
|
|
24
26
|
interface Props {
|
|
25
27
|
dataItem?: any;
|
|
@@ -29,6 +31,8 @@ interface Props {
|
|
|
29
31
|
show3dView?: boolean;
|
|
30
32
|
onSearchImage?: any;
|
|
31
33
|
onAddToCart?: any;
|
|
34
|
+
/** Zero-based position of the product in the rendered result list. */
|
|
35
|
+
indexItem?: number;
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
function ProductDetailView(props: Props) {
|
|
@@ -38,8 +42,10 @@ function ProductDetailView(props: Props) {
|
|
|
38
42
|
show3dView = false,
|
|
39
43
|
onSearchImage,
|
|
40
44
|
onAddToCart,
|
|
45
|
+
indexItem,
|
|
41
46
|
} = props;
|
|
42
47
|
const { sku } = dataItem;
|
|
48
|
+
const productRef = { sku, position: indexItem };
|
|
43
49
|
const isMobile = useMediaQuery({ query: '(max-width: 776px)' });
|
|
44
50
|
const { settings } = window;
|
|
45
51
|
|
|
@@ -76,6 +82,7 @@ function ProductDetailView(props: Props) {
|
|
|
76
82
|
}, []);
|
|
77
83
|
const handleCopy = (value: string, key: 'main' | 'secondary') => {
|
|
78
84
|
navigator.clipboard.writeText(value);
|
|
85
|
+
trackClick(CLICK_SUBTYPE.COPY_DETAILS, productRef);
|
|
79
86
|
setCopiedKey(key);
|
|
80
87
|
if (copyTimeoutRef.current) {
|
|
81
88
|
window.clearTimeout(copyTimeoutRef.current);
|
|
@@ -151,6 +158,7 @@ function ProductDetailView(props: Props) {
|
|
|
151
158
|
}`}
|
|
152
159
|
onClick={() => {
|
|
153
160
|
if (urlImage.length > 1) {
|
|
161
|
+
trackClick(CLICK_SUBTYPE.SIMILAR_PART_SEARCH, productRef);
|
|
154
162
|
onSearchImage(urlImage);
|
|
155
163
|
handleClose?.();
|
|
156
164
|
return;
|
|
@@ -176,6 +184,7 @@ function ProductDetailView(props: Props) {
|
|
|
176
184
|
<div
|
|
177
185
|
className="bg-[#E9E9EC] w-8 h-8 rounded-full flex justify-center items-center cursor-pointer"
|
|
178
186
|
onClick={() => {
|
|
187
|
+
trackClick(CLICK_SUBTYPE.EXPAND_DETAILS, productRef);
|
|
179
188
|
setIs3dView(true);
|
|
180
189
|
}}
|
|
181
190
|
>
|
|
@@ -356,6 +365,10 @@ function ProductDetailView(props: Props) {
|
|
|
356
365
|
if (
|
|
357
366
|
settings.secondaryCTAButton?.secondaryCTALinkField
|
|
358
367
|
) {
|
|
368
|
+
trackConversion(undefined, {
|
|
369
|
+
skus: [sku],
|
|
370
|
+
positions: [indexItem],
|
|
371
|
+
});
|
|
359
372
|
window.open(
|
|
360
373
|
`${get(
|
|
361
374
|
dataItem,
|
|
@@ -406,6 +419,10 @@ function ProductDetailView(props: Props) {
|
|
|
406
419
|
className="flex justify-between items-center w-full px-3 min-h-8 cursor-pointer"
|
|
407
420
|
onClick={() => {
|
|
408
421
|
if (settings.CTAButton?.CTALinkField) {
|
|
422
|
+
trackConversion(undefined, {
|
|
423
|
+
skus: [sku],
|
|
424
|
+
positions: [indexItem],
|
|
425
|
+
});
|
|
409
426
|
window.open(
|
|
410
427
|
`${get(
|
|
411
428
|
dataItem,
|
|
@@ -468,7 +485,7 @@ function ProductDetailView(props: Props) {
|
|
|
468
485
|
<div
|
|
469
486
|
className="flex justify-between items-center w-full px-3 min-h-8 cursor-pointer"
|
|
470
487
|
onClick={() => {
|
|
471
|
-
onAddToCart(dataItem);
|
|
488
|
+
onAddToCart(dataItem, indexItem);
|
|
472
489
|
}}
|
|
473
490
|
>
|
|
474
491
|
<div className="text-f16 fw-600 max-line-1 text-white pr-1.5">
|
|
@@ -495,6 +512,11 @@ function ProductDetailView(props: Props) {
|
|
|
495
512
|
collapsible
|
|
496
513
|
className="w-full"
|
|
497
514
|
defaultValue="view-details"
|
|
515
|
+
onValueChange={value => {
|
|
516
|
+
if (value) {
|
|
517
|
+
trackClick(CLICK_SUBTYPE.EXPAND_DETAILS, productRef);
|
|
518
|
+
}
|
|
519
|
+
}}
|
|
498
520
|
>
|
|
499
521
|
<AccordionItem value="view-details">
|
|
500
522
|
<AccordionTrigger className="w-full button-hover bg-[#F3F3F5] text-[#2b2c46] flex justify-between mt-3 px-4 text-base normal-case">
|
|
@@ -9,13 +9,16 @@ function ProductDetailViewModal({
|
|
|
9
9
|
handlerFeedback,
|
|
10
10
|
onSearchImage,
|
|
11
11
|
onAddToCart,
|
|
12
|
+
indexItem,
|
|
12
13
|
}: {
|
|
13
14
|
openDetailedView: '3d' | 'image' | undefined;
|
|
14
15
|
setOpenDetailedView: (value: '3d' | 'image' | undefined) => void;
|
|
15
16
|
dataItem: any;
|
|
16
17
|
handlerFeedback: (value: string) => void;
|
|
17
18
|
onSearchImage: (url: string) => void;
|
|
18
|
-
onAddToCart: (item: any) => void;
|
|
19
|
+
onAddToCart: (item: any, position?: number) => void;
|
|
20
|
+
/** Zero-based position of the product in the rendered result list. */
|
|
21
|
+
indexItem?: number;
|
|
19
22
|
}) {
|
|
20
23
|
useEffect(() => {
|
|
21
24
|
if (openDetailedView === '3d' || openDetailedView === 'image') {
|
|
@@ -64,6 +67,7 @@ function ProductDetailViewModal({
|
|
|
64
67
|
onSearchImage(url);
|
|
65
68
|
}}
|
|
66
69
|
onAddToCart={onAddToCart}
|
|
70
|
+
indexItem={indexItem}
|
|
67
71
|
/>
|
|
68
72
|
</DialogContent>
|
|
69
73
|
</Dialog>
|
|
@@ -4,6 +4,7 @@ import Product from './Product';
|
|
|
4
4
|
import { useImageSearch } from 'hooks/useImageSearch';
|
|
5
5
|
import useRequestStore from 'stores/request/requestStore';
|
|
6
6
|
import useUiStore from 'stores/ui/uiStore';
|
|
7
|
+
import useScopeStore from 'stores/scope/scopeStore';
|
|
7
8
|
import { useTranslation } from 'react-i18next';
|
|
8
9
|
import { twMerge } from 'tailwind-merge';
|
|
9
10
|
import { filterProducts } from 'utils/specificationFilter';
|
|
@@ -12,9 +13,13 @@ import { useEffectiveGroundingResults } from 'hooks/useEffectiveGroundingResults
|
|
|
12
13
|
|
|
13
14
|
interface Props {
|
|
14
15
|
sendFeedBackAction?: any;
|
|
16
|
+
onRenderedCountChange?: (count: number) => void;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
function ProductList({
|
|
19
|
+
function ProductList({
|
|
20
|
+
sendFeedBackAction,
|
|
21
|
+
onRenderedCountChange,
|
|
22
|
+
}: Props): JSX.Element {
|
|
18
23
|
const settings = window.settings;
|
|
19
24
|
const { singleImageSearch } = useImageSearch();
|
|
20
25
|
const { t } = useTranslation();
|
|
@@ -49,7 +54,15 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
49
54
|
const postFilterSelections = useRequestStore(
|
|
50
55
|
state => state.postFilterSelections,
|
|
51
56
|
);
|
|
52
|
-
|
|
57
|
+
const useApiPostFilters =
|
|
58
|
+
!settings.algolia?.enabled && settings.postFilterUseApi === true;
|
|
59
|
+
|
|
60
|
+
const scopeId = useScopeStore(state => state.scopeId);
|
|
61
|
+
const scopeItemKeyCount = useScopeStore(state => state.itemKeys.length);
|
|
62
|
+
const hasMachineScope =
|
|
63
|
+
Boolean(window.settings.scopes?.scopeID) &&
|
|
64
|
+
Boolean(scopeId) &&
|
|
65
|
+
scopeItemKeyCount > 0;
|
|
53
66
|
const textFilteredProducts = useMemo(() => {
|
|
54
67
|
if (!requestImages?.length) {
|
|
55
68
|
return productsFromFindApi;
|
|
@@ -63,7 +76,7 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
63
76
|
}, [productsFromFindApi, query, requestImages]);
|
|
64
77
|
|
|
65
78
|
const postFilteredProducts = useMemo(() => {
|
|
66
|
-
if (
|
|
79
|
+
if (useApiPostFilters) {
|
|
67
80
|
return textFilteredProducts;
|
|
68
81
|
}
|
|
69
82
|
|
|
@@ -87,7 +100,7 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
87
100
|
return selectedValues.some(value => productValues.includes(value));
|
|
88
101
|
});
|
|
89
102
|
});
|
|
90
|
-
}, [postFilterSelections, textFilteredProducts]);
|
|
103
|
+
}, [postFilterSelections, textFilteredProducts, useApiPostFilters]);
|
|
91
104
|
|
|
92
105
|
const getUrlToCanvasFile = async (url: string) => {
|
|
93
106
|
setQuery('');
|
|
@@ -97,6 +110,7 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
97
110
|
image: url,
|
|
98
111
|
settings,
|
|
99
112
|
showFeedback: true,
|
|
113
|
+
newSearch: true,
|
|
100
114
|
compress: false,
|
|
101
115
|
clearPostFilter: true,
|
|
102
116
|
}).then(() => {});
|
|
@@ -107,14 +121,18 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
107
121
|
const filter = Object.values(specificationFilter || {})[0];
|
|
108
122
|
const baseFindApiProducts = postFilteredProducts;
|
|
109
123
|
|
|
124
|
+
const resultSource = hasMachineScope
|
|
125
|
+
? baseFindApiProducts
|
|
126
|
+
: isAlgoliaEnabled
|
|
127
|
+
? productsFromAlgolia
|
|
128
|
+
: baseFindApiProducts;
|
|
129
|
+
|
|
110
130
|
if (filter) {
|
|
111
|
-
return filterProducts(
|
|
112
|
-
filter,
|
|
113
|
-
isAlgoliaEnabled ? productsFromAlgolia : baseFindApiProducts,
|
|
114
|
-
);
|
|
131
|
+
return filterProducts(filter, resultSource);
|
|
115
132
|
}
|
|
116
133
|
|
|
117
|
-
|
|
134
|
+
// Scoped results always come from Find API. Algolia cannot apply a machine scope.
|
|
135
|
+
if (hasMachineScope || !isAlgoliaEnabled) {
|
|
118
136
|
return baseFindApiProducts;
|
|
119
137
|
}
|
|
120
138
|
|
|
@@ -129,6 +147,7 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
129
147
|
isAlgoliaLoading,
|
|
130
148
|
query,
|
|
131
149
|
postFilteredProducts,
|
|
150
|
+
hasMachineScope,
|
|
132
151
|
]);
|
|
133
152
|
|
|
134
153
|
useEffect(() => {
|
|
@@ -150,14 +169,24 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
150
169
|
return products;
|
|
151
170
|
}, [effectiveGroundingResults, products]);
|
|
152
171
|
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
groundedFilteredProducts &&
|
|
172
|
+
const productsToRender: any[] = useMemo(() => {
|
|
173
|
+
return groundedFilteredProducts &&
|
|
156
174
|
groundedFilteredProducts.length > 0 &&
|
|
157
175
|
showingGroundingFilterResult
|
|
158
|
-
|
|
159
|
-
|
|
176
|
+
? groundedFilteredProducts
|
|
177
|
+
: products;
|
|
178
|
+
}, [groundedFilteredProducts, showingGroundingFilterResult, products]);
|
|
160
179
|
|
|
180
|
+
const isZeroState =
|
|
181
|
+
products?.length === 0 && !isAlgoliaLoading && !isFindApiLoading;
|
|
182
|
+
|
|
183
|
+
const actualRenderedCount = isZeroState ? 0 : productsToRender.length;
|
|
184
|
+
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
onRenderedCountChange?.(actualRenderedCount);
|
|
187
|
+
}, [actualRenderedCount, onRenderedCountChange]);
|
|
188
|
+
|
|
189
|
+
const renderItem = useMemo(() => {
|
|
161
190
|
return (
|
|
162
191
|
<div className={twMerge(['contents'])}>
|
|
163
192
|
{productsToRender?.map((product: any, i: number) => {
|
|
@@ -202,6 +231,7 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
202
231
|
groundedFilteredProducts,
|
|
203
232
|
showingGroundingFilterResult,
|
|
204
233
|
isAiModeOpen,
|
|
234
|
+
productsToRender,
|
|
205
235
|
]);
|
|
206
236
|
|
|
207
237
|
if (
|
|
@@ -209,7 +239,8 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
209
239
|
!isAlgoliaLoading &&
|
|
210
240
|
!isFindApiLoading &&
|
|
211
241
|
!query &&
|
|
212
|
-
!requestImages[0]
|
|
242
|
+
!requestImages[0] &&
|
|
243
|
+
!hasMachineScope
|
|
213
244
|
) {
|
|
214
245
|
return (
|
|
215
246
|
<div className="flex justify-center items-center h-full col-span-full">
|
|
@@ -220,7 +251,11 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
220
251
|
);
|
|
221
252
|
}
|
|
222
253
|
|
|
223
|
-
if (
|
|
254
|
+
if (
|
|
255
|
+
products?.length === 0 &&
|
|
256
|
+
!isAlgoliaLoading &&
|
|
257
|
+
!isFindApiLoading
|
|
258
|
+
) {
|
|
224
259
|
return (
|
|
225
260
|
<div className="flex justify-center items-center h-full col-span-full">
|
|
226
261
|
<div className="text-center text-[#AAABB5]">
|
|
@@ -9,6 +9,8 @@ import { Dialog, DialogContent } from 'components/Modal/Dialog';
|
|
|
9
9
|
import { getCroppedCanvas } from 'utils/misc';
|
|
10
10
|
import { ToastHelper } from 'helpers/ToastHelper';
|
|
11
11
|
import useRequestStore from 'stores/request/requestStore';
|
|
12
|
+
import { trackClick } from 'services/Feedback';
|
|
13
|
+
import { CLICK_SUBTYPE } from 'services/feedbackSubtypes';
|
|
12
14
|
|
|
13
15
|
import { useTranslation } from 'react-i18next';
|
|
14
16
|
interface Props {
|
|
@@ -77,6 +79,7 @@ export default function RfqModal({
|
|
|
77
79
|
});
|
|
78
80
|
setRfqStatus('sent');
|
|
79
81
|
ToastHelper.success(t('Request sent successfully'));
|
|
82
|
+
trackClick(CLICK_SUBTYPE.RAISE_INQUIRY);
|
|
80
83
|
} catch (error) {
|
|
81
84
|
setRfqStatus('inactive');
|
|
82
85
|
|