react-cimpress-comment
Version:
Visualizes comment(s) for a particular platform resource
480 lines (417 loc) • 19.6 kB
JavaScript
'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);