mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-17 17:14:18 +02:00
Newznab Responses for Caps and Movie Search (rough)
This commit is contained in:
55
frontend/src/Components/Form/IndexersSelectInputConnector.js
Normal file
55
frontend/src/Components/Form/IndexersSelectInputConnector.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import EnhancedSelectInput from './EnhancedSelectInput';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state, { value }) => value,
|
||||
(state) => state.indexers,
|
||||
(value, indexers) => {
|
||||
const values = indexers.items.map(({ id, name }) => {
|
||||
return {
|
||||
key: id,
|
||||
value: name
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
value,
|
||||
values
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
class IndexersSelectInputConnector extends Component {
|
||||
|
||||
onChange = ({ name, value }) => {
|
||||
this.props.onChange({ name, value });
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<EnhancedSelectInput
|
||||
{...this.props}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
IndexersSelectInputConnector.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
indexerIds: PropTypes.number.isRequired,
|
||||
value: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
values: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps)(IndexersSelectInputConnector);
|
@@ -26,34 +26,16 @@ function MovieIndexSortMenu(props) {
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
Monitored/Status
|
||||
Status
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="sortTitle"
|
||||
name="name"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
{translate('Title')}
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="studio"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
{translate('Studio')}
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="qualityProfileId"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
{translate('QualityProfile')}
|
||||
{translate('Name')}
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
@@ -66,66 +48,21 @@ function MovieIndexSortMenu(props) {
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="year"
|
||||
name="protocol"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
{translate('Year')}
|
||||
{'Protocol'}
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="inCinemas"
|
||||
name="privacy"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
{translate('InCinemas')}
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="physicalRelease"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
{translate('PhysicalRelease')}
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="digitalRelease"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
{translate('DigitalRelease')}
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="path"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
{translate('Path')}
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="sizeOnDisk"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
{translate('SizeOnDisk')}
|
||||
</SortMenuItem>
|
||||
|
||||
<SortMenuItem
|
||||
name="certification"
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onPress={onSortSelect}
|
||||
>
|
||||
{translate('Certification')}
|
||||
{'Privacy'}
|
||||
</SortMenuItem>
|
||||
</MenuContent>
|
||||
</SortMenu>
|
||||
|
@@ -4,16 +4,16 @@ import Label from 'Components/Label';
|
||||
|
||||
function CapabilitiesLabel(props) {
|
||||
const {
|
||||
supportsBooks,
|
||||
supportsMovies,
|
||||
supportsMusic,
|
||||
supportsTv
|
||||
} = props;
|
||||
movieSearchAvailable,
|
||||
tvSearchAvailable,
|
||||
musicSearchAvailable,
|
||||
bookSearchAvailable
|
||||
} = props.capabilities;
|
||||
|
||||
return (
|
||||
<span>
|
||||
{
|
||||
supportsBooks ?
|
||||
bookSearchAvailable ?
|
||||
<Label>
|
||||
{'Books'}
|
||||
</Label> :
|
||||
@@ -21,7 +21,7 @@ function CapabilitiesLabel(props) {
|
||||
}
|
||||
|
||||
{
|
||||
supportsMovies ?
|
||||
movieSearchAvailable ?
|
||||
<Label>
|
||||
{'Movies'}
|
||||
</Label> :
|
||||
@@ -29,7 +29,7 @@ function CapabilitiesLabel(props) {
|
||||
}
|
||||
|
||||
{
|
||||
supportsMusic ?
|
||||
musicSearchAvailable ?
|
||||
<Label>
|
||||
{'Music'}
|
||||
</Label> :
|
||||
@@ -37,7 +37,7 @@ function CapabilitiesLabel(props) {
|
||||
}
|
||||
|
||||
{
|
||||
supportsTv ?
|
||||
tvSearchAvailable ?
|
||||
<Label>
|
||||
{'TV'}
|
||||
</Label> :
|
||||
@@ -45,7 +45,7 @@ function CapabilitiesLabel(props) {
|
||||
}
|
||||
|
||||
{
|
||||
!supportsTv && !supportsMusic && !supportsMovies && !supportsBooks ?
|
||||
!tvSearchAvailable && !musicSearchAvailable && !movieSearchAvailable && !bookSearchAvailable ?
|
||||
<Label>
|
||||
{'None'}
|
||||
</Label> :
|
||||
@@ -56,10 +56,7 @@ function CapabilitiesLabel(props) {
|
||||
}
|
||||
|
||||
CapabilitiesLabel.propTypes = {
|
||||
supportsTv: PropTypes.bool.isRequired,
|
||||
supportsBooks: PropTypes.bool.isRequired,
|
||||
supportsMusic: PropTypes.bool.isRequired,
|
||||
supportsMovies: PropTypes.bool.isRequired
|
||||
capabilities: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default CapabilitiesLabel;
|
||||
|
@@ -64,10 +64,7 @@ class MovieIndexRow extends Component {
|
||||
protocol,
|
||||
privacy,
|
||||
added,
|
||||
supportsTv,
|
||||
supportsBooks,
|
||||
supportsMusic,
|
||||
supportsMovies,
|
||||
capabilities,
|
||||
columns,
|
||||
isMovieEditorActive,
|
||||
isSelected,
|
||||
@@ -175,10 +172,7 @@ class MovieIndexRow extends Component {
|
||||
className={styles[column.name]}
|
||||
>
|
||||
<CapabilitiesLabel
|
||||
supportsBooks={supportsBooks}
|
||||
supportsMovies={supportsMovies}
|
||||
supportsMusic={supportsMusic}
|
||||
supportsTv={supportsTv}
|
||||
capabilities={capabilities}
|
||||
/>
|
||||
</VirtualTableRowCell>
|
||||
);
|
||||
@@ -243,10 +237,7 @@ MovieIndexRow.propTypes = {
|
||||
enableRss: PropTypes.bool.isRequired,
|
||||
enableAutomaticSearch: PropTypes.bool.isRequired,
|
||||
enableInteractiveSearch: PropTypes.bool.isRequired,
|
||||
supportsTv: PropTypes.bool.isRequired,
|
||||
supportsBooks: PropTypes.bool.isRequired,
|
||||
supportsMusic: PropTypes.bool.isRequired,
|
||||
supportsMovies: PropTypes.bool.isRequired,
|
||||
capabilities: PropTypes.object.isRequired,
|
||||
added: PropTypes.string.isRequired,
|
||||
tags: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
|
6
frontend/src/Search/NoSearchResults.css
Normal file
6
frontend/src/Search/NoSearchResults.css
Normal file
@@ -0,0 +1,6 @@
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
}
|
32
frontend/src/Search/NoSearchResults.js
Normal file
32
frontend/src/Search/NoSearchResults.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './NoSearchResults.css';
|
||||
|
||||
function NoSearchResults(props) {
|
||||
const { totalItems } = props;
|
||||
|
||||
if (totalItems > 0) {
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.message}>
|
||||
{translate('AllIndexersHiddenDueToFilter')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.message}>
|
||||
No search results found, try performing a new search below.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
NoSearchResults.propTypes = {
|
||||
totalItems: PropTypes.number.isRequired
|
||||
};
|
||||
|
||||
export default NoSearchResults;
|
@@ -3,6 +3,11 @@
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.indexerContainer {
|
||||
margin-right: 20px;
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import IndexersSelectInputConnector from 'Components/Form/IndexersSelectInputConnector';
|
||||
import TextInput from 'Components/Form/TextInput';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import PageContentFooter from 'Components/Page/PageContentFooter';
|
||||
@@ -15,7 +16,8 @@ class SearchFooter extends Component {
|
||||
|
||||
this.state = {
|
||||
searchingReleases: false,
|
||||
searchQuery: ''
|
||||
searchQuery: '',
|
||||
indexerIds: []
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,7 +42,7 @@ class SearchFooter extends Component {
|
||||
}
|
||||
|
||||
onSearchPress = () => {
|
||||
this.props.onSearchPress(this.state.searchQuery);
|
||||
this.props.onSearchPress(this.state.searchQuery, this.state.indexerIds);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -52,7 +54,8 @@ class SearchFooter extends Component {
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
searchQuery
|
||||
searchQuery,
|
||||
indexerIds
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
@@ -67,6 +70,16 @@ class SearchFooter extends Component {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.indexerContainer}>
|
||||
<IndexersSelectInputConnector
|
||||
name='indexerIds'
|
||||
placeholder='Indexers'
|
||||
value={indexerIds}
|
||||
isDisabled={isFetching}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.buttonContainer}>
|
||||
<div className={styles.buttonContainerContent}>
|
||||
<div className={styles.buttons}>
|
||||
|
@@ -11,13 +11,13 @@ import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||
import { align, icons, sortDirections } from 'Helpers/Props';
|
||||
import NoIndexer from 'Indexer/NoIndexer';
|
||||
import * as keyCodes from 'Utilities/Constants/keyCodes';
|
||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import SearchIndexFilterMenu from './Menus/SearchIndexFilterMenu';
|
||||
import SearchIndexSortMenu from './Menus/SearchIndexSortMenu';
|
||||
import NoSearchResults from './NoSearchResults';
|
||||
import SearchFooter from './SearchFooter.js';
|
||||
import SearchIndexTableConnector from './Table/SearchIndexTableConnector';
|
||||
import styles from './SearchIndex.css';
|
||||
@@ -126,9 +126,8 @@ class SearchIndex extends Component {
|
||||
this.setState({ jumpToCharacter });
|
||||
}
|
||||
|
||||
onSearchPress = (query) => {
|
||||
console.log('index', query);
|
||||
this.props.onSearchPress({ query });
|
||||
onSearchPress = (query, indexerIds) => {
|
||||
this.props.onSearchPress({ query, indexerIds });
|
||||
}
|
||||
|
||||
onKeyUp = (event) => {
|
||||
@@ -175,6 +174,8 @@ class SearchIndex extends Component {
|
||||
const isLoaded = !!(!error && isPopulated && items.length && scroller);
|
||||
const hasNoIndexer = !totalItems;
|
||||
|
||||
console.log(hasNoIndexer);
|
||||
|
||||
return (
|
||||
<PageContent>
|
||||
<PageToolbar>
|
||||
@@ -246,8 +247,8 @@ class SearchIndex extends Component {
|
||||
}
|
||||
|
||||
{
|
||||
!error && isPopulated && !items.length &&
|
||||
<NoIndexer totalItems={totalItems} />
|
||||
!error && !isFetching && !items.length &&
|
||||
<NoSearchResults totalItems={totalItems} />
|
||||
}
|
||||
</PageContentBody>
|
||||
|
||||
|
@@ -95,25 +95,7 @@ export const defaultState = {
|
||||
],
|
||||
|
||||
sortPredicates: {
|
||||
...sortPredicates,
|
||||
|
||||
studio: function(item) {
|
||||
const studio = item.studio;
|
||||
|
||||
return studio ? studio.toLowerCase() : '';
|
||||
},
|
||||
|
||||
collection: function(item) {
|
||||
const { collection ={} } = item;
|
||||
|
||||
return collection.name;
|
||||
},
|
||||
|
||||
ratings: function(item) {
|
||||
const { ratings = {} } = item;
|
||||
|
||||
return ratings.value;
|
||||
}
|
||||
...sortPredicates
|
||||
},
|
||||
|
||||
selectedFilterKey: 'all',
|
||||
@@ -122,12 +104,6 @@ export const defaultState = {
|
||||
filterPredicates,
|
||||
|
||||
filterBuilderProps: [
|
||||
{
|
||||
name: 'monitored',
|
||||
label: translate('Monitored'),
|
||||
type: filterBuilderTypes.EXACT,
|
||||
valueType: filterBuilderValueTypes.BOOL
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Indexer Name',
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import _ from 'lodash';
|
||||
import { createAction } from 'redux-actions';
|
||||
import { filterTypePredicates, filterTypes, sortDirections } from 'Helpers/Props';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
// import { batchActions } from 'redux-batched-actions';
|
||||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||
import dateFilterPredicate from 'Utilities/Date/dateFilterPredicate';
|
||||
import padNumber from 'Utilities/Number/padNumber';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import { updateItem } from './baseActions';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
@@ -24,123 +23,12 @@ export const filters = [
|
||||
key: 'all',
|
||||
label: translate('All'),
|
||||
filters: []
|
||||
},
|
||||
{
|
||||
key: 'monitored',
|
||||
label: translate('MonitoredOnly'),
|
||||
filters: [
|
||||
{
|
||||
key: 'monitored',
|
||||
value: true,
|
||||
type: filterTypes.EQUAL
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'unmonitored',
|
||||
label: translate('Unmonitored'),
|
||||
filters: [
|
||||
{
|
||||
key: 'monitored',
|
||||
value: false,
|
||||
type: filterTypes.EQUAL
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'missing',
|
||||
label: translate('Missing'),
|
||||
filters: [
|
||||
{
|
||||
key: 'monitored',
|
||||
value: true,
|
||||
type: filterTypes.EQUAL
|
||||
},
|
||||
{
|
||||
key: 'hasFile',
|
||||
value: false,
|
||||
type: filterTypes.EQUAL
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'wanted',
|
||||
label: translate('Wanted'),
|
||||
filters: [
|
||||
{
|
||||
key: 'monitored',
|
||||
value: true,
|
||||
type: filterTypes.EQUAL
|
||||
},
|
||||
{
|
||||
key: 'hasFile',
|
||||
value: false,
|
||||
type: filterTypes.EQUAL
|
||||
},
|
||||
{
|
||||
key: 'isAvailable',
|
||||
value: true,
|
||||
type: filterTypes.EQUAL
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'cutoffunmet',
|
||||
label: translate('CutoffUnmet'),
|
||||
filters: [
|
||||
{
|
||||
key: 'monitored',
|
||||
value: true,
|
||||
type: filterTypes.EQUAL
|
||||
},
|
||||
{
|
||||
key: 'hasFile',
|
||||
value: true,
|
||||
type: filterTypes.EQUAL
|
||||
},
|
||||
{
|
||||
key: 'qualityCutoffNotMet',
|
||||
value: true,
|
||||
type: filterTypes.EQUAL
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export const filterPredicates = {
|
||||
added: function(item, filterValue, type) {
|
||||
return dateFilterPredicate(item.added, filterValue, type);
|
||||
},
|
||||
|
||||
collection: function(item, filterValue, type) {
|
||||
const predicate = filterTypePredicates[type];
|
||||
const { collection } = item;
|
||||
|
||||
return predicate(collection ? collection.name : '', filterValue);
|
||||
},
|
||||
|
||||
inCinemas: function(item, filterValue, type) {
|
||||
return dateFilterPredicate(item.inCinemas, filterValue, type);
|
||||
},
|
||||
|
||||
physicalRelease: function(item, filterValue, type) {
|
||||
return dateFilterPredicate(item.physicalRelease, filterValue, type);
|
||||
},
|
||||
|
||||
digitalRelease: function(item, filterValue, type) {
|
||||
return dateFilterPredicate(item.digitalRelease, filterValue, type);
|
||||
},
|
||||
|
||||
ratings: function(item, filterValue, type) {
|
||||
const predicate = filterTypePredicates[type];
|
||||
|
||||
return predicate(item.ratings.value * 10, filterValue);
|
||||
},
|
||||
|
||||
qualityCutoffNotMet: function(item) {
|
||||
const { movieFile = {} } = item;
|
||||
|
||||
return movieFile.qualityCutoffNotMet;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -165,33 +53,6 @@ export const sortPredicates = {
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
movieStatus: function(item) {
|
||||
let result = 0;
|
||||
let qualityName = '';
|
||||
|
||||
const hasMovieFile = !!item.movieFile;
|
||||
|
||||
if (item.isAvailable) {
|
||||
result++;
|
||||
}
|
||||
|
||||
if (item.monitored) {
|
||||
result += 2;
|
||||
}
|
||||
|
||||
if (hasMovieFile) {
|
||||
// TODO: Consider Quality Weight for Sorting within status of hasMovie
|
||||
if (item.movieFile.qualityCutoffNotMet) {
|
||||
result += 4;
|
||||
} else {
|
||||
result += 8;
|
||||
}
|
||||
qualityName = item.movieFile.quality.quality.name;
|
||||
}
|
||||
|
||||
return padNumber(result.toString(), 2) + qualityName;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -205,7 +66,7 @@ export const defaultState = {
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
items: [],
|
||||
sortKey: 'sortTitle',
|
||||
sortKey: 'name',
|
||||
sortDirection: sortDirections.ASCENDING,
|
||||
pendingChanges: {}
|
||||
};
|
||||
|
@@ -1,74 +0,0 @@
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||
import { set, update } from './baseActions';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'movieTitles';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_MOVIE_TITLES = 'movieTitles/fetchMovieTitles';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchMovieTitles = createThunk(FETCH_MOVIE_TITLES);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[FETCH_MOVIE_TITLES]: function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const promise = createAjaxRequest({
|
||||
url: '/alttitle',
|
||||
data: payload
|
||||
}).request;
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
}, defaultState, section);
|
Reference in New Issue
Block a user