public/components/BatchTag.react.js (186 lines of code) (raw):
import React from 'react';
import ContentList from './ContentList/ContentList';
import PageNavigator from './utils/PageNavigator.react';
import BatchTagControls from './BatchTagControls/BatchTagControls';
import BatchFilters from './BatchTag/BatchFilters.react';
import {BatchTagArbitraryUrls} from "./BatchTagControls/BatchTagArbitraryUrls";
import R from 'ramda';
const CAPI_PAGE_SIZE = 10;
const PAGE_NAV_SPAN = 5;
export class BatchTag extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedContent: [],
showFilters: false
};
this.searchContent = this.searchContent.bind(this);
}
componentDidMount() {
if (!this.props.sections || !this.props.sections.length) {
this.props.sectionActions.getSections();
}
}
UNSAFE_componentWillUpdate(newProps, newState) {
const prevCount = this.state.selectedContent.length;
const newCount = newState.selectedContent.length;
if (prevCount === 0 && newCount > 0) {
window.onbeforeunload = function() {
return 'Unsaved batch tag changes, are you sure you want to leave?';
};
}
if (prevCount > 0 && newCount === 0) {
window.onbeforeunload = null;
}
}
UNSAFE_componentWillUnmount() {
window.onbeforeunload = null;
}
searchFieldChange(type, e) {
const searchTerm = type === 'searchTerm' ? e.target.value : this.props.capiSearch.searchTerm;
const byline = type === 'byline' ? e.target.value : this.props.capiSearch.byline;
this.searchContent(searchTerm, byline);
}
searchContent(searchString, byline, filters, page = 1) {
this.props.capiActions.clearPages();
this.state.selectedContent = [];
const applyFilters = this.state.showFilters ? filters || this.props.capiSearch.filters : {};
const params = Object.assign({}, applyFilters, {
'show-tags': 'all',
'page-size': CAPI_PAGE_SIZE,
'page': page
});
this.props.capiActions.searchPreviewCapi(searchString, byline, params);
}
applyFilters(filters) {
this.props.capiActions.updateFilters(filters);
this.searchContent(this.props.capiSearch.searchTerm, this.props.capiSearch.byline, filters);
}
toggleFilters() {
this.setState({
showFilters: !this.state.showFilters
});
}
toggleContentSelected(content) {
const addSelectedContent = R.append(content.id);
const removeSelectedContent = R.reject(R.equals(content.id));
if (this.state.selectedContent.indexOf(content.id) === -1) {
this.setState({
selectedContent: addSelectedContent(this.state.selectedContent)
});
} else {
this.setState({
selectedContent: removeSelectedContent(this.state.selectedContent)
});
}
}
selectAllContentFromPage(page) {
this.setState({
selectedContent: R.union(this.state.selectedContent, page.filter(c => !!c.fields.internalComposerCode).map(c => c.id))
});
}
deselectAllContentFromPage(page) {
var newContent = R.difference(this.state.selectedContent, page.filter(c => !!c.fields.internalComposerCode).map(c => c.id));
this.setState({
selectedContent: newContent
});
}
toggleAllSelected() {
const currentPage = this.props.capiSearch.pages[this.props.capiSearch.currentPage];
const notSelectedResults = R.difference(currentPage.filter(c => !!c.fields.internalComposerCode).map((content) => content.id), this.state.selectedContent);
if (notSelectedResults.length) {
this.selectAllContentFromPage(currentPage);
} else {
this.deselectAllContentFromPage(currentPage);
}
}
renderSearchStatus() {
if (this.props.capiSearch.pageRequestCount > 0) {
return (
<div className="batch-tag__info">
Searching...
</div>
);
}
if (this.props.capiSearch.pageRequestCount === 0 && this.props.capiSearch.pages[1].length === 0) {
return (
<div className="batch-tag__error">
No results found
</div>
);
}
return false;
}
pageSelectCallback(page) {
const applyFilters = this.state.showFilters ? this.props.capiSearch.filters : {};
const params = Object.assign({}, applyFilters, {
'show-tags': 'all',
'page-size': CAPI_PAGE_SIZE,
'page': page
});
if (this.props.capiSearch.pages[page]) {
// If we already have the page just used the cached version
this.props.capiActions.switchPage(page);
} else {
this.props.capiActions.searchPreviewCapi(this.props.capiSearch.searchTerm, this.props.capiSearch.byline, params);
}
}
renderPageNavigator() {
var count = this.props.capiSearch.count;
if (count > 0 && count > CAPI_PAGE_SIZE) {
return (<PageNavigator
pageSelectCallback={this.pageSelectCallback.bind(this)}
currentPage={this.props.capiSearch.currentPage}
pageSpan={PAGE_NAV_SPAN}
lastPage={Math.ceil(this.props.capiSearch.count / CAPI_PAGE_SIZE)}/>);
}
return false;
}
renderContent() {
if (this.props.capiSearch.count > 0) {
return (<div className="batch-tag__content">
<ContentList
content={this.props.capiSearch.pages[this.props.capiSearch.currentPage]}
selectedContent={this.state.selectedContent}
contentClicked={this.toggleContentSelected.bind(this)}
toggleAllSelected={this.toggleAllSelected.bind(this)}
/>
</div>);
}
return false;
}
render () {
return (
<div className="batch-tag">
<div className="batch-tag__filters">
<div className="batch-tag__filters__group">
<label>Search by query</label>
<input className="batch-tag__input" type="text" value={this.props.capiSearch.searchTerm || ''} onChange={this.searchFieldChange.bind(this, 'searchTerm')} />
</div>
<div className="batch-tag__filters__group">
<label>Search by byline</label>
<input className="batch-tag__input" type="text" value={this.props.capiSearch.byline || ''} onChange={this.searchFieldChange.bind(this, 'byline')} />
</div>
{" OR "}<BatchTagArbitraryUrls addPathsToSelection={(paths) => this.setState({selectedContent: R.union(this.state.selectedContent, paths)})}/>
<div className="batch-tag__show-filters" onClick={this.toggleFilters.bind(this)}>
{ this.state.showFilters ? 'Hide Filters' : 'Show Filters'}
</div>
</div>
{this.state.showFilters ? <BatchFilters filters={this.props.capiSearch.filters || {}} updateFilters={this.applyFilters.bind(this)} sections={this.props.sections}/> : false}
{this.renderSearchStatus()}
{this.renderPageNavigator()}
{this.renderContent()}
{this.renderPageNavigator()}
<div className="batch-tag__status">
<BatchTagControls
selectedContent={this.state.selectedContent}
/>
</div>
</div>
);
}
}
//REDUX CONNECTIONS
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as searchCapi from '../actions/CapiActions/searchCapi';
import * as getSections from '../actions/SectionsActions/getSections';
function mapStateToProps(state) {
return {
config: state.config,
capiSearch: state.capiSearch,
sections: state.sections
};
}
function mapDispatchToProps(dispatch) {
return {
capiActions: bindActionCreators(Object.assign({}, searchCapi), dispatch),
sectionActions: bindActionCreators(Object.assign({}, getSections), dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(BatchTag);