@nyris/nyris-webapp 0.3.65 → 0.3.67
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/index.html +1 -1
- package/build/static/css/main.05cedda2.css +4 -0
- package/build/static/css/main.05cedda2.css.map +1 -0
- package/build/static/js/main.6bc37b78.js +3 -0
- package/build/static/js/main.6bc37b78.js.map +1 -0
- package/package.json +3 -3
- package/src/Store/Store.ts +2 -1
- package/src/Store/constants.ts +1 -0
- package/src/components/DragDropFile.tsx +22 -5
- package/src/components/Experience-visual-search/ExperienceVisualSearch.tsx +43 -29
- package/src/components/ImagePreview.tsx +6 -2
- package/src/components/ProductList/index.tsx +13 -2
- package/src/components/UploadDisclaimer.tsx +4 -1
- package/src/components/drawer/cameraCustom.tsx +33 -17
- package/src/components/input/inputSearch.tsx +33 -14
- package/src/components/pre-filter/index.tsx +40 -1
- package/src/hooks/useCadSearch.ts +179 -0
- package/src/hooks/useImageSearch.ts +23 -9
- package/src/page/landingPage/Home.tsx +47 -4
- package/src/page/landingPage/HomeDesktop.tsx +12 -2
- package/src/page/landingPage/HomeMobile.tsx +12 -2
- package/src/page/result/index.tsx +7 -31
- package/src/services/image.ts +28 -0
- package/src/types.ts +25 -24
- package/src/utils.ts +23 -11
- package/.prettierrc +0 -7
- package/build/static/css/main.3a42f868.css +0 -4
- package/build/static/css/main.3a42f868.css.map +0 -1
- package/build/static/js/main.1bd28035.js +0 -3
- package/build/static/js/main.1bd28035.js.map +0 -1
- /package/build/static/js/{main.1bd28035.js.LICENSE.txt → main.6bc37b78.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { RectCoords } from '@nyris/nyris-api';
|
|
2
|
+
import { isEmpty } from 'lodash';
|
|
3
|
+
import { useCallback } from 'react';
|
|
4
|
+
import { findCad, findRegions, getRequestImage } from 'services/image';
|
|
5
|
+
import useRequestStore from 'Store/requestStore';
|
|
6
|
+
import useResultStore from 'Store/resultStore';
|
|
7
|
+
import {
|
|
8
|
+
setFirstSearchImage,
|
|
9
|
+
setFirstSearchPrefilters,
|
|
10
|
+
setFirstSearchResults,
|
|
11
|
+
setRegions,
|
|
12
|
+
setRequestImage,
|
|
13
|
+
setSearchResults,
|
|
14
|
+
setSelectedRegion,
|
|
15
|
+
setShowFeedback,
|
|
16
|
+
updateStatusLoading,
|
|
17
|
+
} from 'Store/search/Search';
|
|
18
|
+
import { useAppDispatch, useAppSelector } from 'Store/Store';
|
|
19
|
+
import { AppSettings } from 'types';
|
|
20
|
+
|
|
21
|
+
export const useCadSearch = () => {
|
|
22
|
+
const dispatch = useAppDispatch();
|
|
23
|
+
const preFilter = useAppSelector(state => state.search.preFilter);
|
|
24
|
+
|
|
25
|
+
const { setRequestImages, setImageRegions } = useRequestStore(state => ({
|
|
26
|
+
setRequestImages: state.setRequestImages,
|
|
27
|
+
setImageRegions: state.setRegions,
|
|
28
|
+
requestImages: state.requestImages,
|
|
29
|
+
regions: state.regions,
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const { setDetectedObject } = useResultStore(state => ({
|
|
33
|
+
setDetectedObject: state.setDetectedObject,
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
const cadSearch = useCallback(
|
|
37
|
+
async ({
|
|
38
|
+
file,
|
|
39
|
+
settings,
|
|
40
|
+
showFeedback = true,
|
|
41
|
+
imageRegion,
|
|
42
|
+
newSearch,
|
|
43
|
+
}: {
|
|
44
|
+
file: File;
|
|
45
|
+
settings: AppSettings;
|
|
46
|
+
showFeedback?: boolean;
|
|
47
|
+
imageRegion?: RectCoords;
|
|
48
|
+
newSearch?: boolean;
|
|
49
|
+
}) => {
|
|
50
|
+
let res: any;
|
|
51
|
+
|
|
52
|
+
const preFilterValues = [
|
|
53
|
+
{
|
|
54
|
+
key: settings.visualSearchFilterKey,
|
|
55
|
+
values: Object.keys(preFilter),
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
let filters: any[] = [];
|
|
59
|
+
// const canvas = document.createElement('canvas');
|
|
60
|
+
|
|
61
|
+
// dispatch(setRequestImage(file));
|
|
62
|
+
// setRequestImages([file as unknown as HTMLCanvasElement]);
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
res = await findCad({
|
|
66
|
+
file,
|
|
67
|
+
settings,
|
|
68
|
+
filters: !isEmpty(preFilter) ? preFilterValues : undefined,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
res?.responseBody?.results.forEach((item: any) => {
|
|
72
|
+
filters.push({
|
|
73
|
+
sku: item.sku,
|
|
74
|
+
score: item.score,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
const payload = {
|
|
78
|
+
...res?.responseBody,
|
|
79
|
+
filters,
|
|
80
|
+
};
|
|
81
|
+
dispatch(setSearchResults(payload));
|
|
82
|
+
|
|
83
|
+
const queryParams = res?.requestUrl.split('?')[1];
|
|
84
|
+
|
|
85
|
+
// Parse the query string
|
|
86
|
+
const params = new URLSearchParams(queryParams);
|
|
87
|
+
|
|
88
|
+
// Get the value of the 'img' parameter
|
|
89
|
+
const imgValue = params.get('img');
|
|
90
|
+
|
|
91
|
+
const image = await getRequestImage({
|
|
92
|
+
url: encodeURIComponent(imgValue || ''),
|
|
93
|
+
settings,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const blob: Blob = image.data;
|
|
97
|
+
|
|
98
|
+
blobToCanvas(blob)
|
|
99
|
+
.then(async canvas => {
|
|
100
|
+
dispatch(setRequestImage(canvas));
|
|
101
|
+
setRequestImages([canvas]);
|
|
102
|
+
dispatch(setFirstSearchImage(canvas));
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
let region: RectCoords | undefined = imageRegion;
|
|
106
|
+
|
|
107
|
+
let res = await findRegions(canvas, settings);
|
|
108
|
+
setDetectedObject(res.regions, 0);
|
|
109
|
+
dispatch(setRegions(res.regions));
|
|
110
|
+
region = res.selectedRegion;
|
|
111
|
+
dispatch(setSelectedRegion(region));
|
|
112
|
+
setImageRegions([region]);
|
|
113
|
+
} catch (error) {}
|
|
114
|
+
})
|
|
115
|
+
.catch(error => {
|
|
116
|
+
console.error('Error converting Blob to Canvas:', error);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
if (showFeedback) {
|
|
120
|
+
dispatch(setShowFeedback(true));
|
|
121
|
+
}
|
|
122
|
+
// go back
|
|
123
|
+
if (newSearch) {
|
|
124
|
+
dispatch(setFirstSearchResults(payload));
|
|
125
|
+
dispatch(setFirstSearchPrefilters(preFilter));
|
|
126
|
+
}
|
|
127
|
+
} catch (error) {
|
|
128
|
+
dispatch(updateStatusLoading(false));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return res?.responseBody;
|
|
132
|
+
},
|
|
133
|
+
[dispatch, preFilter, setDetectedObject, setImageRegions, setRequestImages],
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
return { cadSearch };
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
function blobToCanvas(blob: Blob): Promise<HTMLCanvasElement> {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
// Step 1: Create a new Image element
|
|
142
|
+
const img = new Image();
|
|
143
|
+
|
|
144
|
+
// Step 2: Create an Object URL from the Blob
|
|
145
|
+
const url = URL.createObjectURL(blob);
|
|
146
|
+
img.src = url;
|
|
147
|
+
|
|
148
|
+
// Step 3: Wait for the image to load
|
|
149
|
+
img.onload = () => {
|
|
150
|
+
// Step 4: Create a Canvas element
|
|
151
|
+
const canvas = document.createElement('canvas');
|
|
152
|
+
const ctx = canvas.getContext('2d');
|
|
153
|
+
|
|
154
|
+
if (!ctx) {
|
|
155
|
+
reject(new Error('Failed to get canvas context'));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Set canvas dimensions to match the image
|
|
160
|
+
canvas.width = img.width;
|
|
161
|
+
canvas.height = img.height;
|
|
162
|
+
|
|
163
|
+
// Step 5: Draw the image onto the Canvas
|
|
164
|
+
ctx.drawImage(img, 0, 0);
|
|
165
|
+
|
|
166
|
+
// Step 6: Revoke the Object URL to free memory
|
|
167
|
+
URL.revokeObjectURL(url);
|
|
168
|
+
|
|
169
|
+
// Resolve the Canvas element
|
|
170
|
+
resolve(canvas);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// Handle errors
|
|
174
|
+
img.onerror = () => {
|
|
175
|
+
URL.revokeObjectURL(url);
|
|
176
|
+
reject(new Error('Failed to load image from Blob'));
|
|
177
|
+
};
|
|
178
|
+
});
|
|
179
|
+
}
|
|
@@ -46,23 +46,31 @@ export const useImageSearch = () => {
|
|
|
46
46
|
showFeedback = true,
|
|
47
47
|
imageRegion,
|
|
48
48
|
newSearch,
|
|
49
|
+
compress = true,
|
|
50
|
+
preFilterParams,
|
|
49
51
|
}: {
|
|
50
52
|
image: any;
|
|
51
53
|
settings: AppSettings;
|
|
52
54
|
showFeedback?: boolean;
|
|
53
55
|
imageRegion?: RectCoords;
|
|
54
56
|
newSearch?: boolean;
|
|
57
|
+
compress?: boolean;
|
|
58
|
+
preFilterParams?: Record<string, boolean>;
|
|
55
59
|
}) => {
|
|
56
60
|
let region: RectCoords | undefined = imageRegion;
|
|
57
61
|
let res: any;
|
|
58
62
|
let compressedBase64;
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
if (compress) {
|
|
65
|
+
try {
|
|
66
|
+
compressedBase64 = await compressImage(image);
|
|
67
|
+
} catch (error) {}
|
|
68
|
+
}
|
|
63
69
|
|
|
64
70
|
let canvasImage = await createImage(compressedBase64 || image);
|
|
65
71
|
|
|
72
|
+
let requestImage = await createImage(image);
|
|
73
|
+
|
|
66
74
|
if (!imageRegion) {
|
|
67
75
|
dispatch(setRequestImage(canvasImage));
|
|
68
76
|
setRequestImages([canvasImage]);
|
|
@@ -70,7 +78,7 @@ export const useImageSearch = () => {
|
|
|
70
78
|
|
|
71
79
|
if (regions && !imageRegion) {
|
|
72
80
|
try {
|
|
73
|
-
let res = await findRegions(
|
|
81
|
+
let res = await findRegions(requestImage, settings);
|
|
74
82
|
setDetectedObject(res.regions, 0);
|
|
75
83
|
dispatch(setRegions(res.regions));
|
|
76
84
|
region = res.selectedRegion;
|
|
@@ -82,16 +90,18 @@ export const useImageSearch = () => {
|
|
|
82
90
|
const preFilterValues = [
|
|
83
91
|
{
|
|
84
92
|
key: settings.visualSearchFilterKey,
|
|
85
|
-
values: Object.keys(preFilter),
|
|
93
|
+
values: Object.keys(preFilterParams || preFilter),
|
|
86
94
|
},
|
|
87
95
|
];
|
|
88
96
|
let filters: any[] = [];
|
|
89
97
|
|
|
90
98
|
try {
|
|
91
99
|
res = await find({
|
|
92
|
-
image:
|
|
100
|
+
image: requestImage,
|
|
93
101
|
settings,
|
|
94
|
-
filters: !isEmpty(preFilter)
|
|
102
|
+
filters: !isEmpty(preFilterParams || preFilter)
|
|
103
|
+
? preFilterValues
|
|
104
|
+
: undefined,
|
|
95
105
|
region,
|
|
96
106
|
});
|
|
97
107
|
|
|
@@ -139,16 +149,18 @@ export const useImageSearch = () => {
|
|
|
139
149
|
settings,
|
|
140
150
|
regions,
|
|
141
151
|
showFeedback = true,
|
|
152
|
+
preFilterParams,
|
|
142
153
|
}: {
|
|
143
154
|
images: HTMLCanvasElement[];
|
|
144
155
|
regions: RectCoords[];
|
|
145
156
|
settings: AppSettings;
|
|
146
157
|
showFeedback?: boolean;
|
|
158
|
+
preFilterParams?: Record<string, boolean>;
|
|
147
159
|
}) => {
|
|
148
160
|
const preFilterValues = [
|
|
149
161
|
{
|
|
150
162
|
key: settings.visualSearchFilterKey,
|
|
151
|
-
values: Object.keys(preFilter),
|
|
163
|
+
values: Object.keys(preFilterParams || preFilter),
|
|
152
164
|
},
|
|
153
165
|
];
|
|
154
166
|
let filters: any[] = [];
|
|
@@ -158,7 +170,9 @@ export const useImageSearch = () => {
|
|
|
158
170
|
images,
|
|
159
171
|
settings,
|
|
160
172
|
regions,
|
|
161
|
-
filters: !isEmpty(preFilter)
|
|
173
|
+
filters: !isEmpty(preFilterParams || preFilter)
|
|
174
|
+
? preFilterValues
|
|
175
|
+
: undefined,
|
|
162
176
|
});
|
|
163
177
|
|
|
164
178
|
res?.results.forEach((item: any) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import 'react-app-polyfill/ie11';
|
|
3
3
|
import 'react-app-polyfill/stable';
|
|
4
4
|
import 'typeface-roboto';
|
|
@@ -6,9 +6,16 @@ import 'index.css';
|
|
|
6
6
|
|
|
7
7
|
import AppMD from 'page/landingPage/HomeDesktop';
|
|
8
8
|
import AppMobile from 'page/landingPage/HomeMobile';
|
|
9
|
-
|
|
9
|
+
import { useAppSelector } from 'Store/Store';
|
|
10
10
|
|
|
11
11
|
function Home(): JSX.Element {
|
|
12
|
+
const experienceVisualSearch = useAppSelector(
|
|
13
|
+
state => state.settings.experienceVisualSearch,
|
|
14
|
+
);
|
|
15
|
+
const experienceVisualSearchImages = useAppSelector(
|
|
16
|
+
state => state.settings.experienceVisualSearchImages,
|
|
17
|
+
);
|
|
18
|
+
|
|
12
19
|
// const clarityId = useAppSelector(state => state.settings.clarityId);
|
|
13
20
|
|
|
14
21
|
// useEffect(() => {
|
|
@@ -38,10 +45,46 @@ function Home(): JSX.Element {
|
|
|
38
45
|
// }
|
|
39
46
|
// };
|
|
40
47
|
|
|
48
|
+
const [experienceVisualSearchBlobs, setExperienceVisualSearchBlobs] =
|
|
49
|
+
useState<Blob[]>([]);
|
|
50
|
+
|
|
51
|
+
const fetchImage = async (url: string) => {
|
|
52
|
+
const response = await fetch(url, { cache: 'force-cache' });
|
|
53
|
+
const blob = await response.blob();
|
|
54
|
+
return blob;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
const fetchAllImages = async () => {
|
|
59
|
+
if (experienceVisualSearch && experienceVisualSearchImages?.length) {
|
|
60
|
+
const randomImages = experienceVisualSearchImages?.slice(
|
|
61
|
+
0,
|
|
62
|
+
Math.min(experienceVisualSearchImages?.length, 4),
|
|
63
|
+
);
|
|
64
|
+
try {
|
|
65
|
+
// randomImages.forEach(url => {
|
|
66
|
+
// fetchImage(url).then(value => {
|
|
67
|
+
// setExperienceVisualSearchBlobs(s => [...s, value]);
|
|
68
|
+
// });
|
|
69
|
+
// });
|
|
70
|
+
|
|
71
|
+
const responses = await Promise.all(
|
|
72
|
+
randomImages.map(url => fetchImage(url)),
|
|
73
|
+
);
|
|
74
|
+
setExperienceVisualSearchBlobs(responses);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error('Error fetching images:', error);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
fetchAllImages();
|
|
82
|
+
}, [experienceVisualSearch, experienceVisualSearchImages]);
|
|
83
|
+
|
|
41
84
|
return (
|
|
42
85
|
<>
|
|
43
|
-
<AppMobile />
|
|
44
|
-
<AppMD />
|
|
86
|
+
<AppMobile experienceVisualSearchBlobs={experienceVisualSearchBlobs} />
|
|
87
|
+
<AppMD experienceVisualSearchBlobs={experienceVisualSearchBlobs} />
|
|
45
88
|
</>
|
|
46
89
|
);
|
|
47
90
|
}
|
|
@@ -8,7 +8,11 @@ import { connectInfiniteHits } from 'react-instantsearch-dom';
|
|
|
8
8
|
import { useAppSelector } from 'Store/Store';
|
|
9
9
|
import { AlgoliaSettings } from '../../types';
|
|
10
10
|
|
|
11
|
-
function AppMD(
|
|
11
|
+
function AppMD({
|
|
12
|
+
experienceVisualSearchBlobs,
|
|
13
|
+
}: {
|
|
14
|
+
experienceVisualSearchBlobs: Blob[];
|
|
15
|
+
}) {
|
|
12
16
|
const { settings } = useAppSelector(state => state);
|
|
13
17
|
const [isLoading, setLoading] = useState<boolean>(false);
|
|
14
18
|
const { apiKey, appId, indexName } = settings.algolia as AlgoliaSettings;
|
|
@@ -54,7 +58,13 @@ function AppMD() {
|
|
|
54
58
|
isLoading={isLoading}
|
|
55
59
|
onChangeLoading={onChangeLoading}
|
|
56
60
|
/>
|
|
57
|
-
{settings.experienceVisualSearch ?
|
|
61
|
+
{settings.experienceVisualSearch ? (
|
|
62
|
+
<ExperienceVisualSearch
|
|
63
|
+
experienceVisualSearchBlobs={experienceVisualSearchBlobs}
|
|
64
|
+
/>
|
|
65
|
+
) : (
|
|
66
|
+
''
|
|
67
|
+
)}
|
|
58
68
|
</div>
|
|
59
69
|
</div>
|
|
60
70
|
);
|
|
@@ -6,7 +6,11 @@ import { useAppSelector } from 'Store/Store';
|
|
|
6
6
|
import ExperienceVisualSearch from '../../components/Experience-visual-search/ExperienceVisualSearch';
|
|
7
7
|
import { Icon } from '@nyris/nyris-react-components';
|
|
8
8
|
|
|
9
|
-
function AppMobile(
|
|
9
|
+
function AppMobile({
|
|
10
|
+
experienceVisualSearchBlobs,
|
|
11
|
+
}: {
|
|
12
|
+
experienceVisualSearchBlobs: Blob[];
|
|
13
|
+
}): JSX.Element {
|
|
10
14
|
const { settings } = useAppSelector(state => state);
|
|
11
15
|
const [isOpenModalCamera, setOpenModalCamera] = useState<boolean>(false);
|
|
12
16
|
|
|
@@ -48,7 +52,13 @@ function AppMobile(): JSX.Element {
|
|
|
48
52
|
}}
|
|
49
53
|
/>
|
|
50
54
|
</div>
|
|
51
|
-
{settings.experienceVisualSearch ?
|
|
55
|
+
{settings.experienceVisualSearch ? (
|
|
56
|
+
<ExperienceVisualSearch
|
|
57
|
+
experienceVisualSearchBlobs={experienceVisualSearchBlobs}
|
|
58
|
+
/>
|
|
59
|
+
) : (
|
|
60
|
+
''
|
|
61
|
+
)}
|
|
52
62
|
</div>
|
|
53
63
|
);
|
|
54
64
|
}
|
|
@@ -85,7 +85,7 @@ function ResultComponent(props: Props) {
|
|
|
85
85
|
const isPostFilterEnabled = settings.postFilterOption;
|
|
86
86
|
const history = useHistory();
|
|
87
87
|
|
|
88
|
-
const { singleImageSearch
|
|
88
|
+
const { singleImageSearch } = useImageSearch();
|
|
89
89
|
|
|
90
90
|
const { resetRegions, imageRegions, requestImages } = useRequestStore(
|
|
91
91
|
state => ({
|
|
@@ -152,7 +152,12 @@ function ResultComponent(props: Props) {
|
|
|
152
152
|
}
|
|
153
153
|
dispatch(loadingActionResults());
|
|
154
154
|
|
|
155
|
-
singleImageSearch({
|
|
155
|
+
singleImageSearch({
|
|
156
|
+
image: url,
|
|
157
|
+
settings,
|
|
158
|
+
showFeedback: true,
|
|
159
|
+
compress: false,
|
|
160
|
+
}).then(() => {
|
|
156
161
|
dispatch(updateStatusLoading(false));
|
|
157
162
|
});
|
|
158
163
|
};
|
|
@@ -183,35 +188,6 @@ function ResultComponent(props: Props) {
|
|
|
183
188
|
setFilterString(filter);
|
|
184
189
|
}, [preFilter, requestImage, searchQuery, settings.alogoliaFilterField]);
|
|
185
190
|
|
|
186
|
-
useEffect(() => {
|
|
187
|
-
if (requestImages.length === 0 || !isAlgoliaEnabled) {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
dispatch(updateStatusLoading(true));
|
|
191
|
-
dispatch(loadingActionResults());
|
|
192
|
-
|
|
193
|
-
if (requestImages.length === 1) {
|
|
194
|
-
singleImageSearch({
|
|
195
|
-
image: requestImages[0],
|
|
196
|
-
settings,
|
|
197
|
-
imageRegion: imageRegions[0],
|
|
198
|
-
}).then(res => {
|
|
199
|
-
dispatch(updateStatusLoading(false));
|
|
200
|
-
});
|
|
201
|
-
} else {
|
|
202
|
-
multiImageSearch({
|
|
203
|
-
images: requestImages,
|
|
204
|
-
settings,
|
|
205
|
-
regions: imageRegions,
|
|
206
|
-
}).then(res => {
|
|
207
|
-
dispatch(updateStatusLoading(false));
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return () => {};
|
|
212
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
213
|
-
}, [preFilter]);
|
|
214
|
-
|
|
215
191
|
useEffect(() => {
|
|
216
192
|
if (!requestImage) return;
|
|
217
193
|
|
package/src/services/image.ts
CHANGED
|
@@ -89,3 +89,31 @@ export const findMulti = ({
|
|
|
89
89
|
|
|
90
90
|
return nyrisApi.findMulti(options, images, regions, filters);
|
|
91
91
|
};
|
|
92
|
+
|
|
93
|
+
export const findCad = ({
|
|
94
|
+
file,
|
|
95
|
+
options,
|
|
96
|
+
settings,
|
|
97
|
+
filters,
|
|
98
|
+
}: {
|
|
99
|
+
file: File;
|
|
100
|
+
settings: NyrisAPISettings;
|
|
101
|
+
options?: ImageSearchOptions;
|
|
102
|
+
filters?: Filter[];
|
|
103
|
+
}) => {
|
|
104
|
+
const nyrisApi = new NyrisAPI(settings);
|
|
105
|
+
|
|
106
|
+
return nyrisApi.findByCad(file, {}, filters);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const getRequestImage = ({
|
|
110
|
+
url,
|
|
111
|
+
settings,
|
|
112
|
+
}: {
|
|
113
|
+
url: string;
|
|
114
|
+
settings: NyrisAPISettings;
|
|
115
|
+
}) => {
|
|
116
|
+
const nyrisApi = new NyrisAPI(settings);
|
|
117
|
+
|
|
118
|
+
return nyrisApi.getCadRequestImage(url);
|
|
119
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -36,33 +36,33 @@ export interface Field {
|
|
|
36
36
|
productDetails: string;
|
|
37
37
|
}
|
|
38
38
|
interface CTAButtonSettings {
|
|
39
|
-
CTAButton?: boolean
|
|
40
|
-
CTAButtonText?: string
|
|
41
|
-
CTAButtonTextColor?: string
|
|
42
|
-
CTAButtonColor?: string
|
|
43
|
-
CTAIcon?: boolean
|
|
44
|
-
CTALinkField?: string
|
|
39
|
+
CTAButton?: boolean;
|
|
40
|
+
CTAButtonText?: string;
|
|
41
|
+
CTAButtonTextColor?: string;
|
|
42
|
+
CTAButtonColor?: string;
|
|
43
|
+
CTAIcon?: boolean;
|
|
44
|
+
CTALinkField?: string;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
interface SecondaryCTAButton {
|
|
48
|
-
secondaryCTAButton?: boolean
|
|
49
|
-
secondaryCTAButtonText?: string
|
|
50
|
-
secondaryCTAButtonTextColor?: string
|
|
51
|
-
secondaryCTAButtonColor?: string
|
|
52
|
-
secondaryCTAIcon?: boolean
|
|
53
|
-
secondaryCTALinkField?: string
|
|
48
|
+
secondaryCTAButton?: boolean;
|
|
49
|
+
secondaryCTAButtonText?: string;
|
|
50
|
+
secondaryCTAButtonTextColor?: string;
|
|
51
|
+
secondaryCTAButtonColor?: string;
|
|
52
|
+
secondaryCTAIcon?: boolean;
|
|
53
|
+
secondaryCTALinkField?: string;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
interface Attributes {
|
|
57
|
-
productAttributes?: boolean
|
|
58
|
-
attributeOneLabelValue?: string
|
|
59
|
-
attributeOneValue?: string
|
|
60
|
-
attributeTwoLabelValue?: string
|
|
61
|
-
attributeTwoValue?: string
|
|
62
|
-
attributeThreeLabelValue?: string
|
|
63
|
-
attributeThreeValue?: string
|
|
64
|
-
attributeFourLabelValue?: string
|
|
65
|
-
attributeFourValue?: string
|
|
57
|
+
productAttributes?: boolean;
|
|
58
|
+
attributeOneLabelValue?: string;
|
|
59
|
+
attributeOneValue?: string;
|
|
60
|
+
attributeTwoLabelValue?: string;
|
|
61
|
+
attributeTwoValue?: string;
|
|
62
|
+
attributeThreeLabelValue?: string;
|
|
63
|
+
attributeThreeValue?: string;
|
|
64
|
+
attributeFourLabelValue?: string;
|
|
65
|
+
attributeFourValue?: string;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export interface AppSettings extends NyrisAPISettings {
|
|
@@ -73,9 +73,9 @@ export interface AppSettings extends NyrisAPISettings {
|
|
|
73
73
|
brandName?: string;
|
|
74
74
|
cadenas?: Cadenas;
|
|
75
75
|
clarityId?: string;
|
|
76
|
-
mainTitle: string
|
|
76
|
+
mainTitle: string;
|
|
77
77
|
productDetails: string;
|
|
78
|
-
secondaryTitle: string
|
|
78
|
+
secondaryTitle: string;
|
|
79
79
|
CTAButton?: CTAButtonSettings;
|
|
80
80
|
secondaryCTAButton?: SecondaryCTAButton;
|
|
81
81
|
attributes?: Attributes;
|
|
@@ -92,6 +92,7 @@ export interface AppSettings extends NyrisAPISettings {
|
|
|
92
92
|
preFilterOption?: boolean;
|
|
93
93
|
preFilterTitle?: string;
|
|
94
94
|
preview: boolean;
|
|
95
|
+
cadSearch?: boolean;
|
|
95
96
|
refinements?: any;
|
|
96
97
|
regions: boolean;
|
|
97
98
|
rfq?: Rfq;
|
|
@@ -103,7 +104,7 @@ export interface AppSettings extends NyrisAPISettings {
|
|
|
103
104
|
showGroup?: boolean;
|
|
104
105
|
showPoweredByNyris?: boolean;
|
|
105
106
|
simpleCardView?: boolean;
|
|
106
|
-
support
|
|
107
|
+
support: Support;
|
|
107
108
|
theme: SearchSuiteSettings;
|
|
108
109
|
visualSearchFilterKey?: string;
|
|
109
110
|
}
|
package/src/utils.ts
CHANGED
|
@@ -41,22 +41,34 @@ export function getThumbSizeLongestEdge(
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
export const compressImage = (
|
|
45
|
-
let blob:
|
|
44
|
+
export const compressImage = async (input: string | Blob): Promise<string> => {
|
|
45
|
+
let blob: Blob;
|
|
46
46
|
|
|
47
|
-
if (typeof
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
if (typeof input === 'string') {
|
|
48
|
+
if (input.startsWith('https:')) {
|
|
49
|
+
// Fetch the image from the URL and convert it to a Blob
|
|
50
|
+
const response = await fetch(input);
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
throw new Error(`Failed to fetch image: ${response.statusText}`);
|
|
53
|
+
}
|
|
54
|
+
blob = await response.blob();
|
|
55
|
+
} else {
|
|
56
|
+
// Convert base64 string to Blob
|
|
57
|
+
const byteString = atob(input.split(',')[1]);
|
|
58
|
+
const mimeString = input.split(',')[0].split(':')[1].split(';')[0];
|
|
59
|
+
const ab = new ArrayBuffer(byteString.length);
|
|
60
|
+
const ia = new Uint8Array(ab);
|
|
61
|
+
for (let i = 0; i < byteString.length; i++) {
|
|
62
|
+
ia[i] = byteString.charCodeAt(i);
|
|
63
|
+
}
|
|
64
|
+
blob = new Blob([ab], { type: mimeString });
|
|
54
65
|
}
|
|
55
|
-
|
|
66
|
+
} else {
|
|
67
|
+
blob = input;
|
|
56
68
|
}
|
|
57
69
|
|
|
58
70
|
return new Promise<string>((resolve, reject) => {
|
|
59
|
-
new Compressor(blob
|
|
71
|
+
new Compressor(blob, {
|
|
60
72
|
quality: 0.91,
|
|
61
73
|
maxHeight: 1024,
|
|
62
74
|
maxWidth: 1024,
|