@nyris/nyris-webapp 0.3.9 → 0.3.12

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 (36) hide show
  1. package/build/asset-manifest.json +11 -11
  2. package/build/index.html +1 -1
  3. package/build/{precache-manifest.a97813497ab8d37548141e5e2618d0dc.js → precache-manifest.1b00dd5c15aa0815244681503d6fa9da.js} +9 -9
  4. package/build/service-worker.js +1 -1
  5. package/build/static/css/main.0c9239ba.chunk.css +2 -0
  6. package/build/static/css/main.0c9239ba.chunk.css.map +1 -0
  7. package/build/static/js/2.520bb6d6.chunk.js +3 -0
  8. package/build/static/js/{2.6e13adbe.chunk.js.LICENSE.txt → 2.520bb6d6.chunk.js.LICENSE.txt} +0 -0
  9. package/build/static/js/2.520bb6d6.chunk.js.map +1 -0
  10. package/build/static/js/main.ef6a9744.chunk.js +2 -0
  11. package/build/static/js/main.ef6a9744.chunk.js.map +1 -0
  12. package/package.json +2 -2
  13. package/src/App.tsx +333 -188
  14. package/src/actions/nyrisAppActions.ts +69 -65
  15. package/src/actions/searchActions.ts +301 -195
  16. package/src/components/CategoryFilter.tsx +16 -13
  17. package/src/components/Codes.tsx +20 -16
  18. package/src/components/ExampleImages.tsx +27 -17
  19. package/src/components/Feedback.tsx +78 -48
  20. package/src/components/FiltersList.tsx +113 -58
  21. package/src/components/Header.tsx +29 -17
  22. package/src/components/PredictedCategories.tsx +15 -12
  23. package/src/components/Result.tsx +186 -113
  24. package/src/components/SelectedFiltersSummary.tsx +85 -0
  25. package/src/components/Sidebar.tsx +44 -34
  26. package/src/epics/index.ts +173 -104
  27. package/src/epics/search.ts +214 -139
  28. package/src/index.css +95 -6
  29. package/src/index.tsx +147 -145
  30. package/src/utils.ts +5 -0
  31. package/build/static/css/main.0481043c.chunk.css +0 -2
  32. package/build/static/css/main.0481043c.chunk.css.map +0 -1
  33. package/build/static/js/2.6e13adbe.chunk.js +0 -3
  34. package/build/static/js/2.6e13adbe.chunk.js.map +0 -1
  35. package/build/static/js/main.f5da7aa4.chunk.js +0 -2
  36. package/build/static/js/main.f5da7aa4.chunk.js.map +0 -1
@@ -1,17 +1,20 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
 
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
- );
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
+ );
15
18
  };
16
19
 
17
20
  export default CategoryFilter;
@@ -1,20 +1,24 @@
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 && <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
-
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
+ );
20
24
  export default Codes;
@@ -1,24 +1,34 @@
1
- import React from 'react';
1
+ import React from "react";
2
2
 
3
3
  interface ExampleImagesProps {
4
- images: string[],
5
- onExampleImageClicked: (url: string) => void
4
+ images: string[];
5
+ onExampleImageClicked: (url: string) => void;
6
6
  }
7
7
 
8
- const ExampleImages : React.FC<ExampleImagesProps> = ({images, onExampleImageClicked}) => {
9
- if (images.length === 0) {
10
- return null;
11
- }
12
- return (
13
- <section className="useExampleImg">
14
- You can also try one of these pictures:
15
- <div className="exampleImages">
16
- <div className="exImagesWrap">
17
- {images.map((i) => (<img key={i} src={i} alt="" onClick={() => onExampleImageClicked(i)}/>))}
18
- </div>
19
- </div>
20
- </section>
21
- );
8
+ const ExampleImages: React.FC<ExampleImagesProps> = ({
9
+ images,
10
+ onExampleImageClicked,
11
+ }) => {
12
+ if (images.length === 0) {
13
+ return null;
14
+ }
15
+ return (
16
+ <section className="useExampleImg">
17
+ You can also try one of these pictures:
18
+ <div className="exampleImages">
19
+ <div className="exImagesWrap">
20
+ {images.map((i) => (
21
+ <img
22
+ key={i}
23
+ src={i}
24
+ alt=""
25
+ onClick={() => onExampleImageClicked(i)}
26
+ />
27
+ ))}
28
+ </div>
29
+ </div>
30
+ </section>
31
+ );
22
32
  };
23
33
 
24
34
  export default ExampleImages;
@@ -1,55 +1,85 @@
1
- import React from 'react';
2
- import {NyrisFeedbackState} from "../actions/nyrisAppActions";
3
- import {Animate} from "react-move";
1
+ import React from "react";
2
+ import { NyrisFeedbackState } from "../actions/nyrisAppActions";
3
+ import { Animate } from "react-move";
4
4
 
5
5
  interface FeedbackProps {
6
- feedbackState: NyrisFeedbackState,
7
- onPositiveFeedback?: () => void,
8
- onNegativeFeedback?: () => void,
9
- onClose?: () => void
6
+ feedbackState: NyrisFeedbackState;
7
+ onPositiveFeedback?: () => void;
8
+ onNegativeFeedback?: () => void;
9
+ onClose?: () => void;
10
10
  }
11
11
 
12
- const Feedback: React.FC<FeedbackProps> = ({feedbackState, onPositiveFeedback, onNegativeFeedback, onClose}) => {
13
- let inner : any = null;
14
- switch (feedbackState) {
15
- case 'question':
16
- inner =
17
- <div className="feedbackForm">
18
- <p>Did you find what you were looking for?</p>
19
- <div className="btn primary positiveFeedback" onClick={onPositiveFeedback}>Yes</div>
20
- <div className="btn secondary negativeFeedback" onClick={onNegativeFeedback}>No</div>
21
- </div>;
22
- break;
23
- case 'positive':
24
- inner = <div className="feedbackMessage positive">Great, thank you for your feedback!</div>
25
- break;
26
- case 'negative':
27
- inner =
28
- <div className="feedbackMessage negative">We saved your request so we can track down the
29
- issue and improve the search experience. Your Feedback helps us to make our service
30
- better for everyone,
31
- thank you!<br/>
32
- <div className="btn dismiss" onClick={onClose}>Dismiss</div>
33
- </div>;
34
- break;
35
- default:
36
- inner = null;
37
- break;
38
- }
39
- return (
40
- <Animate show={feedbackState !== 'hidden'} start={{y: 100, opacity: 0}} enter={{y: [0], opacity: [1]}} leave={{y: [100], opacity: [0] }}>
41
- {({y, opacity}) =>
42
- <section className="feedback" style={{transform: `translateY(${y}%)`, opacity }}>
43
- <div className="wrapper">
44
- {inner}
45
- </div>
46
- <div className="closeFeedbackContainer">
47
- <div className="closeFeedback" onClick={onClose}/>
48
- </div>
49
- </section>
50
- }
51
- </Animate>
52
- );
12
+ const Feedback: React.FC<FeedbackProps> = ({
13
+ feedbackState,
14
+ onPositiveFeedback,
15
+ onNegativeFeedback,
16
+ onClose,
17
+ }) => {
18
+ let inner: any = null;
19
+ switch (feedbackState) {
20
+ case "question":
21
+ inner = (
22
+ <div className="feedbackForm">
23
+ <p>Did you find what you were looking for?</p>
24
+ <div
25
+ className="btn primary positiveFeedback"
26
+ onClick={onPositiveFeedback}
27
+ >
28
+ Yes
29
+ </div>
30
+ <div
31
+ className="btn secondary negativeFeedback"
32
+ onClick={onNegativeFeedback}
33
+ >
34
+ No
35
+ </div>
36
+ </div>
37
+ );
38
+ break;
39
+ case "positive":
40
+ inner = (
41
+ <div className="feedbackMessage positive">
42
+ Great, thank you for your feedback!
43
+ </div>
44
+ );
45
+ break;
46
+ case "negative":
47
+ inner = (
48
+ <div className="feedbackMessage negative">
49
+ We saved your request so we can track down the issue and improve the
50
+ search experience. Your Feedback helps us to make our service better
51
+ for everyone, thank you!
52
+ <br />
53
+ <div className="btn dismiss" onClick={onClose}>
54
+ Dismiss
55
+ </div>
56
+ </div>
57
+ );
58
+ break;
59
+ default:
60
+ inner = null;
61
+ break;
62
+ }
63
+ return (
64
+ <Animate
65
+ show={feedbackState !== "hidden"}
66
+ start={{ y: 100, opacity: 0 }}
67
+ enter={{ y: [0], opacity: [1] }}
68
+ leave={{ y: [100], opacity: [0] }}
69
+ >
70
+ {({ y, opacity }) => (
71
+ <section
72
+ className="feedback"
73
+ style={{ transform: `translateY(${y}%)`, opacity }}
74
+ >
75
+ <div className="wrapper">{inner}</div>
76
+ <div className="closeFeedbackContainer">
77
+ <div className="closeFeedback" onClick={onClose} />
78
+ </div>
79
+ </section>
80
+ )}
81
+ </Animate>
82
+ );
53
83
  };
54
84
 
55
85
  export default Feedback;
@@ -1,67 +1,122 @@
1
-
2
- import React from 'react';
3
- import {Filter} from '../../../nyris-api/index';
4
- import { addToSelectedFilters, removeFromSelectedFilters } from '../actions/searchActions';
5
- import { useDispatch } from 'react-redux';
6
- import { RiLayoutGridLine} from 'react-icons/ri';
1
+ import React, { useEffect, useState } from "react";
2
+ import { Filter } from "@nyris/nyris-api";
3
+ import {
4
+ addToSelectedFilters,
5
+ removeFromSelectedFilters,
6
+ filterChanged,
7
+ searchFilters,
8
+ } from "../actions/searchActions";
9
+ import { useDispatch } from "react-redux";
10
+ import { RiArrowDropUpLine, RiArrowDropDownLine } from "react-icons/ri";
11
+ import { capitalizeFirstLetter } from "../utils";
12
+ import { AiOutlineSearch } from "react-icons/ai";
7
13
 
8
14
  interface FilterProps {
9
- filter : Filter,
10
- selectedValues?: string[]
15
+ filter: Filter;
16
+ selectedValues?: string[];
11
17
  }
12
18
 
13
-
14
-
15
- const FiltersList : React.FC<FilterProps> = ({filter, selectedValues})=>{
16
- const dispatch = useDispatch();
17
-
18
- const onFilterChanged=(e: React.ChangeEvent<HTMLInputElement>,value:string) =>{
19
- if (e.target.checked) {
20
- if(filter.key)
21
- dispatch(addToSelectedFilters(filter.key , value));
22
- } else {
23
- if(filter.key)
24
- dispatch(removeFromSelectedFilters(filter.key, value));
25
- }
19
+ const FiltersList: React.FC<FilterProps> = ({ filter, selectedValues }) => {
20
+ const dispatch = useDispatch();
21
+ const [isCollapsed, setIsCollapsed] = useState(false);
22
+ const [message, setMessage] = useState("");
23
+ const handleToggler = () => {
24
+ if (isCollapsed) {
25
+ setIsCollapsed(false);
26
+ return;
26
27
  }
27
-
28
- if(filter && filter.values && filter.key && filter.values.length > 0){
29
-
30
- return (
31
- <div>
32
- <div className='item'>
33
- <RiLayoutGridLine className="sidebar-icon" />
34
- <span className="sidebar-text"> {filter.key}</span>
35
- </div>
36
-
37
- <div className='item'>
38
- <div className="list-container">
39
-
40
- {filter.values.slice(0, 6).map((item, index) => {
41
- const checked = selectedValues && selectedValues.includes(item);
42
- return (
43
-
44
- <div key={index}>
45
-
46
- <input value={item} checked={checked ? true: false} type="checkbox" onChange={(e)=>onFilterChanged(e,item)} />
47
- <label className='itemLabel'>{item}</label>
48
- </div>
49
- )
50
- })}
51
- </div>
52
- </div>
53
-
54
- </div>
28
+ setIsCollapsed(true);
29
+ };
30
+ const onFilterChanged = (
31
+ e: React.ChangeEvent<HTMLInputElement>,
32
+ value: string
33
+ ) => {
34
+ if (e.target.checked) {
35
+ if (filter.key) dispatch(addToSelectedFilters(filter.key, value));
36
+ } else {
37
+ if (filter.key) dispatch(removeFromSelectedFilters(filter.key, value));
38
+ }
39
+ dispatch(filterChanged());
40
+ };
41
+ // 👇️ called every time input's value changes
42
+ const handleChangeOnSearchInputTyped = (
43
+ e: React.ChangeEvent<HTMLInputElement>
44
+ ) => {
45
+ setMessage(e.target.value);
46
+ };
47
+ const queryFilters = (key: string, value: string) => {
48
+ dispatch(searchFilters(key, value));
49
+ };
55
50
 
56
- );
51
+ useEffect(() => {
52
+ if (message === "") {
53
+ dispatch(searchFilters(filter.key!, ""));
57
54
  }
58
- else{
59
- return (
60
- <div>
61
- No filter to load
62
- </div>
55
+ }, [message, filter.key, dispatch]);
56
+ return (
57
+ <div>
58
+ <div className="item">
59
+ {/* <RiLayoutGridLine className="sidebar-icon" /> */}
60
+ <span className="sidebar-text">
61
+ {" "}
62
+ {capitalizeFirstLetter(filter.key!)}
63
+ </span>
64
+ <RiArrowDropUpLine
65
+ className={
66
+ isCollapsed ? "sidebar-icon" : "sidebar-icon collapsedHide"
67
+ }
68
+ onClick={() => handleToggler()}
69
+ />
70
+ <RiArrowDropDownLine
71
+ className={
72
+ isCollapsed ? "sidebar-icon collapsedHide" : "sidebar-icon"
73
+ }
74
+ onClick={() => handleToggler()}
75
+ />
76
+ </div>
77
+
78
+ <div
79
+ className={
80
+ isCollapsed ? "list-container" : "list-container collapsedHide"
81
+ }
82
+ >
83
+ <div className="searchBar">
84
+ <input
85
+ id="searchQueryInput"
86
+ name="searchQueryInput"
87
+ placeholder="Search"
88
+ value={message}
89
+ onChange={(e) => handleChangeOnSearchInputTyped(e)}
90
+ />
91
+ <button
92
+ id="searchQuerySubmit"
93
+ type="submit"
94
+ name="searchQuerySubmit"
95
+ onClick={() => queryFilters(filter.key!, message)}
96
+ >
97
+ <AiOutlineSearch />
98
+ </button>
99
+ </div>
100
+ {filter &&
101
+ filter.values &&
102
+ filter.values.length > 0 &&
103
+ filter.values.slice(0, 6).map((item, index) => {
104
+ const checked = selectedValues && selectedValues.includes(item);
105
+ return (
106
+ <div key={index}>
107
+ <input
108
+ value={item}
109
+ checked={checked ? true : false}
110
+ type="checkbox"
111
+ onChange={(e) => onFilterChanged(e, item)}
112
+ />
113
+ <span className="itemLabel">{item}</span>
114
+ </div>
115
+ );
116
+ })}
117
+ </div>
118
+ </div>
63
119
  );
64
- }
65
- }
120
+ };
66
121
 
67
- export default FiltersList;
122
+ export default FiltersList;
@@ -1,20 +1,32 @@
1
1
  import React from "react";
2
2
 
3
- const Header = () =>{
4
- return (
3
+ const Header = () => {
4
+ return (
5
5
  <div id="header">
6
-
7
- <section id="branding"></section>
8
- <div id="menu" className="menuWrap" role="navigation" >
9
- <ul>
10
- <li><a href="https://nyris.io/imprint/#privacy" target="_blank"
11
- rel="noopener noreferrer">Privacy Policy</a></li>
12
- <li><a href="https://nyris.io/" target="_blank" rel="noopener noreferrer">Visit our
13
- Website</a></li>
14
- </ul>
15
- </div>
16
- </div>
17
- );
18
-
19
- }
20
- export default Header;
6
+ <section id="branding"></section>
7
+ <div id="menu" className="menuWrap" role="navigation">
8
+ <ul>
9
+ <li>
10
+ <a
11
+ href="https://nyris.io/imprint/#privacy"
12
+ target="_blank"
13
+ rel="noopener noreferrer"
14
+ >
15
+ Privacy Policy
16
+ </a>
17
+ </li>
18
+ <li>
19
+ <a
20
+ href="https://nyris.io/"
21
+ target="_blank"
22
+ rel="noopener noreferrer"
23
+ >
24
+ Visit our Website
25
+ </a>
26
+ </li>
27
+ </ul>
28
+ </div>
29
+ </div>
30
+ );
31
+ };
32
+ export default Header;
@@ -1,14 +1,17 @@
1
- import React from 'react';
2
-
3
- const PredictedCategories = ({cs}: {cs: {name: string, score: number}[]}) =>
4
- <>
5
- {cs.map((c) =>
6
- <small key={c.name}>
7
- {c.name === "" ? "No category" : c.name.split(" > ").slice(-1)[0]}:
8
- {(c.score * 100).toFixed(0)}%
9
- </small>)}
10
- </>
11
- ;
12
-
1
+ import React from "react";
13
2
 
3
+ const PredictedCategories = ({
4
+ cs,
5
+ }: {
6
+ cs: { name: string; score: number }[];
7
+ }) => (
8
+ <>
9
+ {cs.map((c) => (
10
+ <small key={c.name}>
11
+ {c.name === "" ? "No category" : c.name.split(" > ").slice(-1)[0]}:
12
+ {(c.score * 100).toFixed(0)}%
13
+ </small>
14
+ ))}
15
+ </>
16
+ );
14
17
  export default PredictedCategories;