zcash-grant-system/frontend/client/components/CreateFlow/Review.tsx

198 lines
5.4 KiB
TypeScript
Raw Normal View History

import React from 'react';
import { connect } from 'react-redux';
import { Icon, Timeline } from 'antd';
import moment from 'moment';
import { Milestone } from 'modules/create/types';
import { getCreateErrors, KeyOfForm, FIELD_NAME_MAP } from 'modules/create/utils';
import Markdown from 'components/Markdown';
import { AppState } from 'store/reducers';
import { CREATE_STEP } from './index';
import { CATEGORY_UI } from 'api/constants';
import './Review.less';
interface OwnProps {
setStep(step: CREATE_STEP): void;
}
interface StateProps {
form: AppState['create']['form'];
}
type Props = OwnProps & StateProps;
interface Field {
key: KeyOfForm;
content: React.ReactNode;
error: string | undefined | false;
}
interface Section {
step: CREATE_STEP;
name: string;
fields: Field[];
}
class CreateReview extends React.Component<Props> {
render() {
const { form } = this.props;
const errors = getCreateErrors(this.props.form);
const catUI = CATEGORY_UI[form.category] || ({} as any);
const sections: Section[] = [
{
step: CREATE_STEP.BASICS,
name: 'Basics',
fields: [
{
key: 'title',
content: <h2 style={{ fontSize: '1.6rem', margin: 0 }}>{form.title}</h2>,
error: errors.title,
},
{
key: 'brief',
content: form.brief,
error: errors.brief,
},
{
key: 'category',
content: (
<div style={{ color: catUI.color }}>
<Icon type={catUI.icon} /> {catUI.label}
</div>
),
error: errors.category,
},
{
key: 'amountToRaise',
content: <div style={{ fontSize: '1.2rem' }}>{form.amountToRaise} ETH</div>,
error: errors.amountToRaise,
},
],
},
// {
// step: CREATE_STEP.TEAM,
// name: 'Team',
// fields: [],
// },
{
step: CREATE_STEP.DETAILS,
name: 'Details',
fields: [
{
key: 'details',
content: <Markdown source={form.details} />,
error: errors.details,
},
],
},
{
step: CREATE_STEP.MILESTONES,
name: 'Milestones',
fields: [
{
key: 'milestones',
content: <ReviewMilestones milestones={form.milestones} />,
error: errors.milestones && errors.milestones.join(' '),
},
],
},
{
step: CREATE_STEP.GOVERNANCE,
name: 'Governance',
fields: [
{
key: 'payOutAddress',
content: <code>{form.payOutAddress}</code>,
error: errors.payOutAddress,
},
{
key: 'trustees',
content: form.trustees.map(t => (
<div key={t}>
<code>{t}</code>
</div>
)),
error: errors.trustees && errors.trustees.join(' '),
},
{
key: 'deadline',
content: `${Math.floor(moment.duration(form.deadline * 1000).asDays())} days`,
error: errors.deadline,
},
{
key: 'milestoneDeadline',
content: `${Math.floor(
moment.duration(form.milestoneDeadline * 1000).asDays(),
)} days`,
error: errors.milestoneDeadline,
},
],
},
];
return (
<div className="CreateReview">
{sections.map(s => (
<div className="CreateReview-section">
{s.fields.map(f => (
<div className="ReviewField" key={f.key}>
<div className="ReviewField-label">
{FIELD_NAME_MAP[f.key]}
{f.error && <div className="ReviewField-label-error">{f.error}</div>}
</div>
<div className="ReviewField-content">
{this.isEmpty(form[f.key]) ? (
<div className="ReviewField-content-empty">N/A</div>
) : (
f.content
)}
</div>
</div>
))}
<div className="ReviewField">
<div className="ReviewField-label" />
<div className="ReviewField-content">
<button
className="ReviewField-content-edit"
onClick={() => this.setStep(s.step)}
>
Edit {s.name}
</button>
</div>
</div>
</div>
))}
</div>
);
}
private setStep = (step: CREATE_STEP) => {
this.props.setStep(step);
};
private isEmpty(value: any) {
return !value || value.length === 0;
}
}
export default connect<StateProps, {}, OwnProps, AppState>(state => ({
form: state.create.form,
}))(CreateReview);
const ReviewMilestones = ({ milestones }: { milestones: Milestone[] }) => (
<Timeline>
{milestones.map(m => (
<Timeline.Item>
<div className="ReviewMilestone">
<div className="ReviewMilestone-title">{m.title}</div>
<div className="ReviewMilestone-info">
{moment(m.date).format('MMMM YYYY')}
{' '}
{m.payoutPercent}% of funds
</div>
<div className="ReviewMilestone-description">{m.description}</div>
</div>
</Timeline.Item>
))}
</Timeline>
);