116 lines
3.3 KiB
TypeScript
116 lines
3.3 KiB
TypeScript
import React from 'react';
|
|
import { connect } from 'react-redux';
|
|
import { Divider } from 'antd';
|
|
import { fetchRfps } from 'modules/rfps/actions';
|
|
import { AppState } from 'store/reducers';
|
|
import { RFP } from 'types';
|
|
import { RFP_STATUS } from 'api/constants';
|
|
import Loader from 'components/Loader';
|
|
import Placeholder from 'components/Placeholder';
|
|
import RFPItem from './RFPItem';
|
|
import ZCFLogo from 'static/images/zcf.svg';
|
|
import './index.less';
|
|
|
|
interface StateProps {
|
|
rfps: AppState['rfps']['rfps'];
|
|
isFetchingRfps: AppState['rfps']['isFetchingRfps'];
|
|
hasFetchedRfps: AppState['rfps']['hasFetchedRfps'];
|
|
fetchRfpsError: AppState['rfps']['fetchRfpsError'];
|
|
}
|
|
|
|
interface DispatchProps {
|
|
fetchRfps: typeof fetchRfps;
|
|
}
|
|
|
|
type Props = StateProps & DispatchProps;
|
|
|
|
class RFPs extends React.Component<Props> {
|
|
componentDidMount() {
|
|
this.props.fetchRfps();
|
|
}
|
|
|
|
render() {
|
|
const { rfps, isFetchingRfps, hasFetchedRfps, fetchRfpsError } = this.props;
|
|
|
|
let rfpsEl;
|
|
if (fetchRfpsError) {
|
|
rfpsEl = (
|
|
<div className="RFPs-error">
|
|
<Placeholder
|
|
title="Something went wrong"
|
|
subtitle="We had an issue fetching requests, try again later"
|
|
/>
|
|
</div>
|
|
);
|
|
} else if (!hasFetchedRfps && isFetchingRfps) {
|
|
rfpsEl = (
|
|
<div className="RFPs-loading">
|
|
<Loader size="large" />
|
|
</div>
|
|
);
|
|
} else {
|
|
const live = rfps.filter(rfp => rfp.status === RFP_STATUS.LIVE);
|
|
const closed = rfps.filter(rfp => rfp.status === RFP_STATUS.CLOSED);
|
|
rfpsEl = (
|
|
<>
|
|
<Divider>Open Requests</Divider>
|
|
{this.renderRfpsList(live)}
|
|
{!!closed.length && (
|
|
<>
|
|
<Divider>Closed Requests</Divider>
|
|
{this.renderRfpsList(closed, true)}
|
|
</>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="RFPs">
|
|
<div className="RFPs-about">
|
|
<div className="RFPs-about-logo">
|
|
<ZCFLogo />
|
|
</div>
|
|
<div className="RFPs-about-text">
|
|
<h2 className="RFPs-about-text-title">Zcash Foundation Requests</h2>
|
|
<p className="RFPs-about-text-desc">
|
|
The Zcash Foundation periodically makes requests for proposals that solve
|
|
high-priority needs in the Zcash ecosystem. These proposals will typically
|
|
receive large or matched contributions, should they be approved by the
|
|
foundation.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
{rfpsEl}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
private renderRfpsList = (rfps: RFP[], isSmall?: boolean) => {
|
|
return (
|
|
<div className="RFPs-list">
|
|
{rfps.map(rfp => (
|
|
<RFPItem key={rfp.id} rfp={rfp} isSmall={isSmall} />
|
|
))}
|
|
{!rfps.length && (
|
|
<Placeholder
|
|
title="No requests are currently active"
|
|
subtitle="Check back later for more opportunities"
|
|
loading={this.props.isFetchingRfps}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
}
|
|
|
|
export default connect<StateProps, DispatchProps, {}, AppState>(
|
|
state => ({
|
|
rfps: state.rfps.rfps,
|
|
isFetchingRfps: state.rfps.isFetchingRfps,
|
|
hasFetchedRfps: state.rfps.hasFetchedRfps,
|
|
fetchRfpsError: state.rfps.fetchRfpsError,
|
|
}),
|
|
{ fetchRfps },
|
|
)(RFPs);
|