App.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import React, { Component } from 'react';
  2. import logo from './logo.svg';
  3. import './App.css';
  4. function CategoryFlatList(props) {
  5. const { error, isLoaded, items } = props.state;
  6. var content;
  7. if (error) {
  8. content = <div>Error: {error.message}</div>
  9. } else if (!isLoaded) {
  10. content = <div>Loading</div>
  11. } else {
  12. content = (
  13. <select size="10" defaultValue="" onChange={props.onChange}>
  14. <option value="">[ANY]</option>
  15. {items.map(item => (
  16. <option key={item.item} value={item.item}>{item.item} - {item.count}</option>
  17. ))}
  18. </select>
  19. );
  20. }
  21. return (
  22. <div className="category-list">
  23. <h2>{props.title}</h2>
  24. {content}
  25. </div>
  26. );
  27. }
  28. class App extends Component {
  29. constructor(props) {
  30. super(props);
  31. this.categories = [{type: 'artist', title: 'Artists'},
  32. {type: 'year', title: 'Years'},
  33. {type: 'publisher', title: 'Labels'},
  34. {type: 'country', title: 'Countries'},
  35. {type: 'type', title: 'Album types'},
  36. {type: 'status', title: 'Album statuses'}];
  37. this.state = {};
  38. for (var {type} of this.categories) {
  39. this.state[type] = {
  40. error: null,
  41. isLoaded: false,
  42. items: []
  43. };
  44. }
  45. }
  46. fetchCategory(cat) {
  47. const {restrictions} = this.state;
  48. function getQueryString(params) {
  49. var esc = encodeURIComponent;
  50. return Object.keys(params)
  51. .map(k => esc(k) + '=' + esc(params[k]))
  52. .join('&');
  53. }
  54. const params = Object.assign({}, restrictions, {offset:0, limit:100});
  55. const qs = getQueryString(params);
  56. fetch('/cat/' + cat + (qs ? ('?' + qs) : ''))
  57. .then(res => (res.ok ? res.json() : Promise.reject({message:res.statusText})))
  58. .then(result => {
  59. this.setState({[cat]: {
  60. isLoaded: true,
  61. items: result
  62. }});
  63. })
  64. .catch(error => {
  65. this.setState({[cat]: {
  66. isLoaded: true,
  67. error: error
  68. }});
  69. })
  70. }
  71. fetchAll() {
  72. const {restrictions} = this.state;
  73. console.log(restrictions);
  74. this.categories.map(({type}) => !restrictions[type] && this.fetchCategory(type))
  75. }
  76. componentDidMount() {
  77. this.setState({restrictions: {}});
  78. }
  79. componentDidUpdate(prevProps, prevState) {
  80. if (this.state.restrictions !== prevState.restrictions) {
  81. // Reload category filters on restriction changes
  82. this.fetchAll();
  83. }
  84. }
  85. handleCategoryChange(type, value) {
  86. console.log(type, value);
  87. var restrictions = Object.assign({}, this.state.restrictions);
  88. if (value) {
  89. restrictions[type] = value;
  90. } else {
  91. delete restrictions[type];
  92. }
  93. this.setState({restrictions: restrictions});
  94. }
  95. render() {
  96. return (
  97. <div className="App">
  98. <header className="App-header">
  99. <img src={logo} className="App-logo" alt="logo" />
  100. <h1 className="App-title">Chad Music</h1>
  101. </header>
  102. {this.categories.map(({type, title}) => (
  103. <CategoryFlatList key={type} title={title} state={this.state[type]} onChange={e => this.handleCategoryChange(type, e.target.value)}/>
  104. ))}
  105. </div>
  106. );
  107. }
  108. }
  109. export default App;