Skip to content

Commit

Permalink
feat(neuron-ui): add nervos dao view
Browse files Browse the repository at this point in the history
  • Loading branch information
Keith-CY committed Nov 10, 2019
1 parent 5845ca8 commit ca46665
Show file tree
Hide file tree
Showing 30 changed files with 878 additions and 73 deletions.
2 changes: 1 addition & 1 deletion packages/neuron-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"qr.js": "0.0.0",
"react": "16.9.0",
"react-dom": "16.9.0",
"react-i18next": "10.12.2",
"react-i18next": "11.0.1",
"react-router-dom": "5.0.1",
"react-scripts": "3.2.0",
"styled-components": "5.0.0-beta.0"
Expand Down
142 changes: 142 additions & 0 deletions packages/neuron-ui/src/components/CustomRows/DAORecordRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import React, { useEffect, useState } from 'react'
import { DefaultButton } from 'office-ui-fabric-react'
import { useTranslation } from 'react-i18next'
import { ckbCore, getBlockByNumber } from 'services/chain'
import calculateAPY from 'utils/calculateAPY'
import { shannonToCKBFormatter, uniformTimeFormatter, localNumberFormatter } from 'utils/formatters'
import { epochParser } from 'utils/parsers'
import { WITHDRAW_EPOCHS } from 'utils/const'

import * as styles from './daoRecordRow.module.scss'

const DAORecord = ({
daoData,
blockNumber,
blockHash,
outPoint: { txHash, index },
tipBlockNumber,
tipBlockHash,
capacity,
actionLabel,
onClick,
timestamp,
depositOutPoint,
epoch,
}: State.NervosDAORecord & {
actionLabel: string
onClick: any
tipBlockNumber: string
tipBlockHash: string
epoch: string
}) => {
const [t] = useTranslation()
const [withdrawValue, setWithdrawValue] = useState('')
const [depositEpoch, setDepositEpoch] = useState('')

useEffect(() => {
const withdrawBlockHash = depositOutPoint ? blockHash : tipBlockHash
if (!withdrawBlockHash) {
return
}
;(ckbCore.rpc as any)
.calculateDaoMaximumWithdraw({ txHash, index: `0x${BigInt(index).toString(16)}` }, withdrawBlockHash)
.then((res: string) => {
setWithdrawValue(BigInt(res).toString())
})
.catch((err: Error) => {
console.error(err)
})
}, [txHash, index, tipBlockHash, depositOutPoint, blockHash])

useEffect(() => {
if (!depositOutPoint) {
return
}
const depositBlockNumber = ckbCore.utils.bytesToHex(ckbCore.utils.hexToBytes(daoData).reverse())
getBlockByNumber(BigInt(depositBlockNumber))
.then(b => {
setDepositEpoch(b.header.epoch)
})
.catch((err: Error) => {
console.error(err)
})
}, [daoData, depositOutPoint])

const interest = BigInt(withdrawValue) - BigInt(capacity)

let ready = false
let metaInfo = 'Ready'
if (!depositOutPoint) {
const duration = BigInt(tipBlockNumber) - BigInt(blockNumber)
metaInfo = t('nervos-dao.interest-accumulated', {
blockNumber: localNumberFormatter(duration >= BigInt(0) ? duration : 0),
})
} else {
const depositEpochInfo = epochParser(depositEpoch)
const currentEpochInfo = epochParser(epoch)

let depositedEpochs = currentEpochInfo.number - depositEpochInfo.number
const depositEpochFraction = depositEpochInfo.index * currentEpochInfo.length
const currentEpochFraction = currentEpochInfo.index * depositEpochInfo.length
if (currentEpochFraction > depositEpochFraction) {
depositedEpochs += BigInt(1)
}
const minLockEpochs =
((depositedEpochs + BigInt(WITHDRAW_EPOCHS - 1)) / BigInt(WITHDRAW_EPOCHS)) * BigInt(WITHDRAW_EPOCHS)
const targetEpochNumber = depositEpochInfo.number + minLockEpochs

if (targetEpochNumber < currentEpochInfo.number + BigInt(1) && targetEpochNumber >= currentEpochInfo.number) {
metaInfo = 'Ready'
ready = true
} else {
metaInfo = t('nervos-dao.blocks-left', {
epochs: localNumberFormatter(targetEpochNumber - currentEpochInfo.number - BigInt(1)),
blocks: currentEpochInfo.length - currentEpochInfo.index,
})
}
}

return (
<div className={styles.daoRecord}>
<div className={styles.primaryInfo}>
<div>{interest >= BigInt(0) ? `${shannonToCKBFormatter(interest.toString()).toString()} CKB` : ''}</div>
<div>{`${shannonToCKBFormatter(capacity)} CKB`}</div>
<div>
<DefaultButton
text={actionLabel}
data-tx-hash={txHash}
data-index={index}
onClick={onClick}
disabled={depositOutPoint && !ready}
styles={{
flexContainer: {
pointerEvents: 'none',
},
textContainer: {
pointerEvents: 'none',
},
label: {
pointerEvents: 'none',
},
}}
/>
</div>
</div>
<div className={styles.secondaryInfo}>
<span>
{`APY: ~${calculateAPY(
interest >= BigInt(0) ? interest.toString() : '0',
capacity,
`${Date.now() - +timestamp}`
)}%`}
</span>
<span>{uniformTimeFormatter(+timestamp)}</span>
<span>{metaInfo}</span>
</div>
</div>
)
}

DAORecord.displayName = 'DAORecord'

export default DAORecord
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.daoRecord {
display: flex;
flex-direction: column;
border: 1px solid #000;
border-radius: 5px;
margin: 10px 0;
padding: 5px 15px;

.primaryInfo,
.secondaryInfo {
display: flex;
justify-content: space-between;

&>div,
&>span {
flex: 1;
text-align: center;

&:first-child {
text-align: left;
}

&:last-child {
text-align: right;
}
}

}

.secondaryInfo {
font-size: 12px;
color: #666;
}

}
86 changes: 86 additions & 0 deletions packages/neuron-ui/src/components/NervosDAO/DepositDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from 'react'
import {
Stack,
Dialog,
TextField,
Slider,
Text,
DefaultButton,
PrimaryButton,
DialogType,
DialogFooter,
Spinner,
SpinnerSize,
} from 'office-ui-fabric-react'
import { useTranslation } from 'react-i18next'
import { SHANNON_CKB_RATIO } from 'utils/const'

const DepositDialog = ({
show,
value,
fee,
balance,
onChange,
onSlide,
onSubmit,
onDismiss,
isDepositing,
errorMessage,
}: any) => {
const [t] = useTranslation()
const maxValue = +(BigInt(balance) / BigInt(SHANNON_CKB_RATIO)).toString()

if (!show) {
return null
}

return (
<Dialog
hidden={false}
onDismiss={onDismiss}
dialogContentProps={{
type: DialogType.close,
title: t('nervos-dao.deposit-to-nervos-dao'),
}}
modalProps={{
isBlocking: false,
styles: { main: { maxWidth: '500px!important' } },
}}
>
{isDepositing ? (
<Spinner size={SpinnerSize.large} />
) : (
<>
<TextField label={t('nervos-dao.deposit')} value={value} onChange={onChange} suffix="CKB" />
<Slider value={value} min={0} max={maxValue} step={1} showValue={false} onChange={onSlide} />
<Text as="p" variant="small" block>
{`${t('nervos-dao.fee')}: ${fee}`}
</Text>
<Text as="span" variant="tiny" block styles={{ root: { color: 'red' } }}>
{errorMessage}
</Text>
<Stack>
<Text as="h2" variant="large">
{t('nervos-dao.notice')}
</Text>
{t('nervos-dao.deposit-terms')
.split('\n')
.map(term => (
<Text as="p" key={term}>
{term}
</Text>
))}
</Stack>
<DialogFooter>
<DefaultButton onClick={onDismiss} text={t('nervos-dao.cancel')} />
<PrimaryButton onClick={onSubmit} text={t('nervos-dao.proceed')} disabled={errorMessage} />
</DialogFooter>
</>
)}
</Dialog>
)
}

DepositDialog.displayName = 'DepositDialog'

export default DepositDialog
65 changes: 65 additions & 0 deletions packages/neuron-ui/src/components/NervosDAO/WithdrawDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useState, useEffect } from 'react'
import { Dialog, DialogFooter, DefaultButton, PrimaryButton, DialogType } from 'office-ui-fabric-react'
import { useTranslation } from 'react-i18next'
import { shannonToCKBFormatter } from 'utils/formatters'
import { ckbCore } from 'services/chain'

const WithdrawDialog = ({ onDismiss, onSubmit, record, tipBlockHash }: any) => {
const [t] = useTranslation()
const [withdrawValue, setWithdrawValue] = useState('')
useEffect(() => {
if (!record || !tipBlockHash) {
return
}
;(ckbCore.rpc as any)
.calculateDaoMaximumWithdraw(
{
txHash: record.outPoint.txHash,
index: `0x${BigInt(record.outPoint.index).toString(16)}`,
},
tipBlockHash
)
.then((res: string) => {
setWithdrawValue(res)
})
.catch((err: Error) => {
console.error(err)
})
}, [record, tipBlockHash])
return (
<Dialog
hidden={!record}
onDismiss={onDismiss}
dialogContentProps={{ type: DialogType.close, title: t('nervos-dao.withdraw-from-nervos-dao') }}
modalProps={{
isBlocking: false,
styles: { main: { maxWidth: '500px!important' } },
}}
>
{record ? (
<>
<div>
<span>{`${t('nervos-dao.deposit')}:`}</span>
<span>{`${shannonToCKBFormatter(record.capacity)} CKB`}</span>
</div>
<div>
<span>{`${t('nervos-dao.interest')}:`}</span>
<span>
{withdrawValue
? `${shannonToCKBFormatter((BigInt(withdrawValue) - BigInt(record.capacity)).toString())} CKB`
: ''}
</span>
</div>
</>
) : null}
<DialogFooter>
<DefaultButton text={t('nervos-dao.cancel')} onClick={onDismiss} />
<PrimaryButton text={t('nervos-dao.proceed')} onClick={onSubmit} />
</DialogFooter>
</Dialog>
)
}

WithdrawDialog.displayName = 'WithdrawDialog'

export default WithdrawDialog
Loading

0 comments on commit ca46665

Please sign in to comment.