From 213595cfba3c49a24cdaabf9ab66603c9d07cabf Mon Sep 17 00:00:00 2001 From: Danny Skubak Date: Sun, 24 Nov 2019 10:05:08 -0500 Subject: [PATCH] Redesign Campaign Block (#74) * 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 * update campaign block * 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 --- admin/src/components/ProposalDetail/index.tsx | 4 +- .../client/components/Profile/ProfileUser.tsx | 3 +- .../Proposal/CampaignBlock/index.tsx | 83 +++++++++---------- .../Proposal/CampaignBlock/style.less | 19 +++++ .../Proposal/TippingBlock/index.tsx | 50 +++++++++++ .../Proposal/TippingBlock/style.less | 32 +++++++ .../client/components/Proposal/index.less | 15 +++- frontend/client/components/Proposal/index.tsx | 2 + .../client/components/TipJar/TipJarModal.tsx | 20 ++--- 9 files changed, 169 insertions(+), 59 deletions(-) create mode 100644 frontend/client/components/Proposal/TippingBlock/index.tsx create mode 100644 frontend/client/components/Proposal/TippingBlock/style.less diff --git a/admin/src/components/ProposalDetail/index.tsx b/admin/src/components/ProposalDetail/index.tsx index e1d91910..193b0810 100644 --- a/admin/src/components/ProposalDetail/index.tsx +++ b/admin/src/components/ProposalDetail/index.tsx @@ -225,8 +225,8 @@ class ProposalDetailNaked extends React.Component { description={

- This proposal has changes requested. The team will be able to re-submit it for - approval should they desire to do so. + This proposal has changes requested. The team will be able to re-submit it + for approval should they desire to do so.

Reason:
diff --git a/frontend/client/components/Profile/ProfileUser.tsx b/frontend/client/components/Profile/ProfileUser.tsx index a445b936..0564ec36 100644 --- a/frontend/client/components/Profile/ProfileUser.tsx +++ b/frontend/client/components/Profile/ProfileUser.tsx @@ -61,7 +61,8 @@ class ProfileUser extends React.Component {
)} - {!isSelf && } + {!isSelf && + user.tipJarAddress && } ); } diff --git a/frontend/client/components/Proposal/CampaignBlock/index.tsx b/frontend/client/components/Proposal/CampaignBlock/index.tsx index 8c9f0d62..4e4b384c 100644 --- a/frontend/client/components/Proposal/CampaignBlock/index.tsx +++ b/frontend/client/components/Proposal/CampaignBlock/index.tsx @@ -8,9 +8,9 @@ import { compose } from 'recompose'; import { AppState } from 'store/reducers'; import { withRouter } from 'react-router'; import UnitDisplay from 'components/UnitDisplay'; -import { TipJarBlock } from 'components/TipJar'; import Loader from 'components/Loader'; import { PROPOSAL_STAGE } from 'api/constants'; +import ZFGrantsLogo from 'static/images/logo-name-light.svg' import './style.less'; interface OwnProps { @@ -70,13 +70,7 @@ export class ProposalCampaignBlock extends React.Component { } const isAcceptedWithFunding = proposal.acceptedWithFunding === true; - const isAcceptedWithoutFunding = proposal.acceptedWithFunding === false; - const isAccepted = isAcceptedWithFunding || isAcceptedWithoutFunding; - const isCancelled = proposal.stage === PROPOSAL_STAGE.CANCELED; - const isJudged = isAccepted || isCancelled; - - const displayBountyFunding = - !isVersionTwo || (isVersionTwo && isAcceptedWithFunding); + const isCanceled = proposal.stage === PROPOSAL_STAGE.CANCELED; content = ( @@ -97,23 +91,48 @@ export class ProposalCampaignBlock extends React.Component { )} -
-
Funding
-
- / + {!isVersionTwo && ( +
+
Funding
+
+ /{' '} + +
-
+ )} + + {isVersionTwo && ( +
+
+ {isAcceptedWithFunding ? 'Funding' : 'Requested Funding'} +
+
+ +
+
+ )} {bounty && - displayBountyFunding && ( + !isVersionTwo && (
Awarded with bounty
)} - {isAcceptedWithoutFunding && ( -
Accepted without funding
- )} + {isVersionTwo && + isAcceptedWithFunding && ( +
+ Funded through   + +
+ )} + + {isVersionTwo && + !isAcceptedWithFunding && ( +
+ Open for Community Donations +
+ )} {!isVersionTwo && proposal.contributionMatching > 0 && ( @@ -144,7 +163,7 @@ export class ProposalCampaignBlock extends React.Component { ['is-success']: isRaiseGoalReached, })} > - {isCancelled ? ( + {isCanceled ? ( <> Proposal was canceled @@ -175,32 +194,12 @@ export class ProposalCampaignBlock extends React.Component { ))} {isVersionTwo && - isJudged && ( -
- {proposal.stage === PROPOSAL_STAGE.CANCELED ? ( - <> - - Proposal was canceled - - ) : ( - <> - - Proposal has been accepted - - )} + isCanceled && ( +
+ + Proposal was canceled
)} - - {proposal.tipJarAddress && ( -
- -
- )} ); } else { diff --git a/frontend/client/components/Proposal/CampaignBlock/style.less b/frontend/client/components/Proposal/CampaignBlock/style.less index 27d5d1b5..1bb36c06 100644 --- a/frontend/client/components/Proposal/CampaignBlock/style.less +++ b/frontend/client/components/Proposal/CampaignBlock/style.less @@ -57,6 +57,25 @@ margin-top: 0; } + &-with-funding, + &-without-funding { + margin: 0.5rem -1.5rem; + padding: 0.75rem 1rem; + font-size: 1rem; + color: #fff; + align-items: center; + display: flex; + justify-content: center; + } + + &-with-funding { + background: @secondary-color; + } + + &-without-funding { + background: @info-color; + } + &-popover { &-overlay { max-width: 400px; diff --git a/frontend/client/components/Proposal/TippingBlock/index.tsx b/frontend/client/components/Proposal/TippingBlock/index.tsx new file mode 100644 index 00000000..94993238 --- /dev/null +++ b/frontend/client/components/Proposal/TippingBlock/index.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { Tooltip, Icon } from 'antd'; +import { Proposal } from 'types'; +import Loader from 'components/Loader'; +import { TipJarBlock } from 'components/TipJar'; +import { PROPOSAL_STAGE } from 'api/constants'; +import './style.less'; + +interface Props { + proposal: Proposal; +} + +const TippingBlock: React.SFC = ({ proposal }) => { + let content; + if (proposal) { + if (!proposal.tipJarAddress || proposal.stage === PROPOSAL_STAGE.CANCELED) { + return null; + } + content = ( + <> +
+
Tips Received
+
+ ???   + + + +
+
+
+ +
+ + ); + } else { + content = ; + } + + return ( +
+

Tipping

+
{content}
+
+ ); +}; + +export default TippingBlock; diff --git a/frontend/client/components/Proposal/TippingBlock/style.less b/frontend/client/components/Proposal/TippingBlock/style.less new file mode 100644 index 00000000..7bed56b6 --- /dev/null +++ b/frontend/client/components/Proposal/TippingBlock/style.less @@ -0,0 +1,32 @@ +@import '~styles/variables.less'; + +.TippingBlock { + &-info { + display: flex; + justify-content: space-between; + margin-bottom: 0.5rem; + overflow: hidden; + line-height: 1.7rem; + + &-label { + font-size: 0.95rem; + font-weight: 300; + opacity: 0.8; + letter-spacing: 0.05rem; + flex: 0 0 auto; + margin-right: 1.5rem; + } + + &-value { + font-size: 1.1rem; + flex-basis: 0; + flex-grow: 1; + overflow: hidden; + text-align: right; + } + } + + &-tipJarWrapper { + margin-top: 1rem; + } +} diff --git a/frontend/client/components/Proposal/index.less b/frontend/client/components/Proposal/index.less index 7ba70ef0..ffc53bde 100644 --- a/frontend/client/components/Proposal/index.less +++ b/frontend/client/components/Proposal/index.less @@ -205,9 +205,16 @@ margin-left: 0; } - &:last-child { + &:nth-child(2) { + width: calc(50% - 1rem); + } + + &:nth-child(3) { + width: calc(50% - 1rem); + } + + &:nth-child(4) { width: calc(50% - 1rem); - margin-left: 1rem; } } } @@ -218,7 +225,9 @@ > * { &, &:first-child, - &:last-child { + &:nth-child(2), + &:nth-child(3), + &:nth-child(4) { width: auto; margin-left: 0; } diff --git a/frontend/client/components/Proposal/index.tsx b/frontend/client/components/Proposal/index.tsx index 57bfe591..aa3ecb16 100644 --- a/frontend/client/components/Proposal/index.tsx +++ b/frontend/client/components/Proposal/index.tsx @@ -14,6 +14,7 @@ import { AlertProps } from 'antd/lib/alert'; import ExceptionPage from 'components/ExceptionPage'; import HeaderDetails from 'components/HeaderDetails'; import CampaignBlock from './CampaignBlock'; +import TippingBlock from './TippingBlock' import TeamBlock from './TeamBlock'; import RFPBlock from './RFPBlock'; import Milestones from './Milestones'; @@ -246,6 +247,7 @@ export class ProposalDetail extends React.Component {
+ {proposal.rfp && }
diff --git a/frontend/client/components/TipJar/TipJarModal.tsx b/frontend/client/components/TipJar/TipJarModal.tsx index 07b027c6..2a2f30cc 100644 --- a/frontend/client/components/TipJar/TipJarModal.tsx +++ b/frontend/client/components/TipJar/TipJarModal.tsx @@ -3,7 +3,7 @@ import { Modal, Icon, Button, Form, Input } from 'antd'; import classnames from 'classnames'; import QRCode from 'qrcode.react'; import { formatZcashCLI, formatZcashURI } from 'utils/formatters'; -import { getAmountErrorFromString } from 'utils/validators' +import { getAmountErrorFromString } from 'utils/validators'; import Loader from 'components/Loader'; import './TipJarModal.less'; import CopyInput from 'components/CopyInput'; @@ -17,27 +17,25 @@ interface Props { } interface State { - amount: string | null; + amount: string; } export class TipJarModal extends React.Component { - static getDerivedStateFromProps = (nextProps: Props, prevState: State) => { - return prevState.amount === null ? { amount: nextProps.amount } : {}; + static getDerivedStateFromProps = (nextProps: Props) => { + // while modal is closed, set amount state via props + return !nextProps.isOpen ? { amount: nextProps.amount } : {}; }; state: State = { - amount: null, + amount: '', }; render() { const { isOpen, onClose, type, address } = this.props; const { amount } = this.state; - // should not be possible due to derived state, but makes TS happy - if (amount === null) return; - - const amountError = getAmountErrorFromString(amount) - const amountIsValid = !amountError + const amountError = getAmountErrorFromString(amount); + const amountIsValid = !amountError; const cli = amountIsValid ? formatZcashCLI(address, amount) : ''; const uri = amountIsValid ? formatZcashURI(address, amount) : ''; @@ -122,5 +120,5 @@ export class TipJarModal extends React.Component { amount: e.currentTarget.value, }); - private handleAfterClose = () => this.setState({ amount: null }); + private handleAfterClose = () => this.setState({ amount: '' }); }