react_comments-8.x-1.0-beta2/js/src/src/components/Comment.js
js/src/src/components/Comment.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import CommentBox from './CommentBox';
import './Comment.css';
import timeago from 'timeago.js';
import Constants from '../utils/constants';
import ReplyArrow from '../icons/reply-arrow';
import Permalink from '../icons/permalink';
import DeletedComment from './DeletedComment';
import ReplyList from './ReplyList';
import CommentActions from './CommentActions';
import CommentMenu from './CommentMenu';
import UserPicture from './UserPicture';
class Comment extends Component {
state = {
replyActive: false,
editActive: false,
message: null
};
toggleState = (stateToToggle) => {
this.setState({[stateToToggle]: !this.state[stateToToggle]});
};
postReply = (commentText, anonName, anonEmail, notify) => {
return this.props.postReply(this.props.id, commentText, anonName, anonEmail, notify);
};
saveEdit = (commentText, notify) => {
return this.props.saveEdit(this.props.id, commentText, notify);
};
deleteComment = (id) => {
return this.props.deleteComment(id).catch((err) => {
this.setState({
message: {
message: err.message,
type: 'error'
}
})
});
};
closeMenu = () => {
if (this.props.id === this.props.openMenu) {
this.props.toggleMenu(this.props.id);
}
};
convertTimestampToDate = (created_at) => {
const date = new Date(created_at * 1000);
const created_ago = timeago().format(created_at * 1000);
// if the comment was posted more than a week ago show the date instead
if (Date.now() - created_at * 1000 > 604800000) {
return window.Drupal.t('@month/@day/@year', {
'@month': date.getMonth() + 1,
'@day': date.getDate(),
'@year': date.getFullYear()
});
}
// If it seconds/minutes/hours/days ago
const created_ago_parts = created_ago.match(/(\d+)\s([a-zA-Z]+)\sago/);
if (created_ago_parts) {
let created_ago_time = created_ago_parts[2];
switch (created_ago_parts[2]) {
// We need to list all options using Drupal.t, to be able to translate
case 'day': created_ago_time = window.Drupal.t('day'); break;
case 'days': created_ago_time = window.Drupal.t('days'); break;
case 'hour': created_ago_time = window.Drupal.t('hour'); break;
case 'hours': created_ago_time = window.Drupal.t('hours'); break;
case 'minute': created_ago_time = window.Drupal.t('minute'); break;
case 'minutes': created_ago_time = window.Drupal.t('minutes'); break;
case 'second': created_ago_time = window.Drupal.t('second'); break;
case 'seconds': created_ago_time = window.Drupal.t('seconds'); break;
default: break;
}
return window.Drupal.t('@created_ago ago', {
'@created_ago': +created_ago_parts[1] + ' ' + created_ago_time
});
}
// Just now
return window.Drupal.t('just now');
};
componentDidMount() {
window.addEventListener('hashchange', event => {
const [ , id ] = window.location.hash.split('#');
this.scrollToComment(id);
event.preventDefault();
});
const event = document.createEvent('HTMLEvents');
event.initEvent('hashchange', false, true);
window.dispatchEvent(event);
}
scrollToComment(id) {
if (`comment-${this.props.id}` === id) {
const document = window.document.documentElement;
const rect = ReactDOM
.findDOMNode(this.refs[id])
.getBoundingClientRect();
const top = rect.top + window.pageYOffset - document.clientTop;
const margin = window.rcTopMargin > 0 ? window.rcTopMargin : 0;
window.scrollTo(0, top - margin);
}
}
render() {
const { id, currentUser, settings, comment, replies, replyTo, created_at, openMenu, toggleMenu, status, flagComment, publishComment, unpublishComment, published, name, notify } = this.props;
const { replyActive, editActive, message } = this.state;
let { user } = this.props;
if (user.isAnon) {
user.name = name;
}
if (status === Constants.deleted || status === Constants.flaggedUnpublished) {
return !window.commentsAppFullDelete
? <DeletedComment {...this.props} />
: null;
}
return (
<div className={editActive ? "rc_comment rc_comment--edit-active" : "rc_comment"} id={`comment-${id}`} ref={`comment-${id}`}>
<div className={ (published === '0') ? "rc_comment-container rc_comment-container--unpublished" : "rc_comment-container" }>
<UserPicture thumbnail={user.thumbnail} />
<div className="rc_body">
{ message && <div className={`rc_message rc_message-type--${message.type}`}>{message.message}</div> }
<div className="rc_comment-details">
<span className="rc_username">{user.name}</span>
{ replyTo && <span className="rc_reply-to"><ReplyArrow/>{replyTo.name}</span> }
{/* Apparently javascript uses 13 digit timestamps (including milliseconds)... Append 000 to the unix timestamp to get it to work. */}
<span className="rc_time-ago">{this.convertTimestampToDate(created_at)}</span>
<span className="rc_permalink">
<a href={`#comment-${id}`}><Permalink /></a>
</span>
{ window.commentsAppStatus && <CommentMenu
user={user}
currentUser={currentUser}
id={id}
openMenu={openMenu}
closeMenu={this.closeMenu}
toggleMenu={toggleMenu}
flagComment={flagComment}
publishComment={publishComment}
unpublishComment={unpublishComment}
deleteComment={this.deleteComment}
status={status}
published={published}
/> }
</div>
{ editActive ?
<CommentBox
commentId={id}
settings={settings}
text={comment}
notify={notify}
user={currentUser}
isEdit={true}
type="edit"
cancelEdit={() => this.toggleState('editActive')}
saveEdit={this.saveEdit}
/> :
<div className="rc_comment-text" dangerouslySetInnerHTML={{__html: comment.replace(/(?:\r\n|\r|\n)/g, '<br />')}}></div>
}
{ window.commentsAppStatus && <CommentActions
currentUser={currentUser}
user={user}
editActive={editActive}
replyActive={replyActive}
toggleState={this.toggleState}
/> }
{ replyActive &&
<CommentBox
commentId={id}
isReply={true}
type="reply"
user={currentUser}
settings={settings}
postReply={this.postReply}
closeReplyBox={() => this.toggleState('replyActive')}
/> }
</div>
</div>
{ replies &&
<ReplyList
{...this.props}
replyTo={user}
/>
}
</div>
);
}
}
export default Comment;
