mirror of
https://github.com/wassname/talk.git
synced 2026-07-03 23:17:14 +08:00
167 lines
5.3 KiB
JavaScript
167 lines
5.3 KiB
JavaScript
import React, {PropTypes} from 'react';
|
|
import {notifyForNewCommentStatus} from 'coral-plugin-commentbox/CommentBox';
|
|
import {CommentForm} from 'coral-plugin-commentbox/CommentForm';
|
|
import styles from './Comment.css';
|
|
import {CountdownSeconds} from './CountdownSeconds';
|
|
import {getEditableUntilDate} from './util';
|
|
import {can} from 'coral-framework/services/perms';
|
|
import {forEachError} from 'coral-framework/utils';
|
|
|
|
import {Icon} from 'coral-ui';
|
|
import t from 'coral-framework/services/i18n';
|
|
|
|
/**
|
|
* Renders a Comment's body in such a way that the end-user can edit it and save changes
|
|
*/
|
|
export class EditableCommentContent extends React.Component {
|
|
static propTypes = {
|
|
|
|
// show notification to the user (e.g. for errors)
|
|
addNotification: PropTypes.func.isRequired,
|
|
asset: PropTypes.shape({
|
|
settings: PropTypes.shape({
|
|
charCountEnable: PropTypes.bool,
|
|
}),
|
|
}).isRequired,
|
|
|
|
// comment that is being edited
|
|
comment: PropTypes.shape({
|
|
body: PropTypes.string,
|
|
editing: PropTypes.shape({
|
|
edited: PropTypes.bool,
|
|
|
|
// ISO8601
|
|
editableUntil: PropTypes.string,
|
|
})
|
|
}).isRequired,
|
|
|
|
// logged in user
|
|
currentUser: PropTypes.shape({
|
|
id: PropTypes.string.isRequired
|
|
}),
|
|
maxCharCount: PropTypes.number,
|
|
|
|
// edit a comment, passed {{ body }}
|
|
editComment: React.PropTypes.func,
|
|
|
|
// called when editing should be stopped
|
|
stopEditing: React.PropTypes.func,
|
|
}
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
this.editWindowExpiryTimeout = null;
|
|
this.state = {
|
|
body: props.comment.body,
|
|
loadingState: '',
|
|
};
|
|
}
|
|
componentDidMount() {
|
|
const editableUntil = getEditableUntilDate(this.props.comment);
|
|
const now = new Date();
|
|
const editWindowRemainingMs = editableUntil && (editableUntil - now);
|
|
if (editWindowRemainingMs > 0) {
|
|
this.editWindowExpiryTimeout = setTimeout(() => {
|
|
this.forceUpdate();
|
|
}, editWindowRemainingMs);
|
|
}
|
|
}
|
|
componentWillUnmount() {
|
|
if (this.editWindowExpiryTimeout) {
|
|
this.editWindowExpiryTimeout = clearTimeout(this.editWindowExpiryTimeout);
|
|
}
|
|
}
|
|
|
|
handleBodyChange = (body) => {
|
|
this.setState({body});
|
|
}
|
|
|
|
handleSubmit = async () => {
|
|
if (!can(this.props.currentUser, 'INTERACT_WITH_COMMUNITY')) {
|
|
this.props.addNotification('error', t('error.NOT_AUTHORIZED'));
|
|
return;
|
|
}
|
|
|
|
this.setState({loadingState: 'loading'});
|
|
|
|
const {editComment, addNotification, stopEditing} = this.props;
|
|
if (typeof editComment !== 'function') {return;}
|
|
let response;
|
|
try {
|
|
response = await editComment({body: this.state.body});
|
|
this.setState({loadingState: 'success'});
|
|
const status = response.data.editComment.comment.status;
|
|
notifyForNewCommentStatus(this.props.addNotification, status);
|
|
if (typeof stopEditing === 'function') {
|
|
stopEditing();
|
|
}
|
|
} catch (error) {
|
|
this.setState({loadingState: 'error'});
|
|
forEachError(error, ({msg}) => addNotification('error', msg));
|
|
}
|
|
}
|
|
|
|
getEditableUntil = (props = this.props) => {
|
|
return getEditableUntilDate(props.comment);
|
|
}
|
|
|
|
isEditWindowExpired = (props = this.props) => {
|
|
return (this.getEditableUntil(props) - new Date()) < 0;
|
|
}
|
|
|
|
isSubmitEnabled = (comment) => {
|
|
|
|
// should be disabled if user hasn't actually changed their
|
|
// original comment
|
|
return (comment.body !== this.props.comment.body) && !this.isEditWindowExpired();
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<div className={styles.editCommentForm}>
|
|
<CommentForm
|
|
defaultValue={this.props.comment.body}
|
|
charCountEnable={this.props.asset.settings.charCountEnable}
|
|
maxCharCount={this.props.maxCharCount}
|
|
submitEnabled={this.isSubmitEnabled}
|
|
body={this.state.body}
|
|
onBodyChange={this.handleBodyChange}
|
|
onSubmit={this.handleSubmit}
|
|
bodyLabel={t('edit_comment.body_input_label')}
|
|
bodyPlaceholder=""
|
|
submitText={<span>{t('edit_comment.save_button')}</span>}
|
|
submitButtonCStyle="green"
|
|
onCancel={this.props.stopEditing}
|
|
submitButtonClassName={styles.button}
|
|
cancelButtonClassName={styles.button}
|
|
loadingState={this.state.loadingState}
|
|
buttonContainerStart={
|
|
<div className={styles.buttonContainerLeft}>
|
|
<span className={styles.editWindowRemaining}>
|
|
{
|
|
this.isEditWindowExpired()
|
|
? <span>
|
|
{t('edit_comment.edit_window_expired')}
|
|
{
|
|
typeof this.props.stopEditing === 'function'
|
|
? <span> <a className={styles.link} onClick={this.props.stopEditing}>{t('edit_comment.edit_window_expired_close')}</a></span>
|
|
: null
|
|
}
|
|
</span>
|
|
: <span>
|
|
<Icon name="timer"/> {t('edit_comment.edit_window_timer_prefix')}
|
|
<CountdownSeconds
|
|
until={this.getEditableUntil()}
|
|
classNameForMsRemaining={(remainingMs) => (remainingMs <= 10 * 1000) ? styles.editWindowAlmostOver : '' }
|
|
/>
|
|
</span>
|
|
}
|
|
</span>
|
|
</div>
|
|
}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
}
|