'use strict'; import React from 'react'; import { History } from 'react-router'; import Moment from 'moment'; import ReactError from '../../mixins/react_error'; import { ResourceNotFoundError } from '../../models/errors'; import EditionListActions from '../../actions/edition_list_actions'; import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; import PieceActions from '../../actions/piece_actions'; import PieceStore from '../../stores/piece_store'; import PieceListActions from '../../actions/piece_list_actions'; import PieceListStore from '../../stores/piece_list_store'; import FurtherDetails from './further_details'; import DetailProperty from './detail_property'; import HistoryIterator from './history_iterator'; import LicenseDetail from './license_detail'; import Note from './note'; import Piece from './piece'; import AclButtonList from './../ascribe_buttons/acl_button_list'; import AclInformation from '../ascribe_buttons/acl_information'; import CreateEditionsButton from '../ascribe_buttons/create_editions_button'; import DeleteButton from '../ascribe_buttons/delete_button'; import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph'; import CreateEditionsForm from '../ascribe_forms/create_editions_form'; import ListRequestActions from '../ascribe_forms/list_form_request_actions'; import AclProxy from '../acl_proxy'; import ApiUrls from '../../constants/api_urls'; import AscribeSpinner from '../ascribe_spinner'; import { mergeOptions } from '../../utils/general_utils'; import { getLangText } from '../../utils/lang_utils'; import { setDocumentTitle } from '../../utils/dom_utils'; /** * This is the component that implements resource/data specific functionality */ let PieceContainer = React.createClass({ propTypes: { furtherDetailsType: React.PropTypes.func, // Provided from AscribeApp currentUser: React.PropTypes.object.isRequired, whitelabel: React.PropTypes.object, // Provided from router location: React.PropTypes.object, params: React.PropTypes.object }, mixins: [History, ReactError], getDefaultProps() { return { furtherDetailsType: FurtherDetails }; }, getInitialState() { return mergeOptions( PieceListStore.getState(), PieceStore.getInitialState(), { showCreateEditionsDialog: false } ); }, componentDidMount() { PieceListStore.listen(this.onChange); PieceStore.listen(this.onChange); this.loadPiece(); }, // This is done to update the container when the user clicks on the prev or next // button to update the URL parameter (and therefore to switch pieces) or // when the user clicks on a notification while being in another piece view componentWillReceiveProps(nextProps) { if (this.props.params.pieceId !== nextProps.params.pieceId) { PieceActions.flushPiece(); this.loadPiece(nextProps.params.pieceId); } }, componentDidUpdate() { const { err: pieceErr } = this.state.pieceMeta; if (pieceErr && pieceErr.json && pieceErr.json.status === 404) { this.throws(new ResourceNotFoundError(getLangText("Oops, the piece you're looking for doesn't exist."))); } }, componentWillUnmount() { PieceStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange); }, onChange(state) { /* ATTENTION: THIS IS JUST A TEMPORARY USABILITY FIX THAT ESSENTIALLY REMOVES THE LOAN BUTTON FROM THE PIECE DETAIL PAGE SO THAT USERS DO NOT CONFUSE A PIECE WITH AN EDITION. IT SHOULD BE REMOVED AND REPLACED WITH A BETTER SOLUTION ASAP! ALSO, WE ENABLED THE LOAN BUTTON FOR IKONOTV TO LET THEM LOAN ON A PIECE LEVEL */ if (state && state.piece && state.piece.acl && typeof state.piece.acl.acl_loan !== 'undefined') { let pieceState = mergeOptions({}, state.piece); pieceState.acl.acl_loan = false; this.setState({ piece: pieceState }); } else { this.setState(state); } }, loadPiece(pieceId = this.props.params.pieceId) { PieceActions.fetchPiece(pieceId); }, toggleCreateEditionsDialog() { this.setState({ showCreateEditionsDialog: !this.state.showCreateEditionsDialog }); }, handleEditionCreationSuccess() { const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state; PieceActions.updateProperty({ key: 'num_editions', value: 0 }); PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy }); this.toggleCreateEditionsDialog(); }, handleDeleteSuccess(response) { const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state; PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy }); // since we're deleting a piece, we just need to close // all editions dialogs and not reload them EditionListActions.closeAllEditionLists(); EditionListActions.clearAllEditionSelections(); const notification = new GlobalNotificationModel(response.notification, 'success'); GlobalNotificationActions.appendGlobalNotification(notification); this.history.push('/collection'); }, getCreateEditionsDialog() { if (this.state.piece.num_editions < 1 && this.state.showCreateEditionsDialog) { return (

); } else { return (
); } }, handlePollingSuccess(pieceId, numEditions) { const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state; // we need to refresh the num_editions property of the actual piece we're looking at PieceActions.updateProperty({ key: 'num_editions', value: numEditions }); // as well as its representation in the collection // btw.: It's not sufficient to just set num_editions to numEditions, since a single accordion // list item also uses the firstEdition property which we can only get from the server in that case. // Therefore we need to at least refetch the changed piece from the server or on our case simply all PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy }); const notification = new GlobalNotificationModel(getLangText('Editions successfully created'), 'success', 10000); GlobalNotificationActions.appendGlobalNotification(notification); }, getId() { return { 'id': this.state.piece.id }; }, getActions() { const { piece } = this.state; const { currentUser } = this.props; if (piece.notifications && piece.notifications.length > 0) { return ( ); } else { return ( 1}> {/* `acl_view` is always available in `edition.acl`, therefore if it has no more than 1 key, we're hiding the `DetailProperty` actions as otherwise `AclInformation` would show up */} ); } }, render() { const { currentUser, furtherDetailsType: FurtherDetailsType } = this.props; const { piece } = this.state; if (piece.id) { setDocumentTitle(`${piece.artist_name}, ${piece.title}`); return (

{piece.title}

{piece.num_editions > 0 ? : null}
} subheader={
} buttons={this.getActions()}> {this.getCreateEditionsDialog()} 0}> 0 || piece.other_data.length > 0} defaultExpanded={true}>
); } else { return (
); } } }); export default PieceContainer;