zcash-grant-system/frontend/client/components/Comment/index.tsx

137 lines
4.1 KiB
TypeScript

import React from 'react';
import { connect } from 'react-redux';
import moment from 'moment';
import { Button } from 'antd';
import { Link } from 'react-router-dom';
import Markdown from 'components/Markdown';
import UserAvatar from 'components/UserAvatar';
import MarkdownEditor, { MARKDOWN_TYPE } from 'components/MarkdownEditor';
import { postProposalComment } from 'modules/proposals/actions';
import { getIsSignedIn } from 'modules/auth/selectors';
import { Comment as IComment } from 'types';
import { AppState } from 'store/reducers';
import './style.less';
interface OwnProps {
comment: IComment;
}
interface StateProps {
isPostCommentPending: AppState['proposal']['isPostCommentPending'];
postCommentError: AppState['proposal']['postCommentError'];
isSignedIn: ReturnType<typeof getIsSignedIn>;
}
interface DispatchProps {
postProposalComment: typeof postProposalComment;
}
type Props = OwnProps & StateProps & DispatchProps;
interface State {
reply: string;
isReplying: boolean;
}
class Comment extends React.Component<Props> {
state: State = {
reply: '',
isReplying: false,
};
componentDidUpdate(prevProps: Props) {
// TODO: Come up with better check on if our comment post was a success
const { isPostCommentPending, postCommentError } = this.props;
if (!isPostCommentPending && !postCommentError && prevProps.isPostCommentPending) {
this.setState({ reply: '', isReplying: false });
}
}
public render(): React.ReactNode {
const { comment, isSignedIn, isPostCommentPending } = this.props;
const { isReplying, reply } = this.state;
const authorPath = `/profile/${comment.author.userid}`;
return (
<div className="Comment">
<div className="Comment-info">
<Link to={authorPath}>
<div className="Comment-info-thumb">
<UserAvatar user={comment.author} />
</div>
</Link>
<Link to={authorPath}>
<div className="Comment-info-name">{comment.author.displayName}</div>
</Link>
<div className="Comment-info-time">
{moment.unix(comment.dateCreated).fromNow()}
</div>
</div>
<div className="Comment-body">
<Markdown source={comment.content} type={MARKDOWN_TYPE.REDUCED} />
</div>
{isSignedIn && (
<div className="Comment-controls">
<a className="Comment-controls-button" onClick={this.toggleReply}>
{isReplying ? 'Cancel' : 'Reply'}
</a>
{/*<a className="Comment-controls-button">Report</a>*/}
</div>
)}
{(comment.replies.length || isReplying) && (
<div className="Comment-replies">
{isReplying && (
<div className="Comment-replies-form">
<MarkdownEditor
onChange={this.handleChangeReply}
type={MARKDOWN_TYPE.REDUCED}
/>
<div style={{ marginTop: '0.5rem' }} />
<Button
onClick={this.reply}
disabled={!reply.length}
loading={isPostCommentPending}
>
Submit reply
</Button>
</div>
)}
{comment.replies.map(subComment => (
<ConnectedComment key={subComment.id} comment={subComment} />
))}
</div>
)}
</div>
);
}
private toggleReply = () => {
this.setState({ isReplying: !this.state.isReplying });
};
private handleChangeReply = (reply: string) => {
this.setState({ reply });
};
private reply = () => {
const { comment } = this.props;
const { reply } = this.state;
this.props.postProposalComment(comment.proposalId, reply, comment.id);
};
}
const ConnectedComment = connect<StateProps, DispatchProps, OwnProps, AppState>(
(state: AppState) => ({
isPostCommentPending: state.proposal.isPostCommentPending,
postCommentError: state.proposal.postCommentError,
isSignedIn: getIsSignedIn(state),
}),
{
postProposalComment,
},
)(Comment);
export default ConnectedComment;