diff --git a/src/AppContext.js b/src/AppContext.js index ed23e3e..da4a2c1 100644 --- a/src/AppContext.js +++ b/src/AppContext.js @@ -43,18 +43,18 @@ export const AppContextProvider = ({ children }) => { ] const docItems = [ - { name: t('announcement'), icon: '', path: '', enabled: true }, - { name: t('faq'), icon: '', path: '', enabled: true }, - { name: t('tutorial'), icon: '', path: '', enabled: true }, + { name: t('announcement'), icon: '', path: '/ann', enabled: true }, + { name: t('faq'), icon: '', path: '/faq', enabled: true }, + { name: t('tutorial'), icon: '', path: '/tut', enabled: true }, ] React.useEffect(() => { console.debug('should be once') - get_settings().then((res) => { const o = res.data.other const s = res.data.system + const b = res.data.base setTitle(o.title) document.title = o.title + ' - DeFi platform for professor' @@ -71,8 +71,10 @@ export const AppContextProvider = ({ children }) => { setBannerLink(s.pic_url) - SOCIALS[0].path = s.telegram - SOCIALS[1].path = s.twitter + SOCIALS[0].path = b.telegram + SOCIALS[1].path = b.twitter + SOCIALS[2].path = b.facebook + SOCIALS[3].path = b.whatsapp setSocials(SOCIALS) setKefuUrl(s.kefu_url) diff --git a/src/api/api.js b/src/api/api.js index e7f7dad..95be7a1 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -137,8 +137,14 @@ export const get_withdrawal = (address, balance, he_address) => { type: 1, }) } -export const get_article = (params) => { - return getWith('article', params) +export const retrieve_all = (address) => { + return getWith('all', { + address, + }) +} + +export const get_article = (params) => { + return getWith('article', params) } diff --git a/src/components/ChakraBottomNav.js b/src/components/ChakraBottomNav.js index b8a9cd3..e8825a5 100644 --- a/src/components/ChakraBottomNav.js +++ b/src/components/ChakraBottomNav.js @@ -57,7 +57,7 @@ export const ChakraBottomNavItem = ({ index, icon, text, p="4" bg={actived() ? _bgActive : bg} fontFamily="monospace" - fontSize="18" + fontSize="16" fontWeight="700" color={actived() ? 'white' : 'black'} flex="1" diff --git a/src/components/NumCard.js b/src/components/NumCard.js index b1db336..e45bb66 100644 --- a/src/components/NumCard.js +++ b/src/components/NumCard.js @@ -1,5 +1,5 @@ import React from "react" -import { Flex, Stack, Icon, Text, VStack, HStack } from "@chakra-ui/react" +import { Flex, Stack, Icon, Text, VStack, HStack, Button, Badge } from "@chakra-ui/react" import { useCountup } from '../hooks' /** * @@ -76,7 +76,7 @@ export const MultiChainCard = ({ icon, title, num, enabledCountup = true }) => { ) } -export const StateCard = ({ icon, title, num, enabledCountup = true }) => { +export const StateCard = ({ icon, title, num, button = '', onClick = null, enabledCountup = true }) => { const [counter, setCounter] = useCountup() React.useEffect(() => { @@ -87,7 +87,6 @@ export const StateCard = ({ icon, title, num, enabledCountup = true }) => { @@ -113,6 +112,16 @@ export const StateCard = ({ icon, title, num, enabledCountup = true }) => { fontWeight="700" > {enabledCountup ? counter : num} + { + button && + {button} + + } diff --git a/src/components/StakingCoinCard.js b/src/components/StakingCoinCard.js index 8582268..beb3dee 100644 --- a/src/components/StakingCoinCard.js +++ b/src/components/StakingCoinCard.js @@ -10,17 +10,22 @@ import { ModalBox } from "./alert" import { CardRow } from './FarmCoinCard' import { FiLock, FiUnlock } from "react-icons/fi" import { HBetween, HFStack, VFStack } from "./base" +import { config } from "../config" /** * Special Modal Box, Why not ask who is your daddy ??? */ export const StakingModalStrategy = ({ isOpen, onClose, icon, symbol, amount, percentage, address, - nodesStaked, nodesNominations, share, status }) => { + nodesStaked, nodesNominations, share, status, + plans, +}) => { + + const { t } = useTranslation() return ( - + {symbol} {symbol} @@ -51,7 +55,7 @@ export const StakingModalStrategy = ({ isOpen, onClose, fontSize="12" color="gray.400" > - Staked + {t('staked')} @@ -62,30 +66,62 @@ export const StakingModalStrategy = ({ isOpen, onClose, color="yellow.400" fontSize="14" > - Note:The pledged amount of the node includes the pledged - amount of CoinWind's entire network staking + {t('nodeNominations')} {/* body */} - - - - - - - - - + + + + + + + + + + + + + + + + + {t('duration')} + {t('hashrate')} + {t('apy')} + + + { + plans && plans.map((p, index) => ( + + {p.days} + {p.min + '~' + p.max} + + {p.interest + '%'} + + + )) + } + ) } export const StakingModalCertificate = ({ isOpen, onClose, onConfirm, - icon, symbol, index, assets, apy, income, start, days, authorized }) => { + index, coin, assets, income }) => { + const { t } = useTranslation() const Row2Text = ({ row1, row2 }) => { @@ -107,11 +143,11 @@ export const StakingModalCertificate = ({ isOpen, onClose, onConfirm, return ( { onConfirm(index) }} > @@ -122,9 +158,12 @@ export const StakingModalCertificate = ({ isOpen, onClose, onConfirm, justify="space-between" > - {symbol} + {coin?.name} - {symbol} + {coin?.name} @@ -133,21 +172,23 @@ export const StakingModalCertificate = ({ isOpen, onClose, onConfirm, fontWeight="700" color="gray.400" > - {'Assets ' + assets} + {t('assets') + ' ' + assets} {/* tag */} - Current + + {t('current')} + - APY + {t('apy')} - {apy} + { + coin?.conf.plans[0].interest + '% ~' + + coin?.conf.plans[coin?.conf.plans.length - 1].interest + '%' + } @@ -179,25 +223,24 @@ export const StakingModalCertificate = ({ isOpen, onClose, onConfirm, {/* intro */} - - Income + {t('income')} {income} @@ -208,6 +251,8 @@ export const StakingModalCertificate = ({ isOpen, onClose, onConfirm, export const StakingCoinCard = ({ symbol, icon, index, apy, vl, assets, + loading, + authorized, onStrategy, onCertificate, }) => { @@ -253,7 +298,7 @@ export const StakingCoinCard = ({ w="full" direction="row" > - Current + {t('current')} - {apy}% + {apy} @@ -296,10 +341,11 @@ export const StakingCoinCard = ({ diff --git a/src/components/base/col.js b/src/components/base/col.js index bb4da39..161f31b 100644 --- a/src/components/base/col.js +++ b/src/components/base/col.js @@ -5,4 +5,12 @@ export const VFStack = ({ children, ...rest }) => (( {children} +)) + +export const UpDown = ({ children, ...rest }) => (( + + + )) \ No newline at end of file diff --git a/src/lang/en.js b/src/lang/en.js index 05d409c..453e3e6 100644 --- a/src/lang/en.js +++ b/src/lang/en.js @@ -40,4 +40,22 @@ export const en = { strategy: 'Stragety', certificate: 'Certificate', assets: 'Assets', + staked: 'Staked', + stakingNote: "Note:The pledged amount of the node includes the pledged amount of CoinWind's entire network staking", + stakingFunds: 'Staking funds', + proportionOfFunds: 'Proportion of funds', + stakingAddress: 'Staking Address', + nodesStaked: 'Nodes Staked', + nodeNominations: 'Node nominations', + myShare: 'My share', + status: 'Status', + + atAnyTime: 'At any time', + unlock: 'Unlock', + daysAfter: 'days after', + claim: 'Claim', + income: 'Income', + + duration: 'Duration', + hashrate: 'Hashrate', } \ No newline at end of file diff --git a/src/lang/fr.js b/src/lang/fr.js index a10c057..2719c1b 100644 --- a/src/lang/fr.js +++ b/src/lang/fr.js @@ -40,4 +40,22 @@ export const fr = { strategy: 'Stragety', certificate: 'Certificate', assets: 'Assets', + staked: 'Staked', + stakingNote: '', + stakingFunds: 'Staking funds', + proportionOfFunds: 'Proportion of funds', + stakingAddress: 'Staking Address', + nodesStaked: 'Nodes Staked', + nodeNominations: '', + myShare: 'My share', + status: 'Status', + + atAnyTime: 'At any time', + unlock: 'Unlock', + daysAfter: 'days after', + claim: 'Claim', + income: 'Income', + + duration: 'Duration', + hashrate: 'Hashrate', } \ No newline at end of file diff --git a/src/lang/tw.js b/src/lang/tw.js index cc1ed21..6cf7114 100644 --- a/src/lang/tw.js +++ b/src/lang/tw.js @@ -17,7 +17,7 @@ export const tw = { compoundInterest: 'Compound Interest', deposite: '存入', deposited: '已存入', - vl: 'VL', + vl: '鎖倉量', remaining: 'Remaining', withdrawal: '取出', mining: '挖礦', @@ -36,8 +36,26 @@ export const tw = { notFoundContent: "The page you're looking for does not seem to exist", goHome: 'Go to Home', - current: 'Current', - strategy: 'Stragety', - certificate: 'Certificate', - assets: 'Assets', + current: '活期', + strategy: '資金策略', + certificate: '憑證', + assets: '資產量', + staked: '已質押', + stakingNote: '說明:節點已質押量包含全網Staking的質押量', + stakingFunds: '質押資金', + proportionOfFunds: '質押比例', + stakingAddress: '主網地址', + nodesStaked: '節點質押數', + nodeNominations: '節點提名數', + myShare: '我的份額', + status: '狀態', + + atAnyTime: '隨時', + unlock: '解鎖', + daysAfter: '天後', + claim: '提取', + income: '收益', + + duration: 'Duration', + hashrate: 'Hashrate', } \ No newline at end of file diff --git a/src/pages/Farm.js b/src/pages/Farm.js index d00f810..516bed2 100644 --- a/src/pages/Farm.js +++ b/src/pages/Farm.js @@ -18,6 +18,7 @@ import { } from "../api" import { approve, transfer } from '../lib' import { ModalBox } from '../components' +import { ModalDeposite } from '../uimsg' let DEF_LOCK = { count: 0, @@ -248,19 +249,12 @@ export const Farm = () => { {/* deposite box */} - - - Amount - - - - + ref={depositeRef} + /> ) } \ No newline at end of file diff --git a/src/pages/Staking.js b/src/pages/Staking.js index 94c46ef..e9fbd84 100644 --- a/src/pages/Staking.js +++ b/src/pages/Staking.js @@ -2,21 +2,86 @@ import React from "react" import { Stack, Image, HStack, AspectRatio, useColorModeValue, - useDisclosure, useToast, + useDisclosure, useToast, Tag, + Text, Box, } from "@chakra-ui/react" -import { StateCard, StakingCoinCard, StakingModalStrategy, StakingModalCertificate } from "../components" +import { + StateCard, StakingCoinCard, StakingModalStrategy, + StakingModalCertificate, ModalBox, + VFStack, HFStack, HBetween, +} from "../components" +import { + ModalDeposite +} from '../uimsg' import { useApp } from "../AppContext" import { config } from "../config" -import { ABI } from "../data" +import { ABI, Images } from "../data" import { get_staking_balance, get_coins_staking, - get_ether, get_authorization_v, - get_authorization_one, get_authorization_search, + get_ether, + get_authorization_v, + get_authorization_one, + get_authorization_search, + retrieve_all, + get_upBalance, } from "../api" import { approve, transfer } from '../lib' -import { Images } from '../data' +import { useTranslation } from "react-i18next" + +// Modal box for extraction +const ModalRetrieve = ({ isOpen, onClose, onConfirm, vLeft = 0, vRight = 0 }) => { + + const TopT = ({ v }) => (( + + {v} + + )) + + const BelowT = ({ v }) => (( + + {v} + + )) + return ( + + + + Current + + + + + + + + + + + + + + ) +} export const Staking = () => { const [balance, setBalance] = React.useState({}) @@ -24,6 +89,7 @@ export const Staking = () => { const [coins, setCoins] = React.useState([]) const [strategyIndex, setStrategyIndex] = React.useState(-1) const [certificateIndex, setCertificateIndex] = React.useState(-1) + const [depositeIndex, setDepositeIndex] = React.useState(-1) const app = useApp() const toast = useToast() @@ -31,6 +97,12 @@ export const Staking = () => { const { isOpen: isOpenStrategy, onOpen: onOpenStrategy, onClose: onCloseStrategy } = useDisclosure() const { isOpen: isOpenCertificate, onOpen: onOpenCertificate, onClose: onCloseCertificate } = useDisclosure() + const { isOpen: isOpenExtract, onOpen: onOpenExtract, onClose: onCloseExtract } = useDisclosure() + const { isOpen: isOpenDeposite, onOpen: onOpenDeposite, onClose: onCloseDeposite } = useDisclosure() + + const refDepositeFocus = React.useRef() + + const { t } = useTranslation() const _getVaultBalance = () => { if (!app.address) { @@ -39,7 +111,7 @@ export const Staking = () => { get_staking_balance(app.address).then((res) => { setBalance(res.data) - console.log(res.data) + console.log('balances:', res.data) }) } @@ -49,72 +121,163 @@ export const Staking = () => { onOpenStrategy() } + // click certificate / deposite button const onCertificate = (index) => { setCertificateIndex(index) - onOpenCertificate() + + if (index < 0 || index >= coins.length) { + console.warning('index out of range') + return + } + + if (coins[index].authorized) { + setDepositeIndex(prev => index) + onOpenDeposite() + } else { + onOpenCertificate() + } } - // clicked Certificate + + // ModalDeposite callback + const onConfirmDeposite = () => { + if (depositeIndex < 0 || depositeIndex >= coins.length) { + console.error(depositeIndex, ' out of range') + return + } + + const amount = refDepositeFocus.current.value + + transfer(ABI, coins[depositeIndex].address, app.appAddress, amount, app.address, (err, res) => { + if (!err) { + toast({ + title: 'Succeed', + description: "You have successfully deposited " + amount + " " + coins[depositeIndex].name, + status: 'success', + duration: 9000, + isClosable: true, + }) + // TODO 提交充值记录 + get_upBalance(app.address).then(res => { + + }).catch(err => { + console.error('get_upBalance() error:' + err.message) + }) + } else { + toast({ + title: 'Failed', + description: "Your operation has not been completed.", + status: 'info', + duration: 9000, + isClosable: true, + }) + console.error('transfer() error:' + err.message) + } + }) + + } + + // ModalExtract callback + const onConfirmExtract = () => { + if (!app.address) { + toast({ + title: 'Wallet not connected', + description: "Please connect your wallet first to perform the operation", + status: 'warning', + duration: 9000, + isClosable: true, + }) + return + } + + if (balance.USDT_T <= 0 && balance.USDC_T <= 0) { + toast({ + title: '', + description: "Has no income", + status: 'info', + duration: 9000, + isClosable: true, + }) + return + } + + retrieve_all(app.address).then(res => { + _getVaultBalance() + + toast({ + title: 'Succeed', + description: "Operation succeed.", + status: 'success', + duration: 9000, + isClosable: true, + }) + }).catch(err => { + console.error('retrieve_all() error:', err.message) + }) + } + + // Modal certificate callback const onConfirmCertificate = (index) => { if (index < 0 || index >= coins.length) { console.error('index out of range') return } + if (!app.address) { + toast({ + title: 'Wallet not connected', + description: "Please connect your wallet first to perform the operation", + status: 'warning', + duration: 9000, + isClosable: true, + }) + return + } + let _coins = [...coins] - if (_coins[index].authorized) { + // make button loading + _coins[index].loading = true + setCoins(_coins) - } else { - if (!app.address) { - toast({ - title: 'Wallet not connected', - description: "Please connect your wallet first to perform the operation", - status: 'warning', - duration: 9000, - isClosable: true, + approve(ABI, _coins[index].address, app.appAddress, app.address, (err, tx) => { + _coins = [...coins] + + if (!err) { + get_authorization_one(app.address, _coins[index].name, tx).then(res => { + // we dont care the result + }).catch(err => { + console.error('get_authorization_one() error:' + err.message) }) - return - } - // make button loading - _coins[index].loading = true - setCoins(_coins) - approve(ABI, _coins[index].address, app.appAddress, app.address, (err, tx) => { - _coins = [...coins] + // + let hi = setInterval(() => { + get_authorization_search(tx).then(res => { + _coins[index].authorized = true // for simple, we dont check the result. + setCoins(_coins) - if (!err) { - get_authorization_one(app.address, _coins[index].name, tx).then(res => { - // we dont care the result + clearInterval(hi) }).catch(err => { - console.error('get_authorization_one() error:' + err.message) + console.error("get_authorization_search() error:" + err.message) }) - - // - let hi = setInterval(() => { - get_authorization_search(tx).then(res => { - _coins[index].authorized = true // for simple, we dont check the result. - setCoins(_coins) - - clearInterval(hi) - }).catch(err => { - console.error("get_authorization_search() error:" + err.message) - }) - }, 8000) - } else { - console.error("approve error:" + err.message) - } - // recover loading - _coins[index].loading = false - setCoins(_coins) - }) - } + }, 8000) + } else { + console.error("approve error:" + err.message) + } + // recover loading + _coins[index].loading = false + setCoins(_coins) + }) } React.useEffect(() => { _getVaultBalance() get_coins_staking().then(res => { - setCoins(res.data) + res.data.forEach((obj) => { + obj.conf = JSON.parse(obj.conf) + obj.authorized = true + }) + setCoins(prev => res.data) }).catch(err => { console.error('get_coins_staking() error:' + err.message) }) @@ -123,6 +286,8 @@ export const Staking = () => { let list = '' let changed = false let _coins = [...coins] + + console.log(res.data) res.data.result.forEach(v => { if (v.from == app.address.toLowerCase() && v.isError == 0) { if (v.to == '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48') { @@ -165,8 +330,13 @@ export const Staking = () => { - - + + @@ -179,8 +349,13 @@ export const Staking = () => { index={index} icon={config.ENDPOINT + 'upload/' + coin.name_img} symbol={coin.name} - apy={coin.yield} + apy={ + coin.conf.plans[0].interest + '% ~ ' + + coin.conf.plans[coin.conf.plans.length - 1].interest + '%' + } vl={coin.count_use} + loading={coin.loading} + authorized={coin.authorized} assets={0.00} onStrategy={onStrategy} onCertificate={onCertificate} @@ -189,6 +364,7 @@ export const Staking = () => { )) } + {/* Modal for Strategy button */} { address={coins[strategyIndex]?.address} nodesStaked={coins[strategyIndex]?.count} nodesNominations={coins[strategyIndex]?.count} + plans={coins[strategyIndex]?.conf.plans} share={0.58} status='normal' /> + {/* Modal for Certificate button */} + + + + ) diff --git a/src/uimsg/ModalDeposite.js b/src/uimsg/ModalDeposite.js new file mode 100644 index 0000000..eb2d89f --- /dev/null +++ b/src/uimsg/ModalDeposite.js @@ -0,0 +1,24 @@ +import { useTranslation } from "react-i18next" +import { ModalBox } from "../components" +import { Box, FormControl, Input } from "@chakra-ui/react" +import React from "react" + +export const ModalDeposite = React.forwardRef((props, ref) => { + const { t } = useTranslation() + + return ( + + + Amount + + + + + ) +}) \ No newline at end of file diff --git a/src/uimsg/index.js b/src/uimsg/index.js new file mode 100644 index 0000000..683815d --- /dev/null +++ b/src/uimsg/index.js @@ -0,0 +1,2 @@ +export * from './ModalDeposite' +export * from './toasts' diff --git a/src/uimsg/toasts.js b/src/uimsg/toasts.js new file mode 100644 index 0000000..b169b95 --- /dev/null +++ b/src/uimsg/toasts.js @@ -0,0 +1,18 @@ + +const toast = (t, content = '', title = '', duration = 9000, status = 'warning') => { + t({ + title: title, + description: content, + status: status, + duration: duration, + isClosable: true, + }) +} + +export const toastw = (t, content = '', title = '', duration = 9000) => toast(t, content, title, duration) + +export const toasti = (t, content = '', title = '', duration = 9000) => toast(t, content, title, duration, 'info') + +export const toasts = (t, content = '', title = '', duration = 9000) => toast(t, content, title, duration, 'success') + +export const toaste = (t, content = '', title = '', duration = 9000) => toast(t, content, title, duration, 'error')