From 2820b83949b8a45e32537fba95a8b299b65e0a3f Mon Sep 17 00:00:00 2001 From: Keith Date: Wed, 3 Apr 2024 01:58:53 +0900 Subject: [PATCH] refactor: optimize nervos dao calculator --- src/locales/en.json | 16 ++- src/locales/zh.json | 20 +-- .../NervosDao/DaoBanner/DaoBanner.module.scss | 1 + src/pages/NervosDao/DaoBanner/index.tsx | 14 +- .../RewardCalcutorModal.module.scss | 14 ++ .../NervosDao/RewardCalcutorModal/index.tsx | 129 +++++++++++++----- src/styles/index.css | 10 ++ 7 files changed, 147 insertions(+), 57 deletions(-) diff --git a/src/locales/en.json b/src/locales/en.json index 935b8cb5c7..9899fd7359 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -572,11 +572,11 @@ "deposit_address_tooltip": "Number of addresses with non-zero balance of Nervos DAO", "deposit_to_dao": "Deposit to Nervos DAO", "deposit_to_dao_description": "Deposit to receive an equivalent amount of CKB at the same rate as the secondary issuance, keep your assets away from being diluted by the secondary issuance.", - "reward_calculator": "Reward Calculator", + "reward_calculator": "Compensation Calculator", "nervos_dao_rfc": "Nervos DAO RFC", "learn_more": "Learn More", - "dao_reward_calculator": "Nervos DAO Reward Calculator", - "deposit_terms": "Nervos DAO requires 102 CKBytes for storing lock records, and this portion of CKBytes does not generate lock rewards. Please refer to the <0>Nervos DAO RFC for more information on Nervos DAO.", + "dao_reward_calculator": "Nervos DAO Compensation Calculator", + "deposit_terms": "Nervos DAO requires 102 CKBytes for storing cell itself, and this portion of CKBytes won't be compensated. Please refer to the <0>Nervos DAO RFC for more information on Nervos DAO.", "you_deposit": "You Deposit", "you_can_withdraw": "You can withdraw", "estimated_rewards": "Make a withdraw request after almost {{days}} days:", @@ -584,10 +584,14 @@ "estimated_APC": "Estimated APC", "exclude_inactive_ckb": "Exclude inactive CKB", "exclude_inactive_ckb_tip": "", - "estimated_rewards_30": "Estimated Rewards in 30 Days", - "rewards": "Rewards", + "rewards": "Compensation", + "estimated_rewards_in_years": "Estimated compensation in", + "withdrawal": "Withdrawal", + "year": "Year", + "years": "Years", "day": "Days", - "done": "Done" + "done": "Done", + "view_apc_trending": "View APC Trending" }, "error": { "maintain": "The tip block number {{tip}}, the current synced block lagging behind by {{lag}} blocks", diff --git a/src/locales/zh.json b/src/locales/zh.json index 98e7ea3a85..84e619e702 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -571,24 +571,28 @@ "24hrs_update": "24 小时变动(UTC+8:00)", "today_update": "今日变动(UTC+8:00)", "deposit_address_tooltip": "Nervos DAO 锁定余额不为零的地址", - "deposit_to_dao": "锁定到Nervos DAO", + "deposit_to_dao": "锁定到 Nervos DAO", "deposit_to_dao_description": "锁定以获得与二次发行利率相同的等额 CKB,避免您的资产被二次发行稀释。", - "reward_calculator": "奖励计算器", + "reward_calculator": "补贴计算器", "nervos_dao_rfc": "Nervos DAO RFC", "learn_more": "了解更多", - "dao_reward_calculator": "Nervos DAO 奖励计算器", + "dao_reward_calculator": "Nervos DAO 补贴计算器", "deposit_terms": "Nervos DAO 需要 102 CKBytes 作为锁定记录的存储,这部分 CKBytes 是无法产生锁定补贴的。
请查看 <0>Nervos DAO RFC 以了解 Nervos DAO 更多信息。", "you_deposit": "锁定", "you_can_withdraw": "可领取", - "estimated_rewards": "{{days}}天后提出提款申请:", - "deposit_notice": "30天为一个周期,如果您没有提出提款要求,利息将按复利计算", + "estimated_rewards": "{{days}} 天后提出提取申请:", + "deposit_notice": "30天为一个周期,如果您没有提出提取要求,利息将按复利计算", "estimated_APC": "预计年化锁定补贴率", "exclude_inactive_ckb": "不包含非活动的CKB", "exclude_inactive_ckb_tip": "", - "estimated_rewards_30": "30天预计奖励", - "rewards": "奖励", + "rewards": "补贴", + "estimated_rewards_in_years": "预计补贴", + "withdrawal": "提取", + "year": "年", + "years": "年", "day": "天", - "done": "完成" + "done": "完成", + "view_apc_trending": "查看 APC 走势" }, "error": { "maintain": "最新区块为 {{tip}}, 当前同步高度落后 {{lag}} 区块", diff --git a/src/pages/NervosDao/DaoBanner/DaoBanner.module.scss b/src/pages/NervosDao/DaoBanner/DaoBanner.module.scss index 27c85a9ac9..7882a94c36 100644 --- a/src/pages/NervosDao/DaoBanner/DaoBanner.module.scss +++ b/src/pages/NervosDao/DaoBanner/DaoBanner.module.scss @@ -50,6 +50,7 @@ cursor: pointer; font-size: 14px; line-height: 14px; + transition: none; .icon { path { diff --git a/src/pages/NervosDao/DaoBanner/index.tsx b/src/pages/NervosDao/DaoBanner/index.tsx index eabf319aa7..255dd8acfd 100644 --- a/src/pages/NervosDao/DaoBanner/index.tsx +++ b/src/pages/NervosDao/DaoBanner/index.tsx @@ -17,20 +17,20 @@ const DaoBanner = ({ estimatedApc }: { estimatedApc: string }) => {
- - +
diff --git a/src/pages/NervosDao/RewardCalcutorModal/RewardCalcutorModal.module.scss b/src/pages/NervosDao/RewardCalcutorModal/RewardCalcutorModal.module.scss index 4219580d51..83459beb07 100644 --- a/src/pages/NervosDao/RewardCalcutorModal/RewardCalcutorModal.module.scss +++ b/src/pages/NervosDao/RewardCalcutorModal/RewardCalcutorModal.module.scss @@ -94,6 +94,10 @@ .apcTitle { flex: 1; margin: 0; + + a { + margin-left: 4px; + } } div { @@ -145,6 +149,16 @@ } } +.years { + input { + outline: none; + border: 1px solid #e5e5e5; + width: 6ch; + padding: 0 4px; + margin: 0 4px; + } +} + /* stylelint-disable-next-line selector-class-pattern */ :global(.ant-input[disabled]) { color: #333 !important; diff --git a/src/pages/NervosDao/RewardCalcutorModal/index.tsx b/src/pages/NervosDao/RewardCalcutorModal/index.tsx index 764bf87305..4d057e7ad3 100644 --- a/src/pages/NervosDao/RewardCalcutorModal/index.tsx +++ b/src/pages/NervosDao/RewardCalcutorModal/index.tsx @@ -1,40 +1,59 @@ import { useState, useMemo } from 'react' +import { Link } from 'react-router-dom' import { Input } from 'antd' import { Trans, useTranslation } from 'react-i18next' +import BigNumber from 'bignumber.js' import CommonModal from '../../../components/CommonModal' import styles from './RewardCalcutorModal.module.scss' import { ReactChartCore } from '../../StatisticsChart/common' import CloseIcon from '../../../assets/modal_close.png' -import { MIN_DEPOSIT_AMOUNT, MAX_DECIMAL_DIGITS, NERVOS_DAO_RFC_URL } from '../../../constants/common' -import { ckbToShannon, shannonToCkb } from '../../../utils/util' +import { MIN_DEPOSIT_AMOUNT, NERVOS_DAO_RFC_URL, IS_MAINNET, MAX_DECIMAL_DIGITS } from '../../../constants/common' import { localeNumberString } from '../../../utils/number' -import { isMainnet } from '../../../utils/chain' + +const INIT_DEPOSIT_VALUE = '1000' const RewardCalcutorModal = ({ onClose, estimatedApc }: { onClose: () => void; estimatedApc: string }) => { const { t } = useTranslation() - const [depositValue, setDepositValue] = useState('1000') - const [inputVal, setInputVal] = useState(localeNumberString(depositValue)) - - const [annualRewards, monthRewards] = useMemo(() => { - const amount = Number(depositValue) - MIN_DEPOSIT_AMOUNT - const value = ckbToShannon((amount > 0 ? amount : 0).toFixed(MAX_DECIMAL_DIGITS).toString()) + const [depositValue, setDepositValue] = useState(INIT_DEPOSIT_VALUE) + const [years, setYears] = useState(5) - const dpc = Number(estimatedApc || 0) / 365 / 100 + const yearReward = useMemo(() => { + const EMPTY = BigNumber(0) + if (!estimatedApc) return EMPTY + if (!depositValue) return EMPTY + const v = BigNumber(depositValue) - const mRewards = (Number(value) * dpc * 30).toFixed(0).toString() + if (v.isNaN() || v.isNegative()) return EMPTY - const rewerds = (Number(value) * dpc * 360).toFixed(0).toString() + const amount = v.minus(MIN_DEPOSIT_AMOUNT) + if (amount.isNegative()) return EMPTY - return [shannonToCkb(rewerds), shannonToCkb(mRewards)] + const yearReward = amount.multipliedBy(estimatedApc).dividedBy(100) + return yearReward }, [depositValue, estimatedApc]) - const handleInputChange = (e: React.ChangeEvent) => { - let { value } = e.target + const monthReward = yearReward.dividedBy(12) - value = value.replace('。', '.').replace(/^\D*([0-9]\d*\.?\d{0,8})?.*$/, '$1') + const handleDepositChange = (e: React.ChangeEvent) => { + e.stopPropagation() + e.preventDefault() + const { value } = e.currentTarget + const v = value.replace(/,/g, '') + if (!v) { + setDepositValue('') + return + } + setDepositValue(v) + } - setInputVal(value) - setDepositValue(value) + const handleYearChange = (e: React.ChangeEvent) => { + e.stopPropagation() + e.preventDefault() + const y = +e.currentTarget.value + if (y < 1) { + return + } + setYears(y) } return ( @@ -62,56 +81,94 @@ const RewardCalcutorModal = ({ onClose, estimatedApc }: { onClose: () => void; e

{t('nervos_dao.you_deposit')}

setInputVal(depositValue)} - onBlur={() => setInputVal(localeNumberString(depositValue))} - maxLength={15} + value={ + /\.$/.test(depositValue) + ? `${localeNumberString(depositValue.slice(0, -1))}.` + : localeNumberString(depositValue) + } className={styles.input} suffix="CKB" - onChange={handleInputChange} + onChange={handleDepositChange} />

{t('nervos_dao.you_can_withdraw')}

{t(`nervos_dao.estimated_rewards`, { days: 30 })}

- +

{t(`nervos_dao.estimated_rewards`, { days: 360 })}

- +
{t('nervos_dao.deposit_notice')}
-

{t('nervos_dao.estimated_APC')}

+

+ {t('nervos_dao.estimated_APC')} + + {`(${t('nervos_dao.view_apc_trending')})`} + +

-

{t('nervos_dao.estimated_rewards_30')}

+

+ {t('nervos_dao.estimated_rewards_in_years')} + + {t('nervos_dao.years')} +

-

{t('nervos_dao.rewards')}

+

{t('nervos_dao.withdrawal')}

i + 1), + axisLabel: { + formatter: (value: string) => + +value > 1 ? `${value} ${t('nervos_dao.years')}` : `${value} ${t('nervos_dao.year')}`, + }, }, yAxis: { type: 'value', + axisLabel: { + formatter: (value: string) => `${value} CKB`, + }, + boundaryGap: ['5%', '2%'], }, series: [ { - data: [0, Number(monthRewards)], + data: Array.from({ length: years }, (_, i) => yearReward.multipliedBy(i + 1).toNumber()), type: 'line', + stack: 'withdrawal', + areaStyle: {}, + label: { + normal: { + show: years <= 5, + position: 'top', + formatter: '{c} CKB', + }, + }, }, ], }} notMerge lazyUpdate - style={{ - height: '100%', - width: '100%', - }} + style={{ height: '100%', width: '100%' }} /> -

{t('nervos_dao.day')}

+

{t('nervos_dao.years')}

diff --git a/src/styles/index.css b/src/styles/index.css index 7c0047a84b..2685ca6800 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -92,6 +92,16 @@ a { white-space: pre-wrap; } +.ant-input:focus { + border-color: none; +} + +.ant-input-affix-wrapper:hover, +.ant-input-affix-wrapper:focus { + border-color: #e5e5e5 !important; + box-shadow: none; +} + a:hover, .ant-btn-primary:hover, .ant-tabs-tab:hover {