diff --git a/src/js/views/Artist.js b/src/js/views/Artist.js
index f3fb62c3..231a5cb7 100755
--- a/src/js/views/Artist.js
+++ b/src/js/views/Artist.js
@@ -51,9 +51,7 @@ const Artist = ({
useEffect(
() => {
- if (uri) {
- loadArtist(uri, { full: true });
- }
+ if (uri) loadArtist(uri, { full: true });
},
[uri],
);
@@ -81,15 +79,13 @@ const Artist = ({
playURIs(arrayOf('uri', tracks) || albums_uris, uri);
}
- const handleContextMenu = (e) => {
- showContextMenu({
- e,
- context: 'artist',
- items: [artist],
- uris: [uri],
- tracklist_uri: uri,
- });
- }
+ const handleContextMenu = (e) => showContextMenu({
+ e,
+ context: 'artist',
+ items: [artist],
+ uris: [uri],
+ tracklist_uri: uri,
+ });
if (loading) {
return ;
diff --git a/src/js/views/Playlist.js b/src/js/views/Playlist.js
index 88b64d19..bc1d7d23 100755
--- a/src/js/views/Playlist.js
+++ b/src/js/views/Playlist.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import ErrorMessage from '../components/ErrorMessage';
@@ -20,7 +20,6 @@ import * as uiActions from '../services/ui/actions';
import * as mopidyActions from '../services/mopidy/actions';
import * as spotifyActions from '../services/spotify/actions';
import { uriSource } from '../util/helpers';
-import { trackEvent } from '../components/Trackable';
import { i18n, I18n } from '../locale';
import { makeItemSelector, makeLoadingSelector, getSortSelector } from '../util/selectors';
import { sortItems, applyFilter } from '../util/arrays';
@@ -28,126 +27,158 @@ import { decodeUri, encodeUri } from '../util/format';
const SORT_KEY = 'playlist_tracks';
-class Playlist extends React.Component {
- constructor(props) {
- super(props);
+const Actions = ({
+ encodedUri,
+ playlist: {
+ uri,
+ can_edit,
+ name,
+ in_library,
+ },
+ onPlay,
+ handleContextMenu,
+}) => {
+ switch (uriSource(uri)) {
+ case 'm3u':
+ return (
+
+ );
- let { uri } = props;
+ case 'spotify':
+ if (can_edit) {
+ return (
+
+ );
+ }
+ return (
+
+ );
- this.state = {
- filter: '',
- };
+ default:
+ return (
+
+ );
+ }
+}
- // Spotify upgraded their playlists URI to remove user component (Sept 2018)
- // We accept the old format, and redirect to the new one
- if (uri.includes('spotify:user:')) {
- uri = uri.replace(/spotify:user:([^:]*?):/i, 'spotify:');
- props.history.push(`/playlist/${encodeUri(uri)}`);
+const Playlist = ({
+ loading,
+ loading_tracks,
+ slim_mode,
+ history,
+ uri,
+ encodedUri,
+ name,
+ playlist: playlistProp,
+ sortField,
+ sortReverse,
+ coreActions: {
+ loadPlaylist,
+ reorderPlaylistTracks,
+ removeTracksFromPlaylist,
+ addPinned,
+ removePinned,
+ },
+ uiActions: {
+ setSort,
+ setWindowTitle,
+ showContextMenu,
+ hideContextMenu,
+ createNotification,
+ },
+ mopidyActions: {
+ playPlaylist,
+ },
+}) => {
+ const [playlist, setPlaylist] = useState({});
+ const [filter, setFilter] = useState('');
+
+ useEffect(
+ () => {
+ if (uri) loadPlaylist(uri, { full: true, name });
+ },
+ [uri],
+ );
+
+ useEffect(() => {
+ if (playlistProp && playlist && playlistProp.moved_to !== playlist.moved_to) {
+ history.push(`/playlist/${encodeUri(playlistProp.moved_to)}`);
}
- }
+ }, [playlistProp])
- componentDidMount() {
- const {
- coreActions: {
- loadPlaylist,
- },
- uri,
- name,
- } = this.props;
- this.setWindowTitle();
- setTimeout(() => loadPlaylist(uri, { full: true, name }), 1);
- }
-
- componentDidUpdate = ({
- uri: prevUri,
- playlist: prevPlaylist,
- }) => {
- const {
- uri,
- name,
- playlist,
- coreActions: {
- loadPlaylist,
- },
- history: {
- push,
- },
- } = this.props;
-
- if (prevPlaylist && playlist && prevPlaylist.moved_to !== playlist.moved_to) {
- push(`/playlist/${encodeUri(playlist.moved_to)}`);
+ useEffect(() => {
+ if (playlistProp) {
+ setWindowTitle(i18n('playlist.title_window', { name: playlistProp.name }));
+ } else {
+ setWindowTitle(i18n('playlist.title'));
}
+ setPlaylist(playlistProp);
+ }, [playlistProp]);
- if (uri !== prevUri) {
- loadPlaylist(uri, { full: true, name });
- }
-
- if (!prevPlaylist && playlist) this.setWindowTitle(playlist);
- if (prevUri !== uri && playlist) this.setWindowTitle(playlist);
- }
-
- setWindowTitle = (playlist = this.props.playlist) => {
- const { uiActions: { setWindowTitle } } = this.props;
- setWindowTitle(
- playlist ? i18n('playlist.title_window', { name: playlist.name }) : i18n('playlist.title'),
- );
- }
-
- handleContextMenu = (e) => {
- const {
- uiActions: {
- showContextMenu,
- },
- playlist,
- uri,
- name,
- } = this.props;
-
- showContextMenu({
- e,
- context: 'playlist',
- items: [{ name, ...playlist }],
- uris: [uri],
- });
- }
-
- play = () => {
- const {
- mopidyActions: {
- playPlaylist,
- },
- playlist: {
- uri,
- },
- } = this.props;
-
- playPlaylist(uri);
- }
-
- // TODO: Once deletion occurs, remove playlist from global playlists list
- delete = () => {
- const {
- mopidyActions: {
- deletePlaylist,
- },
- playlist: {
- uri,
- },
- } = this.props;
-
- deletePlaylist(uri);
- }
-
- onChangeSort = (field) => {
- const {
- sortField,
- sortReverse,
- uiActions: {
- setSort,
- hideContextMenu,
- },
- } = this.props;
+ const handleContextMenu = (e) => showContextMenu({
+ e,
+ context: 'playlist',
+ items: [{ name, ...playlist }],
+ uris: [uri],
+ });
+ const onChangeSort = (field) => {
let reverse = false;
if (field !== null && sortField === field) {
reverse = !sortReverse;
@@ -155,25 +186,12 @@ class Playlist extends React.Component {
setSort(SORT_KEY, field, reverse);
hideContextMenu();
- }
+ };
- reorderTracks = (indexes, index) => {
- const {
- coreActions: {
- reorderPlaylistTracks,
- },
- uiActions: {
- createNotification,
- },
- playlist: {
- uri,
- snapshot_id,
- tracks,
- },
- sortField,
- sortReverse,
- } = this.props;
- const { filter } = this.state;
+ const onPlay = () => playPlaylist(uri);
+
+ const reorderTracks = (indexes, index) => {
+ const { snapshot_id, tracks } = playlist;
if (sortField !== 'sort_id' || filter !== '') {
createNotification({
@@ -193,286 +211,140 @@ class Playlist extends React.Component {
reorderPlaylistTracks(uri, indexes, index, snapshot_id);
}
- removeTracks = (tracks_indexes) => {
- const {
- coreActions: {
- removeTracksFromPlaylist,
- },
- playlist: {
- uri,
- },
- } = this.props;
-
+ const removeTracks = (tracks_indexes) => {
removeTracksFromPlaylist(uri, tracks_indexes);
}
- inLibrary = () => {
- const { uri } = this.props;
- const libraryName = `${uriSource(uri)}_library_playlists`;
- const { [libraryName]: library } = this.props;
-
- if (!library) return false;
-
- return library.indexOf(uri) > -1;
+ if (loading) {
+ return ;
}
-
- togglePinned = () => {
- const {
- uri,
- coreActions: {
- addPinned,
- removePinned,
- },
- } = this.props;
-
- if (this.isPinned()) {
- removePinned(uri);
- } else {
- addPinned(uri);
- }
- }
-
- renderActions = () => {
- const {
- uri,
- encodedUri,
- playlist: {
- can_edit,
- name,
- in_library,
- },
- } = this.props;
-
- switch (uriSource(uri)) {
- case 'm3u':
- return (
-
- );
-
- case 'spotify':
- if (can_edit) {
- return (
-
- );
- }
- return (
-
- );
-
- default:
- return (
-
- );
- }
- }
-
- render = () => {
- const {
- uri,
- playlist,
- loading,
- loading_tracks,
- slim_mode,
- sortField,
- sortReverse,
- } = this.props;
- const {
- filter,
- } = this.state;
-
- if (loading) {
- return ;
- }
- if (!playlist) {
- return (
-
-
-
-
-
- );
- }
-
- let context = 'playlist';
- if (playlist.can_edit) {
- context = 'editable-playlist';
- }
- let {
- playlist: {
- tracks,
- },
- } = this.props;
-
- if (sortField && tracks) {
- tracks = sortItems(tracks, sortField, sortReverse);
- }
-
- if (filter && filter !== '') {
- tracks = applyFilter('name', filter, tracks);
- }
-
- const sort_options = [
- {
- value: 'sort_id',
- label: i18n('playlist.tracks.sort.sort_id'),
- },
- {
- value: 'name',
- label: i18n('playlist.tracks.sort.name'),
- },
- {
- value: 'artist',
- label: i18n('playlist.tracks.sort.artist'),
- },
- {
- value: 'album',
- label: i18n('playlist.tracks.sort.album'),
- },
- ];
-
+ if (!playlist) {
return (
-
-
-
-
-
-
-
-
{playlist.name}
- {playlist.description && (
-
- )}
-
-
- {!slim_mode && (
- -
-
-
- )}
- {playlist.user && (
- -
-
- {playlist.user.name}
-
-
- )}
- -
-
-
- {!slim_mode && playlist.tracks && playlist.tracks_total > 0 && (
-
- )}
- {!slim_mode && playlist.followers !== undefined && (
- -
-
-
- )}
- {!slim_mode && playlist.last_modified_date && (
- -
-
-
- )}
-
-
-
- {this.renderActions()}
-
-
-
- {loading_tracks && }
-
- this.setState({ filter: value })}
- onSubmit={() => uiActions.hideContextMenu()}
- />
-
-
-
-
-
-
+
+
+
+
+
);
}
+
+ let context = 'playlist';
+ if (playlist.can_edit) context = 'editable-playlist';
+
+ let tracks = playlist?.tracks || [];
+ if (sortField && tracks) tracks = sortItems(tracks, sortField, sortReverse);
+ if (filter && filter !== '') tracks = applyFilter('name', filter, tracks);
+
+ const sort_options = [
+ {
+ value: 'sort_id',
+ label: i18n('playlist.tracks.sort.sort_id'),
+ },
+ {
+ value: 'name',
+ label: i18n('playlist.tracks.sort.name'),
+ },
+ {
+ value: 'artist',
+ label: i18n('playlist.tracks.sort.artist'),
+ },
+ {
+ value: 'album',
+ label: i18n('playlist.tracks.sort.album'),
+ },
+ ];
+
+ return (
+
+
+
+
+
+
+
+
{playlist.name}
+ {playlist.description && (
+
+ )}
+
+
+ {!slim_mode && (
+ -
+
+
+ )}
+ {playlist.user && (
+ -
+
+ {playlist.user.name}
+
+
+ )}
+ -
+
+
+ {!slim_mode && playlist.tracks && playlist.tracks_total > 0 && (
+
+ )}
+ {!slim_mode && playlist.followers !== undefined && (
+ -
+
+
+ )}
+ {!slim_mode && playlist.last_modified_date && (
+ -
+
+
+ )}
+
+
+
+
+
+
+
+ {loading_tracks && }
+
+
+
+
+
+
+
+
+ );
}
const mapStateToProps = (state, ownProps) => {