@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
|
@@ -14,6 +14,11 @@ import useConversationStore, {
|
|
|
14
14
|
} from 'stores/chat/conversationStore';
|
|
15
15
|
import useSmartFiltersStore from 'stores/smartFilters/smartFiltersStore';
|
|
16
16
|
import { chatAnalysis } from 'services/vizo';
|
|
17
|
+
import {
|
|
18
|
+
getChatAttributeFrequency,
|
|
19
|
+
getChatProductAttributes,
|
|
20
|
+
getChatProductMetadata,
|
|
21
|
+
} from 'utils/chatProductMetadata';
|
|
17
22
|
import useRequestStore from 'stores/request/requestStore';
|
|
18
23
|
import { canvasToBase64, cropImage } from 'utils/cropImageToBase64';
|
|
19
24
|
import {
|
|
@@ -47,10 +52,18 @@ export function useResultEvaluator() {
|
|
|
47
52
|
async ({
|
|
48
53
|
imageAnalysis,
|
|
49
54
|
activeProducts,
|
|
55
|
+
query,
|
|
50
56
|
}: {
|
|
51
57
|
imageAnalysis: any;
|
|
52
58
|
activeProducts: any[];
|
|
59
|
+
query: string;
|
|
53
60
|
}) => {
|
|
61
|
+
// Bind this run to the current session; a newer search calls
|
|
62
|
+
// startNewSession, which makes any in-flight evaluation stale.
|
|
63
|
+
const runSessionId = useConversationStore.getState().sessionId;
|
|
64
|
+
const isStale = () =>
|
|
65
|
+
useConversationStore.getState().sessionId !== runSessionId;
|
|
66
|
+
|
|
54
67
|
setIsLoading(true);
|
|
55
68
|
setError(null);
|
|
56
69
|
setRelatedPartsTableSuggestions([]);
|
|
@@ -66,29 +79,8 @@ export function useResultEvaluator() {
|
|
|
66
79
|
const resultsSummary = activeProducts
|
|
67
80
|
.slice(0, 30)
|
|
68
81
|
.map((p: any, i: number) => {
|
|
69
|
-
|
|
70
|
-
const metadata
|
|
71
|
-
const metadataFields = [
|
|
72
|
-
'voltage',
|
|
73
|
-
'size',
|
|
74
|
-
'brand',
|
|
75
|
-
'manufacturer',
|
|
76
|
-
'material',
|
|
77
|
-
'type',
|
|
78
|
-
'category',
|
|
79
|
-
'color',
|
|
80
|
-
'dimensions',
|
|
81
|
-
'power',
|
|
82
|
-
'current',
|
|
83
|
-
'connector',
|
|
84
|
-
'model',
|
|
85
|
-
'series',
|
|
86
|
-
'product_line',
|
|
87
|
-
];
|
|
88
|
-
|
|
89
|
-
metadataFields.forEach(field => {
|
|
90
|
-
if (p[field]) metadata[field] = p[field];
|
|
91
|
-
});
|
|
82
|
+
const fullMetadata = getChatProductMetadata(p);
|
|
83
|
+
const metadata = getChatProductAttributes(fullMetadata);
|
|
92
84
|
|
|
93
85
|
// Extract from title/description using common patterns
|
|
94
86
|
const title = p.title || p.name || '';
|
|
@@ -173,11 +165,8 @@ export function useResultEvaluator() {
|
|
|
173
165
|
|
|
174
166
|
return {
|
|
175
167
|
rank: i + 1,
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
category: p.category || p.type || 'Unknown',
|
|
179
|
-
score: p.score || p.similarity || 0,
|
|
180
|
-
metadata: Object.keys(metadata).length > 0 ? metadata : null,
|
|
168
|
+
metadata: fullMetadata,
|
|
169
|
+
attributes: metadata,
|
|
181
170
|
};
|
|
182
171
|
});
|
|
183
172
|
|
|
@@ -195,39 +184,37 @@ export function useResultEvaluator() {
|
|
|
195
184
|
});
|
|
196
185
|
|
|
197
186
|
// Analyze common attributes across results for filter suggestions
|
|
198
|
-
const attributeFrequency
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
187
|
+
const attributeFrequency = getChatAttributeFrequency(
|
|
188
|
+
resultsSummary.map(result => ({ metadata: result.attributes })),
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const requestImage = useRequestStore.getState().requestImages;
|
|
192
|
+
const regions = useRequestStore.getState().regions;
|
|
193
|
+
const hasRequestImage = requestImage && requestImage[0];
|
|
194
|
+
|
|
195
|
+
const evaluationTarget = hasRequestImage
|
|
196
|
+
? 'the image'
|
|
197
|
+
: 'the user query (keyword input)';
|
|
209
198
|
|
|
210
199
|
const userPrompt = `Evaluate these search results:
|
|
211
200
|
|
|
212
|
-
|
|
201
|
+
user query: ${query || 'N/A'}
|
|
202
|
+
|
|
203
|
+
IMAGE DESCRIPTION: ${hasRequestImage ? imageDescription : 'N/A'}
|
|
213
204
|
|
|
214
205
|
SPECIFICATION (from image analysis):
|
|
215
|
-
${JSON.stringify(p4Specification, null, 2)}
|
|
206
|
+
${hasRequestImage ? JSON.stringify(p4Specification, null, 2) : 'N/A'}
|
|
216
207
|
|
|
217
|
-
TOP 20 RESULTS WITH METADATA:
|
|
218
|
-
${resultsSummary
|
|
219
|
-
.map(
|
|
220
|
-
r =>
|
|
221
|
-
`${r.rank}. ${r.title}${r.description ? ` - ${r.description}` : ''} (Score: ${r.score})${r.metadata ? `\n Metadata: ${JSON.stringify(r.metadata)}` : ''}`,
|
|
222
|
-
)
|
|
223
|
-
.join('\n')}
|
|
224
208
|
|
|
225
209
|
COMMON ATTRIBUTES FOUND IN RESULTS (for filter suggestions):
|
|
226
210
|
${JSON.stringify(attributeFrequency, null, 2)}
|
|
227
211
|
|
|
228
212
|
TOTAL RESULTS: ${resultsSummary.length}
|
|
229
213
|
|
|
230
|
-
Evaluate if these results match
|
|
214
|
+
Evaluate if these results match ${evaluationTarget}. If they do (same type of product), route to P3 and suggest filter options based on the COMMON ATTRIBUTES found above (like voltage, size, brand). Do NOT suggest the obvious category match.
|
|
215
|
+
|
|
216
|
+
${hasRequestImage ? 'The request image is available, use it for evaluation.' : 'The request image is not available, rely solely on the user query for evaluation. Rest of the image information is only result/response images.'}.
|
|
217
|
+
`;
|
|
231
218
|
|
|
232
219
|
const productsForImages = activeProducts.slice(0, 30);
|
|
233
220
|
const imageResults = await Promise.all(
|
|
@@ -250,14 +237,9 @@ Evaluate if these results match the image. If they do (same type of product), ro
|
|
|
250
237
|
mimeType?: string;
|
|
251
238
|
}> = [];
|
|
252
239
|
|
|
253
|
-
resultsSummary.forEach((
|
|
254
|
-
const
|
|
255
|
-
const
|
|
256
|
-
const tagStr = tags
|
|
257
|
-
? ` | TAGS: type=${tags.productType}, color=${tags.color}, shape=${tags.shape}, material=${tags.material}`
|
|
258
|
-
: '';
|
|
259
|
-
|
|
260
|
-
const metaLine = `${result.rank}. ${result.title}${result.description ? ` - ${result.description}` : ''} (Score: ${result.score})${result.metadata ? ` | Metadata: ${JSON.stringify(result.metadata)}` : ''}${tagStr}`;
|
|
240
|
+
resultsSummary.forEach(({ rank, metadata }, i) => {
|
|
241
|
+
const result = { rank, metadata };
|
|
242
|
+
const metaLine = `${JSON.stringify(getChatProductMetadata(result))}. Result_images.`;
|
|
261
243
|
|
|
262
244
|
if (hasVisualContext && imageResults[i]?.base64) {
|
|
263
245
|
productImageParts.push({
|
|
@@ -265,27 +247,32 @@ Evaluate if these results match the image. If they do (same type of product), ro
|
|
|
265
247
|
image: imageResults[i].base64 || '',
|
|
266
248
|
mimeType: 'image/jpeg',
|
|
267
249
|
});
|
|
250
|
+
} else {
|
|
251
|
+
productImageParts.push({ metadata: metaLine });
|
|
268
252
|
}
|
|
269
253
|
});
|
|
270
254
|
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
255
|
+
const multimodalInputs: any[] = [
|
|
256
|
+
{
|
|
257
|
+
metadata: userPrompt,
|
|
258
|
+
},
|
|
259
|
+
];
|
|
260
|
+
|
|
261
|
+
if (hasRequestImage) {
|
|
262
|
+
const croppedCanvas = cropImage(requestImage[0], regions[0]);
|
|
263
|
+
const base64Image = canvasToBase64(croppedCanvas, 'image/jpeg', 1);
|
|
264
|
+
multimodalInputs.push({
|
|
265
|
+
metadata: 'request_image',
|
|
266
|
+
mimeType: 'image/jpeg',
|
|
267
|
+
image: base64Image,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
multimodalInputs.push(...productImageParts);
|
|
275
272
|
|
|
276
273
|
const response = await chatAnalysis({
|
|
277
274
|
promptKey: 'result_evaluator_prompt',
|
|
278
|
-
multimodalInputs
|
|
279
|
-
{
|
|
280
|
-
metadata: userPrompt,
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
metadata: 'request_image',
|
|
284
|
-
mimeType: 'image/jpeg',
|
|
285
|
-
image: base64Image,
|
|
286
|
-
},
|
|
287
|
-
...productImageParts,
|
|
288
|
-
],
|
|
275
|
+
multimodalInputs,
|
|
289
276
|
});
|
|
290
277
|
|
|
291
278
|
const evaluation: P2EvaluationResult = response;
|
|
@@ -315,6 +302,8 @@ Evaluate if these results match the image. If they do (same type of product), ro
|
|
|
315
302
|
// Check lookup table for related parts on fresh image searches and store globally.
|
|
316
303
|
const table = await loadRelatedPartsTable();
|
|
317
304
|
|
|
305
|
+
if (isStale()) return;
|
|
306
|
+
|
|
318
307
|
const tableSuggestions = lookupRelatedParts(
|
|
319
308
|
table,
|
|
320
309
|
imageAnalysis?.specification?.product_category || '',
|
|
@@ -371,6 +360,7 @@ Evaluate if these results match the image. If they do (same type of product), ro
|
|
|
371
360
|
);
|
|
372
361
|
} catch (err: any) {
|
|
373
362
|
console.error('result_evaluator_prompt', err);
|
|
363
|
+
if (isStale()) return;
|
|
374
364
|
setRelatedPartsTableSuggestions([]);
|
|
375
365
|
setError(err.message || 'Failed to evaluate results');
|
|
376
366
|
|
|
@@ -390,7 +380,7 @@ Evaluate if these results match the image. If they do (same type of product), ro
|
|
|
390
380
|
],
|
|
391
381
|
);
|
|
392
382
|
} finally {
|
|
393
|
-
setIsLoading(false);
|
|
383
|
+
if (!isStale()) setIsLoading(false);
|
|
394
384
|
}
|
|
395
385
|
},
|
|
396
386
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
package/src/index.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { memo, useCallback, useEffect, useMemo } from 'react';
|
|
1
|
+
import { memo, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
import { Outlet, useLocation } from 'react-router';
|
|
3
3
|
|
|
4
4
|
import { useAuth0 } from '@auth0/auth0-react';
|
|
@@ -27,7 +27,9 @@ import {
|
|
|
27
27
|
isNyrisApiKeyReady,
|
|
28
28
|
useAuthApiKeyStore,
|
|
29
29
|
} from 'utils/nyrisApiKey';
|
|
30
|
-
import useScopeStore from 'stores/scope/scopeStore';
|
|
30
|
+
import useScopeStore, { hasActiveMachineScope } from 'stores/scope/scopeStore';
|
|
31
|
+
import useConversationStore from 'stores/chat/conversationStore';
|
|
32
|
+
import { useResultEvaluator } from 'hooks/useResultEvaluator';
|
|
31
33
|
|
|
32
34
|
i18n.use(initReactI18next).init({
|
|
33
35
|
resources: translations,
|
|
@@ -66,9 +68,13 @@ function AppLayout(): JSX.Element {
|
|
|
66
68
|
const requestImages = useRequestStore(state => state.requestImages);
|
|
67
69
|
const showLoading = useRequestStore(state => state.showLoading);
|
|
68
70
|
|
|
69
|
-
const { status } = useInstantSearch();
|
|
71
|
+
const { status, results } = useInstantSearch();
|
|
70
72
|
const { items } = useHits();
|
|
71
73
|
|
|
74
|
+
const isAiModeOpen = useUiStore(state => state.isAiModeOpen);
|
|
75
|
+
const { evaluateResults } = useResultEvaluator();
|
|
76
|
+
const lastAlgoliaEvaluationRef = useRef<string | null>(null);
|
|
77
|
+
|
|
72
78
|
useEffect(() => {
|
|
73
79
|
i18n.changeLanguage(window.settings.language);
|
|
74
80
|
console.log('App version:', packageJson.version);
|
|
@@ -97,6 +103,40 @@ function AppLayout(): JSX.Element {
|
|
|
97
103
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
98
104
|
}, [items, scopeItemKeys]);
|
|
99
105
|
|
|
106
|
+
// Algolia text search never goes through singleImageSearch, so run P2 here
|
|
107
|
+
// on the Algolia hits once AI mode is open for the current query.
|
|
108
|
+
// Deliberately not keyed on the conversation session: singleImageSearch
|
|
109
|
+
// calls startNewSession before requestImages is set, and re-running on that
|
|
110
|
+
// session change would start a competing evaluation of stale Algolia hits.
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (requestImages.length > 0 || hasActiveMachineScope()) {
|
|
113
|
+
// An image search or machine scope owns P2. Algolia hits are unscoped.
|
|
114
|
+
lastAlgoliaEvaluationRef.current = null;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (
|
|
119
|
+
!window.settings.algolia?.enabled ||
|
|
120
|
+
!window.settings.vizo?.chat ||
|
|
121
|
+
!isAiModeOpen ||
|
|
122
|
+
isFindApiLoading ||
|
|
123
|
+
!query ||
|
|
124
|
+
status !== 'idle' ||
|
|
125
|
+
results?.query !== query
|
|
126
|
+
) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (lastAlgoliaEvaluationRef.current === query) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
useConversationStore.getState().startNewSession();
|
|
135
|
+
lastAlgoliaEvaluationRef.current = query;
|
|
136
|
+
evaluateResults({ activeProducts: items, imageAnalysis: undefined, query });
|
|
137
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
138
|
+
}, [isAiModeOpen, isFindApiLoading, query, status, results, requestImages]);
|
|
139
|
+
|
|
100
140
|
useEffect(() => {
|
|
101
141
|
if (status === 'loading' || status === 'stalled') {
|
|
102
142
|
setIsAlgoliaLoading(true);
|
package/src/pages/Home.tsx
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { ArrowRight } from 'lucide-react';
|
|
3
5
|
|
|
4
6
|
import DragDropFile from 'components/DragDropFile';
|
|
5
7
|
import MobileCameraCTA from 'components/MobileCameraCTA';
|
|
@@ -15,6 +17,7 @@ import ImageUpload from 'components/ImageUpload';
|
|
|
15
17
|
|
|
16
18
|
function Home() {
|
|
17
19
|
const settings = window.settings;
|
|
20
|
+
const { t } = useTranslation();
|
|
18
21
|
const { experienceVisualSearch, experienceVisualSearchImages, geoLocation } =
|
|
19
22
|
settings;
|
|
20
23
|
const navigate = useNavigate();
|
|
@@ -88,32 +91,75 @@ function Home() {
|
|
|
88
91
|
])}
|
|
89
92
|
>
|
|
90
93
|
{geoLocation && <LocationInfoPopup />}
|
|
91
|
-
<div className="relative flex
|
|
94
|
+
<div className="relative flex w-full flex-col items-center gap-6">
|
|
92
95
|
{settings.headerText && (
|
|
93
96
|
<div
|
|
94
97
|
className={twMerge([
|
|
95
98
|
'absolute',
|
|
96
|
-
'bottom-
|
|
99
|
+
'bottom-full',
|
|
100
|
+
'mb-[25px]',
|
|
101
|
+
'flex',
|
|
102
|
+
'flex-col',
|
|
103
|
+
'items-center',
|
|
104
|
+
'gap-3',
|
|
97
105
|
'text-primary',
|
|
98
106
|
'font-bold',
|
|
99
107
|
])}
|
|
100
108
|
>
|
|
101
|
-
<h1 className="text-[25px]">{settings.headerText}</h1>
|
|
109
|
+
<h1 className="text-[25px] m-0 mb-0">{settings.headerText}</h1>
|
|
110
|
+
{settings.scopes?.scopeID &&
|
|
111
|
+
Boolean(settings.scopes?.typePlateStepOne?.trim()) &&
|
|
112
|
+
Boolean(settings.scopes?.typePlateStepTwo?.trim()) && (
|
|
113
|
+
<div
|
|
114
|
+
className="flex w-full items-center justify-center"
|
|
115
|
+
aria-label="Search flow"
|
|
116
|
+
>
|
|
117
|
+
<div className="flex items-center gap-1.5 shrink-0">
|
|
118
|
+
<span className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-[#F3F4F8] border border-solid border-[#2B2C46] text-[#2B2C46] font-bold text-xs leading-none">
|
|
119
|
+
1
|
|
120
|
+
</span>
|
|
121
|
+
<span className="font-semibold text-[14px] leading-none text-[#2B2C46] whitespace-nowrap">
|
|
122
|
+
{t(settings.scopes!.typePlateStepOne!)}
|
|
123
|
+
</span>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div
|
|
127
|
+
className="flex items-center flex-1 min-w-[20px] max-w-[60px] mx-2.5"
|
|
128
|
+
aria-hidden="true"
|
|
129
|
+
>
|
|
130
|
+
<div className="h-[1.5px] flex-1 bg-[#2B2C46]" />
|
|
131
|
+
<ArrowRight
|
|
132
|
+
className="h-3.5 w-3.5 -ml-1 text-[#2B2C46] shrink-0"
|
|
133
|
+
strokeWidth={2}
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<div className="flex items-center gap-1.5 shrink-0">
|
|
138
|
+
<span className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-[#2B2C46] text-white font-bold text-xs leading-none">
|
|
139
|
+
2
|
|
140
|
+
</span>
|
|
141
|
+
<span className="font-semibold text-[14px] leading-none text-[#2B2C46] whitespace-nowrap">
|
|
142
|
+
{t(settings.scopes!.typePlateStepTwo!)}
|
|
143
|
+
</span>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
)}
|
|
102
147
|
</div>
|
|
103
148
|
)}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
149
|
+
<div className="flex items-center justify-center w-full gap-2">
|
|
150
|
+
<TextSearch className="h-[56px]" showImageUpload={false} />
|
|
151
|
+
<div
|
|
152
|
+
className={twMerge(
|
|
153
|
+
'h-14 w-14 flex items-center justify-center rounded-full bg-[#FFFFFF] hover:bg-[#F3F4F8] border border-solid border-[#DDDEE7]',
|
|
154
|
+
'shadow-ds-2',
|
|
155
|
+
)}
|
|
156
|
+
>
|
|
157
|
+
<ImageUpload />
|
|
158
|
+
</div>
|
|
113
159
|
</div>
|
|
114
160
|
</div>
|
|
115
161
|
<div className="max-w-[532px] relative w-full">
|
|
116
|
-
<DragDropFile />
|
|
162
|
+
{!settings.scopes?.scopeID && <DragDropFile />}
|
|
117
163
|
{settings.experienceVisualSearch && (
|
|
118
164
|
<ExperienceVisualSearchTrigger
|
|
119
165
|
experienceVisualSearchBlobs={experienceVisualSearchBlobs}
|
|
@@ -148,7 +194,7 @@ function Home() {
|
|
|
148
194
|
/>
|
|
149
195
|
)}
|
|
150
196
|
|
|
151
|
-
<div className="flex desktop:hidden w-full fixed bottom-12 px-2 gap-
|
|
197
|
+
<div className="flex desktop:hidden w-full fixed bottom-12 px-2 flex-col gap-4">
|
|
152
198
|
<TextSearch className="flex md:hidden w-full " />
|
|
153
199
|
</div>
|
|
154
200
|
</div>
|