Skip to content

Commit

Permalink
one file app with sort
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeyrudenko committed May 30, 2019
1 parent a3c0d2e commit e31fd22
Show file tree
Hide file tree
Showing 6 changed files with 439 additions and 36 deletions.
25 changes: 21 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"lodash": "^4.17.11",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1"
Expand All @@ -28,5 +29,8 @@
"last 1 safari version"
]
},
"proxy": "https://hn.algolia.com/api/v1/search?query=redux"
"proxy": "https://hn.algolia.com/api/v1/search?query=redux",
"devDependencies": {
"react-test-renderer": "^16.8.6"
}
}
6 changes: 6 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
text-align: center;
}

.loader {
text-align: center;
display: block;
border: 5px solid #38BB6C;
}

.table {
margin: 20px 0;
}
Expand Down
187 changes: 161 additions & 26 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React, { Component } from 'react';
// import ReactDOM from 'react-dom';
// import logo from './logo.svg';
import './App.css';
import { sortBy } from 'lodash';

const DEFAULT_QUERY = 'redux';
const DEFAULT_HPP = '2';

Expand All @@ -11,10 +13,23 @@ const PARAM_SEARCH = 'query=';
const PARAM_PAGE = 'page=';
const PARAM_HPP = 'hitsPerPage=';

const SORTS = {
NONE: list => list,
TITLE: list => sortBy(list, 'title'),
AUTHOR: list => sortBy(list, 'author'),
COMMENTS: list => sortBy(list, 'num_comments').reverse(),
POINTS: list => sortBy(list, 'points').reverse(),
};

// const isSearched = searchTerm => item =>
// item.title.toLowerCase().includes(searchTerm.toLowerCase());
const Loading = () =>
<div className="loader">Загрузка ...</div>

const withLoading = (Component) => ({ isLoading, ...rest }) =>
isLoading
? <Loading />
: <Component {...rest} />

class App extends Component {

Expand All @@ -24,7 +39,10 @@ class App extends Component {
results: null,
searchKey: '',
searchTerm: DEFAULT_QUERY,
isLoading: false,
error: null,
sortKey: 'NONE',
isSortReverse: false,
};

this.needsToSearchTopStories = this.needsToSearchTopStories.bind(this);
Expand All @@ -33,12 +51,18 @@ class App extends Component {
this.onSearchChange = this.onSearchChange.bind(this);
this.onSearchSubmit = this.onSearchSubmit.bind(this);
this.fetchSearchTopStories = this.fetchSearchTopStories.bind(this);
this.onSort = this.onSort.bind(this);
}

needsToSearchTopStories(searchTerm) {
return !this.state.results[searchTerm];
}

onSort(sortKey) {
const isSortReverse = this.state.sortKey === sortKey && !this.state.isSortReverse;
this.setState({ sortKey, isSortReverse });
}

setSearchTopStories(result) {
const { hits, page } = result;
const { searchKey, results } = this.state;
Expand All @@ -55,7 +79,8 @@ class App extends Component {
results: {
...results,
[searchKey]: { hits: updatedHits, page }
}
},
isLoading: false
});
}

Expand Down Expand Up @@ -86,6 +111,7 @@ class App extends Component {
}

fetchSearchTopStories(searchTerm, page = 0) {
this.setState({ isLoading: true });
fetch(`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${searchTerm}&${PARAM_PAGE}${page}&${PARAM_HPP}${DEFAULT_HPP}`)
.then(response => response.json())
.then(result => this.setSearchTopStories(result))
Expand All @@ -108,7 +134,10 @@ class App extends Component {
searchTerm,
results,
searchKey,
error
error,
isLoading,
sortKey,
isSortReverse,
} = this.state;

// if (error) {
Expand Down Expand Up @@ -144,42 +173,117 @@ class App extends Component {
<p>Something went wrong.</p>
</div>
: <Table
sortKey={sortKey}
onSort={this.onSort}
list={list}
onDismiss={this.onDismiss}
isSortReverse={isSortReverse}
/>
}
<div className="interactions">
<Button onClick={() => this.fetchSearchTopStories(searchKey, page + 1)}>
Больше историй
</Button>
<ButtonWithLoading
onClick={() => this.fetchSearchTopStories(searchKey, page + 1)}
isLoading={isLoading}
>
More
</ButtonWithLoading>

</div>
</div>
);
}
}

const Search = ({
value,
onChange,
onSubmit,
children
}) =>
<form onSubmit={onSubmit}>
<input
type="text"
value={value}
onChange={onChange}
/>
<button type="submit">
{children}
</button>
</form>

class Search extends Component {
componentDidMount() {
if (this.input) {
this.input.focus();
}
}
render() {
const {
value,
onChange,
onSubmit,
children
} = this.props;
return (
<form onSubmit={onSubmit}>
<input
type="text"
value={value}
onChange={onChange}
ref={(node) => { this.input = node; }}
/>
<button type="submit">
{children}
</button>
</form>
);
}
}

const Table = ({ list = [], onDismiss }) =>
<div className="table">




const Table = ({
list,
sortKey,
isSortReverse,
onSort,
onDismiss
}) => {
const sortedList = SORTS[sortKey](list);
const reverseSortedList = isSortReverse
? sortedList.reverse()
: sortedList;

return (<div className="table">
{/* {list.filter(isSearched(pattern)).map(item => */}
{list.map(item =>
<div className="table-header">
<span style={{ width: '40%' }}>
<Sort
sortKey={'TITLE'}
onSort={onSort}
activeSortKey={sortKey}
>
Заголовок
</Sort>
</span>
<span style={{ width: '30%' }}>
<Sort
sortKey={'AUTHOR'}
onSort={onSort}
activeSortKey={sortKey}
>
Автор
</Sort>
</span>
<span style={{ width: '10%' }}>
<Sort
sortKey={'COMMENTS'}
onSort={onSort}
activeSortKey={sortKey}
>
Комментарии
</Sort>
</span>
<span style={{ width: '10%' }}>
<Sort
sortKey={'POINTS'}
onSort={onSort}
activeSortKey={sortKey}
>
Очки
</Sort>
</span>
<span style={{ width: '10%' }}>
Архив
</span>
</div>
{reverseSortedList.map(item =>
<div key={item.objectID} className="table-row">
<span style={{ width: '40%' }}>
<a href={item.url}>{item.title}</a>
Expand All @@ -204,8 +308,8 @@ const Table = ({ list = [], onDismiss }) =>
</span>
</div>
)}
</div>

</div>);
}

const Button = ({ onClick, className = '', children }) =>
<button
Expand All @@ -216,4 +320,35 @@ const Button = ({ onClick, className = '', children }) =>
{children}
</button>

const Sort = ({
sortKey,
activeSortKey,
onSort,
children
}) => {
const sortClass = ['button-inline'];
if (sortKey === activeSortKey) {
sortClass.push('button-active');
}
return (
<Button
onClick={() => onSort(sortKey)}
className={sortClass.join(' ')}
>
{children}
</Button>
);
}



const ButtonWithLoading = withLoading(Button);

export default App;

export {
Button,
Search,
Table,
};

Loading

0 comments on commit e31fd22

Please sign in to comment.