@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.
- package/build/asset-manifest.json +11 -11
- package/build/index.html +1 -1
- package/build/{precache-manifest.a97813497ab8d37548141e5e2618d0dc.js → precache-manifest.1b00dd5c15aa0815244681503d6fa9da.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.6e13adbe.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.ef6a9744.chunk.js +2 -0
- package/build/static/js/main.ef6a9744.chunk.js.map +1 -0
- package/package.json +2 -2
- package/src/App.tsx +333 -188
- package/src/actions/nyrisAppActions.ts +69 -65
- package/src/actions/searchActions.ts +301 -195
- 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 +113 -58
- 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 +85 -0
- package/src/components/Sidebar.tsx +44 -34
- package/src/epics/index.ts +173 -104
- package/src/epics/search.ts +214 -139
- package/src/index.css +95 -6
- package/src/index.tsx +147 -145
- package/src/utils.ts +5 -0
- package/build/static/css/main.0481043c.chunk.css +0 -2
- package/build/static/css/main.0481043c.chunk.css.map +0 -1
- package/build/static/js/2.6e13adbe.chunk.js +0 -3
- package/build/static/js/2.6e13adbe.chunk.js.map +0 -1
- package/build/static/js/main.f5da7aa4.chunk.js +0 -2
- package/build/static/js/main.f5da7aa4.chunk.js.map +0 -1
|
@@ -1,137 +1,210 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import {OfferNyrisResult as ResultData} from "@nyris/nyris-api";
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { OfferNyrisResult as ResultData } from "@nyris/nyris-api";
|
|
3
3
|
|
|
4
4
|
// TODO this needs refactoring: Make it one block with parameters for first line, second line, image url ..
|
|
5
5
|
|
|
6
6
|
interface Options {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
result: any;
|
|
8
|
+
noImageUrl: string;
|
|
9
|
+
onImageClick: (e: React.MouseEvent) => void;
|
|
10
|
+
onLinkClick: (e: React.MouseEvent) => void;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const renderPrice = (result: ResultData) =>
|
|
14
|
-
|
|
14
|
+
result.p ? "" + (result.p.vi / 100).toFixed(2) + " " + result.p.c : "";
|
|
15
15
|
|
|
16
|
-
const renderDefault = ({
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<div className="imgWrap">
|
|
24
|
-
<img src={(result.img && result.img.url + '?r=512x512') || noImageUrl} alt={result.title}/>
|
|
25
|
-
</div>
|
|
26
|
-
</div>
|
|
27
|
-
</a>
|
|
28
|
-
<div className="prdctDetailsWrap">
|
|
29
|
-
<div>
|
|
30
|
-
<div className="prdctTitle">{result.title}</div>
|
|
31
|
-
<div className="prdctMeta">
|
|
32
|
-
<span className="prdctPrice">{renderPrice(result)}</span>
|
|
33
|
-
</div>
|
|
34
|
-
<a onClick={onLinkClick} onAuxClick={onLinkClick} className="prdctShopLink" href={result.l}
|
|
35
|
-
target="_blank" rel="noopener noreferrer">Buy Now</a>
|
|
36
|
-
</div>
|
|
37
|
-
</div>
|
|
38
|
-
</>
|
|
39
|
-
);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const renderSnr = ({result, noImageUrl, onImageClick, onLinkClick}: Options) => (
|
|
16
|
+
const renderDefault = ({
|
|
17
|
+
result,
|
|
18
|
+
noImageUrl,
|
|
19
|
+
onImageClick,
|
|
20
|
+
onLinkClick,
|
|
21
|
+
}: Options) => {
|
|
22
|
+
return (
|
|
43
23
|
<>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
<div className="
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
24
|
+
<a
|
|
25
|
+
href={result.l}
|
|
26
|
+
className="imageLink"
|
|
27
|
+
title="Click the image so see similar products"
|
|
28
|
+
onClick={onImageClick}
|
|
29
|
+
onAuxClick={onLinkClick}
|
|
30
|
+
>
|
|
31
|
+
<div className="prdctImg">
|
|
32
|
+
<div className="imgWrap">
|
|
33
|
+
<img
|
|
34
|
+
src={(result.img && result.img.url + "?r=512x512") || noImageUrl}
|
|
35
|
+
alt={result.title}
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</a>
|
|
40
|
+
<div className="prdctDetailsWrap">
|
|
41
|
+
<div>
|
|
42
|
+
<div className="prdctTitle">{result.title}</div>
|
|
43
|
+
<div className="prdctMeta">
|
|
44
|
+
<span className="prdctPrice">{renderPrice(result)}</span>
|
|
45
|
+
</div>
|
|
46
|
+
<a
|
|
47
|
+
onClick={onLinkClick}
|
|
48
|
+
onAuxClick={onLinkClick}
|
|
49
|
+
className="prdctShopLink"
|
|
50
|
+
href={result.l}
|
|
51
|
+
target="_blank"
|
|
52
|
+
rel="noopener noreferrer"
|
|
53
|
+
>
|
|
54
|
+
Buy Now
|
|
55
|
+
</a>
|
|
61
56
|
</div>
|
|
57
|
+
</div>
|
|
62
58
|
</>
|
|
63
|
-
);
|
|
59
|
+
);
|
|
60
|
+
};
|
|
64
61
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
const renderSnr = ({
|
|
63
|
+
result,
|
|
64
|
+
noImageUrl,
|
|
65
|
+
onImageClick,
|
|
66
|
+
onLinkClick,
|
|
67
|
+
}: Options) => (
|
|
68
|
+
<>
|
|
69
|
+
<a
|
|
70
|
+
href={result.l}
|
|
71
|
+
className="imageLink"
|
|
72
|
+
onClick={onImageClick}
|
|
73
|
+
onAuxClick={onLinkClick}
|
|
74
|
+
>
|
|
75
|
+
<div className="prdctImg">
|
|
76
|
+
<div className="imgWrap">
|
|
77
|
+
<img
|
|
78
|
+
src={(result.img && result.img.url + "?r=512x512") || noImageUrl}
|
|
79
|
+
alt={result.title}
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</a>
|
|
84
|
+
<div className="prdctDetailsWrap">
|
|
85
|
+
<div>
|
|
86
|
+
<div className="prdctTitle">{result.sku}</div>
|
|
87
|
+
<div
|
|
88
|
+
className="prdctMeta"
|
|
89
|
+
style={{ height: "5em", whiteSpace: "normal" }}
|
|
90
|
+
>
|
|
91
|
+
{result.title}
|
|
92
|
+
</div>
|
|
93
|
+
<a
|
|
94
|
+
style={{ backgroundImage: "none", paddingLeft: "10px" }}
|
|
95
|
+
className="prdctShopLink"
|
|
96
|
+
href={result.l}
|
|
97
|
+
target="_blank"
|
|
98
|
+
rel="noopener noreferrer"
|
|
99
|
+
onClick={onLinkClick}
|
|
100
|
+
onAuxClick={onLinkClick}
|
|
101
|
+
>
|
|
102
|
+
Info
|
|
74
103
|
</a>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</>
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const renderSnrMultilink = (
|
|
110
|
+
{ result, noImageUrl, onImageClick }: Options,
|
|
111
|
+
onLinkClick: (url: string) => void
|
|
112
|
+
) => (
|
|
113
|
+
<>
|
|
114
|
+
<a
|
|
115
|
+
href={result.l}
|
|
116
|
+
className="imageLink"
|
|
117
|
+
onClick={onImageClick}
|
|
118
|
+
onAuxClick={onImageClick}
|
|
119
|
+
>
|
|
120
|
+
<div className="prdctImg">
|
|
121
|
+
<div className="imgWrap">
|
|
122
|
+
<img
|
|
123
|
+
src={(result.img && result.img.url + "?r=512x512") || noImageUrl}
|
|
124
|
+
alt={result.title}
|
|
125
|
+
/>
|
|
88
126
|
</div>
|
|
89
|
-
|
|
127
|
+
</div>
|
|
128
|
+
</a>
|
|
129
|
+
<div className="prdctDetailsWrap">
|
|
130
|
+
<div>
|
|
131
|
+
<div className="prdctTitle">{result.sku}</div>
|
|
132
|
+
<div
|
|
133
|
+
className="prdctMeta"
|
|
134
|
+
style={{ height: "5em", whiteSpace: "normal" }}
|
|
135
|
+
>
|
|
136
|
+
{result.title}
|
|
137
|
+
</div>
|
|
138
|
+
{result.l.map((l: { text: string; href: string }) => (
|
|
139
|
+
<a
|
|
140
|
+
style={{ backgroundImage: "none", paddingLeft: "10px" }}
|
|
141
|
+
className="prdctShopLink"
|
|
142
|
+
href={l.href}
|
|
143
|
+
onClick={() => onLinkClick(l.href)}
|
|
144
|
+
onAuxClick={() => onLinkClick(l.href)}
|
|
145
|
+
target="_blank"
|
|
146
|
+
key={l.href}
|
|
147
|
+
rel="noopener noreferrer"
|
|
148
|
+
>
|
|
149
|
+
{l.text}
|
|
150
|
+
</a>
|
|
151
|
+
))}
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
</>
|
|
90
155
|
);
|
|
91
156
|
|
|
92
157
|
export interface ResultProps {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
158
|
+
result: any;
|
|
159
|
+
style: any;
|
|
160
|
+
template?: string;
|
|
161
|
+
onImageClick: (pos: number, url: string) => void;
|
|
162
|
+
onLinkClick: (pos: number, url: string) => void;
|
|
163
|
+
noImageUrl?: string;
|
|
99
164
|
}
|
|
100
165
|
|
|
101
|
-
const Result: React.FC<ResultProps> = ({
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
166
|
+
const Result: React.FC<ResultProps> = ({
|
|
167
|
+
result,
|
|
168
|
+
style,
|
|
169
|
+
template,
|
|
170
|
+
onImageClick,
|
|
171
|
+
onLinkClick,
|
|
172
|
+
noImageUrl,
|
|
173
|
+
}) => {
|
|
174
|
+
let options: Options = {
|
|
175
|
+
onImageClick: (e: React.MouseEvent) => {
|
|
176
|
+
e.preventDefault();
|
|
177
|
+
onImageClick(result.position, result.img.url);
|
|
178
|
+
},
|
|
179
|
+
onLinkClick: (e: React.MouseEvent) => {
|
|
180
|
+
e.preventDefault();
|
|
181
|
+
onLinkClick(result.position, result.l);
|
|
182
|
+
},
|
|
183
|
+
noImageUrl: noImageUrl || "images/ic_cam_large_noimage.png",
|
|
184
|
+
result,
|
|
185
|
+
};
|
|
114
186
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
187
|
+
let resultInner = null;
|
|
188
|
+
switch (template) {
|
|
189
|
+
case "snr":
|
|
190
|
+
resultInner = renderSnr(options);
|
|
191
|
+
break;
|
|
192
|
+
case "snr-multilink":
|
|
193
|
+
resultInner = renderSnrMultilink(options, (url) =>
|
|
194
|
+
onLinkClick(result.position, url)
|
|
195
|
+
);
|
|
196
|
+
break;
|
|
197
|
+
case "default":
|
|
198
|
+
default:
|
|
199
|
+
resultInner = renderDefault(options);
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
128
202
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
203
|
+
return (
|
|
204
|
+
<div className="prdctItem" style={{ ...style }}>
|
|
205
|
+
{resultInner}
|
|
206
|
+
</div>
|
|
207
|
+
);
|
|
134
208
|
};
|
|
135
209
|
|
|
136
|
-
|
|
137
210
|
export default Result;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { BsX } from "react-icons/bs";
|
|
3
|
+
import { connect, ConnectedProps, useDispatch } from "react-redux";
|
|
4
|
+
import { AppState } from "../types";
|
|
5
|
+
import { capitalizeFirstLetter } from "../utils";
|
|
6
|
+
import {
|
|
7
|
+
removeFromSelectedFilters,
|
|
8
|
+
clearAllSelectedFilters,
|
|
9
|
+
filterChanged,
|
|
10
|
+
} from "../actions/searchActions";
|
|
11
|
+
|
|
12
|
+
const SelectedFiltersSummary: React.FC<selectedFiltersSummaryProps> = ({
|
|
13
|
+
search,
|
|
14
|
+
}) => {
|
|
15
|
+
const dispatch = useDispatch();
|
|
16
|
+
const handleRemoveFilterButtonClick = (key: string, value: string) => {
|
|
17
|
+
dispatch(removeFromSelectedFilters(key, value));
|
|
18
|
+
dispatch(filterChanged());
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const clearAllSelectedFiltersFromList = () => {
|
|
22
|
+
dispatch(clearAllSelectedFilters());
|
|
23
|
+
dispatch(filterChanged());
|
|
24
|
+
};
|
|
25
|
+
const selectedValues = ([] as string[]).concat.apply(
|
|
26
|
+
[],
|
|
27
|
+
Array.from(search.selectedFilters.values())
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div className="wrap-box-refinements">
|
|
32
|
+
<ul>
|
|
33
|
+
{Array.from(search.selectedFilters.keys()).map(
|
|
34
|
+
(filterKey) =>
|
|
35
|
+
search.selectedFilters.get(filterKey) &&
|
|
36
|
+
search.selectedFilters.get(filterKey)!.map((val) => {
|
|
37
|
+
return (
|
|
38
|
+
<li>
|
|
39
|
+
<button
|
|
40
|
+
onClick={() =>
|
|
41
|
+
handleRemoveFilterButtonClick(filterKey, val)
|
|
42
|
+
}
|
|
43
|
+
>
|
|
44
|
+
<span className="summary-label">
|
|
45
|
+
<div className="summary-label-key-text">
|
|
46
|
+
{capitalizeFirstLetter(val)}
|
|
47
|
+
<BsX />
|
|
48
|
+
</div>
|
|
49
|
+
</span>
|
|
50
|
+
</button>
|
|
51
|
+
</li>
|
|
52
|
+
);
|
|
53
|
+
})
|
|
54
|
+
)}
|
|
55
|
+
<li>
|
|
56
|
+
<button
|
|
57
|
+
className={
|
|
58
|
+
search.selectedFilters &&
|
|
59
|
+
search.selectedFilters.size > 0 &&
|
|
60
|
+
selectedValues &&
|
|
61
|
+
selectedValues.length > 0
|
|
62
|
+
? "clear-all-filters "
|
|
63
|
+
: "clear-all-filters-hidden"
|
|
64
|
+
}
|
|
65
|
+
onClick={() => clearAllSelectedFiltersFromList()}
|
|
66
|
+
>
|
|
67
|
+
{" "}
|
|
68
|
+
Clear All{" "}
|
|
69
|
+
</button>
|
|
70
|
+
</li>
|
|
71
|
+
</ul>
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const mapStateToProps = (state: AppState) => ({
|
|
77
|
+
showPart: state.nyrisDesign.showPart,
|
|
78
|
+
search: {
|
|
79
|
+
filters: state.search.filters,
|
|
80
|
+
selectedFilters: state.search.selectedFilters,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
const connector = connect(mapStateToProps);
|
|
84
|
+
type selectedFiltersSummaryProps = ConnectedProps<typeof connector>;
|
|
85
|
+
export default connect(mapStateToProps)(SelectedFiltersSummary);
|
|
@@ -1,42 +1,52 @@
|
|
|
1
|
-
import React, { useState } from
|
|
2
|
-
import {RiMenuLine} from
|
|
3
|
-
import { Filter } from
|
|
4
|
-
import
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { RiMenuLine } from "react-icons/ri";
|
|
3
|
+
import { Filter } from "../../../nyris-api/index";
|
|
4
|
+
import FiltersList from "./FiltersList";
|
|
5
5
|
|
|
6
6
|
interface SidebarProps {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
filters: Filter[];
|
|
8
|
+
selectedFilters: Map<string, string[]>;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
const Sidebar: React.FC<SidebarProps> = ({filters, selectedFilters}) =>{
|
|
11
|
+
const Sidebar: React.FC<SidebarProps> = ({ filters, selectedFilters }) => {
|
|
12
|
+
console.log(filters);
|
|
12
13
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
13
|
-
const handleToggler =()=>{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
14
|
+
const handleToggler = () => {
|
|
15
|
+
if (isExpanded) {
|
|
16
|
+
setIsExpanded(false);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
setIsExpanded(true);
|
|
20
|
+
};
|
|
20
21
|
return (
|
|
21
|
-
|
|
22
|
-
<div
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
22
|
+
<div className={isExpanded ? "sidebar" : "Sidebar collapsed"}>
|
|
23
|
+
<div
|
|
24
|
+
className={
|
|
25
|
+
isExpanded ? "sidebarContent" : "sidebarContent overflowHidden"
|
|
26
|
+
}
|
|
27
|
+
>
|
|
28
|
+
<div className="sidebarHeader">
|
|
29
|
+
<RiMenuLine className="sidebar-icon" onClick={handleToggler} />
|
|
30
|
+
{/* <h1 className={isExpanded ? "sidebar-logo" : "sidebar-logo collapsedHide"}> Filters </h1>
|
|
31
|
+
*/}
|
|
32
|
+
</div>
|
|
33
|
+
<div
|
|
34
|
+
className={
|
|
35
|
+
isExpanded ? "Sidebar-items" : "Sidebar-items collapsedHide"
|
|
36
|
+
}
|
|
37
|
+
>
|
|
38
|
+
{filters &&
|
|
39
|
+
filters.map((x) => {
|
|
40
|
+
let selectedValues = x.key
|
|
41
|
+
? selectedFilters.get(x.key)
|
|
42
|
+
: undefined;
|
|
43
|
+
return <FiltersList filter={x} selectedValues={selectedValues} />;
|
|
44
|
+
})}
|
|
45
|
+
{/* <FiltersList2/> */}
|
|
46
|
+
</div>
|
|
36
47
|
</div>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
41
51
|
|
|
42
|
-
export default Sidebar
|
|
52
|
+
export default Sidebar;
|