|
@@ -27,26 +27,55 @@ function CategoryFlatList(props) {
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-class App extends Component {
|
|
|
|
|
|
|
+function AlbumList(props) {
|
|
|
|
|
+ const { error, isLoaded, items } = props.state;
|
|
|
|
|
+
|
|
|
|
|
+ var content;
|
|
|
|
|
+ if (error) {
|
|
|
|
|
+ content = <div>Error: {error.message}</div>
|
|
|
|
|
+ } else if (!isLoaded) {
|
|
|
|
|
+ content = <div>Loading</div>
|
|
|
|
|
+ } else {
|
|
|
|
|
+ content = (
|
|
|
|
|
+ <ul>
|
|
|
|
|
+ {items.map(item => (
|
|
|
|
|
+ <li key={item.id}>{item.artist} - {item.year} - {item.album}</li>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div className="AlbumList">
|
|
|
|
|
+ <h2>{props.title}</h2>
|
|
|
|
|
+ {content}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class Player extends Component {
|
|
|
|
|
+ stateLoading = {
|
|
|
|
|
+ error: null,
|
|
|
|
|
+ isLoaded: false,
|
|
|
|
|
+ items: []
|
|
|
|
|
+ };
|
|
|
constructor(props) {
|
|
constructor(props) {
|
|
|
super(props);
|
|
super(props);
|
|
|
this.categories = [{type: 'artist', title: 'Artists'},
|
|
this.categories = [{type: 'artist', title: 'Artists'},
|
|
|
{type: 'year', title: 'Years'},
|
|
{type: 'year', title: 'Years'},
|
|
|
|
|
+ {type: 'genre', title: 'Genres'},
|
|
|
{type: 'publisher', title: 'Labels'},
|
|
{type: 'publisher', title: 'Labels'},
|
|
|
{type: 'country', title: 'Countries'},
|
|
{type: 'country', title: 'Countries'},
|
|
|
{type: 'type', title: 'Album types'},
|
|
{type: 'type', title: 'Album types'},
|
|
|
{type: 'status', title: 'Album statuses'}];
|
|
{type: 'status', title: 'Album statuses'}];
|
|
|
this.state = {};
|
|
this.state = {};
|
|
|
for (var {type} of this.categories) {
|
|
for (var {type} of this.categories) {
|
|
|
- this.state[type] = {
|
|
|
|
|
- error: null,
|
|
|
|
|
- isLoaded: false,
|
|
|
|
|
- items: []
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ this.state[type] = Object.assign({}, this.stateLoading);
|
|
|
}
|
|
}
|
|
|
|
|
+ this.state.album = Object.assign({}, this.stateLoading);
|
|
|
|
|
+ this.filterTimeout = null;
|
|
|
}
|
|
}
|
|
|
fetchCategory(cat) {
|
|
fetchCategory(cat) {
|
|
|
- const {restrictions} = this.state;
|
|
|
|
|
|
|
+ const {restrictions, filter} = this.state;
|
|
|
|
|
|
|
|
function getQueryString(params) {
|
|
function getQueryString(params) {
|
|
|
var esc = encodeURIComponent;
|
|
var esc = encodeURIComponent;
|
|
@@ -54,7 +83,10 @@ class App extends Component {
|
|
|
.map(k => esc(k) + '=' + esc(params[k]))
|
|
.map(k => esc(k) + '=' + esc(params[k]))
|
|
|
.join('&');
|
|
.join('&');
|
|
|
}
|
|
}
|
|
|
- const params = Object.assign({}, restrictions, {offset:0, limit:100});
|
|
|
|
|
|
|
+ var params = Object.assign({}, restrictions, {offset:0, limit:100});
|
|
|
|
|
+ if (cat === 'album' && filter) {
|
|
|
|
|
+ params.filter = filter;
|
|
|
|
|
+ }
|
|
|
const qs = getQueryString(params);
|
|
const qs = getQueryString(params);
|
|
|
|
|
|
|
|
fetch('/cat/' + cat + (qs ? ('?' + qs) : ''))
|
|
fetch('/cat/' + cat + (qs ? ('?' + qs) : ''))
|
|
@@ -70,20 +102,25 @@ class App extends Component {
|
|
|
isLoaded: true,
|
|
isLoaded: true,
|
|
|
error: error
|
|
error: error
|
|
|
}});
|
|
}});
|
|
|
- })
|
|
|
|
|
|
|
+ });
|
|
|
|
|
+ this.setState({[cat]: Object.assign({}, this.stateLoading)});
|
|
|
}
|
|
}
|
|
|
fetchAll() {
|
|
fetchAll() {
|
|
|
const {restrictions} = this.state;
|
|
const {restrictions} = this.state;
|
|
|
console.log(restrictions);
|
|
console.log(restrictions);
|
|
|
this.categories.map(({type}) => !restrictions[type] && this.fetchCategory(type))
|
|
this.categories.map(({type}) => !restrictions[type] && this.fetchCategory(type))
|
|
|
|
|
+ this.fetchCategory('album');
|
|
|
}
|
|
}
|
|
|
componentDidMount() {
|
|
componentDidMount() {
|
|
|
this.setState({restrictions: {}});
|
|
this.setState({restrictions: {}});
|
|
|
}
|
|
}
|
|
|
componentDidUpdate(prevProps, prevState) {
|
|
componentDidUpdate(prevProps, prevState) {
|
|
|
|
|
+ console.log('stateChange');
|
|
|
if (this.state.restrictions !== prevState.restrictions) {
|
|
if (this.state.restrictions !== prevState.restrictions) {
|
|
|
// Reload category filters on restriction changes
|
|
// Reload category filters on restriction changes
|
|
|
this.fetchAll();
|
|
this.fetchAll();
|
|
|
|
|
+ } else if (this.state.filter !== prevState.filter) {
|
|
|
|
|
+ this.fetchCategory('album');
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
handleCategoryChange(type, value) {
|
|
handleCategoryChange(type, value) {
|
|
@@ -96,6 +133,29 @@ class App extends Component {
|
|
|
}
|
|
}
|
|
|
this.setState({restrictions: restrictions});
|
|
this.setState({restrictions: restrictions});
|
|
|
}
|
|
}
|
|
|
|
|
+ handleFilterChange = (e) => {
|
|
|
|
|
+ if (this.filterTimeout) {
|
|
|
|
|
+ clearInterval(this.filterTimeout);
|
|
|
|
|
+ }
|
|
|
|
|
+ const value = e.target.value;
|
|
|
|
|
+ this.filterTimeout = setTimeout(() => this.setState({filter:value}), 500);
|
|
|
|
|
+ }
|
|
|
|
|
+ render() {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <div className="PlayerFilters">
|
|
|
|
|
+ {this.categories.map(({type, title}) => (
|
|
|
|
|
+ <CategoryFlatList key={type} title={title} state={this.state[type]} onChange={e => this.handleCategoryChange(type, e.target.value)}/>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div><div style={{clear:'both', paddingBottom:'20px'}}/>
|
|
|
|
|
+ <input type="text" placeholder="Search albums" onChange={this.handleFilterChange} size={150} />
|
|
|
|
|
+ <AlbumList title="Albums" state={this.state.album} />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class App extends Component {
|
|
|
render() {
|
|
render() {
|
|
|
return (
|
|
return (
|
|
|
<div className="App">
|
|
<div className="App">
|
|
@@ -103,9 +163,7 @@ class App extends Component {
|
|
|
<img src={logo} className="App-logo" alt="logo" />
|
|
<img src={logo} className="App-logo" alt="logo" />
|
|
|
<h1 className="App-title">Chad Music</h1>
|
|
<h1 className="App-title">Chad Music</h1>
|
|
|
</header>
|
|
</header>
|
|
|
- {this.categories.map(({type, title}) => (
|
|
|
|
|
- <CategoryFlatList key={type} title={title} state={this.state[type]} onChange={e => this.handleCategoryChange(type, e.target.value)}/>
|
|
|
|
|
- ))}
|
|
|
|
|
|
|
+ <Player/>
|
|
|
</div>
|
|
</div>
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|