zcash-grant-system/frontend/client/components/Proposal/Comments/index.tsx

183 lines
5.2 KiB
TypeScript
Raw Normal View History

2018-09-10 09:55:26 -07:00
import React from 'react';
import { connect } from 'react-redux';
import { Button, message, Skeleton, Alert } from 'antd';
2018-09-10 09:55:26 -07:00
import { AppState } from 'store/reducers';
import { Proposal } from 'types';
import { fetchProposalComments, postProposalComment } from 'modules/proposals/actions';
2019-02-10 11:33:02 -08:00
import { getIsVerified, getIsSignedIn } from 'modules/auth/selectors';
2018-09-10 09:55:26 -07:00
import Comments from 'components/Comments';
import Placeholder from 'components/Placeholder';
import MarkdownEditor, { MARKDOWN_TYPE } from 'components/MarkdownEditor';
import './index.less';
2018-09-10 09:55:26 -07:00
interface OwnProps {
proposalId: Proposal['proposalId'];
2018-09-10 09:55:26 -07:00
}
interface StateProps {
detailComments: AppState['proposal']['detailComments'];
isPostCommentPending: AppState['proposal']['isPostCommentPending'];
postCommentError: AppState['proposal']['postCommentError'];
isVerified: ReturnType<typeof getIsVerified>;
2019-02-10 11:33:02 -08:00
isSignedIn: ReturnType<typeof getIsSignedIn>;
2018-09-10 09:55:26 -07:00
}
interface DispatchProps {
fetchProposalComments: typeof fetchProposalComments;
postProposalComment: typeof postProposalComment;
2018-09-10 09:55:26 -07:00
}
type Props = DispatchProps & OwnProps & StateProps;
interface State {
comment: string;
curtainsMatchDrapes: boolean;
}
class ProposalComments extends React.Component<Props, State> {
state: State = {
comment: '',
curtainsMatchDrapes: this.props.detailComments.parentId === this.props.proposalId,
};
private editor: MarkdownEditor | null = null;
2018-09-10 09:55:26 -07:00
componentDidMount() {
if (!this.state.curtainsMatchDrapes) {
2018-09-10 09:55:26 -07:00
this.props.fetchProposalComments(this.props.proposalId);
}
}
componentWillReceiveProps(nextProps: Props) {
if (nextProps.proposalId && nextProps.proposalId !== this.props.proposalId) {
this.props.fetchProposalComments(nextProps.proposalId);
}
}
componentDidUpdate(prevProps: Props) {
const { isPostCommentPending, postCommentError } = this.props;
if (!isPostCommentPending && !postCommentError && prevProps.isPostCommentPending) {
this.setState({ comment: '' });
this.editor!.reset();
}
if (postCommentError && postCommentError !== prevProps.postCommentError) {
message.error(postCommentError);
}
}
2018-09-10 09:55:26 -07:00
render() {
const { detailComments, isPostCommentPending, isVerified, isSignedIn } = this.props;
const { comment } = this.state;
2018-09-10 09:55:26 -07:00
let content = null;
const { hasFetched, isFetching, hasMore, pages, fetchError, total } = detailComments;
if (!hasFetched) {
content = [1, 2, 3].map(i => (
<Skeleton
className="ProposalComments-skellie"
key={i}
active
avatar={{ shape: 'square' }}
paragraph={{ rows: 2 }}
/>
));
} else if (total) {
2018-09-10 09:55:26 -07:00
content = (
<>
{pages.map((p, i) => (
<Comments key={i} comments={p} />
))}
<div>
{hasMore && (
<Button
onClick={() => this.props.fetchProposalComments()}
loading={isFetching}
block
>
Older Comments
</Button>
)}
</div>
2018-09-10 09:55:26 -07:00
</>
);
} else {
content = (
<Placeholder
title="No comments have been made yet"
subtitle="Why not be the first?"
/>
);
2018-09-10 09:55:26 -07:00
}
return (
<div className="ProposalComments">
<div className="ProposalComments-post">
2019-02-10 11:33:02 -08:00
{isVerified && (
<>
<MarkdownEditor
ref={el => (this.editor = el)}
onChange={this.handleCommentChange}
type={MARKDOWN_TYPE.REDUCED}
minHeight={100}
/>
<Button
onClick={this.postComment}
disabled={!comment.length}
loading={isPostCommentPending}
>
Submit comment
</Button>
</>
)}
2019-02-10 11:33:02 -08:00
{isSignedIn &&
!isVerified && (
<>
<h4 className="ProposalComments-verify">
Please verify your email to post a comment.
</h4>
<MarkdownEditor
onChange={this.handleCommentChange}
type={MARKDOWN_TYPE.REDUCED}
readOnly={true}
minHeight={100}
2019-02-10 11:33:02 -08:00
/>
</>
)}
</div>
{content}
{fetchError && (
<Alert
className="ProposalComments-alert"
type="error"
message="Oopsy, there was a problem loading comments!"
description={fetchError}
/>
)}
</div>
);
2018-09-10 09:55:26 -07:00
}
private handleCommentChange = (comment: string) => {
this.setState({ comment });
};
private postComment = () => {
this.props.postProposalComment(this.props.proposalId, this.state.comment);
};
2018-09-10 09:55:26 -07:00
}
2018-11-08 11:38:00 -08:00
export default connect<StateProps, DispatchProps, OwnProps, AppState>(
state => ({
detailComments: state.proposal.detailComments,
isPostCommentPending: state.proposal.isPostCommentPending,
postCommentError: state.proposal.postCommentError,
isVerified: getIsVerified(state),
2019-02-10 11:33:02 -08:00
isSignedIn: getIsSignedIn(state),
2018-09-10 09:55:26 -07:00
}),
{
fetchProposalComments,
postProposalComment,
2018-09-10 09:55:26 -07:00
},
)(ProposalComments);