From 27778518893eeac76e0c3d6a68c00a677a0c3120 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Fri, 19 Nov 2021 17:24:30 +1300 Subject: [PATCH] Restructuring and functional component-ifying --- src/js/App.js | 22 +-- src/js/components/Fields/SearchForm.js | 146 ++++++---------- src/js/components/Header.js | 6 +- src/js/services/ui/reducer.js | 13 +- src/js/views/Artist.js | 17 +- .../ArtistAbout.js => Artist/About.js} | 6 +- .../ArtistRelated.js => Artist/Related.js} | 0 .../ArtistTracks.js => Artist/Tracks.js} | 0 .../DiscoverCategories.js | 5 +- .../DiscoverCategory.js | 0 .../DiscoverFeatured.js | 0 .../DiscoverNewReleases.js | 0 .../DiscoverRecommendations.js | 0 .../{library => Library}/LibraryAlbums.js | 0 .../{library => Library}/LibraryArtists.js | 0 .../{library => Library}/LibraryBrowse.js | 0 .../LibraryBrowseDirectory.js | 0 .../{library => Library}/LibraryPlaylists.js | 0 .../{library => Library}/LibraryTracks.js | 0 src/js/views/subviews/ArtistOverview.js | 160 ------------------ 20 files changed, 89 insertions(+), 286 deletions(-) rename src/js/views/{subviews/ArtistAbout.js => Artist/About.js} (95%) rename src/js/views/{subviews/ArtistRelated.js => Artist/Related.js} (100%) rename src/js/views/{subviews/ArtistTracks.js => Artist/Tracks.js} (100%) rename src/js/views/{discover => Discover}/DiscoverCategories.js (92%) rename src/js/views/{discover => Discover}/DiscoverCategory.js (100%) rename src/js/views/{discover => Discover}/DiscoverFeatured.js (100%) rename src/js/views/{discover => Discover}/DiscoverNewReleases.js (100%) rename src/js/views/{discover => Discover}/DiscoverRecommendations.js (100%) rename src/js/views/{library => Library}/LibraryAlbums.js (100%) rename src/js/views/{library => Library}/LibraryArtists.js (100%) rename src/js/views/{library => Library}/LibraryBrowse.js (100%) rename src/js/views/{library => Library}/LibraryBrowseDirectory.js (100%) rename src/js/views/{library => Library}/LibraryPlaylists.js (100%) rename src/js/views/{library => Library}/LibraryTracks.js (100%) delete mode 100644 src/js/views/subviews/ArtistOverview.js diff --git a/src/js/App.js b/src/js/App.js index 1920d8ab..44d06d76 100755 --- a/src/js/App.js +++ b/src/js/App.js @@ -28,18 +28,18 @@ import Debug from './views/Debug'; import Search from './views/Search'; import Settings from './views/Settings'; -import DiscoverRecommendations from './views/discover/DiscoverRecommendations'; -import DiscoverFeatured from './views/discover/DiscoverFeatured'; -import DiscoverCategories from './views/discover/DiscoverCategories'; -import DiscoverCategory from './views/discover/DiscoverCategory'; -import DiscoverNewReleases from './views/discover/DiscoverNewReleases'; +import DiscoverRecommendations from './views/Discover/DiscoverRecommendations'; +import DiscoverFeatured from './views/Discover/DiscoverFeatured'; +import DiscoverCategories from './views/Discover/DiscoverCategories'; +import DiscoverCategory from './views/Discover/DiscoverCategory'; +import DiscoverNewReleases from './views/Discover/DiscoverNewReleases'; -import LibraryArtists from './views/library/LibraryArtists'; -import LibraryAlbums from './views/library/LibraryAlbums'; -import LibraryTracks from './views/library/LibraryTracks'; -import LibraryPlaylists from './views/library/LibraryPlaylists'; -import LibraryBrowse from './views/library/LibraryBrowse'; -import LibraryBrowseDirectory from './views/library/LibraryBrowseDirectory'; +import LibraryArtists from './views/Library/LibraryArtists'; +import LibraryAlbums from './views/Library/LibraryAlbums'; +import LibraryTracks from './views/Library/LibraryTracks'; +import LibraryPlaylists from './views/Library/LibraryPlaylists'; +import LibraryBrowse from './views/Library/LibraryBrowse'; +import LibraryBrowseDirectory from './views/Library/LibraryBrowseDirectory'; import EditPlaylist from './views/modals/EditPlaylist'; import CreatePlaylist from './views/modals/CreatePlaylist'; diff --git a/src/js/components/Fields/SearchForm.js b/src/js/components/Fields/SearchForm.js index 4ae5114f..7f1d1e6f 100755 --- a/src/js/components/Fields/SearchForm.js +++ b/src/js/components/Fields/SearchForm.js @@ -1,65 +1,43 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; -import * as uiActions from '../../services/ui/actions'; +import React, { useState, useEffect } from 'react'; +import { useHistory } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; import { uriType } from '../../util/helpers'; import Icon from '../Icon'; import { i18n } from '../../locale'; import { encodeUri } from '../../util/format'; -class SearchForm extends React.Component { - constructor(props) { - super(props); +const SearchForm = ({ + term: termProp, + onBlur: doBlur, + onReset: doReset, + onSubmit: doSubmit, +}) => { + const history = useHistory(); + const [term, setTerm] = useState(termProp); + const [dirty, setDirty] = useState(); - this.state = { - term: props.term, - pristine: true, - }; - } + useEffect( + () => { + if (termProp && !dirty) setTerm(termProp); + }, + [termProp], + ); - static getDerivedStateFromProps(props, state) { - const { pristine, term } = state; - if (pristine && term === '' && term !== props.term) { - return { - term, - pristine: false, - }; - } - return null; - } + const onChange = (e) => { + setTerm(e.target.value); + setDirty(true); + }; - shouldComponentUpdate = (nextProps, nextState) => { - const { term: termProp } = this.props; - const { term: termState } = this.state; - if (nextProps.term !== termProp) return true; - if (nextState.term !== termState) return true; - - return false; - } - - onChange = (e) => { - this.setState({ - term: e.target.value, - pristine: false, - }); - } - - onBlur = () => { - const { onBlur } = this.props; - const { term } = this.state; - this.setState({ pristine: false }); - if (onBlur) { - onBlur(term); + const onBlur = () => { + setDirty(true); + if (doBlur) { + doBlur(term); } } - onFocus = () => { - this.setState({ pristine: false }); - } + const onFocus = () => setDirty(true); - onSubmit = (e) => { - const { term } = this.state; - const { history } = this.props; + const onSubmit = (e) => { e.preventDefault(); // check for uri type matching @@ -81,52 +59,36 @@ class SearchForm extends React.Component { break; default: - this.props.onSubmit(term); + doSubmit(term); break; } return false; + }; + + const onReset = () => { + setDirty(false); + setTerm(''); + if (doReset) doReset(); } - onReset = () => { - const { onReset: doReset } = this.props; + return ( +
+ + {term && ( + + )} + + ); +}; - this.setState( - { - term: '', - pristine: true, - }, - () => { - doReset(); - }, - ); - } - - render = () => { - const { term } = this.state; - - return ( -
- - {term && ( - - )} - - ); - } -} - -const mapDispatchToProps = (dispatch) => ({ - uiActions: bindActionCreators(uiActions, dispatch), -}); - -export default connect(mapDispatchToProps)(SearchForm); +export default SearchForm; diff --git a/src/js/components/Header.js b/src/js/components/Header.js index 05d3c94c..e3f10f03 100755 --- a/src/js/components/Header.js +++ b/src/js/components/Header.js @@ -1,14 +1,16 @@ import React, { memo } from 'react'; +import { useDispatch } from 'react-redux'; import ContextMenuTrigger from './ContextMenuTrigger'; +import { showContextMenu } from '../services/ui/actions'; export default memo(({ handleContextMenuTrigger, options, title, - uiActions, className, children, }) => { + const dispatch = useDispatch(); const onTrigger = (e) => { if (handleContextMenuTrigger) return handleContextMenuTrigger(e); @@ -19,7 +21,7 @@ export default memo(({ title, options, }; - uiActions.showContextMenu(data); + dispatch(showContextMenu(data)); return true; }; diff --git a/src/js/services/ui/reducer.js b/src/js/services/ui/reducer.js index 8736a69e..14096caa 100755 --- a/src/js/services/ui/reducer.js +++ b/src/js/services/ui/reducer.js @@ -130,10 +130,15 @@ export default function reducer(ui = {}, action) { * Loading and processes * */ - case 'START_LOADING': - var load_queue = { ...(ui.load_queue ? ui.load_queue : {}) }; - load_queue[action.key] = action.source || action.key; - return { ...ui, load_queue }; + case 'START_LOADING': { + return { + ...ui, + load_queue: { + ...ui.load_queue || {}, + [action.key]: action.source || action.key, + }, + }; + } case 'STOP_LOADING': return { diff --git a/src/js/views/Artist.js b/src/js/views/Artist.js index 231a5cb7..0054ca2e 100755 --- a/src/js/views/Artist.js +++ b/src/js/views/Artist.js @@ -8,10 +8,10 @@ import Thumbnail from '../components/Thumbnail'; import Parallax from '../components/Parallax'; import FollowButton from '../components/Fields/FollowButton'; import ContextMenuTrigger from '../components/ContextMenuTrigger'; -import ArtistAbout from './subviews/ArtistAbout'; -import ArtistOverview from './subviews/ArtistOverview'; -import ArtistTracks from './subviews/ArtistTracks'; -import ArtistRelated from './subviews/ArtistRelated'; +import About from './Artist/About'; +import Overview from './Artist/Overview'; +import Tracks from './Artist/Tracks'; +import Related from './Artist/Related'; import Loader from '../components/Loader'; import * as coreActions from '../services/core/actions'; import * as uiActions from '../services/ui/actions'; @@ -23,7 +23,6 @@ import { encodeUri, decodeUri } from '../util/format'; import { arrayOf } from '../util/arrays'; import { i18n, I18n } from '../locale'; import Button from '../components/Button'; -import { trackEvent } from '../components/Trackable'; import { makeItemSelector, makeLoadingSelector, @@ -186,16 +185,16 @@ const Artist = ({
- + - + - + - +
diff --git a/src/js/views/subviews/ArtistAbout.js b/src/js/views/Artist/About.js similarity index 95% rename from src/js/views/subviews/ArtistAbout.js rename to src/js/views/Artist/About.js index 964993eb..902f7d7d 100644 --- a/src/js/views/subviews/ArtistAbout.js +++ b/src/js/views/Artist/About.js @@ -9,7 +9,7 @@ import { import { i18n, I18n } from '../../locale'; import { nice_number } from '../../components/NiceNumber'; -const ArtistAbout = ({ +export default ({ artist, }) => { const thumbnails = artist.images && Array.isArray(artist.images) && artist.images.map( @@ -88,6 +88,4 @@ const ArtistAbout = ({ ); -} - -export default ArtistAbout; +}; diff --git a/src/js/views/subviews/ArtistRelated.js b/src/js/views/Artist/Related.js similarity index 100% rename from src/js/views/subviews/ArtistRelated.js rename to src/js/views/Artist/Related.js diff --git a/src/js/views/subviews/ArtistTracks.js b/src/js/views/Artist/Tracks.js similarity index 100% rename from src/js/views/subviews/ArtistTracks.js rename to src/js/views/Artist/Tracks.js diff --git a/src/js/views/discover/DiscoverCategories.js b/src/js/views/Discover/DiscoverCategories.js similarity index 92% rename from src/js/views/discover/DiscoverCategories.js rename to src/js/views/Discover/DiscoverCategories.js index 505c2e3c..6d32dd5b 100755 --- a/src/js/views/discover/DiscoverCategories.js +++ b/src/js/views/Discover/DiscoverCategories.js @@ -11,11 +11,8 @@ import * as uiActions from '../../services/ui/actions'; import * as spotifyActions from '../../services/spotify/actions'; import { encodeUri } from '../../util/format'; import { i18n, I18n } from '../../locale'; -import { indexToArray } from '../../util/arrays'; +import { indexToArray, applyFilter } from '../../util/arrays'; import { makeLoadingSelector } from '../../util/selectors'; -import { applyFilter } from '../../util/arrays'; - -const SORT_KEY = 'discover_categories'; const DiscoverCategories = ({ loading, diff --git a/src/js/views/discover/DiscoverCategory.js b/src/js/views/Discover/DiscoverCategory.js similarity index 100% rename from src/js/views/discover/DiscoverCategory.js rename to src/js/views/Discover/DiscoverCategory.js diff --git a/src/js/views/discover/DiscoverFeatured.js b/src/js/views/Discover/DiscoverFeatured.js similarity index 100% rename from src/js/views/discover/DiscoverFeatured.js rename to src/js/views/Discover/DiscoverFeatured.js diff --git a/src/js/views/discover/DiscoverNewReleases.js b/src/js/views/Discover/DiscoverNewReleases.js similarity index 100% rename from src/js/views/discover/DiscoverNewReleases.js rename to src/js/views/Discover/DiscoverNewReleases.js diff --git a/src/js/views/discover/DiscoverRecommendations.js b/src/js/views/Discover/DiscoverRecommendations.js similarity index 100% rename from src/js/views/discover/DiscoverRecommendations.js rename to src/js/views/Discover/DiscoverRecommendations.js diff --git a/src/js/views/library/LibraryAlbums.js b/src/js/views/Library/LibraryAlbums.js similarity index 100% rename from src/js/views/library/LibraryAlbums.js rename to src/js/views/Library/LibraryAlbums.js diff --git a/src/js/views/library/LibraryArtists.js b/src/js/views/Library/LibraryArtists.js similarity index 100% rename from src/js/views/library/LibraryArtists.js rename to src/js/views/Library/LibraryArtists.js diff --git a/src/js/views/library/LibraryBrowse.js b/src/js/views/Library/LibraryBrowse.js similarity index 100% rename from src/js/views/library/LibraryBrowse.js rename to src/js/views/Library/LibraryBrowse.js diff --git a/src/js/views/library/LibraryBrowseDirectory.js b/src/js/views/Library/LibraryBrowseDirectory.js similarity index 100% rename from src/js/views/library/LibraryBrowseDirectory.js rename to src/js/views/Library/LibraryBrowseDirectory.js diff --git a/src/js/views/library/LibraryPlaylists.js b/src/js/views/Library/LibraryPlaylists.js similarity index 100% rename from src/js/views/library/LibraryPlaylists.js rename to src/js/views/Library/LibraryPlaylists.js diff --git a/src/js/views/library/LibraryTracks.js b/src/js/views/Library/LibraryTracks.js similarity index 100% rename from src/js/views/library/LibraryTracks.js rename to src/js/views/Library/LibraryTracks.js diff --git a/src/js/views/subviews/ArtistOverview.js b/src/js/views/subviews/ArtistOverview.js deleted file mode 100644 index c1e48fda..00000000 --- a/src/js/views/subviews/ArtistOverview.js +++ /dev/null @@ -1,160 +0,0 @@ -import React, { useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import TrackList from '../../components/TrackList'; -import FilterField from '../../components/Fields/FilterField'; -import DropdownField from '../../components/Fields/DropdownField'; -import { Grid } from '../../components/Grid'; -import Button from '../../components/Button'; -import RelatedArtists from '../../components/RelatedArtists'; -import { i18n, I18n } from '../../locale'; -import { sortItems, applyFilter } from '../../util/arrays'; -import { encodeUri } from '../../util/format'; -import { getSortSelector } from '../../util/selectors'; -import { - hideContextMenu, - setSort, -} from '../../services/ui/actions'; - -const SORT_KEY = 'artist_albums'; - -export default ({ - artist, - albums: albumsProp, -}) => { - const dispatch = useDispatch(); - const [search, setSearch] = useState(''); - const [type, setType] = useState(''); - const [sortField, sortReverse] = useSelector( - (state) => getSortSelector(state, SORT_KEY, null), - ); - const { - uri, - tracks, - related_artists, - } = artist; - let albums = albumsProp; - - const onSortChange = (field) => { - let reverse = false; - if (field !== null && sortField === field) { - reverse = !sortReverse; - } - - dispatch(setSort(SORT_KEY, field, reverse)); - dispatch(hideContextMenu()); - } - - const onSubmit = () => { - dispatch(hideContextMenu()); - }; - - if (sortField && albums) { - albums = sortItems(albums, sortField, sortReverse); - } - - if (type && albums) { - albums = applyFilter('type', type, albums); - } - - if (search && search !== '') { - albums = applyFilter('name', search, albums); - } - - const sort_options = [ - { - value: null, - label: i18n('artist.albums.sort.default'), - }, - { - value: 'name', - label: i18n('artist.albums.sort.name'), - }, - { - value: 'release_date', - label: i18n('artist.albums.sort.release_date'), - }, - { - value: 'tracks', - label: i18n('artist.albums.sort.track_count'), - }, - ]; - - const filter_type_options = [ - { - value: null, - label: i18n('artist.albums.filter.all'), - }, - { - value: 'album', - label: i18n('artist.albums.filter.albums'), - }, - { - value: 'single', - label: i18n('artist.albums.filter.singles'), - }, - ]; - - return ( -
-
0 ? '70' : '100'}`}> - {tracks &&

} -
- -
-
- -
- - {related_artists && related_artists.length > 0 && ( -
-

-
- -
- -
- )} - -
- -
-

- -
- - - -
-

- -
- -
-
-
- ); -}