@nyris/nyris-webapp 0.3.98 → 0.4.0
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 +42 -0
- package/build/static/css/main.a7ff7a7f.css +4 -0
- package/build/static/css/main.a7ff7a7f.css.map +1 -0
- package/build/static/js/main.916c157c.js +3 -0
- package/build/static/js/{main.93fdbd6e.js.map → main.916c157c.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 +42 -0
- package/src/common/assets/images/plate_info.png +0 -0
- package/src/components/Cart.tsx +41 -0
- package/src/components/ChatAssistant/ChatAssistant.test.tsx +213 -0
- package/src/components/ChatAssistant/ChatAssistant.tsx +18 -1
- package/src/components/ChatAssistant/MobileChatAssistant.tsx +18 -1
- package/src/components/ChatAssistant/OptionChip.tsx +23 -1
- package/src/components/ChatAssistant/useChatAssistantLogic.ts +35 -14
- 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 +12 -1
- package/src/components/Inquiry/InquiryModal.tsx +61 -26
- package/src/components/Pagination.tsx +33 -6
- package/src/components/PostFilter/PostFilter.tsx +8 -1
- 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 -18
- 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 +33 -0
- package/src/components/TextSearch.tsx +77 -11
- package/src/components/Tooltip/TooltipComponent.tsx +12 -4
- package/src/components/TypePlateUpload.tsx +132 -0
- package/src/hooks/chatProductMetadata.test.ts +307 -0
- package/src/hooks/useBadResultsRecovery.ts +26 -49
- package/src/hooks/useEffectiveGroundingResults.ts +8 -6
- package/src/hooks/useGoodResultsChat.ts +28 -39
- package/src/hooks/useImageSearch.ts +290 -12
- package/src/hooks/useMachinePartsListingPagination.ts +95 -0
- package/src/hooks/useResultEvaluator.ts +63 -73
- package/src/index.css +1 -1
- package/src/layouts/AppLayout.tsx +43 -3
- package/src/pages/Home.tsx +60 -14
- package/src/pages/Result.tsx +194 -14
- package/src/services/Feedback.ts +225 -34
- package/src/services/feedbackSubtypes.ts +63 -0
- package/src/services/filter.ts +1 -1
- 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 +71 -3
- package/src/services/vizo.ts +4 -3
- package/src/stores/chat/conversationStore.test.ts +133 -0
- package/src/stores/chat/conversationStore.ts +55 -14
- 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 +41 -0
- package/src/utils/chatProductMetadata.test.ts +130 -0
- package/src/utils/chatProductMetadata.ts +93 -0
- package/src/utils/compressImage.ts +3 -3
- package/src/utils/fetchProductImage.ts +1 -0
- package/src/utils/normalizeChatAssistantResponse.ts +227 -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.81216c5d.css +0 -4
- package/build/static/css/main.81216c5d.css.map +0 -1
- package/build/static/js/main.93fdbd6e.js +0 -3
- /package/build/static/js/{main.93fdbd6e.js.LICENSE.txt → main.916c157c.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,8 +76,7 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
63
76
|
}, [productsFromFindApi, query, requestImages]);
|
|
64
77
|
|
|
65
78
|
const postFilteredProducts = useMemo(() => {
|
|
66
|
-
|
|
67
|
-
if (!window.settings.algolia?.enabled && window.settings.postFilterOption) {
|
|
79
|
+
if (useApiPostFilters) {
|
|
68
80
|
return textFilteredProducts;
|
|
69
81
|
}
|
|
70
82
|
|
|
@@ -88,7 +100,7 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
88
100
|
return selectedValues.some(value => productValues.includes(value));
|
|
89
101
|
});
|
|
90
102
|
});
|
|
91
|
-
}, [postFilterSelections, textFilteredProducts]);
|
|
103
|
+
}, [postFilterSelections, textFilteredProducts, useApiPostFilters]);
|
|
92
104
|
|
|
93
105
|
const getUrlToCanvasFile = async (url: string) => {
|
|
94
106
|
setQuery('');
|
|
@@ -98,6 +110,7 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
98
110
|
image: url,
|
|
99
111
|
settings,
|
|
100
112
|
showFeedback: true,
|
|
113
|
+
newSearch: true,
|
|
101
114
|
compress: false,
|
|
102
115
|
clearPostFilter: true,
|
|
103
116
|
}).then(() => {});
|
|
@@ -108,15 +121,18 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
108
121
|
const filter = Object.values(specificationFilter || {})[0];
|
|
109
122
|
const baseFindApiProducts = postFilteredProducts;
|
|
110
123
|
|
|
124
|
+
const resultSource = hasMachineScope
|
|
125
|
+
? baseFindApiProducts
|
|
126
|
+
: isAlgoliaEnabled
|
|
127
|
+
? productsFromAlgolia
|
|
128
|
+
: baseFindApiProducts;
|
|
129
|
+
|
|
111
130
|
if (filter) {
|
|
112
|
-
return filterProducts(
|
|
113
|
-
filter,
|
|
114
|
-
isAlgoliaEnabled ? productsFromAlgolia : baseFindApiProducts,
|
|
115
|
-
);
|
|
131
|
+
return filterProducts(filter, resultSource);
|
|
116
132
|
}
|
|
117
133
|
|
|
118
|
-
//
|
|
119
|
-
if (!isAlgoliaEnabled) {
|
|
134
|
+
// Scoped results always come from Find API. Algolia cannot apply a machine scope.
|
|
135
|
+
if (hasMachineScope || !isAlgoliaEnabled) {
|
|
120
136
|
return baseFindApiProducts;
|
|
121
137
|
}
|
|
122
138
|
|
|
@@ -131,6 +147,7 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
131
147
|
isAlgoliaLoading,
|
|
132
148
|
query,
|
|
133
149
|
postFilteredProducts,
|
|
150
|
+
hasMachineScope,
|
|
134
151
|
]);
|
|
135
152
|
|
|
136
153
|
useEffect(() => {
|
|
@@ -152,14 +169,24 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
152
169
|
return products;
|
|
153
170
|
}, [effectiveGroundingResults, products]);
|
|
154
171
|
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
groundedFilteredProducts &&
|
|
172
|
+
const productsToRender: any[] = useMemo(() => {
|
|
173
|
+
return groundedFilteredProducts &&
|
|
158
174
|
groundedFilteredProducts.length > 0 &&
|
|
159
175
|
showingGroundingFilterResult
|
|
160
|
-
|
|
161
|
-
|
|
176
|
+
? groundedFilteredProducts
|
|
177
|
+
: products;
|
|
178
|
+
}, [groundedFilteredProducts, showingGroundingFilterResult, products]);
|
|
162
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(() => {
|
|
163
190
|
return (
|
|
164
191
|
<div className={twMerge(['contents'])}>
|
|
165
192
|
{productsToRender?.map((product: any, i: number) => {
|
|
@@ -204,6 +231,7 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
204
231
|
groundedFilteredProducts,
|
|
205
232
|
showingGroundingFilterResult,
|
|
206
233
|
isAiModeOpen,
|
|
234
|
+
productsToRender,
|
|
207
235
|
]);
|
|
208
236
|
|
|
209
237
|
if (
|
|
@@ -211,7 +239,8 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
211
239
|
!isAlgoliaLoading &&
|
|
212
240
|
!isFindApiLoading &&
|
|
213
241
|
!query &&
|
|
214
|
-
!requestImages[0]
|
|
242
|
+
!requestImages[0] &&
|
|
243
|
+
!hasMachineScope
|
|
215
244
|
) {
|
|
216
245
|
return (
|
|
217
246
|
<div className="flex justify-center items-center h-full col-span-full">
|
|
@@ -222,7 +251,11 @@ function ProductList({ sendFeedBackAction }: Props): JSX.Element {
|
|
|
222
251
|
);
|
|
223
252
|
}
|
|
224
253
|
|
|
225
|
-
if (
|
|
254
|
+
if (
|
|
255
|
+
products?.length === 0 &&
|
|
256
|
+
!isAlgoliaLoading &&
|
|
257
|
+
!isFindApiLoading
|
|
258
|
+
) {
|
|
226
259
|
return (
|
|
227
260
|
<div className="flex justify-center items-center h-full col-span-full">
|
|
228
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
|
|