2019-01-30 09:59:15 -08:00
|
|
|
import React from 'react';
|
|
|
|
import moment from 'moment';
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
import { Link } from 'react-router-dom';
|
2019-02-18 10:08:20 -08:00
|
|
|
import { Icon, Button, Affix, Tag } from 'antd';
|
2019-02-01 11:25:17 -08:00
|
|
|
import ExceptionPage from 'components/ExceptionPage';
|
2019-01-30 09:59:15 -08:00
|
|
|
import { fetchRfp } from 'modules/rfps/actions';
|
|
|
|
import { getRfp } from 'modules/rfps/selectors';
|
|
|
|
import { RFP } from 'types';
|
|
|
|
import { AppState } from 'store/reducers';
|
|
|
|
import Loader from 'components/Loader';
|
|
|
|
import Markdown from 'components/Markdown';
|
2019-02-01 11:13:30 -08:00
|
|
|
import ProposalCard from 'components/Proposals/ProposalCard';
|
2019-02-08 11:02:34 -08:00
|
|
|
import UnitDisplay from 'components/UnitDisplay';
|
2019-03-13 22:06:22 -07:00
|
|
|
import HeaderDetails from 'components/HeaderDetails';
|
2019-10-24 10:32:00 -07:00
|
|
|
import Like from 'components/Like';
|
2019-10-10 17:12:38 -07:00
|
|
|
import { RFP_STATUS } from 'api/constants';
|
2019-12-03 16:02:39 -08:00
|
|
|
import { formatUsd } from 'utils/formatters';
|
2019-01-30 09:59:15 -08:00
|
|
|
import './index.less';
|
|
|
|
|
|
|
|
interface OwnProps {
|
|
|
|
rfpId: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface StateProps {
|
|
|
|
rfp: RFP | undefined;
|
|
|
|
isFetchingRfps: AppState['rfps']['isFetchingRfps'];
|
|
|
|
fetchRfpsError: AppState['rfps']['fetchRfpsError'];
|
|
|
|
}
|
|
|
|
|
|
|
|
interface DispatchProps {
|
|
|
|
fetchRfp: typeof fetchRfp;
|
|
|
|
}
|
|
|
|
|
|
|
|
type Props = OwnProps & StateProps & DispatchProps;
|
|
|
|
|
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
|
|
|
export class RFPDetail extends React.Component<Props> {
|
2019-01-30 09:59:15 -08:00
|
|
|
componentDidMount() {
|
|
|
|
this.props.fetchRfp(this.props.rfpId);
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const { rfp, isFetchingRfps } = this.props;
|
|
|
|
|
|
|
|
// Optimistically render rfp if we have it, but are updating it
|
|
|
|
if (!rfp) {
|
|
|
|
if (isFetchingRfps) {
|
|
|
|
return <Loader size="large" />;
|
|
|
|
} else {
|
2019-02-01 11:25:17 -08:00
|
|
|
return <ExceptionPage code="404" desc="No request could be found" />;
|
2019-01-30 09:59:15 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-10 17:12:38 -07:00
|
|
|
const isLive = rfp.status === RFP_STATUS.LIVE;
|
2019-02-18 10:08:20 -08:00
|
|
|
const tags = [];
|
|
|
|
|
|
|
|
if (rfp.matching) {
|
|
|
|
tags.push(
|
|
|
|
<Tag key="matching" color="#1890ff">
|
|
|
|
x2 matching
|
|
|
|
</Tag>,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rfp.bounty) {
|
2019-12-03 16:02:39 -08:00
|
|
|
if (rfp.isVersionTwo) {
|
|
|
|
tags.push(
|
|
|
|
<Tag key="bounty" color="#CF8A00">
|
|
|
|
{formatUsd(rfp.bounty.toString(10))} bounty
|
|
|
|
</Tag>,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
tags.push(
|
|
|
|
<Tag key="bounty" color="#CF8A00">
|
|
|
|
<UnitDisplay value={rfp.bounty} symbol="ZEC" /> bounty
|
|
|
|
</Tag>,
|
|
|
|
);
|
|
|
|
}
|
2019-02-18 10:08:20 -08:00
|
|
|
}
|
|
|
|
|
2019-10-10 17:12:38 -07:00
|
|
|
if (!isLive) {
|
|
|
|
tags.push(
|
|
|
|
<Tag key="closed" color="#f5222d">
|
|
|
|
Closed
|
2019-10-16 20:43:20 -07:00
|
|
|
</Tag>,
|
2019-10-10 17:12:38 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-30 09:59:15 -08:00
|
|
|
return (
|
|
|
|
<div className="RFPDetail">
|
2019-03-13 22:06:22 -07:00
|
|
|
<HeaderDetails title={rfp.title} description={rfp.brief} />
|
2019-01-30 09:59:15 -08:00
|
|
|
<div className="RFPDetail-top">
|
|
|
|
<Link className="RFPDetail-top-back" to="/requests">
|
|
|
|
<Icon type="arrow-left" /> Back to Requests
|
|
|
|
</Link>
|
2019-02-18 10:08:20 -08:00
|
|
|
|
2019-01-30 09:59:15 -08:00
|
|
|
<div className="RFPDetail-top-date">
|
2019-02-08 11:02:34 -08:00
|
|
|
Opened {moment(rfp.dateOpened * 1000).format('LL')}
|
2019-01-30 09:59:15 -08:00
|
|
|
</div>
|
2019-10-24 10:32:00 -07:00
|
|
|
<Like rfp={rfp} />
|
2019-01-30 09:59:15 -08:00
|
|
|
</div>
|
2019-02-18 10:08:20 -08:00
|
|
|
|
2019-01-30 09:59:15 -08:00
|
|
|
<h1 className="RFPDetail-title">{rfp.title}</h1>
|
2019-02-18 10:08:20 -08:00
|
|
|
<div className="RFPDetail-tags">{tags}</div>
|
|
|
|
<p className="RFPDetail-brief">{rfp.brief}</p>
|
|
|
|
|
2019-01-30 09:59:15 -08:00
|
|
|
<Markdown className="RFPDetail-content" source={rfp.content} />
|
2019-02-08 11:02:34 -08:00
|
|
|
<div className="RFPDetail-rules">
|
|
|
|
<ul>
|
2019-12-03 16:02:39 -08:00
|
|
|
{rfp.bounty &&
|
|
|
|
rfp.isVersionTwo && (
|
|
|
|
<li>
|
|
|
|
Accepted proposals will be funded up to{' '}
|
|
|
|
<strong>{formatUsd(rfp.bounty.toString(10))}</strong> in ZEC
|
|
|
|
</li>
|
|
|
|
)}
|
|
|
|
{rfp.bounty &&
|
|
|
|
!rfp.isVersionTwo && (
|
|
|
|
<li>
|
|
|
|
Accepted proposals will be funded up to{' '}
|
|
|
|
<strong>
|
|
|
|
<UnitDisplay value={rfp.bounty} symbol="ZEC" />
|
|
|
|
</strong>
|
|
|
|
</li>
|
|
|
|
)}
|
2019-02-08 11:02:34 -08:00
|
|
|
{rfp.matching && (
|
|
|
|
<li>
|
2019-02-15 09:46:50 -08:00
|
|
|
Contributions will have their <strong>funding matched</strong> by the
|
|
|
|
Zcash Foundation
|
2019-02-08 11:02:34 -08:00
|
|
|
</li>
|
|
|
|
)}
|
|
|
|
{rfp.dateCloses && (
|
|
|
|
<li>
|
|
|
|
Proposal submissions end {moment(rfp.dateCloses * 1000).format('LL')}
|
|
|
|
</li>
|
|
|
|
)}
|
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
|
|
|
{rfp.ccr && (
|
|
|
|
<li>
|
|
|
|
Submitted by{' '}
|
|
|
|
<Link to={`/profile/${rfp.ccr.author.userid}`}>
|
|
|
|
{rfp.ccr.author.displayName}
|
|
|
|
</Link>
|
|
|
|
</li>
|
|
|
|
)}
|
2019-02-08 11:02:34 -08:00
|
|
|
</ul>
|
|
|
|
</div>
|
2019-02-01 11:13:30 -08:00
|
|
|
|
|
|
|
{!!rfp.acceptedProposals.length && (
|
|
|
|
<div className="RFPDetail-proposals">
|
|
|
|
<h2 className="RFPDetail-proposals-title">Accepted Proposals</h2>
|
|
|
|
{rfp.acceptedProposals.map(p => (
|
|
|
|
<ProposalCard key={p.proposalId} {...p} />
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
2019-10-10 17:12:38 -07:00
|
|
|
{isLive && (
|
2020-07-24 12:17:07 -07:00
|
|
|
null
|
|
|
|
// <div className="RFPDetail-submit">
|
|
|
|
// <Affix offsetBottom={0}>
|
|
|
|
// <div className="RFPDetail-submit-inner">
|
|
|
|
// <span>Ready to take on this request?</span>{' '}
|
|
|
|
// <Link to={`/create?rfp=${rfp.id}`}>
|
|
|
|
// <Button
|
|
|
|
// className="RFPDetail-submit-inner-button"
|
|
|
|
// type="primary"
|
|
|
|
// size="large"
|
|
|
|
// >
|
|
|
|
// Start a Proposal
|
|
|
|
// <Icon type="right-circle" />
|
|
|
|
// </Button>
|
|
|
|
// </Link>
|
|
|
|
// </div>
|
|
|
|
// </Affix>
|
|
|
|
// </div>
|
2019-10-10 17:12:38 -07:00
|
|
|
)}
|
2019-01-30 09:59:15 -08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default connect<StateProps, DispatchProps, OwnProps, AppState>(
|
|
|
|
(state, ownProps) => ({
|
|
|
|
rfp: getRfp(state, ownProps.rfpId),
|
|
|
|
isFetchingRfps: state.rfps.isFetchingRfps,
|
|
|
|
fetchRfpsError: state.rfps.fetchRfpsError,
|
|
|
|
}),
|
|
|
|
{ fetchRfp },
|
|
|
|
)(RFPDetail);
|