ES6 Plato on Github
Report Home
Summary Display
containers/TagContainer.js
Maintainability
70.22
Lines of code
410
Difficulty
49.73
Estimated Errors
3.05
Function weight
By Complexity
By SLOC
import React from 'react'; import PropTypes from 'prop-types'; import axios from 'axios'; import { connect } from 'react-redux'; import TagList from '../components/Event/Tag/TagList'; import TagEditor from '../components/Event/Tag/TagEditor'; import { getTagsByInvestigationId, createTagsByInvestigationId, updateTagsByInvestigationId } from '../api/icat/icatPlus'; import _ from 'lodash'; import { INFO_MESSAGE_TYPE, ERROR_MESSAGE_TYPE, TAG_MANAGER_CONTEXT, BASIC_EVENT_CONTEXT, TAG_EDITOR_CONTEXT, TAG_CREATOR_CONTEXT, NEW_EVENT_CONTEXT, DETAILED_EVENT_CONTEXT, FETCHED_STATUS, FETCHING_STATUS } from '../constants/EventTypes'; import TagActionBar from '../components/Event/Tag/TagActionBar'; import UserMessage from '../components/UserMessage'; import { SUCCESS_MESSAGE_TYPE } from '../constants/UserMessages'; import { setAvailableTagAction } from '../actions/logbook'; /** * The event tag container in charge of managing event tags. */ class TagContainer extends React.Component { constructor(props) { super(props); this.state = { context: this.props.context, message: null, selectedTags: [], // contains currently selected tags for a given event when tagContainer is used in the context of an event. Contains the edited tag when used with tag editor. tagsUploadStatus: null }; this.isGettingSelectedTagsFromEventProp = true; if (props.setTagContainer) { props.setTagContainer(this); } this.addTagToSelection = this.addTagToSelection.bind(this); this.createNewTag = this.createNewTag.bind(this); this.editTag = this.editTag.bind(this); this.getTagsByInvestigationId = this.getTagsByInvestigationId.bind(this); this.removeTagFromSelection = this.removeTagFromSelection.bind(this); this.setMessage = this.setMessage.bind(this); this.setSelectedTagsFromProps = this.setSelectedTagsFromProps.bind(this); this.showAvailableTags = this.showAvailableTags.bind(this); this.showNewTag = this.showNewTag.bind(this); this.updateTags = this.updateTags.bind(this); } render() { let { investigationId } = this.props; let userMessage = null; if (this.state.message) { userMessage = (<UserMessage type={this.state.message.type} message={this.state.message.text} > </UserMessage>); } if (this.props.availableTagsReceptionStatus === FETCHED_STATUS) { if (this.state.context === BASIC_EVENT_CONTEXT) { return (<div> {userMessage} <TagList selectedTags={this.state.selectedTags} context={BASIC_EVENT_CONTEXT} /> </div>); } if (this.state.context === DETAILED_EVENT_CONTEXT || this.state.context === NEW_EVENT_CONTEXT) { return (<div> {userMessage} <TagList availableTags={this.props.availableTags} addTagToSelection={this.addTagToSelection} context={DETAILED_EVENT_CONTEXT} createNewTag={this.createNewTag} investigationId={investigationId} removeTagFromSelection={this.removeTagFromSelection} selectedTags={this.state.selectedTags} /> </div>); } // no event is provided. if (this.state.context === TAG_MANAGER_CONTEXT) { return (<div> {userMessage} <TagActionBar showNewTag={this.showNewTag} /> <TagList availableTags={this.props.availableTags} context={TAG_MANAGER_CONTEXT} editTag={this.editTag} investigationId={investigationId} updateTags={this.updateTags} /> </div>); } if (this.state.context === TAG_EDITOR_CONTEXT || this.state.context === TAG_CREATOR_CONTEXT) { // if (this.state.selectedTags && this.state.selectedTags.length != 0) { return (<div> {userMessage} <TagEditor showAvailableTags={this.showAvailableTags} tag={this.state.selectedTags.length !== 0 ? this.state.selectedTags[0] : null} createNewTag={this.createNewTag} updateTags={this.updateTags} /> </div>); // } else { // return (<div> // {errorMessage} // <TagList // availableTags={this.props.availableTags} // context={TAG_MANAGER_CONTEXT} // investigationId={investigationId} // updateTags={this.updateTags} // /> // </div>) // } } }; if (!this.props.availableTagsReceptionStatus || this.props.availableTagsReceptionStatus === FETCHING_STATUS) { return <p> Please wait... </p>; }; } componentDidMount() { let onSuccess = (data) => { if (data.data.tags) { this.props.setAvailableTags(data.data.tags); //store available tags in the store } }; let onError = (err) => { this.setMessage(ERROR_MESSAGE_TYPE, 'Error during tag reception'); }; // Checks whether available tags have been fetched already if (this.props.availableTagsReceptionStatus === FETCHED_STATUS) { if (this.props.context === DETAILED_EVENT_CONTEXT || this.props.context === BASIC_EVENT_CONTEXT) { this.isGettingSelectedTagsFromEventProp = false; this.setSelectedTagsFromProps(); }; } else { this.getTagsByInvestigationId(onSuccess, onError); //fetch available tags. }; } componentDidUpdate() { if (this.props.context === DETAILED_EVENT_CONTEXT) { if (this.props.availableTagsReceptionStatus === FETCHED_STATUS) { if (this.isGettingSelectedTagsFromEventProp === true) { this.isGettingSelectedTagsFromEventProp = false; this.setSelectedTagsFromProps(); }; }; }; if (this.props.context === BASIC_EVENT_CONTEXT) { this.setSelectedTagsFromProps(); }; } /** * Set user selected tags for a given event from props */ setSelectedTagsFromProps() { let { event, availableTags } = this.props; if (event) { let selectedTagsFromEventProp = event.tag.map(tagId => { return _.find(availableTags, (tag) => (tag._id === tagId)); }); if (!_.isEqual(this.state.selectedTags, selectedTagsFromEventProp)) { this.setState({ selectedTags: selectedTagsFromEventProp }); }; }; } /** * Request tags associated to the given investigationId * @param {integer} investigationId the investigation indentifier * @param {String} sessionId the session identifier * @param {func} onError the callback function executed when an error occured during the request. */ getTagsByInvestigationId(onSuccess, onError) { let { investigationId } = this.props; let sessionId = this.props.user.sessionId; if (investigationId && sessionId) { axios({ method: 'get', url: getTagsByInvestigationId(sessionId, investigationId), }) .then(data => onSuccess(data)) .catch((error) => { console.log('ERROR] An error occured while retrieving the tag list. The error is ' + error); onError('An error occured while retrieving the tag list.'); }); } else { console.log('[ERROR] Missing parameters in the request handled by getEventsByInvestigationId()'); onError('An error occured while retrieving the tag list.'); }; } /** callBack function triggered when an error occurs. * @param {string} type type of error * @param {string} text text of the message * @param {string} context the context in which the container should enter (if provided) */ setMessage(type, message, context) { if (context) { this.setState({ message: { type: type, text: message, context: context, } }); } else { this.setState({ message: { type: type, text: message } }); }; } /** * Creates a new tag on the server side * @param {Object} newTag tag to create */ createNewTag(newTag) { let _this = this; let nextContext = (this.props.context === TAG_CREATOR_CONTEXT) ? TAG_MANAGER_CONTEXT : this.props.context; // POST the new tag to the server if (newTag) { axios({ method: 'post', url: createTagsByInvestigationId(this.props.user.sessionId, this.props.investigationId), data: newTag, }) .then((data) => { let newlyCreatedTag = data.data; console.log('The new tag was created successfully on ICAT+ server.'); let selectedTags = []; if (this.props.context === DETAILED_EVENT_CONTEXT) { // ADD the new tag in the currently selected tags. selectedTags = _.map(_this.state.selectedTags, _.clone); selectedTags.push(newlyCreatedTag); this.props.canEnableSaveButton({ hasText: true, currentTextEqualsOriginal: false }); } // GET the available tags and finally update the component state let onSuccess = (data) => { if (data.data.tags) { this.setState({ context: nextContext, selectedTags: selectedTags }); if (this.props.context !== DETAILED_EVENT_CONTEXT) { this.setMessage(SUCCESS_MESSAGE_TYPE, 'Tag successfully created'); } this.props.setAvailableTags(data.data.tags); return; } this.setMessage(ERROR_MESSAGE_TYPE, 'Error in server response', nextContext); }; let onError = () => { this.setMessage(ERROR_MESSAGE_TYPE, 'Error while retrieving tags', nextContext); }; this.getTagsByInvestigationId(onSuccess, onError); }) .catch((error) => { console.log('[ERROR] the tag could not be created. The error is : ' + error); this.setMessage(ERROR_MESSAGE_TYPE, '[ERROR] Tag not created.', nextContext); }); } } /** * Update tags on the server side * @param {Array} tags the tags to update on the server */ updateTags(tags) { if (tags) { let promises = []; tags.forEach(tag => { promises.push( axios({ method: 'put', url: updateTagsByInvestigationId(this.props.user.sessionId, this.props.investigationId, tag._id), data: tag, }) ); }); Promise.all(promises) .then((results) => { results.forEach((data) => { console.log('The tag ' + data.name + ' was successfully updated on ICAT+ server.'); }); this.setMessage(INFO_MESSAGE_TYPE, 'Tags was successfully updated'); this.setState({ context: TAG_MANAGER_CONTEXT }); }) .catch((error) => { console.log('[ERROR] At least one tag could not be updated. The error is : ' + error); this.setMessage(ERROR_MESSAGE_TYPE, '[ERROR] All tags could not be updated.'); }); }; } /** Add a tag to the selected Tags */ addTagToSelection(tag) { let selectedTags = _.map(this.state.selectedTags, _.clone); selectedTags.push(tag); // enable the save button in detailed event view this.props.canEnableSaveButton({ hasText: true, currentTextEqualsOriginal: false }); this.setState({ message: null, selectedTags: selectedTags }); } /** * Remove the given tag from the current tags * @param {*} tag */ removeTagFromSelection(tag) { if (tag) { // enable the save button in detailed event view this.props.canEnableSaveButton({ hasText: true, currentTextEqualsOriginal: false }); this.setState({ message: null, selectedTags: _.filter(this.state.selectedTags, (value) => (_.isEqual(value, tag) === false)), }); }; } /** * Edit a given tag * @param {*} tag the tag to be edited */ editTag(tag) { if (tag) { this.setState({ context: TAG_EDITOR_CONTEXT, message: null, selectedTags: [tag], }); }; } showNewTag() { this.setState({ context: TAG_CREATOR_CONTEXT, message: null, }); } /** * Shows available tags in the tag manager */ showAvailableTags() { this.setState({ context: TAG_MANAGER_CONTEXT, }); } } /** * Redux related function which is used to map local props with redux state * @param {*} state redux state */ function mapStateToProps(state) { return { availableTags: state.logbook.availableTags, availableTagsReceptionStatus: state.logbook.availableTagsReceptionStatus, user: state.user }; } /** * Redux related function which is used to map local function with redux dispatch() * @param {*} dispatch redux dispatch function */ function mapDispatchToProps(dispatch) { return { setAvailableTags: availableTags => dispatch(setAvailableTagAction(availableTags)) }; } TagContainer.propTypes = { /* the event to display the tags of. No events means we use the TagManager */ event: PropTypes.object, /* the investigationId to display the event from */ investigationId: PropTypes.string.isRequired, /* Callback function used to enable the save button for a detailed event */ canEnableSaveButton: PropTypes.func, setTagContainer: PropTypes.func, }; export default connect( mapStateToProps, mapDispatchToProps, )(TagContainer);