scratch-www/src/views/preview/comment/compose-comment.jsx
2018-10-12 09:16:27 -04:00

182 lines
6.2 KiB
JavaScript

const React = require('react');
const PropTypes = require('prop-types');
const bindAll = require('lodash.bindall');
const classNames = require('classnames');
const keyMirror = require('keymirror');
const FormattedMessage = require('react-intl').FormattedMessage;
const FlexRow = require('../../../components/flex-row/flex-row.jsx');
const Avatar = require('../../../components/avatar/avatar.jsx');
const InplaceInput = require('../../../components/forms/inplace-input.jsx');
const Button = require('../../../components/forms/button.jsx');
const connect = require('react-redux').connect;
const api = require('../../../lib/api');
require('./comment.scss');
const onUpdate = update => update;
const MAX_COMMENT_LENGTH = 500;
const ComposeStatus = keyMirror({
EDITING: null,
SUBMITTING: null,
REJECTED: null
});
class ComposeComment extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
'handlePost',
'handleCancel',
'handleInput'
]);
this.state = {
message: '',
status: ComposeStatus.EDITING,
error: null
};
}
handleInput (event) {
this.setState({
message: event.target.value,
status: ComposeStatus.EDITING,
error: null
});
}
handlePost () {
this.setState({status: ComposeStatus.SUBMITTING});
api({
uri: `/proxy/comments/project/${this.props.projectId}`,
authentication: this.props.user.token,
withCredentials: true,
method: 'POST',
useCsrf: true,
json: {
content: this.state.message,
parent_id: this.props.parentId || '',
comentee_id: this.props.comenteeId || ''
}
}, (err, body, res) => {
if (err || res.statusCode !== 200) {
body = {rejected: 'error'};
}
if (body.rejected && this.state.status === ComposeStatus.SUBMITTING) {
// Note: does not reset the message state
this.setState({
status: ComposeStatus.REJECTED,
error: body.rejected
});
return;
}
// Clear the text field and reset status on successful submission
this.setState({
message: '',
status: ComposeStatus.EDITING,
error: null
});
// Add the username, which isn't included right now from scratch-api
if (body.author) body.author.username = this.props.user.username;
this.props.onAddComment(body);
});
}
handleCancel () {
this.setState({
message: '',
status: ComposeStatus.EDITING,
error: null
});
if (this.props.onCancel) this.props.onCancel();
}
render () {
return (
<div
className="flex-row comment"
>
<a href={`/users/${this.props.user.username}`}>
<Avatar src={this.props.user.thumbnailUrl} />
</a>
<FlexRow className="compose-comment column">
{this.state.error ? (
<FlexRow className="compose-error-row">
<div className="compose-error-tip">
<FormattedMessage id={`comments.${this.state.error}`} />
</div>
</FlexRow>
) : null}
<InplaceInput
className={classNames('compose-input',
MAX_COMMENT_LENGTH - this.state.message.length >= 0 ? 'compose-valid' : 'compose-invalid')}
handleUpdate={onUpdate}
name="compose-comment"
type="textarea"
value={this.state.message}
onInput={this.handleInput}
/>
<FlexRow className="compose-bottom-row">
<Button
className="compose-post"
disabled={this.state.status === ComposeStatus.SUBMITTING}
onClick={this.handlePost}
>
{this.state.status === ComposeStatus.SUBMITTING ? (
<FormattedMessage id="comments.posting" />
) : (
<FormattedMessage id="comments.post" />
)}
</Button>
<Button
className="compose-cancel"
onClick={this.handleCancel}
>
<FormattedMessage id="comments.cancel" />
</Button>
<span
className={classNames('compose-limit',
MAX_COMMENT_LENGTH - this.state.message.length >= 0 ?
'compose-valid' : 'compose-invalid')}
>
<FormattedMessage
id="comments.lengthWarning"
values={{
remainingCharacters: MAX_COMMENT_LENGTH - this.state.message.length
}}
/>
</span>
</FlexRow>
</FlexRow>
</div>
);
}
}
ComposeComment.propTypes = {
comenteeId: PropTypes.number,
onAddComment: PropTypes.func,
onCancel: PropTypes.func,
parentId: PropTypes.number,
projectId: PropTypes.string,
user: PropTypes.shape({
id: PropTypes.number,
username: PropTypes.string,
token: PropTypes.string,
thumbnailUrl: PropTypes.string
})
};
const mapStateToProps = state => ({
user: state.session.session.user
});
const ConnectedComposeComment = connect(
mapStateToProps
)(ComposeComment);
module.exports = ConnectedComposeComment;