feat: 董事会

This commit is contained in:
gary 2022-04-22 16:59:33 +08:00
parent 977b6fd61b
commit 14009878b3
17 changed files with 191 additions and 118 deletions

View File

@ -48,6 +48,7 @@ const Pool = lazy(() => import('./views/Pool'))
const PoolFinder = lazy(() => import('./views/PoolFinder')) const PoolFinder = lazy(() => import('./views/PoolFinder'))
const RemoveLiquidity = lazy(() => import('./views/RemoveLiquidity')) const RemoveLiquidity = lazy(() => import('./views/RemoveLiquidity'))
const Referral = lazy(() => import('./views/Referral')) const Referral = lazy(() => import('./views/Referral'))
const Board = lazy(() => import('./views/Board'))
// This config is required for number formatting // This config is required for number formatting
BigNumber.config({ BigNumber.config({
@ -89,6 +90,9 @@ const App: React.FC = () => {
<Route path="/referral"> <Route path="/referral">
<Referral /> <Referral />
</Route> </Route>
<Route path="/board">
<Board />
</Route>
{/* <Route path="/lottery"> {/* <Route path="/lottery">
<Lottery /> <Lottery />
</Route> </Route>

View File

@ -1,4 +1,4 @@
export const CACHE_TOKEN = 'token' export const CACHE_TOKEN = 'token'
export const CACHE_USERIFNO = 'userInfo' export const CACHE_USERINFO = 'userInfo'
export const CACHE_ACCOUNT = 'account' export const CACHE_ACCOUNT = 'account'
export const CACHE_INVITE_CODE = 'inviteCode' export const CACHE_INVITE_CODE = 'inviteCode'

View File

@ -33,3 +33,4 @@ export const LOTTERY_TICKET_PRICE = 1
export const DEFAULT_TOKEN_DECIMAL = BIG_TEN.pow(18) export const DEFAULT_TOKEN_DECIMAL = BIG_TEN.pow(18)
export const DEFAULT_GAS_LIMIT = 200000 export const DEFAULT_GAS_LIMIT = 200000
export const DEFAULT_GAS_PRICE = 5 export const DEFAULT_GAS_PRICE = 5
export const TOKEN_SYMBOL = 'HCC'

View File

@ -206,18 +206,18 @@ export const useBoards = (): Boards[] => {
} }
export const useBoardsFromPid = (pid): Boards => { export const useBoardsFromPid = (pid): Boards => {
const node = useSelector((state: State) => state.boards.data.find((p) => p.pid === pid)) const board = useSelector((state: State) => state.boards.data.find((p) => p.pid === pid))
return node return board
} }
export const useNodeUser = (pid) => { export const useBoardUser = (pid) => {
const node = useBoardsFromPid(pid) const board = useBoardsFromPid(pid)
return { return {
allowance: node.userData ? new BigNumber(node.userData.allowance) : new BigNumber(0), allowance: board.userData ? new BigNumber(board.userData.allowance) : new BigNumber(0),
tokenBalance: node.userData ? new BigNumber(node.userData.tokenBalance) : new BigNumber(0), tokenBalance: board.userData ? new BigNumber(board.userData.tokenBalance) : new BigNumber(0),
stakedBalance: node.userData ? new BigNumber(node.userData.stakedBalance) : new BigNumber(0), stakedBalance: board.userData ? new BigNumber(board.userData.stakedBalance) : new BigNumber(0),
unlockTime: node.userData ? node.userData.unlockTime : 0, unlockTime: board.userData ? board.userData.unlockTime : 0,
xCandyBalance: node.userData ? node.userData.xCandyBalance : 0, xCandyBalance: board.userData ? board.userData.xCandyBalance : 0,
} }
} }
// cake // cake

View File

@ -1,6 +1,6 @@
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { queryUserInfo } from 'services/user' import { queryUserInfo } from 'services/user'
import { CACHE_TOKEN, CACHE_ACCOUNT, CACHE_USERIFNO } from 'config/constants/cacheKey' import { CACHE_TOKEN, CACHE_ACCOUNT, CACHE_USERINFO } from 'config/constants/cacheKey'
import multicall from 'utils/multicall' import multicall from 'utils/multicall'
// import inviteAbi from 'config/abi/invite.json' // import inviteAbi from 'config/abi/invite.json'
// import { getInviteAddress } from 'utils/addressHelpers' // import { getInviteAddress } from 'utils/addressHelpers'
@ -39,7 +39,7 @@ export const userInfoSlice = createSlice({
state.account = info.address state.account = info.address
info.token && (state.token = info.token) info.token && (state.token = info.token)
localStorage.setItem(CACHE_TOKEN, state.token) localStorage.setItem(CACHE_TOKEN, state.token)
localStorage.setItem(CACHE_USERIFNO, JSON.stringify(info)) localStorage.setItem(CACHE_USERINFO, JSON.stringify(info))
localStorage.setItem(CACHE_ACCOUNT, info.address) localStorage.setItem(CACHE_ACCOUNT, info.address)
}, },
clearUserInfo: (state) => { clearUserInfo: (state) => {
@ -47,14 +47,14 @@ export const userInfoSlice = createSlice({
state.account = '' state.account = ''
state.token = '' state.token = ''
localStorage.removeItem(CACHE_TOKEN) localStorage.removeItem(CACHE_TOKEN)
localStorage.removeItem(CACHE_USERIFNO) localStorage.removeItem(CACHE_USERINFO)
localStorage.removeItem(CACHE_ACCOUNT) localStorage.removeItem(CACHE_ACCOUNT)
}, },
}, },
extraReducers: (builder) => { extraReducers: (builder) => {
builder.addCase(fetchUserInfo.fulfilled, (state, action) => { builder.addCase(fetchUserInfo.fulfilled, (state, action) => {
state.userInfo = action.payload state.userInfo = action.payload
localStorage.setItem(CACHE_USERIFNO, JSON.stringify(state.userInfo)) localStorage.setItem(CACHE_USERINFO, JSON.stringify(state.userInfo))
}) })
// .addCase(fetchUserInviteInfo.fulfilled, (state, action) => { // .addCase(fetchUserInviteInfo.fulfilled, (state, action) => {
// state.userInfo = { ...state.userInfo, invite_reward: action.payload } // state.userInfo = { ...state.userInfo, invite_reward: action.payload }

View File

@ -4,7 +4,7 @@ import styled, { keyframes } from 'styled-components'
import { Flex, Text, Skeleton } from '@pancakeswap/uikit' import { Flex, Text, Skeleton } from '@pancakeswap/uikit'
import { provider as ProviderType } from 'web3-core' import { provider as ProviderType } from 'web3-core'
import { getBoardAddress } from 'utils/addressHelpers' import { getBoardAddress } from 'utils/addressHelpers'
import useI18n from 'hooks/useI18n' import { useTranslation } from 'contexts/Localization'
import ExpandableSectionButton from 'components/ExpandableSectionButton' import ExpandableSectionButton from 'components/ExpandableSectionButton'
import DetailsSection from './DetailsSection' import DetailsSection from './DetailsSection'
import CardHeading from './CardHeading' import CardHeading from './CardHeading'
@ -63,7 +63,7 @@ const FCard = styled.div`
` `
const Divider = styled.div` const Divider = styled.div`
background-color: ${({ theme }) => theme.colors.borderColor}; background-color: ${({ theme }) => theme.colors.cardBorder};
height: 1px; height: 1px;
margin: 28px auto; margin: 28px auto;
width: 100%; width: 100%;
@ -75,22 +75,22 @@ const ExpandingWrapper = styled.div<{ expanded: boolean }>`
` `
interface NodeCardProps { interface NodeCardProps {
node: any board: any
removed: boolean removed: boolean
provider?: ProviderType provider?: ProviderType
account?: string account?: string
} }
const NodeCard: React.FC<NodeCardProps> = ({ node, account }) => { const NodeCard: React.FC<NodeCardProps> = ({ board, account }) => {
const TranslateString = useI18n() const { t } = useTranslation()
const [showExpandableSection, setShowExpandableSection] = useState(false) const [showExpandableSection, setShowExpandableSection] = useState(false)
return ( return (
<FCard> <FCard>
{/* {true && <StyledCardAccent />} */} {/* {true && <StyledCardAccent />} */}
<CardHeading name={TranslateString(node.stringId, node.name)} img={node.img} tokenSymbol={node.tokenSymbol} /> <CardHeading name={t(board.name)} img={board.img} tokenSymbol={board.tokenSymbol} />
<CardActionsContainer node={node} account={account} /> <CardActionsContainer node={board} account={account} />
<Divider /> <Divider />
<ExpandableSectionButton <ExpandableSectionButton
onClick={() => setShowExpandableSection(!showExpandableSection)} onClick={() => setShowExpandableSection(!showExpandableSection)}
@ -99,7 +99,7 @@ const NodeCard: React.FC<NodeCardProps> = ({ node, account }) => {
<ExpandingWrapper expanded={showExpandableSection}> <ExpandingWrapper expanded={showExpandableSection}>
<DetailsSection <DetailsSection
bscScanAddress={`${process.env.REACT_APP_NETWORK_URL}/address/${getBoardAddress()}`} bscScanAddress={`${process.env.REACT_APP_NETWORK_URL}/address/${getBoardAddress()}`}
totalValueFormated={node.tokenBalance || '-'} totalValueFormated={board.tokenBalance || '-'}
/> />
</ExpandingWrapper> </ExpandingWrapper>
</FCard> </FCard>

View File

@ -3,16 +3,15 @@ import BigNumber from 'bignumber.js'
import styled from 'styled-components' import styled from 'styled-components'
import { provider as ProviderType } from 'web3-core' import { provider as ProviderType } from 'web3-core'
import { getAddress } from 'utils/addressHelpers' import { getAddress } from 'utils/addressHelpers'
import { getBep20Contract } from 'utils/contractHelpers'
import { Button, Flex, Text } from '@pancakeswap/uikit' import { Button, Flex, Text } from '@pancakeswap/uikit'
import { useTranslation } from 'contexts/Localization'
import { Boards } from 'state/types' import { Boards } from 'state/types'
import { useBoardUser } from 'state/hooks' import { useBoardUser } from 'state/hooks'
import { TOKEN_SYMBOL2 } from 'config/index' import { TOKEN_SYMBOL } from 'config/index'
import { getBalanceNumber } from 'utils/formatBalance' import { getBalanceNumber } from 'utils/formatBalance'
import useI18n from 'hooks/useI18n' import { useERC20 } from 'hooks/useContract'
import useWeb3 from 'hooks/useWeb3'
import { useNodeApprove } from 'hooks/useApprove'
import UnlockButton from 'components/UnlockButton' import UnlockButton from 'components/UnlockButton'
import useApproveBoard from '../../hooks/useApproveBoard'
import StakeAction from './StakeAction' import StakeAction from './StakeAction'
const Action = styled.div` const Action = styled.div`
@ -26,16 +25,14 @@ interface NodeCardActionsProps {
} }
const CardActions: React.FC<NodeCardActionsProps> = ({ node, account }) => { const CardActions: React.FC<NodeCardActionsProps> = ({ node, account }) => {
const TranslateString = useI18n() const { t } = useTranslation()
const [requestedApproval, setRequestedApproval] = useState(false) const [requestedApproval, setRequestedApproval] = useState(false)
const pid = node.pid const pid = node.pid
const { allowance, tokenBalance, stakedBalance, xCandyBalance } = useBoardUser(pid) const { allowance, tokenBalance, stakedBalance, xCandyBalance } = useBoardUser(pid)
const isApproved = account && allowance && allowance.isGreaterThan(0) const isApproved = account && allowance && allowance.isGreaterThan(0)
const web3 = useWeb3() const tokenContract = useERC20(getAddress(node.tokenAddresses))
const tokenAddress = getAddress(node.tokenAddresses)
const tokenContract = getBep20Contract(tokenAddress, web3)
const { onApprove } = useNodeApprove(tokenContract) const { onApprove } = useApproveBoard(tokenContract)
const handleApprove = useCallback(async () => { const handleApprove = useCallback(async () => {
try { try {
@ -54,10 +51,10 @@ const CardActions: React.FC<NodeCardActionsProps> = ({ node, account }) => {
<Flex flexDirection="column" alignItems="flex-start" mt="10"> <Flex flexDirection="column" alignItems="flex-start" mt="10">
<Flex> <Flex>
<Text bold textTransform="uppercase" color="secondary" fontSize="12px" pr="3px"> <Text bold textTransform="uppercase" color="secondary" fontSize="12px" pr="3px">
{TOKEN_SYMBOL2} {TOKEN_SYMBOL}
</Text> </Text>
<Text color="textSubtle" fontSize="12px"> <Text color="textSubtle" fontSize="12px">
{TranslateString(101018, 'Amount')} {t('Amount')}
</Text> </Text>
</Flex> </Flex>
<Text bold textTransform="uppercase" fontSize="20px"> <Text bold textTransform="uppercase" fontSize="20px">
@ -67,7 +64,7 @@ const CardActions: React.FC<NodeCardActionsProps> = ({ node, account }) => {
</> </>
) : ( ) : (
<Button mt="8px" width="100%" disabled={requestedApproval} onClick={handleApprove}> <Button mt="8px" width="100%" disabled={requestedApproval} onClick={handleApprove}>
{TranslateString(758, 'Approve Contract')} {t('Approve Contract')}
</Button> </Button>
) )
} }
@ -79,7 +76,7 @@ const CardActions: React.FC<NodeCardActionsProps> = ({ node, account }) => {
{node.tokenSymbol} {node.tokenSymbol}
</Text> </Text>
<Text bold textTransform="uppercase" color="textSubtle" fontSize="12px"> <Text bold textTransform="uppercase" color="textSubtle" fontSize="12px">
{TranslateString(101004, 'Staked')} {t('Staked')}
</Text> </Text>
</Flex> </Flex>
{!account ? <UnlockButton mt="8px" width="100%" /> : renderApprovalOrStakeButton()} {!account ? <UnlockButton mt="8px" width="100%" /> : renderApprovalOrStakeButton()}

View File

@ -2,7 +2,7 @@ import React from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { Tag, Flex, Heading, Image } from '@pancakeswap/uikit' import { Tag, Flex, Heading, Image } from '@pancakeswap/uikit'
import Question from 'components/QuestionHelper' import Question from 'components/QuestionHelper'
import useI18n from 'hooks/useI18n' import { useTranslation } from 'contexts/Localization'
export interface ExpandableSectionProps { export interface ExpandableSectionProps {
name?: string name?: string
@ -18,15 +18,13 @@ const Wrapper = styled(Flex)`
` `
const CardHeading: React.FC<ExpandableSectionProps> = ({ name, img, tokenSymbol }) => { const CardHeading: React.FC<ExpandableSectionProps> = ({ name, img, tokenSymbol }) => {
const TranslateString = useI18n() const { t } = useTranslation()
return ( return (
<Wrapper justifyContent="space-between" alignItems="center" mb="12px"> <Wrapper justifyContent="space-between" alignItems="center" mb="12px">
<Image src={`/images/nodes/${img}.png`} width={64} height={64} /> <Image src={`/images/nodes/${img}.png`} width={64} height={64} />
<Flex> <Flex>
<Heading mb="4px">{name}</Heading> <Heading mb="4px">{name}</Heading>
<Question <Question text={t('To join board, you need to stake at least 0.1% total supply of Token')} />
text={TranslateString(101017, 'To join board, you need to stake at least 0.1% total supply of Token')}
/>
</Flex> </Flex>
</Wrapper> </Wrapper>
) )

View File

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import useI18n from 'hooks/useI18n' import { useTranslation } from 'contexts/Localization'
import styled from 'styled-components' import styled from 'styled-components'
import { Text, Flex, Link, LinkExternal } from '@pancakeswap/uikit' import { Text, Flex, Link, LinkExternal } from '@pancakeswap/uikit'
@ -29,18 +29,18 @@ const StyledLinkExternal = styled(LinkExternal)`
` `
const DetailsSection: React.FC<ExpandableSectionProps> = ({ bscScanAddress, removed, totalValueFormated }) => { const DetailsSection: React.FC<ExpandableSectionProps> = ({ bscScanAddress, removed, totalValueFormated }) => {
const TranslateString = useI18n() const { t } = useTranslation()
return ( return (
<Wrapper> <Wrapper>
<Flex justifyContent="space-between"> <Flex justifyContent="space-between">
<Text>{TranslateString(101010, 'Total Staked')}:</Text> <Text>{t('Total Staked')}:</Text>
<Text>{totalValueFormated}</Text> <Text>{totalValueFormated}</Text>
</Flex> </Flex>
{/* )} */} {/* )} */}
<Flex justifyContent="flex-start"> <Flex justifyContent="flex-start">
<Link external href={bscScanAddress} bold={false}> <Link external href={bscScanAddress} bold={false}>
{TranslateString(356, 'View on BscScan')} {t( 'View on BscScan')}
</Link> </Link>
</Flex> </Flex>
</Wrapper> </Wrapper>

View File

@ -1,16 +1,17 @@
import React, { useMemo } from 'react' import React, { useMemo } from 'react'
import dayjs from 'dayjs' // import dayjs from 'dayjs'
import styled from 'styled-components' import styled from 'styled-components'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import { Button, Flex, Heading, IconButton, AddIcon, MinusIcon, useModal } from '@pancakeswap/uikit' import { Button, Flex, Heading, IconButton, AddIcon, MinusIcon, useModal } from '@pancakeswap/uikit'
import useI18n from 'hooks/useI18n'
import { useNodeStake } from 'hooks/useStake' // import { NODE_UNLOCK_TIME } from 'config/index'
import { useNodeUnstake } from 'hooks/useUnstake' import { getBalanceNumber } from 'utils/formatBalance'
import { NODE_UNLOCK_TIME } from 'config/index'
import { getBalanceNumber, getFullDisplayBalance } from 'utils/formatBalance'
import { useBoardsFromPid } from 'state/hooks' import { useBoardsFromPid } from 'state/hooks'
import { useTranslation } from 'contexts/Localization'
import useToast from 'hooks/useToast' import useToast from 'hooks/useToast'
import DepositModal from '../DepositModal' import DepositModal from '../DepositModal'
import useStakeBoard from '../../hooks/useStakeBoard'
import useUnstakeBoard from '../../hooks/useUnstakeBoard'
import WithdrawModal from '../WithdrawModal' import WithdrawModal from '../WithdrawModal'
interface NodeCardActionsProps { interface NodeCardActionsProps {
@ -28,10 +29,10 @@ const IconButtonWrapper = styled.div`
` `
const StakeAction: React.FC<NodeCardActionsProps> = ({ stakedBalance, tokenBalance, tokenName, pid }) => { const StakeAction: React.FC<NodeCardActionsProps> = ({ stakedBalance, tokenBalance, tokenName, pid }) => {
const TranslateString = useI18n() const { t } = useTranslation()
const { toastWarning } = useToast() const { toastWarning } = useToast()
const { onStake } = useNodeStake(pid) const { onStake } = useStakeBoard(pid)
const { onUnstake } = useNodeUnstake(pid) const { onUnstake } = useUnstakeBoard(pid)
const { tokenDecimals = 18, minStakeAmount, userData } = useBoardsFromPid(pid) const { tokenDecimals = 18, minStakeAmount, userData } = useBoardsFromPid(pid)
const rawStakedBalance = getBalanceNumber(stakedBalance, tokenDecimals, 8) const rawStakedBalance = getBalanceNumber(stakedBalance, tokenDecimals, 8)
const minStakedAmount = useMemo(() => { const minStakedAmount = useMemo(() => {
@ -51,25 +52,25 @@ const StakeAction: React.FC<NodeCardActionsProps> = ({ stakedBalance, tokenBalan
<WithdrawModal max={stakedBalance} tokenDecimals={tokenDecimals} onConfirm={onUnstake} tokenName={tokenName} />, <WithdrawModal max={stakedBalance} tokenDecimals={tokenDecimals} onConfirm={onUnstake} tokenName={tokenName} />,
) )
const handleUnstake = () => { const handleUnstake = () => {
const unstakeDay = new Date().getDay() // const unstakeDay = new Date().getDay()
const unlockTime = userData.unlockTime * 1000 // const unlockTime = userData.unlockTime * 1000
// 只能周五解锁 NEED CHANGE // // 只能周五解锁 NEED CHANGE
if (unstakeDay !== NODE_UNLOCK_TIME || unlockTime > new Date().getTime()) { // if (unstakeDay !== NODE_UNLOCK_TIME || unlockTime > new Date().getTime()) {
toastWarning( // toastWarning(
TranslateString(101012, 'Unlock time'), // TranslateString(101012, 'Unlock time'),
`${dayjs(unlockTime).format('YYYY-MM-DD HH:mm')} Next Friday`, // NEED CHANGE // `${dayjs(unlockTime).format('YYYY-MM-DD HH:mm')} Next Friday`, // NEED CHANGE
) // )
return // return
} // }
if (new BigNumber(userData.stakedBalance).toJSON() !== new BigNumber(userData.xCandyBalance).toJSON()) { // if (new BigNumber(userData.stakedBalance).toJSON() !== new BigNumber(userData.xCandyBalance).toJSON()) {
toastWarning(TranslateString(100103, 'Hint'), TranslateString(101019, 'Unlocking conditions are not met')) // toastWarning(TranslateString(100103, 'Hint'), TranslateString(101019, 'Unlocking conditions are not met'))
return // return
} // }
onUnstake() // onUnstake()
} }
const renderStakingButtons = () => { const renderStakingButtons = () => {
return rawStakedBalance === 0 ? ( return rawStakedBalance === 0 ? (
<Button onClick={onPresentDeposit}>{TranslateString(999, `Stake Token`)}</Button> <Button onClick={onPresentDeposit}>{t(`Stake Token`)}</Button>
) : ( ) : (
<IconButtonWrapper> <IconButtonWrapper>
<IconButton variant="tertiary" onClick={handleUnstake} mr="6px"> <IconButton variant="tertiary" onClick={handleUnstake} mr="6px">

View File

@ -1,10 +1,9 @@
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import React, { useCallback, useMemo, useState } from 'react' import React, { useCallback, useMemo, useState } from 'react'
import { Button, Modal, LinkExternal } from '@pancakeswap/uikit' import { Button, Modal, LinkExternal } from '@pancakeswap/uikit'
import ModalActions from 'components/ModalActions' import { ModalActions, ModalInput } from 'components/Modal'
import ModalInput from 'components/ModalInput' import { useTranslation } from 'contexts/Localization'
import useI18n from 'hooks/useI18n' import useToast from 'hooks/useToast'
import { useToast } from 'state/hooks'
import { getFullDisplayBalance } from 'utils/formatBalance' import { getFullDisplayBalance } from 'utils/formatBalance'
interface DepositModalProps { interface DepositModalProps {
@ -26,10 +25,10 @@ const DepositModal: React.FC<DepositModalProps> = ({
tokenName = '', tokenName = '',
addLiquidityUrl, addLiquidityUrl,
}) => { }) => {
const { toastWarning } = useToast() const { toastSuccess, toastError, toastWarning } = useToast()
const [val, setVal] = useState('') const [val, setVal] = useState('')
const [pendingTx, setPendingTx] = useState(false) const [pendingTx, setPendingTx] = useState(false)
const TranslateString = useI18n() const { t } = useTranslation()
const fullBalance = useMemo(() => { const fullBalance = useMemo(() => {
return getFullDisplayBalance(max, tokenDecimals) return getFullDisplayBalance(max, tokenDecimals)
}, [max, tokenDecimals]) }, [max, tokenDecimals])
@ -46,7 +45,7 @@ const DepositModal: React.FC<DepositModalProps> = ({
}, [fullBalance, setVal]) }, [fullBalance, setVal])
return ( return (
<Modal title={TranslateString(101004, 'Stake tokens')} onDismiss={onDismiss}> <Modal title={t('Stake tokens')} onDismiss={onDismiss}>
<ModalInput <ModalInput
value={val} value={val}
onSelectMax={handleSelectMax} onSelectMax={handleSelectMax}
@ -54,34 +53,41 @@ const DepositModal: React.FC<DepositModalProps> = ({
max={fullBalance} max={fullBalance}
symbol={tokenName} symbol={tokenName}
addLiquidityUrl={addLiquidityUrl} addLiquidityUrl={addLiquidityUrl}
inputTitle={TranslateString(101004, 'Stake')} inputTitle={t('Stake')}
/> />
<ModalActions> <ModalActions>
<Button variant="secondary" onClick={onDismiss} width="100%"> <Button variant="secondary" onClick={onDismiss} width="100%">
{TranslateString(462, 'Cancel')} {t('Cancel')}
</Button> </Button>
<Button <Button
width="100%" width="100%"
disabled={pendingTx || fullBalance === '0' || val === '0'} disabled={pendingTx || fullBalance === '0' || val === '0'}
onClick={async () => { onClick={async () => {
if (Number(val) < min.toNumber()) { if (Number(val) < min.toNumber()) {
toastWarning( toastWarning(t('Hint'), `${t('At least stake ')}${min.toNumber()}`)
TranslateString(100103, 'Hint'),
`${TranslateString(101011, 'At least stake ')}${min.toNumber()}`,
)
return return
} }
setPendingTx(true) setPendingTx(true)
try {
await onConfirm(val) await onConfirm(val)
setPendingTx(false) toastSuccess(t('Staked!'), t('Your funds have been staked in the farm'))
onDismiss() onDismiss()
} catch (e) {
toastError(
t('Error'),
t('Please try again. Confirm the transaction and make sure you are paying enough gas!'),
)
console.error(e)
} finally {
setPendingTx(false)
}
}} }}
> >
{pendingTx ? TranslateString(488, 'Pending Confirmation') : TranslateString(464, 'Confirm')} {pendingTx ? t('Pending Confirmation') : t('Confirm')}
</Button> </Button>
</ModalActions> </ModalActions>
<LinkExternal href={addLiquidityUrl} style={{ alignSelf: 'center' }}> <LinkExternal href={addLiquidityUrl} style={{ alignSelf: 'center' }}>
{TranslateString(100102, 'Get')} {tokenName} {t('Get %symbol%', { symbol: tokenName })}
</LinkExternal> </LinkExternal>
</Modal> </Modal>
) )

View File

@ -1,9 +1,10 @@
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import React, { useCallback, useMemo, useState } from 'react' import React, { useCallback, useMemo, useState } from 'react'
import { Button, Modal } from '@pancakeswap/uikit' import { Button, Modal } from '@pancakeswap/uikit'
import ModalActions from 'components/ModalActions' import useToast from 'hooks/useToast'
import ModalInput from 'components/ModalInput'
import useI18n from 'hooks/useI18n' import { ModalActions, ModalInput } from 'components/Modal'
import { useTranslation } from 'contexts/Localization'
import { getFullDisplayBalance } from 'utils/formatBalance' import { getFullDisplayBalance } from 'utils/formatBalance'
interface WithdrawModalProps { interface WithdrawModalProps {
@ -23,11 +24,14 @@ const WithdrawModal: React.FC<WithdrawModalProps> = ({
}) => { }) => {
const [val, setVal] = useState('') const [val, setVal] = useState('')
const [pendingTx, setPendingTx] = useState(false) const [pendingTx, setPendingTx] = useState(false)
const TranslateString = useI18n() const { t } = useTranslation()
const fullBalance = useMemo(() => { const fullBalance = useMemo(() => {
return getFullDisplayBalance(max, tokenDecimals) return getFullDisplayBalance(max)
}, [max, tokenDecimals]) }, [max])
const { toastSuccess, toastError } = useToast()
const valNumber = new BigNumber(val)
const fullBalanceNumber = new BigNumber(fullBalance)
const handleChange = useCallback( const handleChange = useCallback(
(e: React.FormEvent<HTMLInputElement>) => { (e: React.FormEvent<HTMLInputElement>) => {
setVal(e.currentTarget.value) setVal(e.currentTarget.value)
@ -40,30 +44,40 @@ const WithdrawModal: React.FC<WithdrawModalProps> = ({
}, [fullBalance, setVal]) }, [fullBalance, setVal])
return ( return (
<Modal title={TranslateString(101008, 'Unstake tokens')} onDismiss={onDismiss}> <Modal title={t('Unstake LP tokens')} onDismiss={onDismiss}>
<ModalInput <ModalInput
onSelectMax={handleSelectMax} onSelectMax={handleSelectMax}
onChange={handleChange} onChange={handleChange}
value={val} value={val}
max={fullBalance} max={fullBalance}
symbol={tokenName} symbol={tokenName}
inputTitle={TranslateString(588, 'Unstake')} inputTitle={t('Unstake')}
/> />
<ModalActions> <ModalActions>
<Button variant="secondary" onClick={onDismiss} width="100%"> <Button variant="secondary" onClick={onDismiss} width="100%" disabled={pendingTx}>
{TranslateString(462, 'Cancel')} {t('Cancel')}
</Button> </Button>
<Button <Button
disabled={pendingTx} disabled={pendingTx || !valNumber.isFinite() || valNumber.eq(0) || valNumber.gt(fullBalanceNumber)}
onClick={async () => { onClick={async () => {
setPendingTx(true) setPendingTx(true)
try {
await onConfirm(val) await onConfirm(val)
setPendingTx(false) toastSuccess(t('Unstaked!'), t('Your earnings have also been harvested to your wallet'))
onDismiss() onDismiss()
} catch (e) {
toastError(
t('Error'),
t('Please try again. Confirm the transaction and make sure you are paying enough gas!'),
)
console.error(e)
} finally {
setPendingTx(false)
}
}} }}
width="100%" width="100%"
> >
{pendingTx ? TranslateString(488, 'Pending Confirmation') : TranslateString(464, 'Confirm')} {pendingTx ? t('Pending Confirmation') : t('Confirm')}
</Button> </Button>
</ModalActions> </ModalActions>
</Modal> </Modal>

View File

@ -0,0 +1,20 @@
import { useCallback } from 'react'
import { ethers, Contract } from 'ethers'
import { useBoardchef } from 'hooks/useContract'
const useApproveBoard = (lpContract: Contract) => {
const boardChefContract = useBoardchef()
const handleApprove = useCallback(async () => {
try {
const tx = await lpContract.approve(boardChefContract.address, ethers.constants.MaxUint256)
const receipt = await tx.wait()
return receipt.status
} catch (e) {
return false
}
}, [lpContract, boardChefContract])
return { onApprove: handleApprove }
}
export default useApproveBoard

View File

@ -0,0 +1,15 @@
import { useCallback } from 'react'
import { harvestFarm } from 'utils/calls'
import { useBoardchef } from 'hooks/useContract'
const useHarvestBoard = (boardPid: number) => {
const boardChefContract = useBoardchef()
const handleHarvest = useCallback(async () => {
await harvestFarm(boardChefContract, boardPid)
}, [boardPid, boardChefContract])
return { onReward: handleHarvest }
}
export default useHarvestBoard

View File

@ -1,19 +1,19 @@
export const useNodeStake = (pid: number) => { import { useCallback } from 'react'
const dispatch = useDispatch() import { stakeFarm } from 'utils/calls'
const { account } = useWeb3React() import { useBoardchef } from 'hooks/useContract'
const nodeChefContract = useNodechef()
const { tokenDecimals = 18 } = useNodesFromPid(pid) const useStakeBoard = (pid: number) => {
const boardChefContract = useBoardchef()
const handleStake = useCallback( const handleStake = useCallback(
async (amount: string) => { async (amount: string) => {
const txHash = await nodeStake(nodeChefContract, amount, account, tokenDecimals) const txHash = await stakeFarm(boardChefContract, pid, amount)
// dispatch(fetchFarmsPublicDataAsync())
// dispatch(fetchFarmUserDataAsync(account))
console.info(txHash) console.info(txHash)
}, },
[account, dispatch, nodeChefContract, tokenDecimals], [boardChefContract, pid],
) )
return { onStake: handleStake } return { onStake: handleStake }
} }
export default useNodeStake export default useStakeBoard

View File

@ -0,0 +1,18 @@
import { useCallback } from 'react'
import { unstakeFarm } from 'utils/calls'
import { useBoardchef } from 'hooks/useContract'
const useUnstakeBoard = (pid: number) => {
const boardChefContract = useBoardchef()
const handleUnstake = useCallback(
async (amount: string) => {
await unstakeFarm(boardChefContract, pid, amount)
},
[boardChefContract, pid],
)
return { onUnstake: handleUnstake }
}
export default useUnstakeBoard

View File

@ -10,7 +10,7 @@ import Page from 'components/Layout/Page'
import { useBoards } from 'state/hooks' import { useBoards } from 'state/hooks'
import useRefresh from 'hooks/useRefresh' import useRefresh from 'hooks/useRefresh'
import { fetchBoardUserDataAsync, fetchBoardsPublicDataAsync } from 'state/actions' import { fetchBoardUserDataAsync, fetchBoardsPublicDataAsync } from 'state/actions'
import useI18n from 'hooks/useI18n' import { useTranslation } from 'contexts/Localization'
import BoardCard from './components/BoardCard/BoardCard' import BoardCard from './components/BoardCard/BoardCard'
const Header = styled.div` const Header = styled.div`
@ -28,7 +28,7 @@ const SecondText = styled(Text)`
white-space: break-spaces; white-space: break-spaces;
` `
const Farms: React.FC = () => { const Farms: React.FC = () => {
const TranslateString = useI18n() const { t } = useTranslation()
const boardsList = useBoards() const boardsList = useBoards()
const [query, setQuery] = useState('') const [query, setQuery] = useState('')
const { account } = useWeb3React() const { account } = useWeb3React()
@ -63,11 +63,10 @@ const Farms: React.FC = () => {
<> <>
<Header> <Header>
<Heading as="h1" size="xl" color="text" mb="10px" mt="10px"> <Heading as="h1" size="xl" color="text" mb="10px" mt="10px">
{TranslateString(100004, 'Boards')} {t('Boards')}
</Heading> </Heading>
<SecondText fontSize="28px" color="text"> <SecondText fontSize="28px" color="text">
{TranslateString( {t(
101013,
'Joining the board of directors will obtain the governance token xcandy \n participate in the governance of the project, vote, obtain additional pledge income, \n and have a higher invitation airdrop reward', 'Joining the board of directors will obtain the governance token xcandy \n participate in the governance of the project, vote, obtain additional pledge income, \n and have a higher invitation airdrop reward',
)} )}
</SecondText> </SecondText>