@nyris/nyris-webapp 0.3.13 → 0.3.14

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.
Files changed (29) hide show
  1. package/build/asset-manifest.json +11 -11
  2. package/build/index.html +1 -1
  3. package/build/js/settings.example.js +30 -0
  4. package/build/{precache-manifest.793f0a4375602ec8cd0fba83bf0e3e67.js → precache-manifest.fa9930c6ba4e9fb0ebad3869127ef308.js} +9 -9
  5. package/build/service-worker.js +1 -1
  6. package/build/static/css/{main.0c9239ba.chunk.css → main.6633770c.chunk.css} +2 -2
  7. package/build/static/css/main.6633770c.chunk.css.map +1 -0
  8. package/build/static/js/{2.520bb6d6.chunk.js → 2.0798bb8b.chunk.js} +3 -3
  9. package/build/static/js/{2.520bb6d6.chunk.js.LICENSE.txt → 2.0798bb8b.chunk.js.LICENSE.txt} +0 -0
  10. package/build/static/js/2.0798bb8b.chunk.js.map +1 -0
  11. package/build/static/js/main.31212715.chunk.js +2 -0
  12. package/build/static/js/main.31212715.chunk.js.map +1 -0
  13. package/package.json +2 -2
  14. package/public/js/settings.example.js +30 -0
  15. package/src/App.tsx +141 -268
  16. package/src/actions/searchActions.ts +5 -19
  17. package/src/components/CategoryFilter.tsx +13 -16
  18. package/src/components/Codes.tsx +16 -20
  19. package/src/components/ExampleImages.tsx +17 -27
  20. package/src/components/Feedback.tsx +48 -78
  21. package/src/components/PredictedCategories.tsx +12 -15
  22. package/src/components/Result.tsx +113 -186
  23. package/src/epics/index.ts +94 -143
  24. package/src/epics/search.ts +75 -114
  25. package/src/index.tsx +55 -63
  26. package/build/static/css/main.0c9239ba.chunk.css.map +0 -1
  27. package/build/static/js/2.520bb6d6.chunk.js.map +0 -1
  28. package/build/static/js/main.8405239a.chunk.js +0 -2
  29. package/build/static/js/main.8405239a.chunk.js.map +0 -1
@@ -0,0 +1,30 @@
1
+ var settings = {
2
+ "apiKey": "xxx",
3
+ "maxWidth": 500,
4
+ "maxHeight": 500,
5
+ "jpegQuality": 0.9,
6
+ "regions": true,
7
+ "preview": true,
8
+ "baseUrl": "https://api.nyris.io",
9
+ "xOptions": "",
10
+ "exampleImages": [
11
+ "https://img.nyris.io/demo/everybag/kissen.jpg",
12
+ "https://img.nyris.io/demo/everybag/aspirin.jpg",
13
+ "https://img.nyris.io/demo/everybag/lego.jpg",
14
+ "https://img.nyris.io/demo/everybag/wdr_add_2.jpg",
15
+ "https://img.nyris.io/demo/everybag/mb-dle-4.jpg",
16
+ "https://img.nyris.io/demo/everybag/1.jpg",
17
+ "https://img.nyris.io/demo/everybag/5.jpg",
18
+ "https://img.nyris.io/demo/everybag/6.jpg"
19
+ ],
20
+ "instantRedirectPatterns": [
21
+ '^https?://(www.)?youtube.com/',
22
+ '^https?://(www.)?youtu.be/',
23
+ '^https?://(www.)?vimeo.com/',
24
+ '^https?://(www.)?dailymotion.com/',
25
+ '^https?://(www.)?dai.ly/'
26
+ ]
27
+ };
28
+ settings["customSearchRequest"] = null;
29
+ settings["responseHook"] = null;
30
+
package/src/App.tsx CHANGED
@@ -1,51 +1,44 @@
1
- import React, { useEffect, useState } from "react";
1
+ import './App.css';
2
+ import React, {useEffect, useState} from 'react';
3
+ import Result from './components/Result';
4
+ import ExampleImages from './components/ExampleImages';
5
+ import Feedback from './components/Feedback';
6
+ import CategoryFilter from "./components/CategoryFilter";
7
+ import PredictedCategories from "./components/PredictedCategories";
8
+ import Codes from "./components/Codes";
9
+ import {Code, CategoryPrediction, RectCoords, Region, cadExtensions, Filter} from "@nyris/nyris-api";
10
+ import { useDropzone} from "react-dropzone";
11
+ import classNames from 'classnames';
12
+ import {Animate, NodeGroup} from "react-move";
13
+ import {AppSettings, MDSettings, CanvasWithId} from "./types";
14
+ import {NyrisAppPart, NyrisFeedbackState} from "./actions/nyrisAppActions";
15
+ import {makeFileHandler, Capture, Preview} from "@nyris/nyris-react-components";
16
+ import {Box,Snackbar} from "@material-ui/core";
17
+ import MuiAlert, { AlertProps } from '@material-ui/lab/Alert';
2
18
  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
19
  import { loadFilters } from "./actions/searchActions";
9
- import Result from "./components/Result";
10
20
  import Sidebar from "./components/Sidebar";
11
21
  import Header from "./components/Header";
12
- import Feedback from "./components/Feedback";
13
- import CategoryFilter from "./components/CategoryFilter";
14
- import Codes from "./components/Codes";
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
22
  import SelectedFiltersSummary from "./components/SelectedFiltersSummary";
33
23
 
24
+
34
25
  export interface AppHandlers {
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;
26
+ onExampleImageClick: (url: string) => void,
27
+ onImageClick: (position: number, url: string) => void,
28
+ onLinkClick: (position: number, url: string) => void,
29
+ onFileDropped: (file: File) => void,
30
+ onCaptureComplete: (image: HTMLCanvasElement) => void,
31
+ onCaptureCanceled: () => void,
32
+ onSelectFile: (f: File) => void,
33
+ onCameraClick: () => void,
34
+ onShowStart: () => void,
35
+ onSelectionChange: (r: RectCoords) => void,
36
+ onPositiveFeedback: () => void,
37
+ onNegativeFeedback: () => void,
38
+ onCloseFeedback: () => void,
48
39
  }
40
+
41
+
49
42
  export interface AppProps {
50
43
  search: {
51
44
  results: any[];
@@ -70,41 +63,29 @@ export interface AppProps {
70
63
  mdSettings: MDSettings;
71
64
  }
72
65
 
66
+
67
+ function Alert(props: AlertProps) {
68
+ return <MuiAlert elevation={6} variant="filled" {...props} />;
69
+ }
70
+
71
+
73
72
  const App: React.FC<AppProps> = ({
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,
73
+ search: {results, regions, previewSelection, requestId, duration, errorMessage, filterOptions, categoryPredictions, codes, toastErrorMessage, filters, selectedFilters},
74
+ showPart, settings, handlers, loading, previewImage, feedbackState
94
75
  }) => {
95
- const { getRootProps, getInputProps, isDragActive } = useDropzone({
96
- onDrop: (fs: File[]) => handlers.onFileDropped(fs[0]),
97
- });
76
+
77
+ const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop: (fs: File[]) => handlers.onFileDropped(fs[0])});
98
78
 
99
79
  const minPreviewHeight = 400;
100
80
  const halfOfTheScreenHeight = Math.floor(window.innerHeight * 0.45);
101
81
  const maxPreviewHeight = Math.max(minPreviewHeight, halfOfTheScreenHeight);
82
+ const acceptTypes =
83
+ [ 'image/*' ].concat(
84
+ settings.cadSearch ? cadExtensions : []
85
+ ).join(',');
102
86
  const [toastOpen, setToastOpen] = useState(false);
103
- const dispatch = useDispatch();
104
87
 
105
- const acceptTypes = ["image/*"]
106
- .concat(settings.cadSearch ? cadExtensions : [])
107
- .join(",");
88
+ const dispatch = useDispatch();
108
89
 
109
90
  useEffect(() => {
110
91
  if (toastErrorMessage !== "") {
@@ -123,31 +104,17 @@ const App: React.FC<AppProps> = ({
123
104
  <Sidebar filters={filters} selectedFilters={selectedFilters} />
124
105
 
125
106
  <div className="mainContent">
126
- {showPart === "camera" && (
127
- <Capture
128
- onCaptureComplete={handlers.onCaptureComplete}
129
- onCaptureCanceled={handlers.onCaptureCanceled}
130
- useAppText="Use default camera app"
131
- />
132
- )}
133
-
107
+ {showPart === 'camera' &&
108
+ <Capture onCaptureComplete={handlers.onCaptureComplete} onCaptureCanceled={handlers.onCaptureCanceled}
109
+ useAppText='Use default camera app'/>}
134
110
  <SelectedFiltersSummary />
135
- <div
136
- className={classNames("headSection", {
137
- hidden: showPart === "results",
138
- })}
139
- id="headSection"
140
- >
111
+ <div className={classNames('headSection', {hidden: showPart === 'results'})} id="headSection">
141
112
  <div
142
113
  {...getRootProps({
143
114
  onClick: (e) => {
144
115
  e.stopPropagation();
145
116
  },
146
- })}
147
- className={classNames("wrapper", "dragAndDropActionArea", {
148
- fileIsHover: isDragActive,
149
- })}
150
- >
117
+ })} className={classNames('wrapper', 'dragAndDropActionArea', {'fileIsHover': isDragActive})}>
151
118
  <div className={classNames("contentWrap")}>
152
119
  <Box
153
120
  display="flex"
@@ -157,32 +124,15 @@ const App: React.FC<AppProps> = ({
157
124
  minHeight="100vh"
158
125
  >
159
126
  <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)}
127
+ <input type="button" name="file" id="capture" className="inputfile" accept="image/*"
128
+ capture="environment" onClick={handlers.onCameraClick}/>
129
+ <input type="file" name="file" id="capture_file" className="inputfile" accept={acceptTypes}
130
+ capture="environment"/>
131
+ <input {...getInputProps()} type="file" name="file" id="select_file" className="inputfile"
132
+ accept={acceptTypes}
133
+ onChange={makeFileHandler(handlers.onSelectFile)}
185
134
  />
135
+
186
136
  <div className="onDesktop">
187
137
  Drop an image
188
138
  <div className="smallText">or</div>
@@ -198,34 +148,20 @@ const App: React.FC<AppProps> = ({
198
148
  <span className="onMobile">Take a picture</span>
199
149
  </label>
200
150
  <br />
201
- <label
202
- htmlFor="select_file"
203
- className="btn primary"
204
- style={{ width: "12em" }}
205
- >
206
- <span>Select a file</span>
151
+ <label htmlFor="select_file" className="btn primary" style={{width: '22em'}}>
152
+ <span>Select a file</span>
207
153
  </label>
208
- <label
209
- htmlFor="capture"
210
- className="mobileUploadHandler onMobile"
211
- />
154
+ <label htmlFor="capture" className="mobileUploadHandler onMobile"/>
212
155
  </section>
213
- <ExampleImages
214
- images={settings.exampleImages}
215
- onExampleImageClicked={handlers.onExampleImageClick}
216
- />
156
+ <ExampleImages images={settings.exampleImages} onExampleImageClicked={handlers.onExampleImageClick}/>
217
157
  </Box>
218
158
  </div>
219
159
  </div>
220
160
 
221
161
  <div className="headerSeparatorTop" />
222
162
  <div className="headerSeparatorBack" />
223
- <div
224
- className={classNames("tryDifferent", {
225
- hidden: showPart !== "results",
226
- })}
227
- onClick={handlers.onShowStart}
228
- >
163
+ <div className={classNames('tryDifferent', {hidden: showPart !== 'results'})}
164
+ onClick={handlers.onShowStart}>
229
165
  <div className="icIcon"></div>
230
166
  <div className="textDesc"> Try a different image</div>
231
167
  <br style={{ clear: "both" }} />
@@ -233,155 +169,92 @@ const App: React.FC<AppProps> = ({
233
169
  </div>
234
170
 
235
171
  <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">
245
- {errorMessage}
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>
172
+ className={classNames('results', {resultsActive: showPart === 'results'}, (results.length === 1 ? 'singleProduct' : 'multipleProducts'))}>
173
+ {errorMessage &&
174
+ <div className="errorMsg">
175
+ {errorMessage}
176
+ <div style={{textAlign: 'center', fontSize: '0.7em', paddingTop: '0.8em'}}><span>Make sure to include the request ID when reporting a problem: {requestId}</span>
177
+ </div>
257
178
  </div>
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" />
179
+ }
180
+ <Animate show={loading} start={{opacity: 0.0}} enter={{opacity: [1.0], timing: {duration: 300}}}
181
+ leave={{opacity: [0.0], timing: {duration: 300}}}>
182
+ {s =>
183
+ <div className="loadingOverlay" style={{...s}}>
184
+ <div className="loading"/>
185
+ </div>
186
+ }
187
+ </Animate>
188
+ {settings.preview && previewImage &&
189
+ <div className="preview">
190
+ <Preview key={previewImage.id}
191
+ maxWidth={document.body.clientWidth} maxHeight={maxPreviewHeight}
192
+ dotColor="#4C8F9F"
193
+ onSelectionChange={handlers.onSelectionChange} regions={regions}
194
+ selection={previewSelection} image={previewImage.canvas}/>
269
195
  </div>
270
- )}
271
- </Animate>
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
- )}
286
- <div className="predicted-categories">
287
- <PredictedCategories cs={categoryPredictions} />
288
- </div>
289
- <div className="predicted-categories">
290
- <Codes codes={codes} />
291
- </div>
292
- <CategoryFilter cats={filterOptions} />
196
+ }
197
+ <div className="predicted-categories">
198
+ <PredictedCategories cs={categoryPredictions}/>
199
+ </div>
200
+ <div className="predicted-categories">
201
+ <Codes codes={codes}/>
202
+ </div>
203
+ <CategoryFilter cats={filterOptions}/>
293
204
 
294
- <div className="wrapper">
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
309
- key={key}
310
- noImageUrl={settings.noImageUrl}
311
- template={settings.resultTemplate}
312
- onImageClick={handlers.onImageClick}
313
- onLinkClick={handlers.onLinkClick}
314
- result={data}
315
- style={{
316
- opacity: state.opacity,
317
- transform: `translateX(${state.translateX}%)`,
318
- }}
319
- />
320
- ))}
321
- </>
322
- )}
323
- </NodeGroup>
205
+ <div className="wrapper">
206
+ <NodeGroup data={results}
207
+ keyAccessor={r => r.sku}
208
+ start={(r, i) => ({opacity: 0, translateX: -100})}
209
+ enter={(r, i) => ({
210
+ opacity: [1],
211
+ translateX: [0],
212
+ timing: {delay: i * 100, duration: 300}
213
+ })}
214
+ >
215
+ {rs => <>{rs.map(({key, data, state}) => <Result
216
+ key={key}
217
+ noImageUrl={settings.noImageUrl}
218
+ template={settings.resultTemplate}
219
+ onImageClick={handlers.onImageClick}
220
+ onLinkClick={handlers.onLinkClick}
221
+ result={data}
222
+ style={{opacity: state.opacity, transform: `translateX(${state.translateX}%)`}}/>)}</>}
223
+ </NodeGroup>
324
224
 
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
- )}
225
+ {results.length === 0 && showPart === 'results' && !loading && (
333
226
 
334
- <br style={{ clear: "both" }} />
227
+ <div className="noResults">We did not find anything <span role="img"
228
+ aria-label="sad face">😕</span></div>
229
+ )}
335
230
 
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
- )}
231
+ <br style={{clear: 'both'}}/>
347
232
 
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}
233
+ {duration && showPart === 'results' && (<div style={{textAlign: 'center', fontSize: '0.7em', paddingTop: '0.8em'}}>Search
234
+ took {duration.toFixed(2)} seconds</div>)}
235
+
236
+ {requestId && showPart === 'results' && <div style={{textAlign: 'center', fontSize: '0.7em', paddingTop: '0.8em'}}>Request
237
+ identifier {requestId}</div>}
357
238
  </div>
358
- )}
359
- </div>
360
- </section>
239
+ </section>
240
+
241
+ <Snackbar open={toastOpen} autoHideDuration={3000} onClose={() => setToastOpen(false)}>
242
+ <Alert onClose={() => setToastOpen(false)} severity="error">
243
+ {toastErrorMessage}
244
+ </Alert>
245
+ </Snackbar>
361
246
 
362
- <Snackbar
363
- open={toastOpen}
364
- autoHideDuration={3000}
365
- onClose={() => setToastOpen(false)}
366
- >
367
- <Alert onClose={() => setToastOpen(false)} severity="error">
368
- {toastErrorMessage}
369
- </Alert>
370
- </Snackbar>
371
247
  </div>
372
248
  </div>
373
249
  <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
- />
250
+ <div className="wrapper">
251
+ © 2017 - 2019 <a href="https://nyris.io">nyris GmbH</a> - All rights reserved - <a
252
+ href="https://nyris.io/imprint/">Imprint</a>
253
+ </div>
254
+ </section>
255
+ <Feedback feedbackState={feedbackState} onPositiveFeedback={handlers.onPositiveFeedback}
256
+ onNegativeFeedback={handlers.onNegativeFeedback} onClose={handlers.onCloseFeedback}/>
257
+
385
258
  </React.Fragment>
386
259
  );
387
260
  };
@@ -279,16 +279,9 @@ function ADDtoSelectedfilters(
279
279
  key: string,
280
280
  value: string
281
281
  ): Map<string, string[]> {
282
- if (selectedFilters) {
283
- let values = selectedFilters.get(key);
284
- if (values) {
285
- values.push(value);
286
- } else {
287
- values = new Array<string>(value);
288
- }
289
- selectedFilters.set(key, values);
290
- }
291
- console.log(selectedFilters);
282
+ let values = selectedFilters.get(key) || new Array<string>();
283
+ values.push(value);
284
+ selectedFilters.set(key, values);
292
285
  return selectedFilters;
293
286
  }
294
287
 
@@ -297,26 +290,19 @@ function RemoveFromSelectedFilters(
297
290
  key: string,
298
291
  value: string
299
292
  ): Map<string, string[]> {
300
- if (selectedFilters) {
301
- let values = selectedFilters.get(key);
293
+ let values = selectedFilters.get(key);
302
294
  if (values) {
303
295
  values = values.filter((x) => x !== value);
304
296
  selectedFilters.set(key, values);
305
297
  }
306
- }
307
- console.log(selectedFilters);
298
+
308
299
  return selectedFilters;
309
300
  }
310
301
 
311
302
  function UpdateFilters(filters: Filter[], key: string, values: string[]) {
312
- console.log(filters);
313
- console.log(key);
314
- console.log(values);
315
- console.log(filters.find((x) => x.key === key));
316
303
  if (filters && filters.length > 0 && filters.find((x) => x.key === key)) {
317
304
  let idx = filters.findIndex((x) => x.key === key);
318
305
  filters[idx].values = values;
319
- console.log(filters);
320
306
  }
321
307
 
322
308
  return filters;
@@ -1,20 +1,17 @@
1
- import React from "react";
1
+ import React from 'react';
2
2
 
3
- const CategoryFilter = ({ cats }: { cats: string[] }) => {
4
- if (cats.length === 0) {
5
- return null;
6
- }
7
- return (
8
- <div id="catlist" style={{ textAlign: "center" }}>
9
- {
10
- cats.map((s) => (
11
- <a key={s} href="#top">
12
- {s}
13
- </a>
14
- )) // TODO fix link
15
- }
16
- </div>
17
- );
3
+
4
+ const CategoryFilter = ({cats}: {cats: string[]}) => {
5
+ if (cats.length === 0) {
6
+ return null;
7
+ }
8
+ return (
9
+ <div id="catlist" style={{'textAlign': 'center'}}>
10
+ {
11
+ cats.map((s) => <a key={s} href="#top">{s}</a>) // TODO fix link
12
+ }
13
+ </div>
14
+ );
18
15
  };
19
16
 
20
17
  export default CategoryFilter;
@@ -1,24 +1,20 @@
1
- import React from "react";
2
- import { Code } from "@nyris/nyris-api";
1
+ import React from 'react';
2
+ import {Code} from '@nyris/nyris-api';
3
3
 
4
4
  interface Props {
5
- codes: Code[];
5
+ codes: Code[]
6
6
  }
7
- const Codes = ({ codes }: Props) => (
8
- <>
9
- <div className="codes" style={{ textAlign: "center" }}>
10
- {codes.length > 0 && (
11
- <span style={{ fontSize: "0.8em" }}>
12
- Codes
13
- <br />{" "}
14
- </span>
15
- )}
16
- {codes.map((c, i) => (
17
- <small key={i} title={c.type}>
18
- {c.value}
19
- </small>
20
- ))}
21
- </div>
22
- </>
23
- );
7
+ const Codes = ({codes}: Props) =>
8
+ <>
9
+ <div className="codes" style={{textAlign: 'center'}}>
10
+ {codes.length > 0 && <span style={{fontSize: '0.8em'}}>Codes<br/> </span> }
11
+ {codes.map((c, i) =>
12
+ <small key={i} title={c.type}>
13
+ {c.value}
14
+ </small>)}
15
+ </div>
16
+ </>
17
+ ;
18
+
19
+
24
20
  export default Codes;