1
0
mirror of https://github.com/ascribe/onion.git synced 2024-11-15 09:35:10 +01:00
onion/js/components/piece_list.js

291 lines
12 KiB
JavaScript

'use strict';
import React from 'react';
import { History } from 'react-router';
import PieceListStore from '../stores/piece_list_store';
import PieceListActions from '../actions/piece_list_actions';
import EditionListStore from '../stores/edition_list_store';
import EditionListActions from '../actions/edition_list_actions';
import AccordionList from './ascribe_accordion_list/accordion_list';
import AccordionListItemWallet from './ascribe_accordion_list/accordion_list_item_wallet';
import AccordionListItemTableEditions from './ascribe_accordion_list/accordion_list_item_table_editions';
import AclButtonList from './ascribe_buttons/acl_button_list.js';
import DeleteButton from './ascribe_buttons/delete_button';
import Pagination from './ascribe_pagination/pagination';
import PieceListFilterDisplay from './piece_list_filter_display';
import PieceListBulkModal from './ascribe_piece_list_bulk_modal/piece_list_bulk_modal';
import PieceListToolbar from './ascribe_piece_list_toolbar/piece_list_toolbar';
import AscribeSpinner from './ascribe_spinner';
import { getAvailableAcls } from '../utils/acl_utils';
import { mergeOptions } from '../utils/general_utils';
import { getLangText } from '../utils/lang_utils';
import { setDocumentTitle } from '../utils/dom_utils';
let PieceList = React.createClass({
propTypes: {
accordionListItemType: React.PropTypes.func,
bulkModalButtonListType: React.PropTypes.func,
redirectTo: React.PropTypes.string,
customSubmitButton: React.PropTypes.element,
filterParams: React.PropTypes.array,
orderParams: React.PropTypes.array,
orderBy: React.PropTypes.string,
location: React.PropTypes.object
},
mixins: [History],
getDefaultProps() {
return {
accordionListItemType: AccordionListItemWallet,
bulkModalButtonListType: AclButtonList,
orderParams: ['artist_name', 'title'],
filterParams: [{
label: getLangText('Show works I can'),
items: [
'acl_transfer',
'acl_consign',
'acl_create_editions'
]
}]
};
},
getInitialState() {
const stores = mergeOptions(
PieceListStore.getState(),
EditionListStore.getState()
);
// Use the default filters but use the stores' settings if they're available
stores.filterBy = Object.assign(this.getDefaultFilterBy(), stores.filterBy);
return stores;
},
componentDidMount() {
let page = this.props.location.query.page || 1;
PieceListStore.listen(this.onChange);
EditionListStore.listen(this.onChange);
let orderBy = this.props.orderBy ? this.props.orderBy : this.state.orderBy;
if (this.state.pieceList.length === 0 || this.state.page !== page){
PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search,
orderBy, this.state.orderAsc, this.state.filterBy);
}
},
componentDidUpdate() {
if (this.props.redirectTo && this.state.unfilteredPieceListCount === 0) {
// FIXME: hack to redirect out of the dispatch cycle
window.setTimeout(() => this.history.pushState(null, this.props.redirectTo, this.props.location.query), 0);
}
},
componentWillUnmount() {
PieceListStore.unlisten(this.onChange);
EditionListStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
getDefaultFilterBy() {
const { filterParams } = this.props;
const defaultFilterBy = {};
filterParams.forEach(({ label, items }) => {
items.forEach((item) => {
if (typeof item === 'object' && item.defaultValue) {
defaultFilterBy[item.key] = true;
}
});
});
return defaultFilterBy;
},
paginationGoToPage(page) {
return () => {
// if the users clicks a pager of the pagination,
// the site should go to the top
document.body.scrollTop = document.documentElement.scrollTop = 0;
PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search,
this.state.orderBy, this.state.orderAsc,
this.state.filterBy);
};
},
getPagination() {
let currentPage = parseInt(this.props.location.query.page, 10) || 1;
let totalPages = Math.ceil(this.state.pieceListCount / this.state.pageSize);
if (this.state.pieceListCount > 20) {
return (
<Pagination
currentPage={currentPage}
totalPages={totalPages}
goToPage={this.paginationGoToPage} />
);
}
},
searchFor(searchTerm) {
PieceListActions.fetchPieceList(1, this.state.pageSize, searchTerm, this.state.orderBy,
this.state.orderAsc, this.state.filterBy);
this.history.pushState(null, this.props.location.pathname, {page: 1});
},
applyFilterBy(filterBy){
// first we need to apply the filter on the piece list
PieceListActions.fetchPieceList(1, this.state.pageSize, this.state.search,
this.state.orderBy, this.state.orderAsc, filterBy)
.then(() => {
// but also, we need to filter all the open edition lists
this.state.pieceList
.forEach((piece) => {
// but only if they're actually open
if(this.state.isEditionListOpenForPieceId[piece.id].show) {
EditionListActions.refreshEditionList({
pieceId: piece.id,
filterBy
});
}
});
});
// we have to redirect the user always to page one as it could be that there is no page two
// for filtered pieces
this.history.pushState(null, this.props.location.pathname, {page: 1});
},
applyOrderBy(orderBy) {
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
orderBy, this.state.orderAsc, this.state.filterBy);
},
fetchSelectedPieceEditionList() {
let filteredPieceIdList = Object.keys(this.state.editionList)
.filter((pieceId) => {
return this.state.editionList[pieceId]
.filter((edition) => edition.selected).length > 0;
});
return filteredPieceIdList;
},
fetchSelectedEditionList() {
let selectedEditionList = [];
Object
.keys(this.state.editionList)
.forEach((pieceId) => {
let filteredEditionsForPiece = this.state.editionList[pieceId].filter((edition) => edition.selected);
selectedEditionList = selectedEditionList.concat(filteredEditionsForPiece);
});
return selectedEditionList;
},
handleAclSuccess() {
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
this.state.orderBy, this.state.orderAsc, this.state.filterBy);
this.fetchSelectedPieceEditionList()
.forEach((pieceId) => {
EditionListActions.refreshEditionList({pieceId});
});
EditionListActions.clearAllEditionSelections();
},
render() {
const loadingElement = <AscribeSpinner color='dark-blue' size='lg'/>;
const AccordionListItemType = this.props.accordionListItemType;
const BulkModalButtonListType = this.props.bulkModalButtonListType;
const selectedEditions = this.fetchSelectedEditionList();
const availableAcls = getAvailableAcls(selectedEditions, (aclName) => aclName !== 'acl_view');
setDocumentTitle(getLangText('Collection'));
return (
<div>
<PieceListToolbar
className="ascribe-piece-list-toolbar"
searchFor={this.searchFor}
searchQuery={this.state.search}
filterParams={this.props.filterParams}
orderParams={this.props.orderParams}
filterBy={this.state.filterBy}
orderBy={this.state.orderBy}
applyFilterBy={this.applyFilterBy}
applyOrderBy={this.applyOrderBy}>
{this.props.customSubmitButton ?
this.props.customSubmitButton :
<button className="btn btn-default btn-ascribe-add">
<span className="icon-ascribe icon-ascribe-add" />
</button>
}
</PieceListToolbar>
<PieceListBulkModal
availableAcls={availableAcls}
selectedEditions={selectedEditions}
className="ascribe-piece-list-bulk-modal">
<BulkModalButtonListType
availableAcls={availableAcls}
pieceOrEditions={selectedEditions}
handleSuccess={this.handleAclSuccess}
className="text-center ascribe-button-list collapse-group">
<DeleteButton
handleSuccess={this.handleAclSuccess}
editions={selectedEditions}/>
</BulkModalButtonListType>
</PieceListBulkModal>
<PieceListFilterDisplay
filterBy={this.state.filterBy}
filterParams={this.props.filterParams}/>
<AccordionList
className="ascribe-accordion-list"
changeOrder={this.accordionChangeOrder}
itemList={this.state.pieceList}
count={this.state.pieceListCount}
orderBy={this.state.orderBy}
orderAsc={this.state.orderAsc}
search={this.state.search}
searchFor={this.searchFor}
page={this.state.page}
pageSize={this.state.pageSize}
loadingElement={loadingElement}>
{this.state.pieceList.map((piece, i) => {
return (
<AccordionListItemType
className="col-xs-12 col-sm-10 col-md-8 col-lg-8 col-sm-offset-1 col-md-offset-2 col-lg-offset-2 ascribe-accordion-list-item"
content={piece}
key={i}>
<AccordionListItemTableEditions
className="ascribe-accordion-list-item-table col-xs-12 col-sm-10 col-md-8 col-lg-8 col-sm-offset-1 col-md-offset-2 col-lg-offset-2"
parentId={piece.id} />
</AccordionListItemType>
);
})}
</AccordionList>
{this.getPagination()}
</div>
);
}
});
export default PieceList;