Fix Interactive Import, Add Track Actions and Reducers

pull/6/head
Qstick 7 years ago
parent 8f45fe0afe
commit 90d9741056

@ -114,6 +114,11 @@ class SignalRConnector extends Component {
return;
}
if (name === 'track') {
this.handleTrack(body);
return;
}
if (name === 'episodefile') {
this.handleEpisodeFile(body);
return;
@ -192,6 +197,15 @@ class SignalRConnector extends Component {
}
}
handleTrack = (body) => {
if (body.action === 'updated') {
this.props.updateItem({
section: 'tracks',
updateOnly: true,
...body.resource });
}
}
handleEpisodeFile = (body) => {
if (body.action === 'updated') {
this.props.updateItem({

@ -5,6 +5,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalHeader from 'Components/Modal/ModalHeader';
import ModalBody from 'Components/Modal/ModalBody';
import ModalFooter from 'Components/Modal/ModalFooter';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import SelectAlbumRow from './SelectAlbumRow';
class SelectAlbumModalContent extends Component {
@ -16,7 +17,8 @@ class SelectAlbumModalContent extends Component {
const {
items,
onAlbumSelect,
onModalClose
onModalClose,
isFetching
} = this.props;
return (
@ -26,6 +28,10 @@ class SelectAlbumModalContent extends Component {
</ModalHeader>
<ModalBody>
{
isFetching &&
<LoadingIndicator />
}
{
items.map((item) => {
return (
@ -52,6 +58,7 @@ class SelectAlbumModalContent extends Component {
SelectAlbumModalContent.propTypes = {
items: PropTypes.arrayOf(PropTypes.object).isRequired,
isFetching: PropTypes.bool.isRequired,
onAlbumSelect: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};

@ -2,28 +2,48 @@ import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import connectSection from 'Store/connectSection';
import { createSelector } from 'reselect';
import { updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions';
import createArtistSelector from 'Store/Selectors/createArtistSelector';
import { fetchEpisodes, setEpisodesSort, clearEpisodes } from 'Store/Actions/episodeActions';
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import SelectAlbumModalContent from './SelectAlbumModalContent';
function createMapStateToProps() {
return createSelector(
createArtistSelector(),
(series) => {
return {
items: series.albums
};
createClientSideCollectionSelector(),
(episodes) => {
return episodes;
}
);
}
const mapDispatchToProps = {
fetchEpisodes,
setEpisodesSort,
clearEpisodes,
updateInteractiveImportItem
};
class SelectAlbumModalContentConnector extends Component {
//
// Lifecycle
componentDidMount() {
const {
artistId
} = this.props;
this.props.fetchEpisodes({ artistId });
}
componentWillUnmount() {
// This clears the albums for the queue and hides the queue
// We'll need another place to store albums for manual import
this.props.clearEpisodes();
}
//
// Listeners
@ -58,8 +78,17 @@ SelectAlbumModalContentConnector.propTypes = {
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
artistId: PropTypes.number.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
fetchEpisodes: PropTypes.func.isRequired,
setEpisodesSort: PropTypes.func.isRequired,
clearEpisodes: PropTypes.func.isRequired,
updateInteractiveImportItem: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(SelectAlbumModalContentConnector);
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
undefined,
undefined,
{ section: 'episodes' }
)(SelectAlbumModalContentConnector);

@ -293,7 +293,7 @@ class InteractiveImportModalContent extends Component {
<SelectAlbumModal
isOpen={isSelectAlbumModalOpen}
ids={selectedIds}
artistId={selectedItem && selectedItem.series && selectedItem.series.id}
artistId={selectedItem && selectedItem.artist && selectedItem.artist.id}
onModalClose={this.onSelectAlbumModalClose}
/>
</ModalContent>

@ -177,7 +177,7 @@ class InteractiveImportRow extends Component {
const artistName = artist ? artist.artistName : '';
const albumTitle = album ? album.title : '';
const trackNumbers = tracks.map((episode) => episode.trackNumber)
const trackNumbers = tracks.map((track) => track.trackNumber)
.join(', ');
const showArtistPlaceholder = isSelected && !artist;

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { createSelector } from 'reselect';
import connectSection from 'Store/connectSection';
import { fetchEpisodes, setEpisodesSort, clearEpisodes } from 'Store/Actions/episodeActions';
import { fetchTracks, setTracksSort, clearTracks } from 'Store/Actions/trackActions';
import { updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions';
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import SelectTrackModalContent from './SelectTrackModalContent';
@ -11,16 +11,16 @@ import SelectTrackModalContent from './SelectTrackModalContent';
function createMapStateToProps() {
return createSelector(
createClientSideCollectionSelector(),
(episodes) => {
return episodes;
(tracks) => {
return tracks;
}
);
}
const mapDispatchToProps = {
fetchEpisodes,
setEpisodesSort,
clearEpisodes,
fetchTracks,
setTracksSort,
clearTracks,
updateInteractiveImportItem
};
@ -35,25 +35,25 @@ class SelectTrackModalContentConnector extends Component {
albumId
} = this.props;
this.props.fetchEpisodes({ artistId, albumId });
this.props.fetchTracks({ artistId, albumId });
}
componentWillUnmount() {
// This clears the episodes for the queue and hides the queue
// We'll need another place to store episodes for manual import
this.props.clearEpisodes();
// This clears the tracks for the queue and hides the queue
// We'll need another place to store tracks for manual import
this.props.clearTracks();
}
//
// Listeners
onSortPress = (sortKey, sortDirection) => {
this.props.setEpisodesSort({ sortKey, sortDirection });
this.props.setTracksSort({ sortKey, sortDirection });
}
onTracksSelect = (episodeIds) => {
onTracksSelect = (trackIds) => {
const tracks = _.reduce(this.props.items, (acc, item) => {
if (episodeIds.indexOf(item.id) > -1) {
if (trackIds.indexOf(item.id) > -1) {
acc.push(item);
}
@ -87,9 +87,9 @@ SelectTrackModalContentConnector.propTypes = {
artistId: PropTypes.number.isRequired,
albumId: PropTypes.number.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
fetchEpisodes: PropTypes.func.isRequired,
setEpisodesSort: PropTypes.func.isRequired,
clearEpisodes: PropTypes.func.isRequired,
fetchTracks: PropTypes.func.isRequired,
setTracksSort: PropTypes.func.isRequired,
clearTracks: PropTypes.func.isRequired,
updateInteractiveImportItem: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
@ -99,5 +99,5 @@ export default connectSection(
mapDispatchToProps,
undefined,
undefined,
{ section: 'episodes' }
{ section: 'tracks' }
)(SelectTrackModalContentConnector);

@ -84,6 +84,14 @@ export const CLEAR_EPISODES = 'CLEAR_EPISODES';
export const TOGGLE_EPISODE_MONITORED = 'TOGGLE_EPISODE_MONITORED';
export const TOGGLE_EPISODES_MONITORED = 'TOGGLE_EPISODES_MONITORED';
//
// Tracks
export const FETCH_TRACKS = 'FETCH_TRACKS';
export const SET_TRACKS_SORT = 'SET_TRACKS_SORT';
export const SET_TRACKS_TABLE_OPTION = 'SET_TRACKS_TABLE_OPTION';
export const CLEAR_TRACKS = 'CLEAR_TRACKS';
//
// Episode Files

@ -0,0 +1,11 @@
import createFetchHandler from './Creators/createFetchHandler';
import * as types from './actionTypes';
const section = 'tracks';
const trackActionHandlers = {
[types.FETCH_TRACKS]: createFetchHandler(section, '/track')
};
export default trackActionHandlers;

@ -0,0 +1,8 @@
import { createAction } from 'redux-actions';
import * as types from './actionTypes';
import trackActionHandlers from './trackActionHandlers';
export const fetchTracks = trackActionHandlers[types.FETCH_TRACKS];
export const setTracksSort = createAction(types.SET_TRACKS_SORT);
export const setTracksTableOption = createAction(types.SET_TRACKS_TABLE_OPTION);
export const clearTracks = createAction(types.CLEAR_TRACKS);

@ -2,6 +2,7 @@ import _ from 'lodash';
import persistState from 'redux-localstorage';
import * as addArtistReducers from 'Store/Reducers/addArtistReducers';
import * as episodeReducers from 'Store/Reducers/episodeReducers';
import * as trackReducers from 'Store/Reducers/trackReducers';
import * as artistIndexReducers from 'Store/Reducers/artistIndexReducers';
import * as artistEditorReducers from 'Store/Reducers/artistEditorReducers';
import * as albumStudioReducers from 'Store/Reducers/albumStudioReducers';
@ -17,6 +18,7 @@ import * as queueReducers from 'Store/Reducers/queueReducers';
const reducers = [
addArtistReducers,
episodeReducers,
trackReducers,
artistIndexReducers,
artistEditorReducers,
albumStudioReducers,

@ -13,6 +13,7 @@ import history, { defaultState as defaultHistoryState } from './historyReducers'
import queue, { defaultState as defaultQueueState } from './queueReducers';
import blacklist, { defaultState as defaultBlacklistState } from './blacklistReducers';
import episodes, { defaultState as defaultEpisodesState } from './episodeReducers';
import tracks, { defaultState as defaultTracksState } from './trackReducers';
import episodeFiles, { defaultState as defaultEpisodeFilesState } from './episodeFileReducers';
import albumHistory, { defaultState as defaultAlbumHistoryState } from './albumHistoryReducers';
import releases, { defaultState as defaultReleasesState } from './releaseReducers';
@ -41,6 +42,7 @@ export const defaultState = {
queue: defaultQueueState,
blacklist: defaultBlacklistState,
episodes: defaultEpisodesState,
tracks: defaultTracksState,
episodeFiles: defaultEpisodeFilesState,
albumHistory: defaultAlbumHistoryState,
releases: defaultReleasesState,
@ -70,6 +72,7 @@ export default enableBatching(combineReducers({
queue,
blacklist,
episodes,
tracks,
episodeFiles,
albumHistory,
releases,

@ -0,0 +1,70 @@
import { handleActions } from 'redux-actions';
import * as types from 'Store/Actions/actionTypes';
import { sortDirections } from 'Helpers/Props';
import createSetReducer from './Creators/createSetReducer';
import createSetTableOptionReducer from './Creators/createSetTableOptionReducer';
import createUpdateReducer from './Creators/createUpdateReducer';
import createUpdateItemReducer from './Creators/createUpdateItemReducer';
import createSetClientSideCollectionSortReducer from './Creators/createSetClientSideCollectionSortReducer';
export const defaultState = {
isFetching: false,
isPopulated: false,
error: null,
sortKey: 'trackNumber',
sortDirection: sortDirections.DESCENDING,
items: [],
columns: [
{
name: 'trackNumber',
label: 'Track Number',
isVisible: true
},
{
name: 'title',
label: 'Title',
isVisible: true
},
{
name: 'duration',
label: 'Duration',
isVisible: true
},
{
name: 'actions',
columnLabel: 'Actions',
isVisible: true,
isModifiable: false
}
]
};
export const persistState = [
'tracks.columns'
];
const reducerSection = 'tracks';
const trackReducers = handleActions({
[types.SET]: createSetReducer(reducerSection),
[types.UPDATE]: createUpdateReducer(reducerSection),
[types.UPDATE_ITEM]: createUpdateItemReducer(reducerSection),
[types.SET_TRACKS_TABLE_OPTION]: createSetTableOptionReducer(reducerSection),
[types.CLEAR_TRACKS]: (state) => {
return Object.assign({}, state, {
isFetching: false,
isPopulated: false,
error: null,
items: []
});
},
[types.SET_TRACKS_SORT]: createSetClientSideCollectionSortReducer(reducerSection)
}, defaultState);
export default trackReducers;

@ -0,0 +1,14 @@
import _ from 'lodash';
import { createSelector } from 'reselect';
function createTrackSelector() {
return createSelector(
(state, { trackId }) => trackId,
(state) => state.tracks,
(trackId, tracks) => {
return _.find(tracks.items, { id: trackId });
}
);
}
export default createTrackSelector;
Loading…
Cancel
Save