diff --git a/app/src/components/BalanceToken.js b/app/src/components/BalanceToken.js index 8515ed5..a6a3548 100644 --- a/app/src/components/BalanceToken.js +++ b/app/src/components/BalanceToken.js @@ -17,9 +17,11 @@ const BalanceToken = ({ amount, symbol, verified, convertedAmount = -1 }) => (
- {splitAmount(amount.toFixed(3))}{' '} + {amount ? splitAmount(amount.toFixed(3)) : ' - '}{' '} + + + {symbol || ' ? '} - {symbol || '?'}
{convertedAmount >= 0 diff --git a/app/src/components/ConvictionVisuals.js b/app/src/components/ConvictionVisuals.js index e5efca1..0692b7b 100644 --- a/app/src/components/ConvictionVisuals.js +++ b/app/src/components/ConvictionVisuals.js @@ -16,6 +16,7 @@ import { getConvictionTrend, } from '../lib/conviction' import { useBlockNumber } from '../BlockContext' +import { fromDecimals } from '../lib/math-utils' function getStakesAndThreshold(proposal = {}) { const { appState } = useAragonApi() @@ -37,7 +38,7 @@ function getStakesAndThreshold(proposal = {}) { return { stakes, totalTokensStaked, threshold, max } } -export function ConvictionChart({ proposal }) { +export function ConvictionChart({ proposal, width = '50%' }) { const { stakes, threshold } = getStakesAndThreshold(proposal) const currentBlock = useBlockNumber() const { connectedAccount } = useAragonApi() @@ -64,6 +65,7 @@ export function ConvictionChart({ proposal }) { return ( i - Math.floor((lines[0].length - 1) / 2)} @@ -116,7 +118,13 @@ export function ConvictionBar({ proposal }) { {Math.round(stakedConviction * 100)}% {' '} - ({Math.round(neededConviction * 100)}% conviction needed) + ( + {isFinite(neededConviction) ? ( + `${Math.round(neededConviction * 100)}% ` + ) : ( + + )} + conviction needed) @@ -147,14 +155,15 @@ export function ConvictionButton({ proposal, onStake, onWithdraw, onExecute }) { } export function ConvictionCountdown({ proposal }) { - const { alpha } = getGlobalParams() + const { alpha, maxRatio } = getGlobalParams() const { appState: { - stakeToken: { tokenSymbol }, + stakeToken: { tokenSymbol, tokenDecimals }, }, } = useAragonApi() const blockNumber = useBlockNumber() const theme = useTheme() + const { executed } = proposal const { stakes, totalTokensStaked, threshold } = getStakesAndThreshold( proposal ) @@ -171,8 +180,16 @@ export function ConvictionCountdown({ proposal }) { const UNABLE_TO_PASS = 0 const MAY_PASS = 1 const AVAILABLE = 2 + const EXECUTED = 3 + const getView = () => - conviction >= threshold ? AVAILABLE : time > 0 ? MAY_PASS : UNABLE_TO_PASS + executed + ? EXECUTED + : conviction >= threshold + ? AVAILABLE + : time > 0 + ? MAY_PASS + : UNABLE_TO_PASS const [view, setView] = useState(getView()) const NOW = Date.now() @@ -189,15 +206,31 @@ export function ConvictionCountdown({ proposal }) { ✘ Won't pass
- Insufficient staked tokens + {!isNaN(neededTokens) + ? 'Insufficient staked tokens' + : 'Not enough funds in the organization'}
- (At least{' '} - - {neededTokens} {tokenSymbol} - {' '} - more needed). + ( + {!isNaN(neededTokens) ? ( + + At least{' '} + + {parseFloat( + fromDecimals(neededTokens.toString(), tokenDecimals) + ) + .toFixed(2) + .toString()}{' '} + {tokenSymbol} + {' '} + more needed + + ) : ( + `Funding requests must be below ${maxRatio * + 100}% organization total funds` + )} + ).
@@ -210,6 +243,8 @@ export function ConvictionCountdown({ proposal }) { {!!endDate && } + ) : view === EXECUTED ? ( + ✓ Executed ) : ( <> ✓ Available for execution diff --git a/app/src/components/ModifiedLineChart.js b/app/src/components/ModifiedLineChart.js index d788bb2..e05becc 100644 --- a/app/src/components/ModifiedLineChart.js +++ b/app/src/components/ModifiedLineChart.js @@ -1,11 +1,38 @@ -import React, { useMemo, useCallback } from 'react' +import React, { useMemo, useCallback, useEffect, useRef, useState } from 'react' import { Spring } from 'react-spring' import { unselectable, springs } from '@aragon/ui' const LABELS_HEIGHT = 30 +const WIDTH_DEFAULT = 300 + +function useMeasuredWidth() { + const ref = useRef() + const [measuredWidth, setMeasuredWidth] = useState(WIDTH_DEFAULT) + + const onResize = useCallback(() => { + if (ref.current) { + setMeasuredWidth(ref.current.clientWidth) + } + }, []) + + const onRef = useCallback( + element => { + ref.current = element + onResize() + }, + [onResize] + ) + + useEffect(() => { + window.addEventListener('resize', onResize) + return () => window.removeEventListener('resize', onResize) + }, [onResize]) + + return [measuredWidth, onRef] +} const ModifiedLineChart = ({ - width, + width: widthProps, height, borderColor, dotRadius, @@ -20,6 +47,8 @@ const ModifiedLineChart = ({ total, ...props }) => { + const [width, onSvgRef] = useMeasuredWidth() + // the total amount of values const lines = useMemo(() => { return linesProps.map(lineOrValues => @@ -90,8 +119,8 @@ const ModifiedLineChart = ({ {({ progress }) => ( diff --git a/app/src/screens/ProposalDetail.js b/app/src/screens/ProposalDetail.js index 445764c..77b3e05 100644 --- a/app/src/screens/ProposalDetail.js +++ b/app/src/screens/ProposalDetail.js @@ -9,6 +9,7 @@ import { useLayout, useTheme, Link, + Split, } from '@aragon/ui' import styled from 'styled-components' import { useAragonApi } from '@aragon/api-react' @@ -22,7 +23,7 @@ import { } from '../components/ConvictionVisuals' import { addressesEqualNoSum as addressesEqual } from '../lib/web3-utils' -const Wrapper = styled.div` +/* const Wrapper = styled.div` display: grid; grid-template-columns: auto; grid-column-gap: ${2.5 * GU}px; @@ -31,7 +32,8 @@ const Wrapper = styled.div` } min-height: 100vh; width: 100%; -` +` */ + const H2 = styled.h2` ${textStyle('label2')}; color: ${props => props.color}; @@ -41,120 +43,158 @@ const H2 = styled.h2` const Progress = styled.div` width: 100%; ` - +const Chart = styled.div` + width: 100%; +` function ProposalDetail({ proposal, onBack, requestToken }) { const theme = useTheme() const { layoutName } = useLayout() const { api, connectedAccount } = useAragonApi() - const { id, name, creator, beneficiary, link, requestedAmount } = proposal - + const { + id, + name, + creator, + beneficiary, + link, + requestedAmount, + executed, + } = proposal return ( - -
- - - - -
-

- #{id} {name} -

-
- -
-

Links

- {link ? ( - - Read more - - ) : ( - - No link provided. - - )} -
-
-

Created By

-
+ + + + + +
+

- -

-
-
-

Recipient

+ #{id} {name} +
- +
+

Links

+ {link ? ( + + Read more + + ) : ( + + No link provided. + + )} +
+
+

Created By

+
+ +
+
+
+

Recipient

+
+ +
+
-
-
- -

Conviction Progress

- -
- api.stakeAllToProposal(id).toPromise()} - onWithdraw={() => api.withdrawAllFromProposal(id).toPromise()} - onExecute={() => api.executeProposal(id, true).toPromise()} - /> -
-
-
-
- - - - - - -
- + {!executed && ( + + +

+ Conviction Progress +

+ +
+ +

+ Conviction prediction +

+
+ +
+
+ api.stakeAllToProposal(id).toPromise()} + onWithdraw={() => + api.withdrawAllFromProposal(id).toPromise() + } + onExecute={() => + api.executeProposal(id, true).toPromise() + } + /> +
+ )} + + + + } + secondary={ +
+ + + +
+ } + /> + ) } diff --git a/app/src/screens/Proposals.js b/app/src/screens/Proposals.js index ecbe4ae..0c13723 100644 --- a/app/src/screens/Proposals.js +++ b/app/src/screens/Proposals.js @@ -72,7 +72,7 @@ const Proposals = React.memo(function Proposals({ } entries={filteredProposals} renderEntry={proposal => { - return [ + const entriesElements = [ , -
- -
, - , ] + if (!proposal.executed) + entriesElements.push( +
+ +
, + + ) + return entriesElements }} tableRowHeight={14 * GU} heading={ diff --git a/package.json b/package.json index fdece8c..a1512e9 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "@aragon/os": "^4.3.0" }, "devDependencies": { - "@aragon/cli": "^7.0.3", + "@aragon/cli": "7.0.3", "@aragon/templates-shared": "^1.0.1", "@aragon/test-helpers": "^2.0.0", "@aragon/truffle-config-v5": "^1.0.0",