2015-06-05 11:06:36 +02:00
|
|
|
'use strict';
|
|
|
|
|
2015-05-19 17:13:09 +02:00
|
|
|
import React from 'react';
|
2015-10-01 11:16:38 +02:00
|
|
|
import { History } from 'react-router';
|
2015-05-19 17:13:09 +02:00
|
|
|
|
|
|
|
import PieceListStore from '../stores/piece_list_store';
|
|
|
|
import PieceListActions from '../actions/piece_list_actions';
|
2015-05-20 15:22:29 +02:00
|
|
|
|
2015-08-07 13:05:50 +02:00
|
|
|
import EditionListStore from '../stores/edition_list_store';
|
|
|
|
import EditionListActions from '../actions/edition_list_actions';
|
|
|
|
|
2015-05-29 16:28:05 +02:00
|
|
|
import AccordionList from './ascribe_accordion_list/accordion_list';
|
2015-08-11 12:06:01 +02:00
|
|
|
import AccordionListItemWallet from './ascribe_accordion_list/accordion_list_item_wallet';
|
2015-06-01 11:51:03 +02:00
|
|
|
import AccordionListItemTableEditions from './ascribe_accordion_list/accordion_list_item_table_editions';
|
2015-05-21 16:02:42 +02:00
|
|
|
|
2015-10-26 19:17:06 +01:00
|
|
|
import AclButtonList from './ascribe_buttons/acl_button_list.js';
|
|
|
|
import DeleteButton from './ascribe_buttons/delete_button';
|
|
|
|
|
2015-05-27 13:57:11 +02:00
|
|
|
import Pagination from './ascribe_pagination/pagination';
|
|
|
|
|
2015-09-16 21:21:30 +02:00
|
|
|
import PieceListFilterDisplay from './piece_list_filter_display';
|
|
|
|
|
2015-06-02 09:10:26 +02:00
|
|
|
import PieceListBulkModal from './ascribe_piece_list_bulk_modal/piece_list_bulk_modal';
|
2015-06-02 10:10:09 +02:00
|
|
|
import PieceListToolbar from './ascribe_piece_list_toolbar/piece_list_toolbar';
|
2015-05-19 17:13:09 +02:00
|
|
|
|
2015-10-08 11:12:15 +02:00
|
|
|
import AscribeSpinner from './ascribe_spinner';
|
|
|
|
|
2015-10-26 19:17:06 +01:00
|
|
|
import { getAvailableAcls } from '../utils/acl_utils';
|
2015-11-24 19:26:45 +01:00
|
|
|
import { mergeOptions, isShallowEqual } from '../utils/general_utils';
|
2015-09-16 21:21:30 +02:00
|
|
|
import { getLangText } from '../utils/lang_utils';
|
2015-10-13 16:42:40 +02:00
|
|
|
import { setDocumentTitle } from '../utils/dom_utils';
|
2015-09-16 21:21:30 +02:00
|
|
|
|
2015-05-20 16:44:45 +02:00
|
|
|
|
2015-05-19 17:16:01 +02:00
|
|
|
let PieceList = React.createClass({
|
2015-06-05 11:06:36 +02:00
|
|
|
propTypes: {
|
2015-08-11 17:12:12 +02:00
|
|
|
accordionListItemType: React.PropTypes.func,
|
2015-10-26 19:17:06 +01:00
|
|
|
bulkModalButtonListType: React.PropTypes.func,
|
2015-11-24 19:26:45 +01:00
|
|
|
canLoadPieceList: React.PropTypes.bool,
|
2015-07-14 21:13:15 +02:00
|
|
|
redirectTo: React.PropTypes.string,
|
2015-12-14 18:34:27 +01:00
|
|
|
shouldRedirect: React.PropTypes.func,
|
2015-08-14 14:58:23 +02:00
|
|
|
customSubmitButton: React.PropTypes.element,
|
2015-12-04 13:52:17 +01:00
|
|
|
customThumbnailPlaceholder: React.PropTypes.func,
|
2015-08-14 14:58:23 +02:00
|
|
|
filterParams: React.PropTypes.array,
|
2015-08-26 15:46:27 +02:00
|
|
|
orderParams: React.PropTypes.array,
|
2015-10-01 11:16:38 +02:00
|
|
|
orderBy: React.PropTypes.string,
|
|
|
|
location: React.PropTypes.object
|
2015-06-05 11:06:36 +02:00
|
|
|
},
|
|
|
|
|
2015-10-01 11:16:38 +02:00
|
|
|
mixins: [History],
|
2015-06-16 09:27:04 +02:00
|
|
|
|
2015-08-11 12:06:01 +02:00
|
|
|
getDefaultProps() {
|
|
|
|
return {
|
2015-08-14 14:58:23 +02:00
|
|
|
accordionListItemType: AccordionListItemWallet,
|
2015-10-26 19:17:06 +01:00
|
|
|
bulkModalButtonListType: AclButtonList,
|
2015-11-24 19:26:45 +01:00
|
|
|
canLoadPieceList: true,
|
2015-08-14 14:58:23 +02:00
|
|
|
orderParams: ['artist_name', 'title'],
|
2015-09-16 23:36:21 +02:00
|
|
|
filterParams: [{
|
|
|
|
label: getLangText('Show works I can'),
|
|
|
|
items: [
|
2015-09-17 11:39:45 +02:00
|
|
|
'acl_transfer',
|
|
|
|
'acl_consign',
|
|
|
|
'acl_create_editions'
|
|
|
|
]
|
2015-09-16 23:36:21 +02:00
|
|
|
}]
|
2015-08-11 12:06:01 +02:00
|
|
|
};
|
|
|
|
},
|
2015-11-06 14:10:54 +01:00
|
|
|
|
2015-05-21 12:12:25 +02:00
|
|
|
getInitialState() {
|
2015-11-24 19:26:45 +01:00
|
|
|
const pieceListStore = PieceListStore.getState();
|
2015-11-06 14:10:54 +01:00
|
|
|
const stores = mergeOptions(
|
2015-11-24 19:26:45 +01:00
|
|
|
pieceListStore,
|
|
|
|
EditionListStore.getState(),
|
|
|
|
{
|
|
|
|
isFilterDirty: false
|
|
|
|
}
|
2015-08-07 13:05:50 +02:00
|
|
|
);
|
2015-11-06 14:10:54 +01:00
|
|
|
|
2015-11-24 19:26:45 +01:00
|
|
|
// Use the default filters but use the pieceListStore's settings if they're available
|
|
|
|
stores.filterBy = Object.assign(this.getDefaultFilterBy(), pieceListStore.filterBy);
|
2015-11-06 14:10:54 +01:00
|
|
|
|
|
|
|
return stores;
|
2015-05-21 12:12:25 +02:00
|
|
|
},
|
|
|
|
|
2015-05-19 17:13:09 +02:00
|
|
|
componentDidMount() {
|
2015-05-26 11:47:56 +02:00
|
|
|
PieceListStore.listen(this.onChange);
|
2015-08-07 13:05:50 +02:00
|
|
|
EditionListStore.listen(this.onChange);
|
2015-08-31 16:36:24 +02:00
|
|
|
|
2015-11-24 19:26:45 +01:00
|
|
|
let page = this.props.location.query.page || 1;
|
|
|
|
if (this.props.canLoadPieceList && (this.state.pieceList.length === 0 || this.state.page !== page)) {
|
|
|
|
this.loadPieceList({ page });
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
|
let filterBy;
|
|
|
|
let page = this.props.location.query.page || 1;
|
|
|
|
|
|
|
|
// If the user hasn't changed the filter and the new default filter is different
|
|
|
|
// than the current filter, apply the new default filter
|
|
|
|
if (!this.state.isFilterDirty) {
|
|
|
|
const newDefaultFilterBy = this.getDefaultFilterBy(nextProps);
|
|
|
|
|
|
|
|
// Only need to check shallowly since the filterBy shouldn't be nested
|
|
|
|
if (!isShallowEqual(this.state.filterBy, newDefaultFilterBy)) {
|
|
|
|
filterBy = newDefaultFilterBy;
|
|
|
|
page = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only load if we are applying a new filter or if it's the first time we can
|
|
|
|
// load the piece list
|
|
|
|
if (nextProps.canLoadPieceList && (filterBy || !this.props.canLoadPieceList)) {
|
|
|
|
this.loadPieceList({ page, filterBy });
|
2015-06-09 16:10:38 +02:00
|
|
|
}
|
2015-05-19 17:13:09 +02:00
|
|
|
},
|
|
|
|
|
2015-07-13 22:05:16 +02:00
|
|
|
componentDidUpdate() {
|
2016-01-05 17:27:25 +01:00
|
|
|
const { location: { query }, redirectTo, shouldRedirect } = this.props;
|
2015-12-14 18:34:27 +01:00
|
|
|
const { unfilteredPieceListCount } = this.state;
|
|
|
|
|
|
|
|
if (redirectTo && unfilteredPieceListCount === 0 &&
|
|
|
|
(typeof shouldRedirect === 'function' && shouldRedirect(unfilteredPieceListCount))) {
|
2015-07-14 23:11:23 +02:00
|
|
|
// FIXME: hack to redirect out of the dispatch cycle
|
2016-01-05 17:27:25 +01:00
|
|
|
window.setTimeout(() => this.history.push({ query, pathname: redirectTo }), 0);
|
2015-07-13 22:05:16 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-05-22 17:11:17 +02:00
|
|
|
componentWillUnmount() {
|
|
|
|
PieceListStore.unlisten(this.onChange);
|
2015-08-07 13:05:50 +02:00
|
|
|
EditionListStore.unlisten(this.onChange);
|
2015-05-22 17:11:17 +02:00
|
|
|
},
|
|
|
|
|
2015-05-26 13:14:35 +02:00
|
|
|
onChange(state) {
|
|
|
|
this.setState(state);
|
2015-05-22 17:11:17 +02:00
|
|
|
},
|
|
|
|
|
2015-11-24 19:26:45 +01:00
|
|
|
getDefaultFilterBy(props = this.props) {
|
|
|
|
const { filterParams } = props;
|
2015-11-06 14:10:54 +01:00
|
|
|
const defaultFilterBy = {};
|
|
|
|
|
2015-11-24 19:26:45 +01:00
|
|
|
if (filterParams && typeof filterParams.forEach === 'function') {
|
2015-12-02 12:23:38 +01:00
|
|
|
filterParams.forEach(({ items }) => {
|
2015-11-24 19:26:45 +01:00
|
|
|
items.forEach((item) => {
|
|
|
|
if (typeof item === 'object' && item.defaultValue) {
|
|
|
|
defaultFilterBy[item.key] = true;
|
|
|
|
}
|
|
|
|
});
|
2015-11-06 14:10:54 +01:00
|
|
|
});
|
2015-11-24 19:26:45 +01:00
|
|
|
}
|
2015-11-06 14:10:54 +01:00
|
|
|
|
|
|
|
return defaultFilterBy;
|
|
|
|
},
|
|
|
|
|
2015-05-22 12:58:06 +02:00
|
|
|
paginationGoToPage(page) {
|
2015-08-07 13:05:50 +02:00
|
|
|
return () => {
|
|
|
|
// if the users clicks a pager of the pagination,
|
|
|
|
// the site should go to the top
|
|
|
|
document.body.scrollTop = document.documentElement.scrollTop = 0;
|
2015-11-24 19:26:45 +01:00
|
|
|
this.loadPieceList({ page });
|
2015-08-07 13:05:50 +02:00
|
|
|
};
|
2015-05-22 13:58:09 +02:00
|
|
|
},
|
|
|
|
|
2015-07-13 21:51:05 +02:00
|
|
|
getPagination() {
|
2015-10-01 11:16:38 +02:00
|
|
|
let currentPage = parseInt(this.props.location.query.page, 10) || 1;
|
2015-07-13 21:51:05 +02:00
|
|
|
let totalPages = Math.ceil(this.state.pieceListCount / this.state.pageSize);
|
|
|
|
|
2015-10-09 02:00:02 +02:00
|
|
|
if (this.state.pieceListCount > 20) {
|
2015-07-13 21:51:05 +02:00
|
|
|
return (
|
|
|
|
<Pagination
|
|
|
|
currentPage={currentPage}
|
|
|
|
totalPages={totalPages}
|
|
|
|
goToPage={this.paginationGoToPage} />
|
|
|
|
);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-01-05 17:27:25 +01:00
|
|
|
searchFor(search) {
|
|
|
|
const { location: { pathname } } = this.props;
|
|
|
|
|
|
|
|
this.loadPieceList({ search, page: 1 });
|
|
|
|
this.history.push({ pathname, query: { page: 1 } });
|
2015-06-16 09:27:04 +02:00
|
|
|
},
|
|
|
|
|
2016-01-05 17:27:25 +01:00
|
|
|
applyFilterBy(filterBy) {
|
|
|
|
const { location: { pathname } } = this.props;
|
|
|
|
|
2015-11-24 19:26:45 +01:00
|
|
|
this.setState({
|
|
|
|
isFilterDirty: true
|
|
|
|
});
|
|
|
|
|
2015-08-07 13:05:50 +02:00
|
|
|
// first we need to apply the filter on the piece list
|
2015-11-24 19:26:45 +01:00
|
|
|
this
|
|
|
|
.loadPieceList({ page: 1, 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
|
2015-12-09 18:02:14 +01:00
|
|
|
const isEditionListOpenForPiece = this.state.isEditionListOpenForPieceId[piece.id];
|
|
|
|
|
|
|
|
if (isEditionListOpenForPiece && isEditionListOpenForPiece.show) {
|
2015-11-24 19:26:45 +01:00
|
|
|
EditionListActions.refreshEditionList({
|
|
|
|
pieceId: piece.id,
|
|
|
|
filterBy
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2015-08-07 13:05:50 +02:00
|
|
|
|
2015-08-06 13:15:52 +02:00
|
|
|
// we have to redirect the user always to page one as it could be that there is no page two
|
|
|
|
// for filtered pieces
|
2016-01-05 17:27:25 +01:00
|
|
|
this.history.push({ pathname, query: { page: 1 } });
|
2015-08-06 13:15:52 +02:00
|
|
|
},
|
|
|
|
|
2015-08-19 15:30:48 +02:00
|
|
|
applyOrderBy(orderBy) {
|
2015-12-08 15:09:03 +01:00
|
|
|
const { filterBy, orderAsc, page, pageSize, search } = this.state;
|
2016-01-18 10:53:01 +01:00
|
|
|
PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
|
2015-05-22 12:58:06 +02:00
|
|
|
},
|
|
|
|
|
2015-11-24 19:26:45 +01:00
|
|
|
loadPieceList({ page, filterBy = this.state.filterBy, search = this.state.search }) {
|
2015-12-08 15:09:03 +01:00
|
|
|
const { orderAsc, pageSize } = this.state;
|
2015-12-02 12:23:38 +01:00
|
|
|
const orderBy = this.state.orderBy || this.props.orderBy;
|
2015-11-24 19:26:45 +01:00
|
|
|
|
2016-01-18 10:53:01 +01:00
|
|
|
return PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
|
2015-11-24 19:26:45 +01:00
|
|
|
},
|
|
|
|
|
2015-10-26 19:17:06 +01:00
|
|
|
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() {
|
2015-12-08 15:09:03 +01:00
|
|
|
const { filterBy, orderBy, orderAsc, page, pageSize, search } = this.state;
|
|
|
|
|
2016-01-18 10:53:01 +01:00
|
|
|
PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
|
2015-10-26 19:17:06 +01:00
|
|
|
|
|
|
|
this.fetchSelectedPieceEditionList()
|
|
|
|
.forEach((pieceId) => {
|
2015-11-04 00:41:12 +01:00
|
|
|
EditionListActions.refreshEditionList({pieceId});
|
2015-10-26 19:17:06 +01:00
|
|
|
});
|
|
|
|
EditionListActions.clearAllEditionSelections();
|
|
|
|
},
|
|
|
|
|
2015-05-19 17:13:09 +02:00
|
|
|
render() {
|
2015-12-02 19:31:50 +01:00
|
|
|
const {
|
|
|
|
accordionListItemType: AccordionListItemType,
|
|
|
|
bulkModalButtonListType: BulkModalButtonListType,
|
|
|
|
customSubmitButton,
|
|
|
|
customThumbnailPlaceholder,
|
|
|
|
filterParams,
|
|
|
|
orderParams } = this.props;
|
|
|
|
|
2015-10-26 19:17:06 +01:00
|
|
|
const loadingElement = <AscribeSpinner color='dark-blue' size='lg'/>;
|
|
|
|
|
|
|
|
const selectedEditions = this.fetchSelectedEditionList();
|
|
|
|
const availableAcls = getAvailableAcls(selectedEditions, (aclName) => aclName !== 'acl_view');
|
2015-08-28 15:24:32 +02:00
|
|
|
|
2015-10-13 16:42:40 +02:00
|
|
|
setDocumentTitle(getLangText('Collection'));
|
2015-05-29 16:28:05 +02:00
|
|
|
return (
|
2015-06-01 11:51:03 +02:00
|
|
|
<div>
|
2015-07-14 18:54:47 +02:00
|
|
|
<PieceListToolbar
|
|
|
|
className="ascribe-piece-list-toolbar"
|
2015-08-06 13:15:52 +02:00
|
|
|
searchFor={this.searchFor}
|
2015-10-12 16:38:00 +02:00
|
|
|
searchQuery={this.state.search}
|
2015-12-02 19:31:50 +01:00
|
|
|
filterParams={filterParams}
|
|
|
|
orderParams={orderParams}
|
2015-08-06 13:15:52 +02:00
|
|
|
filterBy={this.state.filterBy}
|
2015-08-14 14:58:23 +02:00
|
|
|
orderBy={this.state.orderBy}
|
|
|
|
applyFilterBy={this.applyFilterBy}
|
|
|
|
applyOrderBy={this.applyOrderBy}>
|
2015-12-02 19:31:50 +01:00
|
|
|
{customSubmitButton ?
|
|
|
|
customSubmitButton :
|
2015-10-12 15:25:21 +02:00
|
|
|
<button className="btn btn-default btn-ascribe-add">
|
|
|
|
<span className="icon-ascribe icon-ascribe-add" />
|
|
|
|
</button>
|
2015-10-12 12:08:53 +02:00
|
|
|
}
|
2015-07-14 21:13:15 +02:00
|
|
|
</PieceListToolbar>
|
2015-10-21 17:37:29 +02:00
|
|
|
<PieceListBulkModal
|
2015-10-26 19:17:06 +01:00
|
|
|
availableAcls={availableAcls}
|
|
|
|
selectedEditions={selectedEditions}
|
|
|
|
className="ascribe-piece-list-bulk-modal">
|
|
|
|
<BulkModalButtonListType
|
|
|
|
availableAcls={availableAcls}
|
2015-11-03 12:10:21 +01:00
|
|
|
pieceOrEditions={selectedEditions}
|
2015-10-26 19:17:06 +01:00
|
|
|
handleSuccess={this.handleAclSuccess}
|
|
|
|
className="text-center ascribe-button-list collapse-group">
|
|
|
|
<DeleteButton
|
|
|
|
handleSuccess={this.handleAclSuccess}
|
|
|
|
editions={selectedEditions}/>
|
|
|
|
</BulkModalButtonListType>
|
|
|
|
</PieceListBulkModal>
|
2015-09-16 23:36:21 +02:00
|
|
|
<PieceListFilterDisplay
|
|
|
|
filterBy={this.state.filterBy}
|
2015-12-02 19:31:50 +01:00
|
|
|
filterParams={filterParams}/>
|
2015-05-29 16:28:05 +02:00
|
|
|
<AccordionList
|
2015-06-01 11:51:03 +02:00
|
|
|
className="ascribe-accordion-list"
|
2015-05-29 16:28:05 +02:00
|
|
|
changeOrder={this.accordionChangeOrder}
|
|
|
|
itemList={this.state.pieceList}
|
2015-07-07 09:22:46 +02:00
|
|
|
count={this.state.pieceListCount}
|
2015-05-29 16:28:05 +02:00
|
|
|
orderBy={this.state.orderBy}
|
|
|
|
orderAsc={this.state.orderAsc}
|
|
|
|
search={this.state.search}
|
2015-10-13 17:28:10 +02:00
|
|
|
searchFor={this.searchFor}
|
2015-05-29 16:28:05 +02:00
|
|
|
page={this.state.page}
|
2015-06-16 09:57:14 +02:00
|
|
|
pageSize={this.state.pageSize}
|
|
|
|
loadingElement={loadingElement}>
|
2015-07-07 09:31:56 +02:00
|
|
|
{this.state.pieceList.map((piece, i) => {
|
2015-05-29 16:28:05 +02:00
|
|
|
return (
|
2015-08-11 12:06:01 +02:00
|
|
|
<AccordionListItemType
|
2015-05-29 16:28:05 +02:00
|
|
|
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"
|
2015-07-07 09:31:56 +02:00
|
|
|
content={piece}
|
2015-12-02 19:31:50 +01:00
|
|
|
thumbnailPlaceholder={customThumbnailPlaceholder}
|
2015-06-01 11:51:03 +02:00
|
|
|
key={i}>
|
2015-07-09 14:04:48 +02:00
|
|
|
<AccordionListItemTableEditions
|
2015-07-09 16:29:10 +02:00
|
|
|
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"
|
2015-07-09 14:04:48 +02:00
|
|
|
parentId={piece.id} />
|
2015-08-11 12:06:01 +02:00
|
|
|
</AccordionListItemType>
|
2015-05-29 16:28:05 +02:00
|
|
|
);
|
|
|
|
})}
|
|
|
|
</AccordionList>
|
2015-07-13 21:51:05 +02:00
|
|
|
{this.getPagination()}
|
2015-05-29 16:28:05 +02:00
|
|
|
</div>
|
|
|
|
);
|
2015-05-19 17:13:09 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
export default PieceList;
|