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

206 lines
5.7 KiB
TypeScript

import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { Button, Divider, List, message, Popconfirm, Spin } from 'antd';
import Placeholder from 'components/Placeholder';
import { getIsVerified } from 'modules/auth/selectors';
import Loader from 'components/Loader';
import { ProposalDraft, STATUS } from 'types';
import {
createDraft,
deleteDraft,
fetchDrafts,
fetchAndCreateDrafts,
} from 'modules/create/actions';
import { AppState } from 'store/reducers';
import './style.less';
interface StateProps {
drafts: AppState['create']['drafts'];
isFetchingDrafts: AppState['create']['isFetchingDrafts'];
fetchDraftsError: AppState['create']['fetchDraftsError'];
isCreatingDraft: AppState['create']['isCreatingDraft'];
createDraftError: AppState['create']['createDraftError'];
isDeletingDraft: AppState['create']['isDeletingDraft'];
deleteDraftError: AppState['create']['deleteDraftError'];
isVerified: ReturnType<typeof getIsVerified>;
}
interface DispatchProps {
fetchDrafts: typeof fetchDrafts;
createDraft: typeof createDraft;
deleteDraft: typeof deleteDraft;
fetchAndCreateDrafts: typeof fetchAndCreateDrafts;
}
interface OwnProps {
createIfNone?: boolean;
createWithRfpId?: number;
}
type Props = StateProps & DispatchProps & OwnProps;
interface State {
deletingId: number | null;
}
const EMAIL_VERIFIED_RELOAD_TIMEOUT = 10000;
class DraftList extends React.Component<Props, State> {
state: State = {
deletingId: null,
};
private reloadTimeout: number | null = null;
componentDidMount() {
const { createIfNone, createWithRfpId, isVerified } = this.props;
if (createIfNone || createWithRfpId) {
this.props.fetchAndCreateDrafts({
rfpId: createWithRfpId,
redirect: true,
});
} else {
this.props.fetchDrafts();
}
if (!isVerified) {
this.reloadTimeout = window.setTimeout(() => {
window.location.reload();
}, EMAIL_VERIFIED_RELOAD_TIMEOUT);
}
}
componentWillUnmount() {
if (this.reloadTimeout !== null) {
window.clearTimeout(this.reloadTimeout);
}
}
componentDidUpdate(prevProps: Props) {
const { isDeletingDraft, deleteDraftError, createDraftError } = this.props;
if (prevProps.isDeletingDraft && !isDeletingDraft) {
this.setState({ deletingId: null });
}
if (deleteDraftError && prevProps.deleteDraftError !== deleteDraftError) {
message.error(deleteDraftError, 3);
}
if (createDraftError && prevProps.createDraftError !== createDraftError) {
message.error(createDraftError, 3);
}
}
render() {
const { drafts, isCreatingDraft, isFetchingDrafts, isVerified } = this.props;
const { deletingId } = this.state;
if (!isVerified) {
return (
<div className="DraftList">
<Placeholder
title="Your email is not verified"
subtitle="Please confirm your email before making a proposal."
/>
</div>
);
}
if (!drafts || isCreatingDraft) {
return <Loader size="large" />;
}
let draftsEl;
if (drafts.length) {
draftsEl = (
<List
itemLayout="horizontal"
dataSource={drafts}
loading={isFetchingDrafts}
renderItem={(d: ProposalDraft) => {
const actions = [
<Link key="edit" to={`/proposals/${d.proposalId}/edit`}>
Edit
</Link>,
<Popconfirm
key="delete"
title="Are you sure?"
onConfirm={() => this.deleteDraft(d.proposalId)}
>
<a>Delete</a>
</Popconfirm>,
];
return (
<Spin tip="deleting..." spinning={deletingId === d.proposalId}>
<List.Item actions={actions}>
<List.Item.Meta
title={
<>
{d.title || <em>Untitled proposal</em>}
{d.status === STATUS.REJECTED && <em> (changes requested)</em>}
</>
}
description={d.brief || <em>No description</em>}
/>
</List.Item>
</Spin>
);
}}
/>
);
} else {
draftsEl = (
<Placeholder
title="You have no drafts"
subtitle="Why not make one now? Click below to start."
/>
);
}
return (
<div className="DraftList">
<h2 className="DraftList-title">Your drafts</h2>
{draftsEl}
<Divider>or</Divider>
<Button
className="DraftList-create"
type="primary"
size="large"
block
onClick={() => this.createDraft()}
loading={isCreatingDraft}
>
Create a new Proposal
</Button>
</div>
);
}
private createDraft = (rfpId?: number) => {
this.props.createDraft({ rfpId, redirect: true });
};
private deleteDraft = (proposalId: number) => {
this.props.deleteDraft(proposalId);
this.setState({ deletingId: proposalId });
};
}
export default connect<StateProps, DispatchProps, OwnProps, AppState>(
state => ({
drafts: state.create.drafts,
isFetchingDrafts: state.create.isFetchingDrafts,
fetchDraftsError: state.create.fetchDraftsError,
isCreatingDraft: state.create.isCreatingDraft,
createDraftError: state.create.createDraftError,
isDeletingDraft: state.create.isDeletingDraft,
deleteDraftError: state.create.deleteDraftError,
isVerified: getIsVerified(state),
}),
{
fetchDrafts,
createDraft,
deleteDraft,
fetchAndCreateDrafts,
},
)(DraftList);