UNPKG

react-cimpress-comment

Version:

Visualizes comment(s) for a particular platform resource

480 lines (417 loc) 19.6 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); require('../style/index.css'); require('../style/select.css'); var _Comment = require('./components/Comment'); var _Comment2 = _interopRequireDefault(_Comment); var _visibility = require('./tools/visibility'); var _reactComponents = require('@cimpress/react-components'); var _CommentsClient = require('./clients/CommentsClient'); var _CommentsClient2 = _interopRequireDefault(_CommentsClient); var _i18n = require('./tools/i18n'); var _reactI18next = require('react-i18next'); var _helper = require('./tools/helper'); var _AddNewCommentForm = require('./components/AddNewCommentForm'); var _AddNewCommentForm2 = _interopRequireDefault(_AddNewCommentForm); var _puremail = require('./clients/puremail'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Spinner = _reactComponents.shapes.Spinner; var Comments = function (_React$Component) { _inherits(Comments, _React$Component); function Comments(props) { _classCallCheck(this, Comments); var _this = _possibleConstructorReturn(this, (Comments.__proto__ || Object.getPrototypeOf(Comments)).call(this, props)); _this.commentsClient = new _CommentsClient2.default(props.accessToken, props.resourceUri); _this.jwtSub = (0, _helper.getSubFromJWT)(_this.props.accessToken); _this.state = { blockEnter: false, loading: false, commentsIds: [], commentObjects: {}, commentToAdd: props.initialValue || '', failed: false, failedPost: false, alertDismissed: true, commentVisibilityLevels: (0, _visibility.getVisibilityLevels)(_this.tt.bind(_this)), userAccessLevel: null }; return _this; } _createClass(Comments, [{ key: 'componentDidMount', value: function componentDidMount() { this._ismounted = true; this.init(); this.fetchComments(); this.resetSelectedVisibilityOptions(); } }, { key: 'componentDidUpdate', value: function componentDidUpdate(prevProps) { this.jwtSub = (0, _helper.getSubFromJWT)(this.props.accessToken); if (this.props.accessToken !== prevProps.accessToken) { this.jwtSub = (0, _helper.getSubFromJWT)(this.props.accessToken); } if (this.props.resourceUri !== prevProps.resourceUri || this.props.newestFirst !== prevProps.newestFirst || this.props.accessToken !== prevProps.accessToken) { this.commentsClient = new _CommentsClient2.default(this.props.accessToken, this.props.resourceUri); this.fetchComments(); } } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { this._ismounted = false; clearTimeout(this._markAsReadAfterHandle); clearInterval(this._refreshIntervalHandle); } }, { key: 'safeSetState', value: function safeSetState(data, callback) { if (this._ismounted) { this.setState(data, callback); } } }, { key: 'init', value: function init() { var _this2 = this; clearInterval(this._refreshIntervalHandle); this._refreshIntervalHandle = setInterval(function () { return _this2.fetchComments(); }, Math.max((this.props.refreshInterval || 60) * 1000, 5000)); // Creating these clients is inexpensive and do not clear caching this.commentsClient = new _CommentsClient2.default(this.props.accessToken, this.props.resourceUri); } }, { key: 'resetSelectedVisibilityOptions', value: function resetSelectedVisibilityOptions() { var newCommentVisibilityLevels = (0, _visibility.getVisibilityLevels)(this.tt.bind(this), this.state.userAccessLevel); if (this.state.commentVisibilityLevels !== newCommentVisibilityLevels) { this.safeSetState({ commentVisibilityLevels: newCommentVisibilityLevels }); } } }, { key: 'markAsReadAfter', value: function markAsReadAfter(date) { this.commentsClient.markAsReadAfter(date); } }, { key: 'fetchComments', value: function fetchComments() { var _this3 = this; this.safeSetState({ loading: true, failed: false }); this.commentsClient.fetchComments().then(function (_ref) { var responseJson = _ref.responseJson, userAccessLevel = _ref.userAccessLevel; if (!_this3._ismounted) { return; } var sortedComments = responseJson.sort(function (a, b) { if (_this3.props.newestFirst === true) { return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(); } else { return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(); } }); var lastestCommentDate = sortedComments.length > 0 ? _this3.props.newestFirst ? sortedComments[0].createdAt : sortedComments[sortedComments.length - 1].createdAt : null; _this3.safeSetState({ userAccessLevel: userAccessLevel, loading: false, failed: false, commentsIds: responseJson.sort(function (a, b) { if (_this3.props.newestFirst === true) { return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(); } else { return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(); } }).map(function (c) { return c.id; }), commentObjects: responseJson.reduce(function (acc, curr) { acc[curr.id] = curr; return acc; }, {}) }, function () { _this3.resetSelectedVisibilityOptions(); }); // mark all as read after 1s if (lastestCommentDate) { _this3._markAsReadAfterHandle = setTimeout(function () { return _this3.markAsReadAfter(lastestCommentDate); }, 1000); } }).catch(function (err) { _this3.safeSetState({ loading: false, failed: true, error: err }); }); } }, { key: 'postComment', value: function postComment(comment, visibilty) { var _this4 = this; if (!comment || comment.length === 0) { return; } var tempId = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5); if (this.props.newestFirst) { this.state.commentsIds.unshift(tempId); } else { this.state.commentsIds.push(tempId); } var newCommentObjects = Object.assign(_defineProperty({}, tempId, { createdBy: this.jwtSub, visibility: visibilty, comment: comment }), this.state.commentObjects); this.safeSetState({ failed: false, failedPostComment: '', error: undefined, commentsIds: this.state.commentsIds.slice(0), commentObjects: newCommentObjects }); return this.commentsClient.postComment(comment, visibilty).then(function (newComment) { _this4.safeSetState({ failedPost: false, failedPostComment: '', error: undefined }); _this4.fetchComments(); if (_this4.props.emailing && _this4.props.emailing.enabled === true && _this4.props.emailing.newCommentsTemplateId) { (0, _puremail.sendEmail)(_this4.props.accessToken, _this4.props.emailing.newCommentsTemplateId, { comment: newComment, links: { createdBy: { href: 'https://api.cimpress.io/auth/access-management/v1/principals/' + encodeURIComponent(newComment.createdBy), rel: 'createdBy' } }, payload: _this4.props.emailing.newCommentsTemplatePayload || {} }); } }).catch(function (err) { var newCommentObjects = Object.assign({}, _this4.state.commentObjects); delete newCommentObjects[tempId]; _this4.safeSetState({ failedPost: true, failedPostComment: comment, error: err, commentsIds: _this4.state.commentsIds.filter(function (id) { return id !== tempId; }), commentObjects: newCommentObjects }); }); } }, { key: 'handleDelete', value: function handleDelete(comment) { var newCommentObjects = Object.assign({}, this.state.commentObjects); delete newCommentObjects[comment.id]; this.safeSetState({ commentsIds: this.state.commentsIds.filter(function (id) { return id !== comment.id; }), commentObjects: newCommentObjects }); } }, { key: 'renderLoading', value: function renderLoading() { return _react2.default.createElement( 'div', null, _react2.default.createElement( 'div', { className: 'inline-spinner' }, _react2.default.createElement(Spinner, { size: 'small' }) ), _react2.default.createElement( 'div', { className: 'inline-spinner' }, this.tt('retrieving_comments') ) ); } }, { key: 'tt', value: function tt(key) { // eslint-disable-next-line react/prop-types var _props = this.props, t = _props.t, locale = _props.locale; if (locale.length > 2) { locale = locale.substr(0, 2); } return t(key, { lng: locale }); } }, { key: 'renderComments', value: function renderComments(commentIds) { var _this5 = this; var uri = this.commentsClient.getResourceCommentsUri(); var jwt = (0, _helper.getSubFromJWT)(this.props.accessToken); return commentIds.map(function (commentId, index) { var className = 'comment ' + (index % 2 === 0 ? 'comment-even' : 'comment-odd'); return _react2.default.createElement(_Comment2.default, { key: commentId, locale: _this5.props.locale, accessToken: _this5.props.accessToken, className: className, jwtSub: jwt, commentsClient: _this5.commentsClient, commentUri: uri + '/' + commentId, comment: _this5.state.commentObjects[commentId], editComments: _this5.props.editComments, deleteComments: _this5.props.deleteComments, onDelete: _this5.handleDelete.bind(_this5), commentVisibilityLevels: _this5.state.commentVisibilityLevels, showAvatar: _this5.props.showAvatar }); }); } }, { key: 'renderError', value: function renderError(defaultErrorMessage) { var dismissible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var onDismiss = arguments[2]; if (!this.state.failed && !this.state.failedPost) { return null; } var title = void 0; var e = this.state.error; var message = void 0; if (!e) { message = defaultErrorMessage; } else { var details = (0, _helper.errorToString)(e); title = defaultErrorMessage; message = this.tt(details); } return _react2.default.createElement(_reactComponents.Alert, { type: 'danger', title: title, message: message, dismissible: dismissible, onDismiss: onDismiss }); } }, { key: 'render', value: function render() { var _this6 = this; var comments = null; if (!this.props.resourceUri) { comments = _react2.default.createElement( 'p', null, this.tt('incorrect_component_setup') ); } else if (this.state.commentsIds.length > 0) { comments = this.props.renderComments ? this.props.renderComments.bind(this)(this.state.commentsIds) : this.renderComments(this.state.commentsIds); } else if (this.state.loading) { comments = this.renderLoading(); } else if (this.state.failed) { comments = this.renderError(this.tt('unable_to_retrieve_comments')); } else { comments = _react2.default.createElement( 'div', { className: 'no-comments' }, this.tt('no_comments_exist') ); } var addCommentBox = _react2.default.createElement( 'div', null, this.state.failedPost ? this.renderError(this.tt('unable_to_post_comment'), true, function () { _this6.safeSetState({ failedPost: false }); }) : null, _react2.default.createElement(_AddNewCommentForm2.default, { locale: this.props.locale, initialValue: this.state.failedPostComment || this.props.initialValue, accessToken: this.props.accessToken, commentsClient: this.commentsClient, resourceUri: this.props.resourceUri, newestFirst: this.props.newestFirst, showVisibilityLevels: this.props.showVisibilityLevels, autoFocus: this.props.autoFocus, enforceVisibilityLevel: this.props.enforceVisibilityLevel, textOverrides: this.props.textOverrides, onPostComment: function onPostComment(comment, visibilityOption) { return _this6.postComment(comment, visibilityOption); } }) ); return _react2.default.createElement( 'div', null, this.props.newestFirst ? addCommentBox : null, _react2.default.createElement( 'div', { className: 'comments' }, comments ), !this.props.newestFirst ? addCommentBox : null ); } }]); return Comments; }(_react2.default.Component); Comments.propTypes = { locale: _propTypes2.default.string, accessToken: _propTypes2.default.string.isRequired, resourceUri: _propTypes2.default.string.isRequired, newestFirst: _propTypes2.default.bool, editComments: _propTypes2.default.bool, deleteComments: _propTypes2.default.bool, refreshInterval: _propTypes2.default.number, commentCountRefreshed: _propTypes2.default.func, initialValue: _propTypes2.default.string, showVisibilityLevels: _propTypes2.default.bool, autoFocus: _propTypes2.default.bool, enforceVisibilityLevel: _propTypes2.default.oneOf(['public', 'internal']), renderComments: _propTypes2.default.func, showAvatar: _propTypes2.default.bool, textOverrides: _propTypes2.default.shape({ placeholder: _propTypes2.default.string, subscribe: _propTypes2.default.string, unsubscribe: _propTypes2.default.string, postComment: _propTypes2.default.string }), emailing: _propTypes2.default.shape({ enabled: _propTypes2.default.bool, newCommentsTemplateId: _propTypes2.default.string, newCommentsTemplatePayload: _propTypes2.default.any }) }; Comments.defaultProps = { locale: 'en', showVisibilityLevels: true, showAvatar: false, autoFocus: true, textOverrides: { placeholder: null, subscribe: null, unsubscribe: null, postComment: null }, emailing: { enabled: false, newCommentsTemplateId: null, newCommentsTemplatePayload: {} } }; exports.default = (0, _reactI18next.translate)('translations', { i18n: (0, _i18n.getI18nInstance)() })(Comments);