@nyris/nyris-webapp 0.3.6 → 0.3.13
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 +11 -11
- package/build/index.html +1 -1
- package/build/{precache-manifest.bffed513ca17d8ac16af1cc3aaa7d908.js → precache-manifest.793f0a4375602ec8cd0fba83bf0e3e67.js} +9 -9
- package/build/service-worker.js +1 -1
- package/build/static/css/main.0c9239ba.chunk.css +2 -0
- package/build/static/css/main.0c9239ba.chunk.css.map +1 -0
- package/build/static/js/2.520bb6d6.chunk.js +3 -0
- package/build/static/js/{2.4e9a4ce1.chunk.js.LICENSE.txt → 2.520bb6d6.chunk.js.LICENSE.txt} +0 -0
- package/build/static/js/2.520bb6d6.chunk.js.map +1 -0
- package/build/static/js/main.8405239a.chunk.js +2 -0
- package/build/static/js/main.8405239a.chunk.js.map +1 -0
- package/package.json +2 -2
- package/src/App.tsx +346 -213
- package/src/actions/nyrisAppActions.ts +69 -65
- package/src/actions/searchActions.ts +301 -196
- package/src/components/CategoryFilter.tsx +16 -13
- package/src/components/Codes.tsx +20 -16
- package/src/components/ExampleImages.tsx +27 -17
- package/src/components/Feedback.tsx +78 -48
- package/src/components/FiltersList.tsx +106 -59
- package/src/components/Header.tsx +29 -17
- package/src/components/PredictedCategories.tsx +15 -12
- package/src/components/Result.tsx +186 -113
- package/src/components/SelectedFiltersSummary.tsx +84 -0
- package/src/components/Sidebar.tsx +41 -32
- package/src/epics/index.ts +173 -104
- package/src/epics/search.ts +209 -177
- package/src/index.css +98 -9
- package/src/index.tsx +148 -144
- package/src/utils.ts +5 -0
- package/build/static/css/main.2a76dc8a.chunk.css +0 -2
- package/build/static/css/main.2a76dc8a.chunk.css.map +0 -1
- package/build/static/js/2.4e9a4ce1.chunk.js +0 -3
- package/build/static/js/2.4e9a4ce1.chunk.js.map +0 -1
- package/build/static/js/main.ec93aa4d.chunk.js +0 -2
- package/build/static/js/main.ec93aa4d.chunk.js.map +0 -1
- package/src/Demo2.tsx +0 -220
package/src/App.tsx
CHANGED
|
@@ -1,256 +1,389 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { useDispatch } from "react-redux";
|
|
3
|
+
import { Animate, NodeGroup } from "react-move";
|
|
4
|
+
import { useDropzone } from "react-dropzone";
|
|
5
|
+
import { Box, Snackbar } from "@material-ui/core";
|
|
6
|
+
import { Alert } from "@material-ui/lab";
|
|
7
|
+
import classNames from "classnames";
|
|
8
|
+
import { loadFilters } from "./actions/searchActions";
|
|
9
|
+
import Result from "./components/Result";
|
|
10
|
+
import Sidebar from "./components/Sidebar";
|
|
11
|
+
import Header from "./components/Header";
|
|
12
|
+
import Feedback from "./components/Feedback";
|
|
6
13
|
import CategoryFilter from "./components/CategoryFilter";
|
|
7
|
-
import PredictedCategories from "./components/PredictedCategories";
|
|
8
14
|
import Codes from "./components/Codes";
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
import PredictedCategories from "./components/PredictedCategories";
|
|
16
|
+
import ExampleImages from "./components/ExampleImages";
|
|
17
|
+
import {
|
|
18
|
+
makeFileHandler,
|
|
19
|
+
Capture,
|
|
20
|
+
Preview,
|
|
21
|
+
} from "@nyris/nyris-react-components";
|
|
22
|
+
import {
|
|
23
|
+
RectCoords,
|
|
24
|
+
cadExtensions,
|
|
25
|
+
CategoryPrediction,
|
|
26
|
+
Code,
|
|
27
|
+
Region,
|
|
28
|
+
Filter,
|
|
29
|
+
} from "@nyris/nyris-api";
|
|
30
|
+
import { AppSettings, CanvasWithId, MDSettings } from "./types";
|
|
31
|
+
import { NyrisAppPart, NyrisFeedbackState } from "./actions/nyrisAppActions";
|
|
32
|
+
import SelectedFiltersSummary from "./components/SelectedFiltersSummary";
|
|
22
33
|
|
|
23
34
|
export interface AppHandlers {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
onExampleImageClick: (url: string) => void;
|
|
36
|
+
onImageClick: (position: number, url: string) => void;
|
|
37
|
+
onLinkClick: (position: number, url: string) => void;
|
|
38
|
+
onFileDropped: (file: File) => void;
|
|
39
|
+
onCaptureComplete: (image: HTMLCanvasElement) => void;
|
|
40
|
+
onCaptureCanceled: () => void;
|
|
41
|
+
onSelectFile: (f: File) => void;
|
|
42
|
+
onCameraClick: () => void;
|
|
43
|
+
onShowStart: () => void;
|
|
44
|
+
onSelectionChange: (r: RectCoords) => void;
|
|
45
|
+
onPositiveFeedback: () => void;
|
|
46
|
+
onNegativeFeedback: () => void;
|
|
47
|
+
onCloseFeedback: () => void;
|
|
37
48
|
}
|
|
38
|
-
|
|
39
49
|
export interface AppProps {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
function Alert(props: AlertProps) {
|
|
63
|
-
return <MuiAlert elevation={6} variant="filled" {...props} />;
|
|
50
|
+
search: {
|
|
51
|
+
results: any[];
|
|
52
|
+
requestId?: string;
|
|
53
|
+
duration?: number;
|
|
54
|
+
categoryPredictions: CategoryPrediction[];
|
|
55
|
+
codes: Code[];
|
|
56
|
+
filterOptions: string[];
|
|
57
|
+
errorMessage?: string;
|
|
58
|
+
regions: Region[];
|
|
59
|
+
previewSelection: RectCoords;
|
|
60
|
+
toastErrorMessage?: string;
|
|
61
|
+
filters: Filter[];
|
|
62
|
+
selectedFilters: Map<string, string[]>;
|
|
63
|
+
};
|
|
64
|
+
previewImage?: CanvasWithId;
|
|
65
|
+
settings: AppSettings;
|
|
66
|
+
loading: boolean;
|
|
67
|
+
showPart: NyrisAppPart;
|
|
68
|
+
feedbackState: NyrisFeedbackState;
|
|
69
|
+
handlers: AppHandlers;
|
|
70
|
+
mdSettings: MDSettings;
|
|
64
71
|
}
|
|
65
72
|
|
|
66
73
|
const App: React.FC<AppProps> = ({
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
search: {
|
|
75
|
+
results,
|
|
76
|
+
regions,
|
|
77
|
+
previewSelection,
|
|
78
|
+
requestId,
|
|
79
|
+
duration,
|
|
80
|
+
errorMessage,
|
|
81
|
+
filterOptions,
|
|
82
|
+
categoryPredictions,
|
|
83
|
+
codes,
|
|
84
|
+
toastErrorMessage,
|
|
85
|
+
filters,
|
|
86
|
+
selectedFilters,
|
|
87
|
+
},
|
|
88
|
+
showPart,
|
|
89
|
+
settings,
|
|
90
|
+
handlers,
|
|
91
|
+
loading,
|
|
92
|
+
previewImage,
|
|
93
|
+
feedbackState,
|
|
94
|
+
}) => {
|
|
95
|
+
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
|
96
|
+
onDrop: (fs: File[]) => handlers.onFileDropped(fs[0]),
|
|
97
|
+
});
|
|
80
98
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
99
|
+
const minPreviewHeight = 400;
|
|
100
|
+
const halfOfTheScreenHeight = Math.floor(window.innerHeight * 0.45);
|
|
101
|
+
const maxPreviewHeight = Math.max(minPreviewHeight, halfOfTheScreenHeight);
|
|
102
|
+
const [toastOpen, setToastOpen] = useState(false);
|
|
103
|
+
const dispatch = useDispatch();
|
|
104
|
+
|
|
105
|
+
const acceptTypes = ["image/*"]
|
|
106
|
+
.concat(settings.cadSearch ? cadExtensions : [])
|
|
107
|
+
.join(",");
|
|
108
|
+
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (toastErrorMessage !== "") {
|
|
111
|
+
setToastOpen(true);
|
|
112
|
+
}
|
|
113
|
+
}, [toastErrorMessage]);
|
|
114
|
+
|
|
115
|
+
useEffect(() => {
|
|
88
116
|
dispatch(loadFilters());
|
|
89
|
-
|
|
117
|
+
}, [showPart, dispatch]);
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<React.Fragment>
|
|
121
|
+
<Header />
|
|
122
|
+
<div className="wrapperBody">
|
|
123
|
+
<Sidebar filters={filters} selectedFilters={selectedFilters} />
|
|
124
|
+
|
|
125
|
+
<div className="mainContent">
|
|
126
|
+
{showPart === "camera" && (
|
|
127
|
+
<Capture
|
|
128
|
+
onCaptureComplete={handlers.onCaptureComplete}
|
|
129
|
+
onCaptureCanceled={handlers.onCaptureCanceled}
|
|
130
|
+
useAppText="Use default camera app"
|
|
131
|
+
/>
|
|
132
|
+
)}
|
|
90
133
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
134
|
+
<SelectedFiltersSummary />
|
|
135
|
+
<div
|
|
136
|
+
className={classNames("headSection", {
|
|
137
|
+
hidden: showPart === "results",
|
|
138
|
+
})}
|
|
139
|
+
id="headSection"
|
|
140
|
+
>
|
|
141
|
+
<div
|
|
142
|
+
{...getRootProps({
|
|
143
|
+
onClick: (e) => {
|
|
144
|
+
e.stopPropagation();
|
|
145
|
+
},
|
|
146
|
+
})}
|
|
147
|
+
className={classNames("wrapper", "dragAndDropActionArea", {
|
|
148
|
+
fileIsHover: isDragActive,
|
|
149
|
+
})}
|
|
150
|
+
>
|
|
151
|
+
<div className={classNames("contentWrap")}>
|
|
152
|
+
<Box
|
|
153
|
+
display="flex"
|
|
154
|
+
flexDirection="column"
|
|
155
|
+
justifyContent="center"
|
|
156
|
+
alignItems="center"
|
|
157
|
+
minHeight="100vh"
|
|
158
|
+
>
|
|
159
|
+
<section className="uploadImage">
|
|
160
|
+
<input
|
|
161
|
+
type="button"
|
|
162
|
+
name="file"
|
|
163
|
+
id="capture"
|
|
164
|
+
className="inputfile"
|
|
165
|
+
accept="image/*"
|
|
166
|
+
capture="environment"
|
|
167
|
+
onClick={handlers.onCameraClick}
|
|
168
|
+
/>
|
|
169
|
+
<input
|
|
170
|
+
type="file"
|
|
171
|
+
name="file"
|
|
172
|
+
id="capture_file"
|
|
173
|
+
className="inputfile"
|
|
174
|
+
accept={acceptTypes}
|
|
175
|
+
capture="environment"
|
|
176
|
+
/>
|
|
177
|
+
<input
|
|
178
|
+
{...getInputProps()}
|
|
179
|
+
type="file"
|
|
180
|
+
name="file"
|
|
181
|
+
id="select_file"
|
|
182
|
+
className="inputfile"
|
|
183
|
+
accept={acceptTypes}
|
|
184
|
+
onChange={makeFileHandler(handlers.onSelectFile)}
|
|
185
|
+
/>
|
|
186
|
+
<div className="onDesktop">
|
|
187
|
+
Drop an image
|
|
188
|
+
<div className="smallText">or</div>
|
|
107
189
|
</div>
|
|
108
|
-
|
|
190
|
+
<div className="onMobile camIcon">
|
|
191
|
+
<img src="./images/ic_cam_large.svg" alt="Camera" />
|
|
192
|
+
</div>
|
|
193
|
+
<label
|
|
194
|
+
htmlFor="capture"
|
|
195
|
+
className="btn primary onMobile"
|
|
196
|
+
style={{ marginBottom: "2em", width: "12em" }}
|
|
197
|
+
>
|
|
198
|
+
<span className="onMobile">Take a picture</span>
|
|
199
|
+
</label>
|
|
200
|
+
<br />
|
|
201
|
+
<label
|
|
202
|
+
htmlFor="select_file"
|
|
203
|
+
className="btn primary"
|
|
204
|
+
style={{ width: "12em" }}
|
|
205
|
+
>
|
|
206
|
+
<span>Select a file</span>
|
|
207
|
+
</label>
|
|
208
|
+
<label
|
|
209
|
+
htmlFor="capture"
|
|
210
|
+
className="mobileUploadHandler onMobile"
|
|
211
|
+
/>
|
|
212
|
+
</section>
|
|
213
|
+
<ExampleImages
|
|
214
|
+
images={settings.exampleImages}
|
|
215
|
+
onExampleImageClicked={handlers.onExampleImageClick}
|
|
216
|
+
/>
|
|
217
|
+
</Box>
|
|
218
|
+
</div>
|
|
109
219
|
</div>
|
|
110
|
-
<div {...getRootProps({
|
|
111
|
-
onClick: e => {
|
|
112
|
-
e.stopPropagation();
|
|
113
|
-
}
|
|
114
|
-
})} className={classNames('wrapper', 'dragAndDropActionArea', {'fileIsHover': isDragActive})}>
|
|
115
|
-
<section style={{width:'350px', height: '100%' , marginTop: '100px', borderRight:'4px solid rgba(255, 255, 255, .12)'}}>
|
|
116
|
-
<Toolbar>
|
|
117
220
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
capture="environment"/>
|
|
130
|
-
<input {...getInputProps()} type="file" name="file" id="select_file" className="inputfile"
|
|
131
|
-
accept={acceptTypes}
|
|
132
|
-
onChange={makeFileHandler(handlers.onSelectFile)}
|
|
133
|
-
/>
|
|
134
|
-
<div className="onDesktop">
|
|
135
|
-
Drop an image
|
|
136
|
-
<div className="smallText">or</div>
|
|
137
|
-
</div>
|
|
138
|
-
<div className="onMobile camIcon">
|
|
139
|
-
<img src="./images/ic_cam_large.svg" alt="Camera"/>
|
|
140
|
-
</div>
|
|
141
|
-
<label htmlFor="capture" className="btn primary onMobile"
|
|
142
|
-
style={{marginBottom: '2em', width: '22em'}}>
|
|
143
|
-
<span className="onMobile">Take a picture</span>
|
|
144
|
-
</label>
|
|
145
|
-
<br/>
|
|
146
|
-
<label htmlFor="select_file" className="btn primary" style={{width: '22em'}}>
|
|
147
|
-
<span>Select a file</span>
|
|
148
|
-
</label>
|
|
149
|
-
<label htmlFor="capture" className="mobileUploadHandler onMobile"/>
|
|
150
|
-
</section>
|
|
151
|
-
<ExampleImages images={settings.exampleImages} onExampleImageClicked={handlers.onExampleImageClick}/>
|
|
152
|
-
</div>
|
|
153
|
-
</div>
|
|
154
|
-
<div className={classNames('tryDifferent', {hidden: showPart !== 'results'})}
|
|
155
|
-
onClick={handlers.onShowStart}>
|
|
156
|
-
<div className="icIcon">
|
|
157
|
-
</div>
|
|
158
|
-
<div className="textDesc"> Try a different image</div>
|
|
159
|
-
<br style={{clear: 'both'}}/>
|
|
221
|
+
<div className="headerSeparatorTop" />
|
|
222
|
+
<div className="headerSeparatorBack" />
|
|
223
|
+
<div
|
|
224
|
+
className={classNames("tryDifferent", {
|
|
225
|
+
hidden: showPart !== "results",
|
|
226
|
+
})}
|
|
227
|
+
onClick={handlers.onShowStart}
|
|
228
|
+
>
|
|
229
|
+
<div className="icIcon"></div>
|
|
230
|
+
<div className="textDesc"> Try a different image</div>
|
|
231
|
+
<br style={{ clear: "both" }} />
|
|
160
232
|
</div>
|
|
161
|
-
|
|
162
|
-
<div className="headerSeparatorBack"/>
|
|
163
|
-
</div>
|
|
233
|
+
</div>
|
|
164
234
|
|
|
165
|
-
|
|
166
|
-
className={classNames(
|
|
167
|
-
|
|
168
|
-
|
|
235
|
+
<section
|
|
236
|
+
className={classNames(
|
|
237
|
+
{ hideResults: showPart !== "results" },
|
|
238
|
+
"results",
|
|
239
|
+
{ resultsActive: showPart === "results" },
|
|
240
|
+
results.length === 1 ? "singleProduct" : "multipleProducts"
|
|
241
|
+
)}
|
|
242
|
+
>
|
|
243
|
+
{errorMessage && (
|
|
244
|
+
<div className="errorMsg">
|
|
169
245
|
{errorMessage}
|
|
170
|
-
<div
|
|
246
|
+
<div
|
|
247
|
+
style={{
|
|
248
|
+
textAlign: "center",
|
|
249
|
+
fontSize: "0ß.7em",
|
|
250
|
+
paddingTop: "0.8em",
|
|
251
|
+
}}
|
|
252
|
+
>
|
|
253
|
+
<span>
|
|
254
|
+
Make sure to include the request ID when reporting a
|
|
255
|
+
problem: {requestId}
|
|
256
|
+
</span>
|
|
171
257
|
</div>
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
<Animate
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
258
|
+
</div>
|
|
259
|
+
)}
|
|
260
|
+
<Animate
|
|
261
|
+
show={loading}
|
|
262
|
+
start={{ opacity: 0.0 }}
|
|
263
|
+
enter={{ opacity: [1.0], timing: { duration: 300 } }}
|
|
264
|
+
leave={{ opacity: [0.0], timing: { duration: 300 } }}
|
|
265
|
+
>
|
|
266
|
+
{(s) => (
|
|
267
|
+
<div className="loadingOverlay" style={{ ...s }}>
|
|
268
|
+
<div className="loading" />
|
|
269
|
+
</div>
|
|
270
|
+
)}
|
|
181
271
|
</Animate>
|
|
182
|
-
{settings.preview && previewImage &&
|
|
183
|
-
|
|
184
|
-
<Preview
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
272
|
+
{settings.preview && previewImage && (
|
|
273
|
+
<div className="preview">
|
|
274
|
+
<Preview
|
|
275
|
+
key={previewImage.id}
|
|
276
|
+
maxWidth={document.body.clientWidth}
|
|
277
|
+
maxHeight={maxPreviewHeight}
|
|
278
|
+
dotColor="#4C8F9F"
|
|
279
|
+
onSelectionChange={handlers.onSelectionChange}
|
|
280
|
+
regions={regions}
|
|
281
|
+
selection={previewSelection}
|
|
282
|
+
image={previewImage.canvas}
|
|
283
|
+
/>
|
|
284
|
+
</div>
|
|
285
|
+
)}
|
|
191
286
|
<div className="predicted-categories">
|
|
192
|
-
|
|
287
|
+
<PredictedCategories cs={categoryPredictions} />
|
|
193
288
|
</div>
|
|
194
289
|
<div className="predicted-categories">
|
|
195
|
-
|
|
290
|
+
<Codes codes={codes} />
|
|
196
291
|
</div>
|
|
197
|
-
<CategoryFilter cats={filterOptions}/>
|
|
292
|
+
<CategoryFilter cats={filterOptions} />
|
|
198
293
|
|
|
199
294
|
<div className="wrapper">
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
295
|
+
<NodeGroup
|
|
296
|
+
data={results}
|
|
297
|
+
keyAccessor={(r) => r.sku}
|
|
298
|
+
start={(r, i) => ({ opacity: 0, translateX: -100 })}
|
|
299
|
+
enter={(r, i) => ({
|
|
300
|
+
opacity: [1],
|
|
301
|
+
translateX: [0],
|
|
302
|
+
timing: { delay: i * 100, duration: 300 },
|
|
303
|
+
})}
|
|
304
|
+
>
|
|
305
|
+
{(rs) => (
|
|
306
|
+
<>
|
|
307
|
+
{rs.map(({ key, data, state }) => (
|
|
308
|
+
<Result
|
|
210
309
|
key={key}
|
|
211
310
|
noImageUrl={settings.noImageUrl}
|
|
212
311
|
template={settings.resultTemplate}
|
|
213
312
|
onImageClick={handlers.onImageClick}
|
|
214
313
|
onLinkClick={handlers.onLinkClick}
|
|
215
314
|
result={data}
|
|
216
|
-
style={{
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
315
|
+
style={{
|
|
316
|
+
opacity: state.opacity,
|
|
317
|
+
transform: `translateX(${state.translateX}%)`,
|
|
318
|
+
}}
|
|
319
|
+
/>
|
|
320
|
+
))}
|
|
321
|
+
</>
|
|
223
322
|
)}
|
|
323
|
+
</NodeGroup>
|
|
224
324
|
|
|
225
|
-
|
|
325
|
+
{results.length === 0 && showPart === "results" && !loading && (
|
|
326
|
+
<div className="noResults">
|
|
327
|
+
We did not find anything{" "}
|
|
328
|
+
<span role="img" aria-label="sad face">
|
|
329
|
+
😕
|
|
330
|
+
</span>
|
|
331
|
+
</div>
|
|
332
|
+
)}
|
|
226
333
|
|
|
227
|
-
|
|
228
|
-
took {duration.toFixed(2)} seconds</div>)}
|
|
334
|
+
<br style={{ clear: "both" }} />
|
|
229
335
|
|
|
230
|
-
|
|
231
|
-
|
|
336
|
+
{duration && showPart === "results" && (
|
|
337
|
+
<div
|
|
338
|
+
style={{
|
|
339
|
+
textAlign: "center",
|
|
340
|
+
fontSize: "0.7em",
|
|
341
|
+
paddingTop: "0.8em",
|
|
342
|
+
}}
|
|
343
|
+
>
|
|
344
|
+
Search took {duration.toFixed(2)} seconds
|
|
345
|
+
</div>
|
|
346
|
+
)}
|
|
347
|
+
|
|
348
|
+
{requestId && showPart === "results" && (
|
|
349
|
+
<div
|
|
350
|
+
style={{
|
|
351
|
+
textAlign: "center",
|
|
352
|
+
fontSize: "0.7em",
|
|
353
|
+
paddingTop: "0.8em",
|
|
354
|
+
}}
|
|
355
|
+
>
|
|
356
|
+
Request identifier {requestId}
|
|
357
|
+
</div>
|
|
358
|
+
)}
|
|
232
359
|
</div>
|
|
233
|
-
|
|
360
|
+
</section>
|
|
234
361
|
|
|
235
|
-
|
|
362
|
+
<Snackbar
|
|
363
|
+
open={toastOpen}
|
|
364
|
+
autoHideDuration={3000}
|
|
365
|
+
onClose={() => setToastOpen(false)}
|
|
366
|
+
>
|
|
236
367
|
<Alert onClose={() => setToastOpen(false)} severity="error">
|
|
237
|
-
|
|
368
|
+
{toastErrorMessage}
|
|
238
369
|
</Alert>
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
</
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
370
|
+
</Snackbar>
|
|
371
|
+
</div>
|
|
372
|
+
</div>
|
|
373
|
+
<section className="footnote">
|
|
374
|
+
<div className="wrapper">
|
|
375
|
+
© 2017 - 2019 <a href="https://nyris.io">nyris GmbH</a> - All rights
|
|
376
|
+
reserved - <a href="https://nyris.io/imprint/">Imprint</a>
|
|
377
|
+
</div>
|
|
378
|
+
</section>
|
|
379
|
+
<Feedback
|
|
380
|
+
feedbackState={feedbackState}
|
|
381
|
+
onPositiveFeedback={handlers.onPositiveFeedback}
|
|
382
|
+
onNegativeFeedback={handlers.onNegativeFeedback}
|
|
383
|
+
onClose={handlers.onCloseFeedback}
|
|
384
|
+
/>
|
|
385
|
+
</React.Fragment>
|
|
386
|
+
);
|
|
252
387
|
};
|
|
253
388
|
|
|
254
|
-
|
|
255
|
-
|
|
256
389
|
export default App;
|