-
-
-
-
-
-
-
-
-
-
-
-
- - Last Modified
- - {formatDate(new Date(lastModified))}
-
+class EntityFooter extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ message: {
+ text: null,
+ type: null
+ },
+ showModal: false
+ };
+
+ this.onCloseModal = this.onCloseModal.bind(this);
+ this.handleShowModal = this.handleShowModal.bind(this);
+ this.handleAlertDismiss = this.handleAlertDismiss.bind(this);
+ this.closeModalAndShowMessage = this.closeModalAndShowMessage.bind(this);
+ }
+
+ onCloseModal() {
+ this.setState({showModal: false});
+ }
+
+ handleShowModal() {
+ if (this.props.user) {
+ this.setState({showModal: true});
+ }
+ else {
+ this.setState({
+ message: {
+ text: 'You need to be logged in',
+ type: 'danger'
+ }
+ });
+ }
+ }
+
+ closeModalAndShowMessage(message) {
+ this.setState({
+ message,
+ showModal: false
+ });
+ }
+
+ handleAlertDismiss() {
+ this.setState({message: {}});
+ }
+
+ render() {
+ return (
+
+ {
+ this.props.user ?
+
: null
+ }
+ {
+ this.state.message.text ?
+
{this.state.message.text} : null
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Last Modified
+ - {formatDate(new Date(this.props.lastModified))}
+
+
-
- );
+ );
+ }
}
EntityFooter.displayName = 'EntityFooter';
EntityFooter.propTypes = {
bbid: PropTypes.string.isRequired,
deleted: PropTypes.bool,
+ entityType: PropTypes.string.isRequired,
entityUrl: PropTypes.string.isRequired,
- lastModified: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]).isRequired
+ lastModified: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]).isRequired,
+ user: PropTypes.object.isRequired
};
EntityFooter.defaultProps = {
deleted: false
diff --git a/src/client/components/pages/entities/publisher.js b/src/client/components/pages/entities/publisher.js
index e993f5e4a6..8f07e986c1 100644
--- a/src/client/components/pages/entities/publisher.js
+++ b/src/client/components/pages/entities/publisher.js
@@ -18,7 +18,6 @@
import * as bootstrap from 'react-bootstrap';
import * as entityHelper from '../../../helpers/entity';
-
import EditionTable from './edition-table';
import EntityFooter from './footer';
import EntityImage from './image';
@@ -80,7 +79,7 @@ PublisherAttributes.propTypes = {
};
-function PublisherDisplayPage({entity, identifierTypes}) {
+function PublisherDisplayPage({entity, identifierTypes, user}) {
const urlPrefix = getEntityUrl(entity);
return (
@@ -110,8 +109,10 @@ function PublisherDisplayPage({entity, identifierTypes}) {
);
@@ -119,7 +120,8 @@ function PublisherDisplayPage({entity, identifierTypes}) {
PublisherDisplayPage.displayName = 'PublisherDisplayPage';
PublisherDisplayPage.propTypes = {
entity: PropTypes.object.isRequired,
- identifierTypes: PropTypes.array
+ identifierTypes: PropTypes.array,
+ user: PropTypes.object.isRequired
};
PublisherDisplayPage.defaultProps = {
identifierTypes: []
diff --git a/src/client/components/pages/entities/work.js b/src/client/components/pages/entities/work.js
index 16c055ace6..5b99b1e424 100644
--- a/src/client/components/pages/entities/work.js
+++ b/src/client/components/pages/entities/work.js
@@ -71,7 +71,7 @@ WorkAttributes.propTypes = {
};
-function WorkDisplayPage({entity, identifierTypes}) {
+function WorkDisplayPage({entity, identifierTypes, user}) {
// relationshipTypeId = 10 refers the relation (
is contained by )
const relationshipTypeId = 10;
const editionsContainWork = getRelationshipSourceByTypeId(entity, relationshipTypeId);
@@ -107,8 +107,10 @@ function WorkDisplayPage({entity, identifierTypes}) {
);
@@ -116,7 +118,8 @@ function WorkDisplayPage({entity, identifierTypes}) {
WorkDisplayPage.displayName = 'WorkDisplayPage';
WorkDisplayPage.propTypes = {
entity: PropTypes.object.isRequired,
- identifierTypes: PropTypes.array
+ identifierTypes: PropTypes.array,
+ user: PropTypes.object.isRequired
};
WorkDisplayPage.defaultProps = {
identifierTypes: []
diff --git a/src/client/components/pages/parts/add-to-collection-modal.js b/src/client/components/pages/parts/add-to-collection-modal.js
new file mode 100644
index 0000000000..a8e3d04305
--- /dev/null
+++ b/src/client/components/pages/parts/add-to-collection-modal.js
@@ -0,0 +1,317 @@
+import * as bootstrap from 'react-bootstrap';
+import CustomInput from '../../../input';
+import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
+import PropTypes from 'prop-types';
+import React from 'react';
+import ReactSelect from 'react-select';
+import SelectWrapper from '../../input/select-wrapper';
+import _ from 'lodash';
+import request from 'superagent';
+
+
+const {Alert, Col, Button, Modal} = bootstrap;
+
+class AddToCollectionModal extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ collectionsAvailable: [],
+ message: {
+ text: null,
+ type: null
+ },
+ selectedCollections: [],
+ showCollectionForm: false
+ };
+
+ this.getCollections = this.getCollections.bind(this);
+ this.handleAddToCollection = this.handleAddToCollection.bind(this);
+ this.toggleRow = this.toggleRow.bind(this);
+ this.handleShowCollectionForm = this.handleShowCollectionForm.bind(this);
+ this.handleShowAllCollections = this.handleShowAllCollections.bind(this);
+ this.handleAddToNewCollection = this.handleAddToNewCollection.bind(this);
+ this.isValid = this.isValid.bind(this);
+ }
+
+ async componentDidMount() {
+ const collections = await this.getCollections();
+ // eslint-disable-next-line react/no-did-mount-set-state
+ this.setState({collectionsAvailable: collections});
+ }
+
+ toggleRow(collectionId) {
+ const oldSelected = this.state.selectedCollections;
+ let newSelected;
+ if (oldSelected.find(selectedId => selectedId === collectionId)) {
+ newSelected = oldSelected.filter(selectedId => selectedId !== collectionId);
+ }
+ else {
+ newSelected = [...oldSelected, collectionId];
+ }
+ this.setState({
+ selectedCollections: newSelected
+ });
+ }
+
+ async getCollections() {
+ try {
+ // Get all collections of the user (unlikely that a user will have more than 10000 collections
+ const req = await request.get(`/editor/${this.props.userId}/collections/collections?type=${this.props.entityType}&size=10000`);
+ const collections = req.body;
+ return collections;
+ }
+ catch (err) {
+ return this.setState({
+ message: {
+ text: 'Sorry, we could not fetch your collections ',
+ type: 'danger'
+ }
+ });
+ }
+ }
+
+ async handleAddToCollection() {
+ const {bbids} = this.props;
+ const {selectedCollections} = this.state;
+ if (selectedCollections.length) {
+ try {
+ const promiseArray = [];
+ selectedCollections.forEach((collectionId) => {
+ const submissionURL = `/collection/${collectionId}/add`;
+ promiseArray.push(
+ request.post(submissionURL)
+ .send({bbids})
+ );
+ });
+ await Promise.all(promiseArray);
+ this.setState({selectedCollections: []}, () => {
+ this.props.closeModalAndShowMessage({
+ text: `Successfully added to selected collection${selectedCollections.length > 1 ? 's' : ''}`,
+ type: 'success'
+ });
+ });
+ }
+ catch (err) {
+ this.setState({
+ message: {
+ text: 'Something went wrong! Please try again later',
+ type: 'danger'
+ }
+ });
+ }
+ }
+ else {
+ this.setState({
+ message: {
+ text: 'No collection selected',
+ type: 'danger'
+ }
+ });
+ }
+ }
+
+ handleShowCollectionForm() {
+ this.setState({message: {}, showCollectionForm: true});
+ }
+
+ handleShowAllCollections() {
+ this.setState({message: {}, showCollectionForm: false});
+ }
+
+ handleAddToNewCollection(evt) {
+ evt.preventDefault();
+
+ if (!this.isValid()) {
+ this.setState({
+ message: {
+ text: 'The form is incomplete. Please fill in a name and privacy option before continuing.',
+ type: 'danger'
+ }
+ });
+ return;
+ }
+
+ const description = this.description.getValue();
+ const name = this.name.getValue();
+ const privacy = this.privacy.getValue();
+ const {entityType} = this.props;
+
+ const data = {
+ description,
+ entityType,
+ name,
+ privacy
+ };
+ const {bbids} = this.props;
+ request.post('/collection/create/handler')
+ .send(data)
+ .then((res) => {
+ request.post(`/collection/${res.body.id}/add`)
+ .send({bbids}).then(() => {
+ this.setState({selectedCollections: []}, () => {
+ this.props.closeModalAndShowMessage({
+ text: `Successfully added to your new collection: ${name}`,
+ type: 'success'
+ });
+ });
+ });
+ }, (error) => {
+ this.setState({
+ message: {
+ text: 'Something went wrong! Please try again later',
+ type: 'danger'
+ }
+ });
+ });
+ }
+
+ isValid() {
+ return _.trim(this.name.getValue()).length && this.privacy.getValue();
+ }
+
+ /* eslint-disable react/jsx-no-bind */
+ render() {
+ let messageComponent = null;
+ if (this.state.message.text) {
+ messageComponent = (
+
+ Oops, looks like you do not yet have any collection of {this.props.entityType}s .
+ Click on the button below to create a new collection
+
+ );
+ }
+
+ const privacyOptions = ['Private', 'Public'].map((option) => ({
+ name: option
+ }));
+ const collectionForm = (
+