Skip to content

Commit 5e7cb9b

Browse files
committed
Advanced Sorting (End 5 Chapter)
1 parent 5e39a27 commit 5e7cb9b

File tree

5 files changed

+277
-23
lines changed

5 files changed

+277
-23
lines changed

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
"private": true,
55
"dependencies": {
66
"axios": "^0.18.0",
7+
"classnames": "^2.2.6",
8+
"lodash": "^4.17.11",
79
"react": "^16.8.4",
810
"react-dom": "^16.8.4",
911
"react-scripts": "2.1.8"

src/App.js

Lines changed: 120 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import React, { Component } from 'react';
22
import axios from 'axios';
3+
import { sortBy } from 'lodash';
4+
import classNames from 'classnames';
35
import './App.css';
46

57
const DEFAULT_QUERY = 'redux';
@@ -23,6 +25,14 @@ const smallColumn = {
2325
width: '10%',
2426
};
2527

28+
const SORTS = {
29+
NONE: list => list,
30+
TITLE: list => sortBy(list, 'title'),
31+
AUTHOR: list => sortBy(list, 'author'),
32+
COMMENTS: list => sortBy(list, 'num_comments').reverse(),
33+
POINTS: list => sortBy(list, 'points').reverse(),
34+
};
35+
2636
class App extends Component {
2737
constructor(props) {
2838
super(props);
@@ -33,6 +43,8 @@ class App extends Component {
3343
searchTerm: DEFAULT_QUERY,
3444
error: null,
3545
isLoading: false,
46+
sortKey: 'NONE',
47+
isSortReverse: false,
3648
};
3749

3850
this.needsToSearchTopStories = this.needsToSearchTopStories.bind(this);
@@ -41,6 +53,7 @@ class App extends Component {
4153
this.onSearchChange = this.onSearchChange.bind(this);
4254
this.onSearchSubmit = this.onSearchSubmit.bind(this);
4355
this.onDismiss = this.onDismiss.bind(this);
56+
this.onSort = this.onSort.bind(this);
4457
}
4558

4659
needsToSearchTopStories(searchTerm) {
@@ -113,13 +126,20 @@ class App extends Component {
113126
});
114127
}
115128

129+
onSort(sortKey) {
130+
const isSortReverse = this.state.sortKey === sortKey && !this.state.isSortReverse;
131+
this.setState({ sortKey, isSortReverse });
132+
}
133+
116134
render() {
117135
const {
118136
searchTerm,
119137
results,
120138
searchKey,
121139
error,
122-
isLoading
140+
isLoading,
141+
sortKey,
142+
isSortReverse
123143
} = this.state;
124144

125145
const page = (
@@ -151,6 +171,9 @@ class App extends Component {
151171
</div>
152172
: <Table
153173
list={list}
174+
sortKey={sortKey}
175+
isSortReverse={isSortReverse}
176+
onSort={this.onSort}
154177
onDismiss={this.onDismiss}
155178
/>
156179
}
@@ -184,34 +207,109 @@ const Search = ({
184207
</button>
185208
</form>
186209

187-
const Table = ({ list, onDismiss }) =>
188-
<div className="table">
189-
{list.map(item =>
190-
<div key={item.objectID} className="table-row">
191-
<span style={largeColumn}>
192-
<a href={item.url}>{item.title}</a>
193-
</span>
194-
<span style={midColumn}>
195-
{item.author}
210+
const Table = ({
211+
list,
212+
sortKey,
213+
isSortReverse,
214+
onSort,
215+
onDismiss
216+
}) => {
217+
const sortedList = SORTS[sortKey](list);
218+
const reverseSortedList = isSortReverse
219+
? sortedList.reverse()
220+
: sortedList;
221+
222+
return (
223+
<div className="table">
224+
<div className="table-header">
225+
<span style={{ width: '40%' }}>
226+
<Sort
227+
sortKey={'TITLE'}
228+
onSort={onSort}
229+
activeSortKey={sortKey}
230+
>
231+
Title
232+
</Sort>
196233
</span>
197-
<span style={smallColumn}>
198-
{item.num_comments}
234+
<span style={{ width: '30%' }}>
235+
<Sort
236+
sortKey={'AUTHOR'}
237+
onSort={onSort}
238+
activeSortKey={sortKey}
239+
>
240+
Author
241+
</Sort>
199242
</span>
200-
<span style={smallColumn}>
201-
{item.points}
243+
<span style={{ width: '10%' }}>
244+
<Sort
245+
sortKey={'COMMENTS'}
246+
onSort={onSort}
247+
activeSortKey={sortKey}
248+
>
249+
Comments
250+
</Sort>
202251
</span>
203-
<span style={smallColumn}>
204-
<Button
205-
onClick={() => onDismiss(item.objectID)}
206-
className="button-inline"
252+
<span style={{ width: '10%' }}>
253+
<Sort
254+
sortKey={'POINTS'}
255+
onSort={onSort}
256+
activeSortKey={sortKey}
207257
>
208-
Dismiss
209-
</Button>
258+
Points
259+
</Sort>
260+
</span>
261+
<span style={{ width: '10%' }}>
262+
Archive
210263
</span>
211264
</div>
212-
)}
213-
</div>
265+
{reverseSortedList.map(item =>
266+
<div key={item.objectID} className="table-row">
267+
<span style={largeColumn}>
268+
<a href={item.url}>{item.title}</a>
269+
</span>
270+
<span style={midColumn}>
271+
{item.author}
272+
</span>
273+
<span style={smallColumn}>
274+
{item.num_comments}
275+
</span>
276+
<span style={smallColumn}>
277+
{item.points}
278+
</span>
279+
<span style={smallColumn}>
280+
<Button
281+
onClick={() => onDismiss(item.objectID)}
282+
className="button-inline"
283+
>
284+
Dismiss
285+
</Button>
286+
</span>
287+
</div>
288+
)}
289+
</div>
290+
);
291+
}
214292

293+
const Sort = ({
294+
sortKey,
295+
activeSortKey,
296+
onSort,
297+
children
298+
}) => {
299+
const sortClass = classNames(
300+
'button-inline',
301+
{ 'button-active': sortKey === activeSortKey }
302+
);
303+
304+
return (
305+
<Button
306+
onClick={() => onSort(sortKey)}
307+
className={sortClass}
308+
>
309+
{children}
310+
</Button>
311+
);
312+
}
215313

216314
const Button = ({
217315
onClick,

src/App.test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ describe('Table', () => {
6868
{ title: '1', author: '1', num_comments: 1, points: 2, objectID: 'y' },
6969
{ title: '2', author: '2', num_comments: 1, points: 2, objectID: 'z' },
7070
],
71+
sortKey: 'TITLE',
72+
isSortReverse: false,
7173
};
7274

7375
it('renders without crashing', () => {

src/__snapshots__/App.test.js.snap

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,81 @@ exports[`App has a valid snapshot 1`] = `
2424
</div>
2525
<div
2626
className="table"
27-
/>
27+
>
28+
<div
29+
className="table-header"
30+
>
31+
<span
32+
style={
33+
Object {
34+
"width": "40%",
35+
}
36+
}
37+
>
38+
<button
39+
className="button-inline"
40+
onClick={[Function]}
41+
type="button"
42+
>
43+
Title
44+
</button>
45+
</span>
46+
<span
47+
style={
48+
Object {
49+
"width": "30%",
50+
}
51+
}
52+
>
53+
<button
54+
className="button-inline"
55+
onClick={[Function]}
56+
type="button"
57+
>
58+
Author
59+
</button>
60+
</span>
61+
<span
62+
style={
63+
Object {
64+
"width": "10%",
65+
}
66+
}
67+
>
68+
<button
69+
className="button-inline"
70+
onClick={[Function]}
71+
type="button"
72+
>
73+
Comments
74+
</button>
75+
</span>
76+
<span
77+
style={
78+
Object {
79+
"width": "10%",
80+
}
81+
}
82+
>
83+
<button
84+
className="button-inline"
85+
onClick={[Function]}
86+
type="button"
87+
>
88+
Points
89+
</button>
90+
</span>
91+
<span
92+
style={
93+
Object {
94+
"width": "10%",
95+
}
96+
}
97+
>
98+
Archive
99+
</span>
100+
</div>
101+
</div>
28102
<div
29103
className="interactions"
30104
>
@@ -61,6 +135,79 @@ exports[`Table has a valid snapshot 1`] = `
61135
<div
62136
className="table"
63137
>
138+
<div
139+
className="table-header"
140+
>
141+
<span
142+
style={
143+
Object {
144+
"width": "40%",
145+
}
146+
}
147+
>
148+
<button
149+
className="button-inline button-active"
150+
onClick={[Function]}
151+
type="button"
152+
>
153+
Title
154+
</button>
155+
</span>
156+
<span
157+
style={
158+
Object {
159+
"width": "30%",
160+
}
161+
}
162+
>
163+
<button
164+
className="button-inline"
165+
onClick={[Function]}
166+
type="button"
167+
>
168+
Author
169+
</button>
170+
</span>
171+
<span
172+
style={
173+
Object {
174+
"width": "10%",
175+
}
176+
}
177+
>
178+
<button
179+
className="button-inline"
180+
onClick={[Function]}
181+
type="button"
182+
>
183+
Comments
184+
</button>
185+
</span>
186+
<span
187+
style={
188+
Object {
189+
"width": "10%",
190+
}
191+
}
192+
>
193+
<button
194+
className="button-inline"
195+
onClick={[Function]}
196+
type="button"
197+
>
198+
Points
199+
</button>
200+
</span>
201+
<span
202+
style={
203+
Object {
204+
"width": "10%",
205+
}
206+
}
207+
>
208+
Archive
209+
</span>
210+
</div>
64211
<div
65212
className="table-row"
66213
>

0 commit comments

Comments
 (0)