Adding feedback to LastFm love/unlove; Using selectors for love/follow buttons

This commit is contained in:
James Barnsley
2020-11-22 20:54:52 +13:00
parent fb30825e21
commit 879b1b7ead
4 changed files with 74 additions and 62 deletions

View File

@ -6,6 +6,7 @@ import * as spotifyActions from '../../services/spotify/actions';
import { isLoading, getFromUri } from '../../util/helpers';
import { i18n } from '../../locale';
import { Button } from '../Button';
import { makeLoadingSelector } from '../../util/selectors';
class FollowButton extends React.Component {
remove = () => {
@ -34,23 +35,16 @@ class FollowButton extends React.Component {
removeText,
spotify_authorized,
is_following,
load_queue,
loading,
} = this.props;
if (!uri) return null;
const working = isLoading(load_queue, [
'spotify_me/tracks?',
'spotify_me/albums?',
'spotify_me/following?',
`spotify_playlists/${getFromUri('playlistid', uri)}/followers?`,
]);
if (!spotify_authorized) {
return (
<Button
disabled
working={working}
working={loading}
onClick={this.unauthorized}
tracking={{ category: 'FollowButton', action: 'Add (disabled)' }}
>
@ -61,7 +55,7 @@ class FollowButton extends React.Component {
return (
<Button
type="destructive"
working={working}
working={loading}
onClick={this.remove}
tracking={{ category: 'FollowButton', action: 'Remove' }}
>
@ -72,7 +66,7 @@ class FollowButton extends React.Component {
return (
<Button
onClick={this.add}
working={working}
working={loading}
tracking={{ category: 'FollowButton', action: 'Add' }}
>
{addText || i18n('actions.add_to_library')}
@ -81,10 +75,23 @@ class FollowButton extends React.Component {
}
}
const mapStateToProps = (state) => ({
load_queue: state.ui.load_queue,
spotify_authorized: state.spotify.authorization,
});
const mapStateToProps = (state, ownProps) => {
const {
uri,
} = ownProps;
const loadingSelector = makeLoadingSelector([
'spotify_me/tracks?',
'spotify_me/albums?',
'spotify_me/following?',
`spotify_playlists/${getFromUri('playlistid', uri)}/followers?`,
]);
return {
loading: loadingSelector(state),
spotify_authorized: state.spotify.authorization,
};
};
const mapDispatchToProps = (dispatch) => ({
uiActions: bindActionCreators(uiActions, dispatch),

View File

@ -6,6 +6,7 @@ import * as uiActions from '../../services/ui/actions';
import * as lastfmActions from '../../services/lastfm/actions';
import { i18n } from '../../locale';
import Button from '../Button';
import { makeLoadingSelector } from '../../util/selectors';
const FollowButton = ({
uri,
@ -14,7 +15,6 @@ const FollowButton = ({
addText,
removeText,
is_loved,
className: classNameProp = '',
lastfm_authorized,
uiActions: {
createNotification,
@ -23,6 +23,7 @@ const FollowButton = ({
unloveTrack,
loveTrack,
},
loading,
}) => {
const onRemove = () => unloveTrack(uri, artist, track);
const onAdd = () => loveTrack(uri, artist, track);
@ -33,17 +34,14 @@ const FollowButton = ({
});
};
if (!uri) {
return false;
}
const className = `button ${classNameProp}`;
if (!uri) return false;
if (!lastfm_authorized) {
return (
<Button
disabled
onClick={onDisabledClick}
working={loading}
tracking={{ category: 'Lastfm', action: 'Love', label: 'Disabled' }}
>
{addText || i18n('services.lastfm.love')}
@ -54,6 +52,7 @@ const FollowButton = ({
<Button
type="destructive"
onClick={onRemove}
working={loading}
tracking={{ category: 'Lastfm', action: 'Unlove' }}
>
{removeText || i18n('services.lastfm.unlove')}
@ -63,6 +62,7 @@ const FollowButton = ({
return (
<Button
onClick={onAdd}
working={loading}
tracking={{ category: 'Lastfm', action: 'Love' }}
>
{addText || i18n('services.lastfm.love')}
@ -70,10 +70,13 @@ const FollowButton = ({
);
};
const mapStateToProps = (state) => ({
load_queue: state.ui.load_queue,
lastfm_authorized: state.lastfm.authorization,
});
const mapStateToProps = (state) => {
const loadingSelector = makeLoadingSelector(['love', 'unlove']);
return {
loading: loadingSelector(state),
lastfm_authorized: state.lastfm.authorization,
};
};
const mapDispatchToProps = (dispatch) => ({
uiActions: bindActionCreators(uiActions, dispatch),

View File

@ -1,3 +1,4 @@
import React from 'react';
import {
collate,
formatImages,
@ -6,7 +7,8 @@ import {
formatAlbum,
} from '../../util/format';
import { generateGuid } from '../../util/helpers';
import { makeItemSelector } from '../../util/selectors';
import { makeItemSelector, getItem } from '../../util/selectors';
import URILink from '../../components/URILink';
const coreActions = require('../core/actions');
const uiActions = require('../ui/actions');
@ -357,34 +359,36 @@ export function getImages(context, uri) {
export function loveTrack(uri) {
return (dispatch, getState) => {
const track = getState().core.items[uri];
if (getState().core.items[uri] !== undefined) {
if (!track.artists) {
dispatch(coreActions.handleException(
'Could not love LastFM track',
track,
'Track has no artists',
));
return;
}
} else {
const asset = getItem(getState(), uri) || {};
if (!asset) {
dispatch(coreActions.handleException(
'Could not love LastFM track',
track,
asset,
'Could not find track in index',
));
return;
}
if (asset && !asset.artists) {
dispatch(coreActions.handleException(
'Could not love LastFM track',
asset,
'Track has no artists',
));
return;
}
const artist = encodeURIComponent(track.artists[0].name);
const params = `method=track.love&track=${track.name}&artist=${artist}`;
const artist = encodeURIComponent(asset.artists[0].name);
const params = `method=track.love&track=${asset.name}&artist=${artist}`;
sendSignedRequest(dispatch, getState, params)
.then(
(response) => {
() => {
dispatch(coreActions.itemLoaded({
uri,
userloved: true,
}));
dispatch(uiActions.createNotification({
content: <span>Loved <URILink uri={uri}>{asset ? asset.name : type}</URILink></span>,
}));
},
);
};
@ -392,34 +396,36 @@ export function loveTrack(uri) {
export function unloveTrack(uri) {
return (dispatch, getState) => {
if (getState().core.items[uri] !== undefined) {
var track = getState().core.items[uri];
if (!track.artists) {
dispatch(coreActions.handleException(
'Could not unlove LastFM track',
track,
'Track has no artists',
));
return;
}
} else {
const asset = getItem(getState(), uri) || {};
if (!asset) {
dispatch(coreActions.handleException(
'Could not unlove LastFM track',
track,
'Could not love LastFM track',
asset,
'Could not find track in index',
));
return;
}
if (asset && !asset.artists) {
dispatch(coreActions.handleException(
'Could not love LastFM track',
asset,
'Track has no artists',
));
return;
}
const artist = encodeURIComponent(track.artists[0].name);
const params = `method=track.unlove&track=${track.name}&artist=${artist}`;
const artist = encodeURIComponent(asset.artists[0].name);
const params = `method=track.unlove&track=${asset.name}&artist=${artist}`;
sendSignedRequest(dispatch, getState, params)
.then(
(response) => {
() => {
dispatch(coreActions.itemLoaded({
uri,
userloved: false,
}));
dispatch(uiActions.createNotification({
content: <span>Unloved <URILink uri={uri}>{asset ? asset.name : type}</URILink></span>,
}));
},
);
};

View File

@ -1,9 +1,5 @@
import React from 'react';
import {
arrayOf,
shuffle,
} from '../../util/arrays';
import { arrayOf } from '../../util/arrays';
import {
generateGuid,
getFromUri,