AlbumPage.js 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import './AlbumPage.css';
  2. import { Link } from 'react-router5'
  3. import {useRouteNode} from 'react-router5'
  4. import {unslugify, formatDuration} from './utils.js';
  5. import {useReducer, useEffect} from 'react';
  6. import {fetchAlbums} from './AlbumList';
  7. import {fetchTracks} from './Album';
  8. function pageReducer(state, action) {
  9. switch (action.type) {
  10. case 'LOAD_ALBUMS':
  11. if (!action.payload.items || !action.payload.items.length)
  12. return {error: 'Not found'};
  13. const album = action.payload.items[0];
  14. return {...state, album};
  15. case 'SHOW_ALBUM':
  16. const tracks = action.payload.tracks;
  17. return {...state, tracks, loading: false};
  18. default: throw new Error(`Unknown action type: ${action.type}`);
  19. }
  20. }
  21. export default function AlbumPage({dispatch, scrollRef}) {
  22. const { route } = useRouteNode('album');
  23. const { artist: artistSlug, album: albumSlug } = route.params;
  24. const artistName = unslugify(artistSlug);
  25. const albumName = unslugify(albumSlug);
  26. const [{album, tracks, loading, error}, dispatchPage] = useReducer(pageReducer, {loading: true});
  27. useEffect(()=>{
  28. if (album)
  29. fetchTracks(album.id, 'SHOW_ALBUM', dispatchPage)
  30. else
  31. fetchAlbums({artist: artistName, album: albumName}, 0, dispatchPage);
  32. }, [artistName, albumName, album, dispatch]);
  33. return (
  34. <div className="AlbumPage">
  35. <h1>
  36. <Link routeName="artist" routeParams={{artist: artistSlug}}>
  37. {artistName}
  38. </Link>
  39. </h1>
  40. <h2>{albumName}</h2>{tracks && (<div className="Album-actions">
  41. <button onClick={(e)=>dispatch({type:'ALBUM_PLAY', payload: {tracks, pos: 0}})}>
  42. <svg viewBox="0 0 24 24"><g><path d="M8 5v14l11-7z"/></g></svg>
  43. </button>
  44. <button onClick={(e)=>dispatch({type: 'ALBUM_ENQUEUE', payload: {tracks}})}>
  45. <svg viewBox="0 0 24 24"><g><path d="M10 6h4v4h4v4h-4v4h-4v-4h-4v-4h4z"/></g></svg>
  46. </button>
  47. </div>)}
  48. {album && (<>
  49. {album.date && <h3>Date: {album.year}</h3>}
  50. {album.country && <h3>Country: {album.country}</h3>}
  51. {album.track_count && <h3>Tracks: {album.track_count}</h3>}
  52. {album.total_duration && <h3>Duration: {formatDuration(album.total_duration)}</h3>}
  53. {album.publisher && <h3>Publisher: {album.publisher}</h3>}
  54. {album.genre && <h3>Genre: {album.genre}</h3>}
  55. </>)}
  56. <Link routeName="browser">Browse</Link>
  57. {loading && <h3>Loading...</h3>}
  58. {error && <h3>{ error }</h3>}
  59. {tracks && (
  60. <table><tbody>
  61. {tracks.map((track, i) => (
  62. <tr key={i}>
  63. <td>{track.no}.</td>
  64. <td>{track.title}</td>
  65. <td>{track.bit_rate} kbps</td>
  66. <td>{formatDuration(track.duration)}</td>
  67. <td><button onClick={() => dispatch({type:'ALBUM_PLAY', payload: {tracks, pos: i}})}>
  68. <svg viewBox="0 0 24 24"><g><path d="M8 5v14l11-7z"/></g></svg>
  69. </button></td>
  70. </tr>))
  71. }
  72. </tbody></table>
  73. )}
  74. </div>
  75. );
  76. }