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

186 lines
6.0 KiB
TypeScript
Raw Normal View History

ZF Grants 2.1 (#496) * fix ccr pagination defaults * add ccr admin tests * add ccr user tests * checkpoint * fix tslint * request changes discussion flow mvp * admin - add discussion status * backend - add live drafts * admin - add live drafts * frontend - add live drafts * frontend - add edit discussion proposal * fix tsc * include DISCUSSION status in propsal listview * do not make live draft on admin request changes * hide live drafts from user proposal draft list * fix backend tests * add admin tests * add user tests * fix: liking, viewing discussion proposals, admin menu * admin - update hints for live drafts * fe - add better messaging when updating a proposal * be - fix like test * remove TODO comments * add new email types * fix storybook * add revision tab story * backend - implement proposal revisions * frontend - implement proposal revisions * update revision tab story * fix lint * remove set detection * email proposal followers on revision * restrict banner to team members only * misc bug fixes * update, add backend tests * add milestone title change to revision history story * fix milestones display in preview * allow archived proposals to be queried * implement archived proposal page * fix tsc * implement archived proposal get route * move styling into less * remove proposal archive parent id * handle archived proposal status * cleanup * remove contributions, switch to USD, implement quarters * use Qs to preserve formatting * handle edit only kyc * prevent ARCHIVED proposals from being sent to admin * display latest revision first * admin - proposal & ccr reject permanently * backend - proposal & ccr reject permanently * frontend - proposal & ccr reject permanently * fix tsc * use $ in milestone payout email * introduce custom filters to proposal listview * hide archive link on first revision * upgrade packages * add bech32 implementation * add z address validation with tests * fix tslint * use local address validation * fix tests, remove blockchain mock gets * add additional bad addresses * update briefs to include page break message * remove contributions routes, menu entry * disable countribution count admin stats * remove matching and pretty print in finance * fix tslint * separate out rejected permanently proposals * make removing proposals generic * allow linked tabs to be ignored * remove rejected permanently, bugfix * update preview link to point to rejected tab * implement rejected permanently tab, add tab message * refactor variable * fix tslint * fix tslint * send ccr reject permanently email on rejection * fix preview message * wire up proposal arbiter and rejected emails * disable tip jar in proposal and profile * sync ccr/proposal drafts on create form init * check invites on submit modal open * update team invite language * update team text when edit * fix ccr rejected permanently tag * text changes, email preview fix * display changes requested tag when in discussion with changes requested * enable social share on open for discussion proposals, update language * place sort below filter * derive filter from query string * use better filter names in query params * fix tslint * create snapshot of original proposal on first revision * clear invites between edits, account for additional changes not tracked in revisions * update tests * fix test * remove print * SameSite Fixes (#150) * QA Fixes 2 (#151) * set filters as query strings on change * remove rejected permanently tags * add dollar sign in financials legend * fix tsc * Copy Touchups (#152) * Email Fixes (#155) * fix ZEC in milestone payout emails * fix links in rejected permanently CCR/proposal emails * Poll for Team and Invite Changes in Create Flow (#153) * poll for team and invite changes in create flow * fix tslint Co-authored-by: Daniel Ternyak <dternyak@gmail.com> * pretty print payouts by quarter (#156) Co-authored-by: Daniel Ternyak <dternyak@gmail.com> * Remove Blockchain Module (#154) * remove blockchain route from backend, remove calls to node * revert blockchain_get removal * Add Tags to Proposal Cards (#157) * add tag to proposals and dynamically set v1 card height * listen on window resize * make card height props optional * set tag in bottom right, remove dynamic card resize, add dynamic tag resize * cleanup * cleanup Co-authored-by: Daniel Ternyak <dternyak@gmail.com> * Improve Frontend Address Validation (#158) Co-authored-by: Daniel Ternyak <dternyak@gmail.com> * Remove blockchain module (#162) * remove blockchain route from backend, remove calls to node * revert blockchain_get removal * Remove Blockchain App (#160) * remove blockchain app * remove blockchain app from travis Co-authored-by: Danny Skubak <skubakdj@gmail.com> * Proposal Edit Fixes (#161) * fe - display error if edit creation fails * be - restrict live draft publish Co-authored-by: Daniel Ternyak <dternyak@gmail.com> * Restrict Arbiter Assignment (#159) Co-authored-by: Daniel Ternyak <dternyak@gmail.com> * Email Copy updates * Remove Admin Financials Card * Hookup 'proposal_approved_without_funding' to admin email example * bump various package versions * Update yarn.lock files * Attach 'proposal_approved_without_funding' to backend example email * bump package versions Co-authored-by: Danny Skubak <skubakdj@gmail.com>
2020-04-07 19:56:32 -07:00
import React from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import moment from 'moment';
import Placeholder from 'components/Placeholder';
import { AppState } from 'store/reducers';
import { Proposal, Revision, RevisionChange, REVISION_CHANGE_TYPES } from 'types';
import { fetchProposalRevisions } from 'modules/proposals/actions';
import {
getProposalRevisions,
getIsFetchingRevisions,
getRevisionsError,
} from 'modules/proposals/selectors';
import { Icon } from 'antd';
import './index.less';
interface OwnProps {
proposalId: Proposal['proposalId'];
}
interface StateProps {
revisions: ReturnType<typeof getProposalRevisions>;
isFetchingRevisions: ReturnType<typeof getIsFetchingRevisions>;
revisionsError: ReturnType<typeof getRevisionsError>;
}
interface DispatchProps {
fetchProposalRevisions: typeof fetchProposalRevisions;
}
type Props = DispatchProps & OwnProps & StateProps;
export class ProposalRevision extends React.Component<Props> {
componentDidMount() {
if (this.props.proposalId) {
this.props.fetchProposalRevisions(this.props.proposalId);
}
}
componentWillReceiveProps(nextProps: Props) {
if (nextProps.proposalId && nextProps.proposalId !== this.props.proposalId) {
this.props.fetchProposalRevisions(nextProps.proposalId);
}
}
render() {
const { revisions, isFetchingRevisions, revisionsError } = this.props;
let content = null;
if (isFetchingRevisions) {
content = <Placeholder loading={true} />;
} else if (revisionsError) {
content = <Placeholder title="Something went wrong" subtitle={revisionsError} />;
} else if (revisions) {
if (revisions.length >= 2) {
revisions.reverse();
content = revisions.map((revision, index) => (
<div key={revision.revisionId} className="ProposalRevision-revision">
{index === revisions.length - 1 ? (
<>
<h3 className="ProposalRevision-revision-title">Original Proposal</h3>
<div className="ProposalRevision-revision-controls">
<Link
to={`/proposals/${revision.proposalArchiveId}/archive`}
className="ProposalRevision-revision-controls-button"
>
View archived
</Link>
</div>
</>
) : (
<>
<h3 className="ProposalRevision-revision-title">
{moment(revision.dateCreated * 1000).format('MMMM Do, YYYY')}
</h3>
<div className="ProposalRevision-revision-date">
{`Revision ${revision.revisionIndex}`}
</div>
<div className="ProposalRevision-revision-body">
{this.renderRevisionBody(revision)}
</div>
<div className="ProposalRevision-revision-controls">
{index !== 0 && (
<Link
to={`/proposals/${revision.proposalArchiveId}/archive`}
className="ProposalRevision-revision-controls-button"
>
View archived
</Link>
)}
</div>
</>
)}
</div>
));
} else {
content = (
<Placeholder
title="No revisions have been made"
subtitle="Edits to this proposal will be tracked here"
/>
);
}
}
return <div className="ProposalRevision">{content}</div>;
}
renderRevisionBody = (revision: Revision) => {
return (
<div>
{revision.changes.map((change, index) => (
<div
key={`${revision.revisionId}-${index}`}
className="ProposalRevision-revision-body-list"
>
<div className="ProposalRevision-revision-body-list-icon">
{this.renderChangeIcon(change)}
</div>
<div>{this.renderChangeMsg(change)}</div>
</div>
))}
</div>
);
};
renderChangeIcon = (change: RevisionChange) => {
if (change.type === 'MILESTONE_ADD') {
return <Icon type="plus" />;
}
if (change.type === 'MILESTONE_REMOVE') {
return <Icon type="minus" />;
}
return <Icon type="edit" />;
};
renderChangeMsg = (change: RevisionChange) => {
const msMsg =
change.milestoneIndex !== undefined
? `Milestone ${change.milestoneIndex + 1}`
: 'Milestone';
switch (change.type) {
case REVISION_CHANGE_TYPES.PROPOSAL_EDIT_BRIEF:
return 'Proposal brief edited';
case REVISION_CHANGE_TYPES.PROPOSAL_EDIT_CONTENT:
return 'Proposal content edited';
case REVISION_CHANGE_TYPES.PROPOSAL_EDIT_TARGET:
return 'Proposal target edited';
case REVISION_CHANGE_TYPES.PROPOSAL_EDIT_TITLE:
return 'Proposal title edited';
case REVISION_CHANGE_TYPES.MILESTONE_ADD:
return `${msMsg} added`;
case REVISION_CHANGE_TYPES.MILESTONE_REMOVE:
return `${msMsg} removed`;
case REVISION_CHANGE_TYPES.MILESTONE_EDIT_AMOUNT:
return `${msMsg} amount edited`;
case REVISION_CHANGE_TYPES.MILESTONE_EDIT_DAYS:
return `${msMsg} estimated days edited`;
case REVISION_CHANGE_TYPES.MILESTONE_EDIT_IMMEDIATE_PAYOUT:
return `${msMsg} immediate payout edited`;
case REVISION_CHANGE_TYPES.MILESTONE_EDIT_PERCENT:
return `${msMsg} payout percent edited`;
case REVISION_CHANGE_TYPES.MILESTONE_EDIT_CONTENT:
return `${msMsg} content edited`;
case REVISION_CHANGE_TYPES.MILESTONE_EDIT_TITLE:
return `${msMsg} title edited`;
default:
return '';
}
};
}
export default connect(
(state: AppState, ownProps: OwnProps) => ({
revisions: getProposalRevisions(state, ownProps.proposalId),
isFetchingRevisions: getIsFetchingRevisions(state),
revisionsError: getRevisionsError(state),
}),
{
fetchProposalRevisions,
},
)(ProposalRevision);