对接盲盒、NFT市场、NFT盒子
This commit is contained in:
parent
202ab6b28f
commit
25e6b44560
|
|
@ -24,8 +24,8 @@ REACT_APP_SNAPSHOT_VOTING_API = "https://xtjyd0liqe.execute-api.ap-northeast-1.a
|
|||
|
||||
|
||||
# REACT_APP_REQUEST_URL = 'http://192.253.237.94:9090'
|
||||
REACT_APP_REQUEST_URL = 'http://HousedeMacBook-Air.local:8080'
|
||||
# REACT_APP_REQUEST_URL = 'http://101.35.117.69:9090'
|
||||
# REACT_APP_REQUEST_URL = 'http://HousedeMacBook-Air.local:8080'
|
||||
REACT_APP_REQUEST_URL = 'http://101.35.117.69:9090'
|
||||
# REACT_APP_REQUEST_URL = 'http://192.168.2.147:8080'
|
||||
# REACT_APP_REQUEST_URL = 'http://192.168.2.:8080'
|
||||
# REACT_APP_REQUEST_URL = 'http://6o7g1fv83e.51xd.pub'
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 173 KiB |
|
|
@ -1184,6 +1184,7 @@
|
|||
"social contact demo": "社交demo",
|
||||
"The rate of": "出率",
|
||||
"%hour%hour": "%hour%小时",
|
||||
"%minute%minute": "%minute%分钟",
|
||||
"limit the quantity of": "限量",
|
||||
"time limit": "限时",
|
||||
"nft Smoking in the probability": "NFT抽中概率",
|
||||
|
|
@ -1213,12 +1214,12 @@
|
|||
"NFT name (grade) of successful synthesis = NFT name (grade) of raw material x quantity + synthesis cost": "合成成功NFT名称(等级)=原料NFT名称(等级)×数量+合成费用",
|
||||
"bazaar": "市场",
|
||||
"auction": "拍卖",
|
||||
"I sell": "我的售卖",
|
||||
"I want to sell": "我要售卖",
|
||||
"transaction record": "交易记录",
|
||||
"The total volume": "总交易额",
|
||||
"The total number of transactions": "总交易数",
|
||||
"Total number of auctions": "总拍卖次数",
|
||||
"Total auction commission": "总拍卖返佣",
|
||||
"Total transaction rebate": "总交易返佣",
|
||||
"trading value": "出售价格",
|
||||
|
||||
"Detail": "详情",
|
||||
|
|
@ -1269,5 +1270,19 @@
|
|||
"unit price": "单价",
|
||||
"seller": "卖方",
|
||||
"purchaser": "买方",
|
||||
"trading hour": "交易时间"
|
||||
"trading hour": "交易时间",
|
||||
"Please select quantity": "请选择数量",
|
||||
"No data yet": "还没有数据哦~",
|
||||
"purchase succeeds": "购买成功",
|
||||
"Copy success": "复制成功",
|
||||
"NFT Holder": "NFT 持有者",
|
||||
"NFT With the total": "NFT拥有总量",
|
||||
"official market": "官方市场",
|
||||
"finished": "已结束",
|
||||
"have not started": "未开始",
|
||||
"category": "类别",
|
||||
"GIVING": "礼物",
|
||||
"PROPS": "道具",
|
||||
"rarity": "稀有度",
|
||||
"success": "成功"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
import React from 'react'
|
||||
import styled, { keyframes } from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Flex, Text, Image } from '@pancakeswap/uikit'
|
||||
|
||||
interface EmptyProps {
|
||||
title?: string
|
||||
marginTop?: string
|
||||
}
|
||||
|
||||
const EmptyFlex = styled(Flex)`
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
`
|
||||
const EmptyText = styled(Text)`
|
||||
font-size: 16px;
|
||||
color: #505f79;
|
||||
margin-top: 12px;
|
||||
`
|
||||
|
||||
const Empty: React.FC<EmptyProps> = ({ title, marginTop = '20px' }) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<EmptyFlex style={{ marginTop }}>
|
||||
<Image src="/images/empty.svg" width={228} height={200} />
|
||||
<EmptyText>{title ? t(title) : t('No data yet')}</EmptyText>
|
||||
</EmptyFlex>
|
||||
)
|
||||
}
|
||||
export default Empty
|
||||
|
|
@ -29,6 +29,11 @@ export default {
|
|||
56: '0x9ee1c805a9508c0799b157ebbe3108d57c8d8588', // NEED CHANGE 持币人分红
|
||||
5: '0xd91740ABe3C54f9e9D8A2c80615618a5dd234556',
|
||||
},
|
||||
holderPool: {
|
||||
97: '0xb9d1567848771b984f0330c49933b27f1dea0675',
|
||||
56: '0xb9d1567848771b984f0330c49933b27f1dea0675', // NEED CHANGE NFT持有者
|
||||
5: '0xb9d1567848771b984f0330c49933b27f1dea0675',
|
||||
},
|
||||
referralChef: {
|
||||
97: '0x0866962d208e91ea8804db3f547cccf22fe39ea7',
|
||||
56: '0x0866962d208e91ea8804db3f547cccf22fe39ea7', // NEED CHANGE 邀请或则军团长
|
||||
|
|
@ -47,7 +52,7 @@ export default {
|
|||
blindBox: {
|
||||
97: '0x0e226d7b83b511ce224803b1330beb4a59bfa5d6',
|
||||
56: '0x0e226d7b83b511ce224803b1330beb4a59bfa5d6', // NEED CHANGE 官方市场 盲盒
|
||||
5: '0x0e226d7b83b511ce224803b1330beb4a59bfa5d6',
|
||||
5: '0x99d61f4724d520246c43d0f1dea22c1f21c42a4e',
|
||||
},
|
||||
lotteryV2: {
|
||||
97: '0x5790c3534F30437641541a0FA04C992799602998',
|
||||
|
|
@ -57,7 +62,7 @@ export default {
|
|||
multiCall: {
|
||||
56: '0xfF6FD90A470Aaa0c1B8A54681746b07AcdFedc9B',
|
||||
97: '0x8F3273Fb89B075b1645095ABaC6ed17B2d4Bc576',
|
||||
5: '0xfF6FD90A470Aaa0c1B8A54681746b07AcdFedc9B',
|
||||
5: '0x3a648f94783e35526072c02d7ce89c385b41ac19',
|
||||
},
|
||||
pancakeProfile: {
|
||||
56: '0xDf4dBf6536201370F95e06A0F8a7a70fE40E388a',
|
||||
|
|
|
|||
|
|
@ -1311,6 +1311,7 @@
|
|||
"social contact demo": "social contact demo",
|
||||
"The rate of": "The rate of",
|
||||
"%hour%hour": "%hour%hour",
|
||||
"%minute%minute": "%minute%minute",
|
||||
"limit the quantity of": "limit the quantity of",
|
||||
"time limit": "time limit",
|
||||
"nft Smoking in the probability": "nft Smoking in the probability",
|
||||
|
|
@ -1340,12 +1341,12 @@
|
|||
"NFT name (grade) of successful synthesis = NFT name (grade) of raw material x quantity + synthesis cost": "NFT name (grade) of successful synthesis = NFT name (grade) of raw material x quantity + synthesis cost",
|
||||
"bazaar": "bazaar",
|
||||
"auction": "auction",
|
||||
"I sell": "I sell",
|
||||
"I want to sell": "I want to sell",
|
||||
"transaction record": "transaction record",
|
||||
"The total volume": "The total volume",
|
||||
"The total number of transactions": "The total number of transactions",
|
||||
"Total number of auctions": "Total number of auctions",
|
||||
"Total auction commission": "Total auction commission",
|
||||
"Total transaction rebate": "Total transaction rebate",
|
||||
"trading value": "trading value",
|
||||
|
||||
"Detail": "Detail",
|
||||
|
|
@ -1396,5 +1397,19 @@
|
|||
"unit price": "unit price",
|
||||
"seller": "seller",
|
||||
"purchaser": "purchaser",
|
||||
"trading hour": "trading hour"
|
||||
"trading hour": "trading hour",
|
||||
"Please select quantity": "Please select quantity",
|
||||
"No data yet": "No data yet~",
|
||||
"purchase succeeds": "purchase succeeds",
|
||||
"Copy success": "Copy success",
|
||||
"NFT Holder": "NFT Holder",
|
||||
"NFT With the total": "NFT With the total",
|
||||
"official market": "official market",
|
||||
"finished": "finished",
|
||||
"have not started": "have not started",
|
||||
"category": "category",
|
||||
"GIVING": "GIVING",
|
||||
"PROPS": "PROPS",
|
||||
"rarity": "rarity",
|
||||
"success": "success"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ import {
|
|||
getBoardchefContract,
|
||||
getReferralRewardchefContract,
|
||||
getIdoPurchaseContract,
|
||||
getHccGiftNftContract,
|
||||
getBlindBoxContract,
|
||||
getHolderPoolContract,
|
||||
} from 'utils/contractHelpers'
|
||||
|
||||
// Imports below migrated from Exchange useContract.ts
|
||||
|
|
@ -115,9 +116,13 @@ export const useIdoPurchase = () => {
|
|||
const { library } = useActiveWeb3React()
|
||||
return useMemo(() => getIdoPurchaseContract(library.getSigner()), [library])
|
||||
}
|
||||
export const useHccGiftNft = () => {
|
||||
export const useBlindBox = () => {
|
||||
const { library } = useActiveWeb3React()
|
||||
return useMemo(() => getHccGiftNftContract(library.getSigner()), [library])
|
||||
return useMemo(() => getBlindBoxContract(library.getSigner()), [library])
|
||||
}
|
||||
export const useHolderPool = () => {
|
||||
const { library } = useActiveWeb3React()
|
||||
return useMemo(() => getHolderPoolContract(library.getSigner()), [library])
|
||||
}
|
||||
export const useReferralRewardchef = () => {
|
||||
const { library } = useActiveWeb3React()
|
||||
|
|
|
|||
|
|
@ -7,5 +7,33 @@ export const getOfficialPage = (params) => {
|
|||
params,
|
||||
})
|
||||
}
|
||||
export const getOfficialPurchase = (id, params) => {
|
||||
return request.request({
|
||||
url: `/high_city/app/api/market/official/purchase/${id}`,
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
export const checkBuyResult = (params) => {
|
||||
return request.request({
|
||||
url: `/high_city/app/api/market/official/purchase/tx`,
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
export const getPurchaseRecord = (params) => {
|
||||
return request.request({
|
||||
url: `/high_city/app/api/market/official/purchase/record`,
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
export const getNftDetail = (id, params) => {
|
||||
return request.request({
|
||||
url: `/high_city/app/api/nft/detail/${id}`,
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
export default getOfficialPage
|
||||
|
|
|
|||
|
|
@ -14,10 +14,18 @@ export const getBoxDetail = (id) => {
|
|||
method: 'get',
|
||||
})
|
||||
}
|
||||
export const getPurchase = (id) => {
|
||||
export const getPurchase = (id, params) => {
|
||||
return request.request({
|
||||
url: `/high_city/app/api/box/purchase/${id}`,
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
export const checkBuyResult = (params) => {
|
||||
return request.request({
|
||||
url: `/high_city/app/api/box/purchase/tx`,
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
import request from 'utils/request'
|
||||
|
||||
export const getSelfPage = (params) => {
|
||||
return request.request({
|
||||
url: '/high_city/app/api/nft/self/page',
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
export const getNftDetails = (token, params) => {
|
||||
return request.request({
|
||||
url: `/high_city/app/api/nft/detail/${token}`,
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
export default getSelfPage
|
||||
|
|
@ -6,6 +6,7 @@ export interface ListProps {
|
|||
price?: undefined
|
||||
priceList?: PriceProps[]
|
||||
type?: string
|
||||
record?: boolean
|
||||
}
|
||||
export interface CoverResourceProps {
|
||||
path?: string
|
||||
|
|
|
|||
|
|
@ -80,3 +80,6 @@ export const getIdoPurchaseAddress = () => {
|
|||
export const getBlindBoxAddress = () => {
|
||||
return getAddress(addresses.blindBox)
|
||||
}
|
||||
export const getHolderPoolAddress = () => {
|
||||
return getAddress(addresses.holderPool)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const stakeBoard = async (masterChefContract, pid, amount) => {
|
|||
}
|
||||
|
||||
export const unstakeBoard = async (masterChefContract) => {
|
||||
console.log(masterChefContract)
|
||||
const tx = await masterChefContract.withdrawHCC(options)
|
||||
const receipt = await tx.wait()
|
||||
return receipt.status
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
getReferralRewardAddress,
|
||||
getIdoPurchaseAddress,
|
||||
getBlindBoxAddress,
|
||||
getHolderPoolAddress,
|
||||
} from 'utils/addressHelpers'
|
||||
|
||||
// ABI
|
||||
|
|
@ -62,6 +63,7 @@ import MultiCallAbi from 'config/abi/Multicall.json'
|
|||
import bunnySpecialCakeVaultAbi from 'config/abi/bunnySpecialCakeVault.json'
|
||||
import bunnySpecialPredictionAbi from 'config/abi/bunnySpecialPrediction.json'
|
||||
import idoPurchase from 'config/abi/idoPurchase.json'
|
||||
import holderPool from 'config/abi/holderPool.json'
|
||||
import blindBox from 'config/abi/blindBox.json'
|
||||
import { ChainLinkOracleContract, PredictionsContract } from './types'
|
||||
|
||||
|
|
@ -134,7 +136,10 @@ export const getReferralRewardchefContract = (signer?: ethers.Signer | ethers.pr
|
|||
export const getIdoPurchaseContract = (signer?: ethers.Signer | ethers.providers.Provider) => {
|
||||
return getContract(idoPurchase, getIdoPurchaseAddress(), signer)
|
||||
}
|
||||
export const getHccGiftNftContract = (signer?: ethers.Signer | ethers.providers.Provider) => {
|
||||
export const getHolderPoolContract = (signer?: ethers.Signer | ethers.providers.Provider) => {
|
||||
return getContract(holderPool, getHolderPoolAddress(), signer)
|
||||
}
|
||||
export const getBlindBoxContract = (signer?: ethers.Signer | ethers.providers.Provider) => {
|
||||
return getContract(blindBox, getBlindBoxAddress(), signer)
|
||||
}
|
||||
export const getClaimRefundContract = (signer?: ethers.Signer | ethers.providers.Provider) => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Flex, Button, Text, Image } from '@pancakeswap/uikit'
|
||||
import { getContract } from 'services/referral'
|
||||
import FlexCom from './FlexCom'
|
||||
|
||||
interface DetailProps {
|
||||
typeIndex: number
|
||||
}
|
||||
|
||||
const DetailFlex = styled(Flex)`
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 278px;
|
||||
background: #f5ffff;
|
||||
opacity: 1;
|
||||
border-radius: 20px;
|
||||
padding: 24px 30px;
|
||||
margin-top: 24px;
|
||||
`
|
||||
|
||||
const AssetsInfo: React.FC<DetailProps> = ({ typeIndex }) => {
|
||||
const { t } = useTranslation()
|
||||
const [link, setLink] = useState('')
|
||||
|
||||
const getLinkAddress = async () => {
|
||||
const data = await getContract()
|
||||
setLink(data)
|
||||
}
|
||||
useEffect(() => {
|
||||
getLinkAddress()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<DetailFlex>
|
||||
{typeIndex !== 0 && <FlexCom name={t('owner')} value="钱包地址" />}
|
||||
<FlexCom
|
||||
name={t('Contract address')}
|
||||
typeLink={`https://bscscan.com/token/${link}`}
|
||||
value={`${link && link.substring(0, 6)}...${link && link.substring(link.length - 4, link.length)}`}
|
||||
/>
|
||||
{typeIndex !== 0 && <FlexCom name="token ID" value="token ID" />}
|
||||
<FlexCom name={t('Assets agreement')} value="ERC721" />
|
||||
<FlexCom name={t('Assets and chain')} value="BSC" />
|
||||
</DetailFlex>
|
||||
)
|
||||
}
|
||||
export default AssetsInfo
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Flex, Button, Text, Image } from '@pancakeswap/uikit'
|
||||
import { useAccount } from 'state/userInfo/hooks'
|
||||
import { fetchBlindBoxUserAllowances } from 'state/blindBox'
|
||||
import { getAddress } from 'utils/addressHelpers'
|
||||
import { useERC20 } from 'hooks/useContract'
|
||||
import tokens from 'config/constants/tokens'
|
||||
import useRefresh from 'hooks/useRefresh'
|
||||
import useToast from 'hooks/useToast'
|
||||
import { ListProps } from 'types/bazaar'
|
||||
import { checkBuyResult } from 'services/bazaar'
|
||||
import UnlockButton from 'components/UnlockButton'
|
||||
import { useBuyTransaction, useApproveHcc } from '../hooks'
|
||||
import { useCheckHccTokenBalance, useCheckTokenBalance } from '../../BlindBox/hooks'
|
||||
|
||||
interface DetailProps {
|
||||
detail: ListProps
|
||||
}
|
||||
|
||||
const PriceButton = styled(Button)`
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background: linear-gradient(269deg, #1fc8d3 0%, #1fd4b0 100%);
|
||||
border-radius: 30px;
|
||||
font-size: 16px;
|
||||
margin: 30px 0;
|
||||
`
|
||||
const AuthorizationBtn = styled(Button)`
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background: linear-gradient(269deg, #1fc8d3 0%, #1fd4b0 100%);
|
||||
border-radius: 30px;
|
||||
font-size: 16px;
|
||||
margin: 30px 0;
|
||||
`
|
||||
|
||||
const UnlockButtonDiv = styled(UnlockButton)`
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background: linear-gradient(269deg, #1fc8d3 0%, #1fd4b0 100%);
|
||||
border-radius: 30px;
|
||||
font-size: 16px;
|
||||
margin: 30px 0;
|
||||
`
|
||||
|
||||
const BtnStatus: React.FC<DetailProps> = ({ detail }) => {
|
||||
const { t } = useTranslation()
|
||||
const [txId, setTxId] = useState()
|
||||
const [price, setPrice] = useState('')
|
||||
const [allowanceList, setAllowanceList] = useState({ USDT: 0, HCC: 0 })
|
||||
const [loading, setLoading] = useState(false)
|
||||
const { toastSuccess, toastError } = useToast()
|
||||
const { fastRefresh } = useRefresh()
|
||||
const account = useAccount()
|
||||
// const [link, setLink] = useState('')
|
||||
const [buyVisible, setBuyVisible] = useState(false)
|
||||
|
||||
const usdtContract = useERC20(getAddress(tokens.usdt.address))
|
||||
const hccContract = useERC20(getAddress(tokens.hcc.address))
|
||||
const { onApprove: onUsdtApprove } = useApproveHcc(usdtContract)
|
||||
const { onApprove: onHccApprove } = useApproveHcc(hccContract)
|
||||
|
||||
const getAllowances = async () => {
|
||||
const allowances = await fetchBlindBoxUserAllowances(account)
|
||||
detail.priceList &&
|
||||
detail.priceList.forEach((item) => {
|
||||
if (detail.priceList.length === 2) {
|
||||
if (allowances.usdt && allowances.hcc) {
|
||||
setBuyVisible(true)
|
||||
}
|
||||
} else {
|
||||
console.log(' ')
|
||||
if (allowances.hcc && item.label === 'HCC') {
|
||||
setBuyVisible(true)
|
||||
} else if (allowances.usdt && item.label === 'USDT') {
|
||||
setBuyVisible(true)
|
||||
}
|
||||
}
|
||||
})
|
||||
setAllowanceList({
|
||||
USDT: allowances.usdt,
|
||||
HCC: allowances.hcc,
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (detail.priceList) {
|
||||
const priceList = detail.priceList.map((item) => {
|
||||
return `${Number(item.value).toFixed(3)} ${item.label}`
|
||||
})
|
||||
setPrice(priceList.join('-'))
|
||||
}
|
||||
if (account) {
|
||||
getAllowances()
|
||||
}
|
||||
}, [account])
|
||||
const buyTransaction = useBuyTransaction()
|
||||
|
||||
const [onCheckBalanceHcc] = useCheckHccTokenBalance()
|
||||
const [onCheckBalanceUsdt] = useCheckTokenBalance()
|
||||
const handleBuy = async () => {
|
||||
let HccBalance = true
|
||||
detail.priceList &&
|
||||
detail.priceList.forEach((item) => {
|
||||
if (item.label === 'HCC') {
|
||||
HccBalance = onCheckBalanceHcc(Number(item.value))
|
||||
} else {
|
||||
HccBalance = onCheckBalanceUsdt(Number(item.value))
|
||||
}
|
||||
})
|
||||
if (!HccBalance) {
|
||||
return
|
||||
}
|
||||
setLoading(true)
|
||||
const res = await buyTransaction(detail.id, {
|
||||
id: detail.id,
|
||||
num: 1,
|
||||
})
|
||||
setTxId(res.hash)
|
||||
}
|
||||
|
||||
const getTransactionResult = async () => {
|
||||
const res = await checkBuyResult({ tx: txId })
|
||||
if (res) {
|
||||
setLoading(false)
|
||||
setTxId(undefined)
|
||||
toastSuccess(t('purchase succeeds'))
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
if (txId && loading) {
|
||||
getTransactionResult()
|
||||
}
|
||||
}, [fastRefresh])
|
||||
|
||||
const handleApprove = async (approve) => {
|
||||
try {
|
||||
setLoading(true)
|
||||
await approve()
|
||||
setLoading(false)
|
||||
getAllowances()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{buyVisible && <PriceButton onClick={handleBuy}>{t('Buy It Now')}</PriceButton>}
|
||||
<Flex style={{ width: '100%' }}>
|
||||
{detail.priceList.map((item, i) =>
|
||||
item.label === 'HCC' && !allowanceList.HCC ? (
|
||||
<AuthorizationBtn
|
||||
key={item.label}
|
||||
disabled={loading}
|
||||
onClick={() => {
|
||||
handleApprove(onHccApprove)
|
||||
}}
|
||||
>
|
||||
{t('Approve %coin% Contract', { coin: 'HCC' })}
|
||||
</AuthorizationBtn>
|
||||
) : item.label === 'USDT' && !allowanceList.USDT ? (
|
||||
<AuthorizationBtn
|
||||
key={item.label}
|
||||
disabled={loading}
|
||||
onClick={() => {
|
||||
handleApprove(onUsdtApprove)
|
||||
}}
|
||||
>
|
||||
{t('Approve %coin% Contract', { coin: 'USDT' })}
|
||||
</AuthorizationBtn>
|
||||
) : (
|
||||
''
|
||||
),
|
||||
)}
|
||||
</Flex>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default BtnStatus
|
||||
|
|
@ -1,12 +1,16 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import qs from 'querystring'
|
||||
import { useLocation, useHistory, useParams } from 'react-router-dom'
|
||||
import styled, { keyframes } from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import Pagination from '@mui/material/Pagination'
|
||||
import { Flex, Text, Input, Image, Dropdown } from '@pancakeswap/uikit'
|
||||
import { useAccount } from 'state/userInfo/hooks'
|
||||
import useRefresh from 'hooks/useRefresh'
|
||||
import useToast from 'hooks/useToast'
|
||||
import { ListProps } from 'types/bazaar'
|
||||
|
||||
import Empty from 'components/Empty'
|
||||
import { useGetOfficialPage } from '../hooks'
|
||||
import HeaderOperation from './HeaderOperation'
|
||||
import ContentShop from './ContentShop'
|
||||
|
|
@ -129,10 +133,13 @@ const FlexOption = styled(Flex)`
|
|||
|
||||
const Content: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const location = useLocation()
|
||||
const history = useHistory()
|
||||
const { toastSuccess, toastError } = useToast()
|
||||
const [detail, setDetail] = useState<ListProps>({})
|
||||
const [detailVisible, setDetailVisible] = useState(false)
|
||||
const typeList = [
|
||||
{ label: t('All'), type: 1 },
|
||||
{ label: t('official market'), type: 1 },
|
||||
{ label: t('bazaar'), type: 2 },
|
||||
{ label: t('auction'), type: 3 },
|
||||
]
|
||||
|
|
@ -155,10 +162,10 @@ const Content: React.FC = () => {
|
|||
const [list, setList] = useState<ListProps[]>([])
|
||||
const statusList = [
|
||||
{ label: t('All'), id: '1', grade: '' },
|
||||
{ label: t('common'), id: '5', grade: 'NORMAL' },
|
||||
{ label: t('uncommon'), id: '4', grade: 'RARE' },
|
||||
{ label: t('epic'), id: '2', grade: 'EPIC' },
|
||||
{ label: t('legend'), id: '3', grade: 'LEGEND' },
|
||||
{ label: t('uncommon'), id: '4', grade: 'RARE' },
|
||||
{ label: t('common'), id: '5', grade: 'NORMAL' },
|
||||
]
|
||||
const [statusIndex, setStatusIndex] = useState(0)
|
||||
|
||||
|
|
@ -173,6 +180,7 @@ const Content: React.FC = () => {
|
|||
const params = {
|
||||
page: pageNum,
|
||||
size: 10,
|
||||
name: searchTitle,
|
||||
grade: searchGrade,
|
||||
}
|
||||
const data = await getOfficialPage(params)
|
||||
|
|
@ -187,6 +195,15 @@ const Content: React.FC = () => {
|
|||
arr.push(obj)
|
||||
})
|
||||
setList(arr)
|
||||
if (location.search) {
|
||||
const locationData = qs.parse(location.search.slice(1))
|
||||
arr.forEach((item) => {
|
||||
if (item.id === locationData.id) {
|
||||
setDetail(item)
|
||||
setDetailVisible(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
setCount(getTotalPageNum(data.total, data.size))
|
||||
}
|
||||
|
||||
|
|
@ -194,16 +211,19 @@ const Content: React.FC = () => {
|
|||
getData()
|
||||
}, [pageNum, searchGrade])
|
||||
|
||||
useEffect(() => {
|
||||
setPriceSelect({ label: t('Prices go from low to high'), value: '3' })
|
||||
}, [t])
|
||||
|
||||
const handleChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { value } = evt.target
|
||||
setSearchTitle(value)
|
||||
}
|
||||
const searchList = () => {
|
||||
console.log('search')
|
||||
setPage(1)
|
||||
getData()
|
||||
}
|
||||
const showDetail = (val) => {
|
||||
console.log(val)
|
||||
setDetail(val)
|
||||
setDetailVisible(!detailVisible)
|
||||
}
|
||||
|
|
@ -220,10 +240,27 @@ const Content: React.FC = () => {
|
|||
setGrade(grade)
|
||||
setPage(1)
|
||||
}
|
||||
const changePage = (index) => {
|
||||
if (index !== 0) {
|
||||
toastError(t('This page is not currently open'))
|
||||
return
|
||||
}
|
||||
setTypeIndex(index)
|
||||
}
|
||||
const lookDetail = (val) => {
|
||||
setDetail(val)
|
||||
setDetailVisible(true)
|
||||
// detail
|
||||
}
|
||||
|
||||
const closeDetail = () => {
|
||||
history.push('/bazaar')
|
||||
setDetailVisible(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{detailVisible && <ShopDetail detail={detail} typeIndex={typeIndex} close={() => setDetailVisible(false)} />}
|
||||
{detailVisible && <ShopDetail detail={detail} typeIndex={typeIndex} close={closeDetail} />}
|
||||
|
||||
{!detailVisible && (
|
||||
<>
|
||||
|
|
@ -233,7 +270,7 @@ const Content: React.FC = () => {
|
|||
return (
|
||||
<TypeItem
|
||||
key={item.type}
|
||||
onClick={() => setTypeIndex(index)}
|
||||
onClick={() => changePage(index)}
|
||||
className={typeIndex === index ? 'active' : ''}
|
||||
>
|
||||
{item.label}
|
||||
|
|
@ -242,7 +279,7 @@ const Content: React.FC = () => {
|
|||
})}
|
||||
</TypeFlex>
|
||||
|
||||
<HeaderOperation activeIndex={typeIndex} />
|
||||
<HeaderOperation activeIndex={typeIndex} getDetail={(v) => lookDetail(v)} />
|
||||
</HeaderFlex>
|
||||
<Transaction />
|
||||
<StatusFlex>
|
||||
|
|
@ -281,6 +318,7 @@ const Content: React.FC = () => {
|
|||
</Dropdown>
|
||||
</SelectMain>
|
||||
)}
|
||||
{typeIndex !== 0 && (
|
||||
<SelectMain>
|
||||
<Dropdown
|
||||
position="bottom"
|
||||
|
|
@ -300,6 +338,7 @@ const Content: React.FC = () => {
|
|||
})}
|
||||
</Dropdown>
|
||||
</SelectMain>
|
||||
)}
|
||||
</Flex>
|
||||
</StatusFlex>
|
||||
<SearchDiv>
|
||||
|
|
@ -311,9 +350,12 @@ const Content: React.FC = () => {
|
|||
</InputMain>
|
||||
</SearchDiv>
|
||||
<ContentShop list={list} getDetail={(v) => showDetail(v)} />
|
||||
{list.length > 0 && (
|
||||
<Flex justifyContent="center" padding={10}>
|
||||
<Pagination count={count} onChange={pageChange} page={pageNum} />
|
||||
</Flex>
|
||||
)}
|
||||
{list.length === 0 && <Empty />}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import styled, { keyframes } from 'styled-components'
|
|||
import { useTranslation } from 'contexts/Localization'
|
||||
import { formatTimeNumber } from 'utils/formatBalance'
|
||||
import { Flex, Text, Image } from '@pancakeswap/uikit'
|
||||
import useToast from 'hooks/useToast'
|
||||
import { ListProps } from 'types/bazaar'
|
||||
import { useAccount } from 'state/userInfo/hooks'
|
||||
import useRefresh from 'hooks/useRefresh'
|
||||
|
|
@ -67,6 +68,8 @@ const FooterValue = styled(Flex)`
|
|||
|
||||
const ContentShop: React.FC<ContentShop> = ({ list, getDetail }) => {
|
||||
const { t } = useTranslation()
|
||||
const account = useAccount()
|
||||
const { toastSuccess, toastError } = useToast()
|
||||
|
||||
const showDetail = (id) => {
|
||||
getDetail(id)
|
||||
|
|
@ -80,7 +83,7 @@ const ContentShop: React.FC<ContentShop> = ({ list, getDetail }) => {
|
|||
<ShopList
|
||||
item={item}
|
||||
width={278}
|
||||
height={280}
|
||||
height={302}
|
||||
img={item.coverResource.url}
|
||||
grade={item.grade}
|
||||
borderRadius="20px 20px 0 0"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ const FlexDiv = styled(Flex)`
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 14px;
|
||||
& > .linkText:hover {
|
||||
color: #1fc7d4 !important;
|
||||
border-bottom: 1px solid #1fc7d4 !important;
|
||||
}
|
||||
`
|
||||
const TextLink = styled(Text)`
|
||||
cursor: pointer;
|
||||
|
|
@ -46,6 +50,7 @@ const FlexCom: React.FC<FlexProps> = ({
|
|||
color={rightColor}
|
||||
style={{ color: textColor, borderBottom: `1px solid ${textColor}` }}
|
||||
onClick={openPage}
|
||||
className="linkText"
|
||||
>
|
||||
{value}
|
||||
</TextLink>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import SellModal from './SellModal'
|
|||
|
||||
interface HeaderOperationProps {
|
||||
activeIndex?: number
|
||||
getDetail?: (v) => void
|
||||
}
|
||||
|
||||
const HeaderButton = styled(Button)`
|
||||
|
|
@ -34,16 +35,18 @@ const HeaderButton = styled(Button)`
|
|||
}
|
||||
`
|
||||
|
||||
const HeaderOperation: React.FC<HeaderOperationProps> = ({ activeIndex }) => {
|
||||
const HeaderOperation: React.FC<HeaderOperationProps> = ({ activeIndex, getDetail }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [onTransactionRecord] = useModal(<TransactionRecord />)
|
||||
const [onTransactionRecord] = useModal(
|
||||
<TransactionRecord activeIndex={activeIndex} recordDetail={(v) => getDetail(v)} />,
|
||||
)
|
||||
const [onAuctionRecord] = useModal(<AuctionRecord />)
|
||||
const [onSellModal] = useModal(<SellModal />)
|
||||
|
||||
return (
|
||||
<Flex alignContent="center">
|
||||
<HeaderButton onClick={onSellModal}>{t('I sell')}</HeaderButton>
|
||||
<HeaderButton onClick={onSellModal}>{t('I want to sell')}</HeaderButton>
|
||||
{/* 当顶部切换选中的是全部和市场则显示交易记录,选中拍卖时展示拍卖纪录 */}
|
||||
{activeIndex === 2 ? (
|
||||
<HeaderButton onClick={onAuctionRecord}>{t('Auctions a record')}</HeaderButton>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,25 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import styled, { keyframes } from 'styled-components'
|
||||
import styled from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Heading, Flex, Button, Text, Input, Image, useModal } from '@pancakeswap/uikit'
|
||||
import { Flex, Button, Text, Image } from '@pancakeswap/uikit'
|
||||
import { useAccount } from 'state/userInfo/hooks'
|
||||
import useRefresh from 'hooks/useRefresh'
|
||||
import useToast from 'hooks/useToast'
|
||||
import { ListProps } from 'types/bazaar'
|
||||
import { getContract } from 'services/referral'
|
||||
import { checkBuyResult } from 'services/bazaar'
|
||||
import UnlockButton from 'components/UnlockButton'
|
||||
import ShopList from './ShopList'
|
||||
import FlexCom from './FlexCom'
|
||||
import AuctionTable from './AuctionTable'
|
||||
import TransactionTable from './TransactionTable'
|
||||
import AuctionRule from './AuctionRule'
|
||||
import AssetsInfo from './AssetsInfo'
|
||||
import BtnStatus from './BtnStatus'
|
||||
|
||||
interface DetailProps {
|
||||
close: () => void
|
||||
detail: ListProps
|
||||
typeIndex: number | string
|
||||
typeIndex: number
|
||||
}
|
||||
|
||||
const HeaderFlex = styled(Flex)`
|
||||
|
|
@ -35,7 +39,7 @@ const ShopText = styled(Text)`
|
|||
const MainFlex = styled(Flex)`
|
||||
margin-top: 36px;
|
||||
padding: 30px;
|
||||
background: rgba(255, 255, 255, 0.39);
|
||||
background: #fff;
|
||||
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.16);
|
||||
border-radius: 20px;
|
||||
align-items: center;
|
||||
|
|
@ -51,23 +55,17 @@ const MainFlex = styled(Flex)`
|
|||
`
|
||||
const ShopFlex = styled(Flex)`
|
||||
width: 476px;
|
||||
height: 590px;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
box-shadow: 0px 1px 8px rgba(0, 0, 0, 0.15);
|
||||
opacity: 1;
|
||||
border-radius: 20px;
|
||||
position: relative;
|
||||
`
|
||||
const Detail = styled.div`
|
||||
const Detail = styled(Flex)`
|
||||
width: 614px;
|
||||
height: 590px;
|
||||
/* min-height: 580px; */
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
/* height: 590px; */
|
||||
box-sizing: border-box;
|
||||
background: rgba(245, 255, 255, 0.39);
|
||||
box-shadow: 0px 2px 8px rgba(0, 67, 70, 0.15);
|
||||
border-radius: 20px;
|
||||
padding: 20px 30px;
|
||||
margin-left: 30px;
|
||||
${({ theme }) => theme.mediaQueries.xs} {
|
||||
margin-top: 30px;
|
||||
|
|
@ -84,7 +82,6 @@ const TitleText = styled(Text)`
|
|||
font-size: 28px;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
`
|
||||
const PriceButton = styled(Button)`
|
||||
width: 100%;
|
||||
|
|
@ -94,18 +91,78 @@ const PriceButton = styled(Button)`
|
|||
font-size: 16px;
|
||||
margin: 30px 0;
|
||||
`
|
||||
const AuthorizationBtn = styled(Button)`
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background: linear-gradient(269deg, #1fc8d3 0%, #1fd4b0 100%);
|
||||
border-radius: 30px;
|
||||
font-size: 16px;
|
||||
margin: 30px 0;
|
||||
`
|
||||
|
||||
const UnlockButtonDiv = styled(UnlockButton)`
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background: linear-gradient(269deg, #1fc8d3 0%, #1fd4b0 100%);
|
||||
border-radius: 30px;
|
||||
font-size: 16px;
|
||||
margin: 30px 0;
|
||||
`
|
||||
const DetailFlexInfo = styled(Flex)`
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 304px;
|
||||
background: #f5ffff;
|
||||
box-shadow: 0px 2px 8px rgba(0, 67, 70, 0.15);
|
||||
border-radius: 20px;
|
||||
padding: 26px 30px;
|
||||
`
|
||||
const DetailHeaderFlex = styled(Flex)`
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
const ShopDetail: React.FC<DetailProps> = ({ close, detail, typeIndex }) => {
|
||||
const { t } = useTranslation()
|
||||
const [link, setLink] = useState('')
|
||||
const [txId, setTxId] = useState()
|
||||
const [price, setPrice] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const { toastSuccess, toastError } = useToast()
|
||||
const { fastRefresh } = useRefresh()
|
||||
const account = useAccount()
|
||||
useEffect(() => {
|
||||
if (detail.priceList) {
|
||||
const priceList = detail.priceList.map((item) => {
|
||||
return `${Number(item.value).toFixed(3)} ${item.label}`
|
||||
})
|
||||
setPrice(priceList.join('-'))
|
||||
}
|
||||
}, [account])
|
||||
|
||||
const getLinkAddress = async () => {
|
||||
const data = await getContract()
|
||||
setLink(data)
|
||||
const getTransactionResult = async () => {
|
||||
const res = await checkBuyResult({ tx: txId })
|
||||
if (res) {
|
||||
setLoading(false)
|
||||
setTxId(undefined)
|
||||
toastSuccess(t('purchase succeeds'))
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
getLinkAddress()
|
||||
}, [])
|
||||
if (txId && loading) {
|
||||
getTransactionResult()
|
||||
}
|
||||
}, [fastRefresh])
|
||||
|
||||
const getLink = () => {
|
||||
const createInput = document.createElement('input')
|
||||
createInput.value = `${window.location.href}?id=${detail.id}`
|
||||
document.body.appendChild(createInput)
|
||||
createInput.select()
|
||||
document.execCommand('Copy')
|
||||
createInput.remove()
|
||||
toastSuccess(t('Copy success'))
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeaderFlex>
|
||||
|
|
@ -118,52 +175,57 @@ const ShopDetail: React.FC<DetailProps> = ({ close, detail, typeIndex }) => {
|
|||
item={detail}
|
||||
width={476}
|
||||
height={606}
|
||||
img={detail.coverResource.url}
|
||||
img={detail?.coverResource.url}
|
||||
grade={detail.grade}
|
||||
borderRadius="20px"
|
||||
/>
|
||||
</ShopFlex>
|
||||
<Detail>
|
||||
<Flex justifyContent="flex-end">
|
||||
<Image src="/images/nft/share.svg" width={35} height={35} style={{ cursor: 'pointer' }} />
|
||||
</Flex>
|
||||
<DetailFlexInfo>
|
||||
<DetailHeaderFlex>
|
||||
<TitleText>{detail.name}</TitleText>
|
||||
<Image
|
||||
src="/images/nft/share.svg"
|
||||
width={35}
|
||||
height={35}
|
||||
onClick={getLink}
|
||||
style={{ cursor: 'pointer' }}
|
||||
/>
|
||||
</DetailHeaderFlex>
|
||||
{typeIndex !== 0 && (
|
||||
<FlexCom
|
||||
name={t('Auction countdown')}
|
||||
value="10:57:55:79"
|
||||
size="18px"
|
||||
rightSize="30px"
|
||||
textColor="#333333"
|
||||
textColor="#666666"
|
||||
/>
|
||||
)}
|
||||
<FlexCom
|
||||
name={t('present price%price%', { price: '(HCC)=100U' })}
|
||||
value="70.000.000"
|
||||
name={t('present price%price%', { price: '' })}
|
||||
value={price}
|
||||
size="18px"
|
||||
rightSize="30px"
|
||||
textColor="#1FC7D4"
|
||||
/>
|
||||
{typeIndex === 0 ? (
|
||||
<PriceButton>{t('Buy It Now')}</PriceButton>
|
||||
{detail.record ? (
|
||||
''
|
||||
) : typeIndex === 0 ? (
|
||||
!account ? (
|
||||
<UnlockButtonDiv />
|
||||
) : (
|
||||
<BtnStatus detail={detail} />
|
||||
)
|
||||
) : (
|
||||
<PriceButton>{t('Fixed markup (%price% premium)', { price: '10%' })}</PriceButton>
|
||||
)}
|
||||
{typeIndex !== 0 && <FlexCom name={t('owner')} value="钱包地址" />}
|
||||
{/* <FlexCom name={t('Contract address')} value={t('Contract address')} /> */}
|
||||
<FlexCom
|
||||
name={t('Contract address')}
|
||||
typeLink={`https://bscscan.com/token/${link}`}
|
||||
value={`${link && link.substring(0, 6)}...${link && link.substring(link.length - 4, link.length)}`}
|
||||
/>
|
||||
{typeIndex !== 0 && <FlexCom name="token ID" value="token ID" />}
|
||||
<FlexCom name={t('Assets agreement')} value="ERC721" />
|
||||
<FlexCom name={t('Assets and chain')} value="BSC" />
|
||||
</DetailFlexInfo>
|
||||
<AssetsInfo typeIndex={typeIndex} />
|
||||
</Detail>
|
||||
</MainFlex>
|
||||
<AuctionTable />
|
||||
<TransactionTable />
|
||||
<AuctionRule />
|
||||
{typeIndex !== 0 && <AuctionTable />}
|
||||
{typeIndex !== 0 && <TransactionTable />}
|
||||
{typeIndex !== 0 && <AuctionRule />}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import styled, { keyframes } from 'styled-components'
|
||||
import styled from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Flex, Image } from '@pancakeswap/uikit'
|
||||
|
||||
|
|
@ -49,14 +49,25 @@ const ShopItem = styled(Flex)`
|
|||
text-align: center;
|
||||
transform: rotate(-45deg);
|
||||
position: relative;
|
||||
padding: 2px 0;
|
||||
left: -36px;
|
||||
top: 14px;
|
||||
width: 121px;
|
||||
padding: 8px 0;
|
||||
left: -33px;
|
||||
top: 26px;
|
||||
width: 150px;
|
||||
color: white;
|
||||
box-shadow: 0 5px 5px rgba(0, 0, 0, 0.1);
|
||||
letter-spacing: 1px;
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
|
||||
${({ theme }) => theme.mediaQueries.xs} {
|
||||
padding: 2px 0;
|
||||
left: -43px;
|
||||
top: 16px;
|
||||
}
|
||||
${({ theme }) => theme.mediaQueries.lg} {
|
||||
padding: 8px 0;
|
||||
left: -33px;
|
||||
top: 26px;
|
||||
}
|
||||
}
|
||||
& > .epic {
|
||||
background: linear-gradient(-90deg, #efea48 0%, #f32121 100%);
|
||||
|
|
@ -72,10 +83,6 @@ const ShopItem = styled(Flex)`
|
|||
}
|
||||
}
|
||||
`
|
||||
const ItemText = styled(Flex)`
|
||||
padding: 25px 0;
|
||||
justify-content: center;
|
||||
`
|
||||
|
||||
interface ShopListItemProps {
|
||||
item?: Detail
|
||||
|
|
@ -130,10 +137,6 @@ const ShopList: React.FC<ShopListItemProps> = ({
|
|||
{grade === 'RARE' && <div className="ribbon1 uncommon">{t('uncommon')}</div>}
|
||||
{grade === 'NORMAL' && <div className="ribbon1 common">{t('common')}</div>}
|
||||
</div>
|
||||
{/* {item.type === 1 && <Image src="/images/nft/epic-icon.svg" width={width} height={height} />}
|
||||
{item.type === 2 && <Image src="/images/nft/legend-icon.svg" width={width} height={height} />}
|
||||
{item.type === 3 && <Image src="/images/nft/uncommon-icon.svg" width={width} height={height} />}
|
||||
{item.type === 4 && <Image src="/images/nft/box.svg" width={width} height={height} />} */}
|
||||
{img ? (
|
||||
<Image src={img} width={width} height={height} />
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -50,23 +50,23 @@ const Transaction: React.FC = () => {
|
|||
return (
|
||||
<TransactionFlex>
|
||||
<TransactionItem>
|
||||
<TransactionItemNum>1.000000</TransactionItemNum>
|
||||
<TransactionItemNum>0</TransactionItemNum>
|
||||
<TransactionItemLabel>{t('The total volume')}</TransactionItemLabel>
|
||||
</TransactionItem>
|
||||
<Separate />
|
||||
<TransactionItem>
|
||||
<TransactionItemNum>1.000000</TransactionItemNum>
|
||||
<TransactionItemNum>0</TransactionItemNum>
|
||||
<TransactionItemLabel>{t('The total number of transactions')}</TransactionItemLabel>
|
||||
</TransactionItem>
|
||||
<Separate />
|
||||
<TransactionItem>
|
||||
<TransactionItemNum>1.000000</TransactionItemNum>
|
||||
<TransactionItemNum>0</TransactionItemNum>
|
||||
<TransactionItemLabel>{t('Total number of auctions')}</TransactionItemLabel>
|
||||
</TransactionItem>
|
||||
<Separate />
|
||||
<TransactionItem>
|
||||
<TransactionItemNum>1.000000</TransactionItemNum>
|
||||
<TransactionItemLabel>{t('Total auction commission')}</TransactionItemLabel>
|
||||
<TransactionItemNum>0</TransactionItemNum>
|
||||
<TransactionItemLabel>{t('Total transaction rebate')}</TransactionItemLabel>
|
||||
</TransactionItem>
|
||||
</TransactionFlex>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
import React, { useState } from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import styled from 'styled-components'
|
||||
import Pagination from '@mui/material/Pagination'
|
||||
import { Text, Button, Image, Flex } from '@pancakeswap/uikit'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import Empty from 'components/Empty'
|
||||
import { useGetPurchaseRecord, useGetNftDetail } from '../hooks'
|
||||
|
||||
interface TransactionRecordProps {
|
||||
onDismiss?: () => void
|
||||
activeIndex?: number
|
||||
recordDetail?: (v) => void
|
||||
}
|
||||
|
||||
const FlexMain = styled.div`
|
||||
|
|
@ -70,7 +76,10 @@ const ThemedItem = styled.div`
|
|||
color: #666666;
|
||||
border-top: 1px solid #e3e3e3;
|
||||
`
|
||||
const TableBody = styled.div``
|
||||
const TableBody = styled.div`
|
||||
height: 420px;
|
||||
overflow-y: auto;
|
||||
`
|
||||
const TrFlex = styled(Flex)`
|
||||
padding: 10px 0;
|
||||
border-top: 1px solid #e3e3e3;
|
||||
|
|
@ -112,7 +121,7 @@ const HashText = styled(Text)`
|
|||
border-bottom: 1px solid #1fc7d4;
|
||||
`
|
||||
|
||||
const TransactionRecord: React.FC<TransactionRecordProps> = ({ onDismiss }) => {
|
||||
const TransactionRecord: React.FC<TransactionRecordProps> = ({ onDismiss, activeIndex, recordDetail }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const typeList = [
|
||||
|
|
@ -125,14 +134,56 @@ const TransactionRecord: React.FC<TransactionRecordProps> = ({ onDismiss }) => {
|
|||
|
||||
const ThemedList = [t('NFT name'), t('price'), t('Time'), t('state'), t('operation')]
|
||||
|
||||
const list = [
|
||||
{ name: 'Cat goddess Emerald ', icon: '', price: '1', time: '2022-02-02', status: t('Has been selling'), id: '1' },
|
||||
]
|
||||
const [list, setList] = useState([])
|
||||
|
||||
const [pageNum, setPage] = useState(1)
|
||||
const [count, setCount] = useState(undefined)
|
||||
|
||||
const getPurchaseRecord = useGetPurchaseRecord()
|
||||
const getList = async () => {
|
||||
const result = await getPurchaseRecord(pageNum, 10)
|
||||
setCount(getTotalPageNum(result.total, result.size))
|
||||
const arr = []
|
||||
result.content.forEach((item) => {
|
||||
const obj = item
|
||||
obj.priceList = []
|
||||
Object.keys(obj.price).forEach((childItem) => {
|
||||
obj.priceList.push({ label: childItem, value: obj.price[childItem] })
|
||||
})
|
||||
obj.price = undefined
|
||||
arr.push(obj)
|
||||
})
|
||||
setList(arr)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getList()
|
||||
}, [pageNum])
|
||||
|
||||
const pageChange = (event, page) => {
|
||||
setPage(page)
|
||||
}
|
||||
const getTotalPageNum = (total, pageSize) => {
|
||||
const countTotal = ((Number(total) + Number(pageSize) - 1) / Number(pageSize)).toString()
|
||||
return parseInt(countTotal)
|
||||
}
|
||||
const goHash = (val) => {
|
||||
window.open(`https://goerli.etherscan.io/tx/${val.tx}`)
|
||||
}
|
||||
const getNftDetail = useGetNftDetail()
|
||||
const lookDetail = async (item) => {
|
||||
const res = await getNftDetail(item.token, { token: item.token })
|
||||
const obj = res.info
|
||||
obj.record = true
|
||||
recordDetail(obj)
|
||||
onDismiss()
|
||||
}
|
||||
|
||||
return (
|
||||
<FlexMain>
|
||||
<CloseImage src="/images/nft/close.svg" width={15} height={15} onClick={onDismiss} />
|
||||
<HeaderText>{t('transaction record')}</HeaderText>
|
||||
{activeIndex !== 0 && (
|
||||
<TypeFlex>
|
||||
{typeList.map((item, index) => {
|
||||
return (
|
||||
|
|
@ -146,6 +197,7 @@ const TransactionRecord: React.FC<TransactionRecordProps> = ({ onDismiss }) => {
|
|||
)
|
||||
})}
|
||||
</TypeFlex>
|
||||
)}
|
||||
<>
|
||||
<TableThemed>
|
||||
{ThemedList.map((item) => {
|
||||
|
|
@ -153,24 +205,35 @@ const TransactionRecord: React.FC<TransactionRecordProps> = ({ onDismiss }) => {
|
|||
})}
|
||||
</TableThemed>
|
||||
<TableBody>
|
||||
{list.length === 0 && <Empty />}
|
||||
{list.map((item) => {
|
||||
return (
|
||||
<TrFlex key={item.id}>
|
||||
<TdFlex>{item.goodsName}</TdFlex>
|
||||
<TdFlex>
|
||||
<TdImage src="/images/nft/epic-icon.svg" width={24} height={40} />
|
||||
{item.name}
|
||||
{item.priceList.map((childItem, childIndex) => {
|
||||
return (
|
||||
<Flex alignItems="center" key={childItem.label}>
|
||||
<>{Number(childItem.value).toFixed(2)}</>
|
||||
<Text color="text">{childItem.label}</Text>
|
||||
{childIndex === 0 && item.priceList.length === 2 && <Text margin="0 5px">-</Text>}
|
||||
</Flex>
|
||||
)
|
||||
})}
|
||||
</TdFlex>
|
||||
<TdFlex>{item.price}</TdFlex>
|
||||
<TdFlex>{item.time}</TdFlex>
|
||||
<TdFlex>{item.status}</TdFlex>
|
||||
<TdFlex>{dayjs(Number(item.tradeTime)).format('YYYY-MM-DD HH:mm:ss')}</TdFlex>
|
||||
<TdFlex>{item.status ? item.status : t('success')}</TdFlex>
|
||||
<TdBtnFlex>
|
||||
<DetailButton>{t('Detail')}</DetailButton>
|
||||
<HashText>{t('deal Hash')}</HashText>
|
||||
<DetailButton onClick={() => lookDetail(item)}>{t('Detail')}</DetailButton>
|
||||
<HashText onClick={() => goHash(item)}>{t('deal Hash')}</HashText>
|
||||
</TdBtnFlex>
|
||||
</TrFlex>
|
||||
)
|
||||
})}
|
||||
</TableBody>
|
||||
<Flex justifyContent="center" padding={10}>
|
||||
<Pagination count={count} onChange={pageChange} page={pageNum} />
|
||||
</Flex>
|
||||
</>
|
||||
</FlexMain>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import { useCallback } from 'react'
|
||||
import { getOfficialPage } from 'services/bazaar'
|
||||
import { useBlindBox } from 'hooks/useContract'
|
||||
import { getAddress, getBlindBoxAddress } from 'utils/addressHelpers'
|
||||
import { getOfficialPage, getOfficialPurchase, getPurchaseRecord, getNftDetail } from 'services/bazaar'
|
||||
import { ethers, Contract } from 'ethers'
|
||||
|
||||
export const useGetOfficialPage = () => {
|
||||
const data = async (params) => {
|
||||
|
|
@ -9,4 +12,76 @@ export const useGetOfficialPage = () => {
|
|||
return data
|
||||
}
|
||||
|
||||
// 授权usdt
|
||||
export const useApproveUsdt = (tokenContract: Contract) => {
|
||||
const handleApprove = useCallback(async () => {
|
||||
try {
|
||||
const tx = await tokenContract.approve(getBlindBoxAddress(), ethers.constants.MaxUint256)
|
||||
const receipt = await tx.wait()
|
||||
return receipt.status
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}, [tokenContract])
|
||||
|
||||
return { onApprove: handleApprove }
|
||||
}
|
||||
export const useApproveHcc = (tokenContract: Contract) => {
|
||||
const handleApprove = useCallback(async () => {
|
||||
try {
|
||||
const tx = await tokenContract.approve(getBlindBoxAddress(), ethers.constants.MaxUint256)
|
||||
const receipt = await tx.wait()
|
||||
return receipt.status
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}, [tokenContract])
|
||||
|
||||
return { onApprove: handleApprove }
|
||||
}
|
||||
// 购买
|
||||
// export const useGetPurchase = () => {
|
||||
// const data = async (id, params) => {
|
||||
// const result = await getOfficialPurchase(id, params)
|
||||
// console.log(result)
|
||||
// return result
|
||||
// }
|
||||
// return data
|
||||
// }
|
||||
|
||||
// 交易记录
|
||||
export const useGetPurchaseRecord = () => {
|
||||
const data = async (page, size) => {
|
||||
const result = await getPurchaseRecord({ page, size })
|
||||
console.log(result)
|
||||
return result
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// 购买合约
|
||||
export const useBuyTransaction = () => {
|
||||
const blindBox = useBlindBox()
|
||||
const address = getBlindBoxAddress()
|
||||
const transaction = async (id, params) => {
|
||||
const result = await getOfficialPurchase(id, params)
|
||||
const { num, hccPrice, otherPaymentPrice, timestamp, code, type, sign } = result
|
||||
const mintParams = [address, num, hccPrice, otherPaymentPrice, timestamp, code, type, sign]
|
||||
const res = await blindBox.mint(...mintParams)
|
||||
console.log(res)
|
||||
return res
|
||||
}
|
||||
return transaction
|
||||
}
|
||||
|
||||
// 交易详情
|
||||
export const useGetNftDetail = () => {
|
||||
const data = async (token, params) => {
|
||||
const result = await getNftDetail(token, params)
|
||||
console.log(result)
|
||||
return result
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
export default useGetOfficialPage
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import React, { useEffect } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import styled from 'styled-components'
|
||||
import useRefresh from 'hooks/useRefresh'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Flex, Text, useModal } from '@pancakeswap/uikit'
|
||||
import SeriesDetail from './SeriesDetail'
|
||||
|
|
@ -19,18 +21,8 @@ interface DetailProp {
|
|||
|
||||
interface OperationProp {
|
||||
detail: DetailProp
|
||||
totalNumber?: number
|
||||
}
|
||||
// interface listProps {
|
||||
// beginTime?: string
|
||||
// coverResource: coverResourceProps
|
||||
// endTime?: string
|
||||
// id?: string
|
||||
// name?: string
|
||||
// price: priceProps
|
||||
// purchased?: string | number
|
||||
// total?: string | number
|
||||
// type?: string
|
||||
// }
|
||||
interface coverResourceProps {
|
||||
path?: string
|
||||
url?: string
|
||||
|
|
@ -72,17 +64,109 @@ const TipFlex = styled(Flex)`
|
|||
cursor: pointer;
|
||||
`
|
||||
|
||||
const Header: React.FC<OperationProp> = ({ detail }) => {
|
||||
const Header: React.FC<OperationProp> = ({ detail, totalNumber }) => {
|
||||
const { t } = useTranslation()
|
||||
const [onSeriesDetail] = useModal(<SeriesDetail detail={detail} />)
|
||||
const [countDown, setCountDown] = useState('')
|
||||
|
||||
const [quantitativeType, setQuantitativeType] = useState(0)
|
||||
const [timeLimit, setTimeLimit] = useState(0)
|
||||
const { fastRefresh } = useRefresh()
|
||||
useEffect(() => {
|
||||
if (detail.type === 'QUANTITATIVE') {
|
||||
const num = totalNumber
|
||||
switch (new Date(detail.beginTime).getTime() > new Date().getTime()) {
|
||||
case true:
|
||||
setQuantitativeType(0)
|
||||
break
|
||||
case false:
|
||||
if (num > 0) {
|
||||
setQuantitativeType(1)
|
||||
} else {
|
||||
setQuantitativeType(2)
|
||||
}
|
||||
break
|
||||
default:
|
||||
setQuantitativeType(0)
|
||||
}
|
||||
} else {
|
||||
const date2 = dayjs(new Date(detail.endTime).getTime()).diff(dayjs())
|
||||
switch (new Date(detail.beginTime).getTime() > new Date().getTime()) {
|
||||
case true:
|
||||
setTimeLimit(0)
|
||||
break
|
||||
case false:
|
||||
if (date2 > 0) {
|
||||
setTimeLimit(1)
|
||||
} else {
|
||||
setTimeLimit(2)
|
||||
}
|
||||
break
|
||||
default:
|
||||
setTimeLimit(1)
|
||||
}
|
||||
}
|
||||
}, [fastRefresh])
|
||||
|
||||
const countDownFun = (date) => {
|
||||
const date1 = dayjs()
|
||||
const date2 = dayjs(date)
|
||||
const time = date2.diff(date1)
|
||||
if (time > 0) {
|
||||
const hour = Math.floor(time / (1000 * 60 * 60))
|
||||
const minute = Math.floor((time / (1000 * 60)) % 60)
|
||||
const second = Math.round((time / 1000) % 60)
|
||||
setCountDown(`${hour}:${minute}:${second}`)
|
||||
} else {
|
||||
setTimeLimit(2)
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
const date2 = dayjs(new Date(detail.endTime).getTime()).diff(dayjs())
|
||||
if (date2 > 0) {
|
||||
setTimeout(() => {
|
||||
const time = new Date(detail.endTime).getTime() - 1
|
||||
countDownFun(time)
|
||||
}, 1000)
|
||||
} else {
|
||||
setTimeLimit(2)
|
||||
}
|
||||
}, [countDown])
|
||||
|
||||
const getTime = (date) => {
|
||||
const date1 = dayjs()
|
||||
const date2 = dayjs(date)
|
||||
const time = date2.diff(date1)
|
||||
return time
|
||||
}
|
||||
|
||||
return (
|
||||
<HeaderFlex>
|
||||
<div />
|
||||
<div style={{ width: '35px', marginLeft: '20px' }} />
|
||||
{detail.type === 'QUANTITATIVE' && (
|
||||
<>
|
||||
{quantitativeType === 0 && <TextKey>{t('have not started')}</TextKey>}
|
||||
{quantitativeType === 1 && (
|
||||
<Flex>
|
||||
<TextKey>{t('remaining quantity')}</TextKey>
|
||||
<TextVal>{totalNumber}</TextVal>
|
||||
</Flex>
|
||||
)}
|
||||
{quantitativeType === 2 && <TextKey>{t('finished')}</TextKey>}
|
||||
</>
|
||||
)}
|
||||
{detail.type === 'TIME_LIMIT' && (
|
||||
<>
|
||||
{timeLimit === 0 && <TextKey>{t('have not started')}</TextKey>}
|
||||
{timeLimit === 1 && (
|
||||
<Flex>
|
||||
<TextKey>{t('time remaining')}</TextKey>
|
||||
<TextVal>{t('%hour%hour', { hour: 7 })}</TextVal>
|
||||
<TextVal>{countDown}</TextVal>
|
||||
</Flex>
|
||||
)}
|
||||
{timeLimit === 2 && <TextKey>{t('finished')}</TextKey>}
|
||||
</>
|
||||
)}
|
||||
<TipFlex onClick={onSeriesDetail}>?</TipFlex>
|
||||
</HeaderFlex>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,17 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { formatTimeNumber } from 'utils/formatBalance'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Flex, Text } from '@pancakeswap/uikit'
|
||||
import { TOKEN_SYMBOL } from 'config/index'
|
||||
import { ListProp } from 'types/blindBox'
|
||||
import StepCom from './StepCom'
|
||||
|
||||
interface OperationProp {
|
||||
detail: ListProp
|
||||
stepNum: number
|
||||
getNum?: (v) => void
|
||||
}
|
||||
|
||||
const DetailDiv = styled.div`
|
||||
margin-top: -100px;
|
||||
padding-bottom: 45px;
|
||||
`
|
||||
|
||||
|
|
@ -34,13 +31,12 @@ const HeaderText = styled(Text)`
|
|||
margin: 0 5px 0 10px;
|
||||
`
|
||||
|
||||
const Operation: React.FC<OperationProp> = ({ detail, getNum }) => {
|
||||
const Operation: React.FC<OperationProp> = ({ detail, getNum, stepNum }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const getStepValue = (v) => {
|
||||
getNum(v)
|
||||
}
|
||||
|
||||
return (
|
||||
<DetailDiv>
|
||||
<DetailInfo>
|
||||
|
|
@ -53,7 +49,7 @@ const Operation: React.FC<OperationProp> = ({ detail, getNum }) => {
|
|||
{detail.priceList.map((item, index) => {
|
||||
return (
|
||||
<Flex alignItems="center" key={item.label}>
|
||||
<HeaderText>{formatTimeNumber(item.value)}</HeaderText>
|
||||
<HeaderText>{item.value}</HeaderText>
|
||||
<Text color="text">{item.label}</Text>
|
||||
{index === 0 && detail.priceList.length === 2 && <Text marginLeft="10px">-</Text>}
|
||||
</Flex>
|
||||
|
|
@ -63,7 +59,7 @@ const Operation: React.FC<OperationProp> = ({ detail, getNum }) => {
|
|||
</DetailInfo>
|
||||
<DetailInfo>
|
||||
<Text color="textSubtle">{t('quantity')}</Text>
|
||||
<StepCom number={detail.num} value={(v) => getStepValue(v)} />
|
||||
<StepCom number={stepNum} value={(v) => getStepValue(v)} />
|
||||
</DetailInfo>
|
||||
</DetailDiv>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import styled from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Modal, Flex, Text, Image } from '@pancakeswap/uikit'
|
||||
|
|
@ -89,13 +90,17 @@ const SeriesDetail: React.FC<SeriesDetailProp> = ({ name, value, onDismiss, deta
|
|||
const [list, setList] = useState([])
|
||||
const [totalNum, setTotal] = useState(0)
|
||||
const [size, setSize] = useState(0)
|
||||
const [typeStatus, setType] = useState('')
|
||||
const [countDown, setCountDown] = useState('')
|
||||
const [timeLimit, setTimeLimit] = useState(0)
|
||||
const getDetail = useGetBoxDetail()
|
||||
const getData = async () => {
|
||||
const { contentList, total } = await getDetail(detail.id)
|
||||
const { contentList, total, type } = await getDetail(detail.id)
|
||||
setSize(contentList.length)
|
||||
setTotal(total)
|
||||
setType(type)
|
||||
const dataList = []
|
||||
contentList.forEach((item, index) => {
|
||||
contentList.forEach((item) => {
|
||||
const has = dataList.findIndex((o) => o.grade === item.grade)
|
||||
if (has === -1) {
|
||||
dataList.push({
|
||||
|
|
@ -111,13 +116,69 @@ const SeriesDetail: React.FC<SeriesDetailProp> = ({ name, value, onDismiss, deta
|
|||
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, [])
|
||||
if (detail.type === 'TIME_LIMIT') {
|
||||
const date2 = dayjs(new Date(detail.endTime).getTime()).diff(dayjs())
|
||||
switch (new Date(detail.beginTime).getTime() > new Date().getTime()) {
|
||||
case true:
|
||||
setTimeLimit(0)
|
||||
break
|
||||
case false:
|
||||
if (date2 > 0) {
|
||||
setTimeLimit(1)
|
||||
} else {
|
||||
setTimeLimit(2)
|
||||
}
|
||||
break
|
||||
default:
|
||||
setTimeLimit(1)
|
||||
}
|
||||
}
|
||||
}, [detail])
|
||||
|
||||
const countDownFun = (date) => {
|
||||
const date1 = dayjs()
|
||||
const date2 = dayjs(date)
|
||||
const time = date2.diff(date1)
|
||||
if (time > 0) {
|
||||
const hour = Math.floor(time / (1000 * 60 * 60))
|
||||
const minute = Math.floor((time / (1000 * 60)) % 60)
|
||||
const second = Math.round((time / 1000) % 60)
|
||||
setCountDown(`${hour}:${minute}:${second}`)
|
||||
} else {
|
||||
setTimeLimit(2)
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
const date2 = dayjs(new Date(detail.endTime).getTime()).diff(dayjs())
|
||||
if (date2 > 0) {
|
||||
setTimeout(() => {
|
||||
const time = new Date(detail.endTime).getTime() - 1
|
||||
countDownFun(time)
|
||||
}, 1000)
|
||||
} else {
|
||||
setTimeLimit(2)
|
||||
}
|
||||
}, [countDown])
|
||||
|
||||
const getTime = (date) => {
|
||||
const date1 = dayjs()
|
||||
const date2 = dayjs(date)
|
||||
const time = date2.diff(date1)
|
||||
return time
|
||||
}
|
||||
|
||||
return (
|
||||
<Main title={detail.name} onDismiss={onDismiss}>
|
||||
<FlexBetween>
|
||||
<TypeText>{t('limit the quantity of')}</TypeText>
|
||||
<TypeNum>{totalNum}</TypeNum>
|
||||
<TypeText>{detail.type === 'QUANTITATIVE' ? t('limit the quantity of') : t('time limit')}</TypeText>
|
||||
{detail.type === 'QUANTITATIVE' && <TypeNum>{totalNum}</TypeNum>}
|
||||
{detail.type === 'TIME_LIMIT' && (
|
||||
<>
|
||||
{timeLimit === 0 && <TypeNum>{t('have not started')}</TypeNum>}
|
||||
{timeLimit === 1 && <TypeNum>{countDown}</TypeNum>}
|
||||
{timeLimit === 2 && <TypeNum>{t('finished')}</TypeNum>}
|
||||
</>
|
||||
)}
|
||||
</FlexBetween>
|
||||
<Detail>
|
||||
<FlexBetween style={{ paddingRight: '20px' }}>
|
||||
|
|
@ -134,7 +195,7 @@ const SeriesDetail: React.FC<SeriesDetailProp> = ({ name, value, onDismiss, deta
|
|||
{item.grade === 'NORMAL' && <ShopText>{t('common')}</ShopText>}
|
||||
<Shop>
|
||||
{item.list.map((childItem) => {
|
||||
return <ShopList key={childItem.id} item={childItem} grade={item.grade} />
|
||||
return <ShopList key={childItem.id} item={childItem} grade={item.grade} type={typeStatus} />
|
||||
})}
|
||||
</Shop>
|
||||
</ShopMain>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import styled, { keyframes } from 'styled-components'
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Flex, Image } from '@pancakeswap/uikit'
|
||||
import { coverResourceProps } from 'types/blindBox'
|
||||
|
||||
const ShopItem = styled.div`
|
||||
/* height: 358px; */
|
||||
width: 211px;
|
||||
border-radius: 20px;
|
||||
/* background: rgba(255, 255, 255, 0.39);
|
||||
box-shadow: 0px 1px 8px rgba(0, 0, 0, 0.15); */
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
|
|
@ -45,16 +44,16 @@ const ShopItem = styled.div`
|
|||
}
|
||||
}
|
||||
& > .epic {
|
||||
background: linear-gradient(180deg, #efea48 0%, #f32121 100%);
|
||||
background: linear-gradient(110deg, #efea48 0%, #f32121 100%);
|
||||
}
|
||||
& > .legend {
|
||||
background: linear-gradient(180deg, #4b84f5 0%, #bc21f3 100%);
|
||||
background: linear-gradient(110deg, #4b84f5 0%, #bc21f3 100%);
|
||||
}
|
||||
& > .uncommon {
|
||||
background: linear-gradient(180deg, #3dffec 0%, #24bf52 100%);
|
||||
background: linear-gradient(110deg, #3dffec 0%, #24bf52 100%);
|
||||
}
|
||||
& > .common {
|
||||
background: linear-gradient(180deg, #b5e9f3 0%, #1195d9 100%);
|
||||
background: linear-gradient(110deg, #b5e9f3 0%, #1195d9 100%);
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
@ -65,15 +64,17 @@ const ItemText = styled(Flex)`
|
|||
color: #707070;
|
||||
text-align: center;
|
||||
`
|
||||
const ImageType = styled.img`
|
||||
const ImageType = styled(Image)`
|
||||
border-radius: 20px;
|
||||
`
|
||||
const ProbabilityFlex = styled(Flex)`
|
||||
width: 100%;
|
||||
font-size: 26px;
|
||||
justify-content: center;
|
||||
color: #3cbbcc;
|
||||
`
|
||||
const ProbabilityTitle = styled(Flex)`
|
||||
width: 100%;
|
||||
font-size: 18px;
|
||||
color: #666666;
|
||||
margin-top: 5px;
|
||||
|
|
@ -83,16 +84,19 @@ const ProbabilityTitle = styled(Flex)`
|
|||
interface ShopListItemProps {
|
||||
item?: Detail
|
||||
grade?: string
|
||||
type?: string
|
||||
}
|
||||
interface Detail {
|
||||
goodsId?: string
|
||||
grade?: string
|
||||
id?: string
|
||||
num?: string
|
||||
name?: string
|
||||
proportion?: number | string
|
||||
coverResource?: coverResourceProps
|
||||
}
|
||||
|
||||
const ShopList: React.FC<ShopListItemProps> = ({ item, grade }) => {
|
||||
const ShopList: React.FC<ShopListItemProps> = ({ item, grade, type }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
|
|
@ -103,14 +107,10 @@ const ShopList: React.FC<ShopListItemProps> = ({ item, grade }) => {
|
|||
{grade === 'RARE' && <div className="ribbon1 uncommon">{t('uncommon')}</div>}
|
||||
{grade === 'NORMAL' && <div className="ribbon1 common">{t('common')}</div>}
|
||||
</div>
|
||||
{/* <ImageType src="/images/nft/epic.svg" width={211} height={213} /> */}
|
||||
{grade === 'EPIC' && <ImageType src="/images/nft/epic.svg" width={211} height={213} />}
|
||||
{grade === 'LEGEND' && <ImageType src="/images/nft/legend.svg" width={211} height={213} />}
|
||||
{grade === 'RARE' && <ImageType src="/images/nft/uncommon.svg" width={211} height={213} />}
|
||||
{grade === 'NORMAL' && <ImageType src="/images/nft/common.svg" width={211} height={213} />}
|
||||
<ImageType src={item.coverResource.url} width={211} height={213} />
|
||||
<ItemText>{item.name}</ItemText>
|
||||
<ProbabilityFlex>{item.proportion}%</ProbabilityFlex>
|
||||
<ProbabilityTitle>{t('The rate of')}</ProbabilityTitle>
|
||||
<ProbabilityFlex>{type === 'QUANTITATIVE' ? item.num : `${item.proportion}%`}</ProbabilityFlex>
|
||||
<ProbabilityTitle>{type === 'QUANTITATIVE' ? t('quantity') : t('The rate of')}</ProbabilityTitle>
|
||||
</ShopItem>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { Flex, Text, Button } from '@pancakeswap/uikit'
|
||||
|
||||
|
|
@ -32,7 +32,11 @@ interface StepProp {
|
|||
}
|
||||
|
||||
const StepCom: React.FC<StepProp> = ({ number, max = 5, value }) => {
|
||||
const [valNumber, setInputState] = useState(number)
|
||||
const [valNumber, setInputState] = useState(1)
|
||||
|
||||
useEffect(() => {
|
||||
setInputState(number)
|
||||
}, [number])
|
||||
|
||||
const onChange = (type) => {
|
||||
let num = valNumber
|
||||
|
|
@ -42,7 +46,7 @@ const StepCom: React.FC<StepProp> = ({ number, max = 5, value }) => {
|
|||
value(num)
|
||||
setInputState(num)
|
||||
} else {
|
||||
if (valNumber === 0) return
|
||||
if (valNumber === 1) return
|
||||
num -= 1
|
||||
value(num)
|
||||
setInputState(num)
|
||||
|
|
|
|||
|
|
@ -1,16 +1,66 @@
|
|||
import { useCallback } from 'react'
|
||||
import { useHccGiftNft } from 'hooks/useContract'
|
||||
import { useBlindBox } from 'hooks/useContract'
|
||||
import blindBox from 'config/abi/blindBox.json'
|
||||
import useTokenBalance from 'hooks/useTokenBalance'
|
||||
import { getAddress, getBlindBoxAddress } from 'utils/addressHelpers'
|
||||
import multicall from 'utils/multicall'
|
||||
import { ethers, Contract } from 'ethers'
|
||||
import tokensList from 'config/constants/tokens'
|
||||
import useToast from 'hooks/useToast'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { getBoxPage, getBoxDetail, getPurchase } from 'services/blindBox'
|
||||
import { getBalanceNumber, getDecimalAmountNumber } from 'utils/formatBalance'
|
||||
|
||||
export const useCheckTokenBalance = () => {
|
||||
const { balance: usdtTokenBalance } = useTokenBalance(getAddress(tokensList.usdt.address))
|
||||
const { toastWarning } = useToast()
|
||||
const { t } = useTranslation()
|
||||
const onCheck = useCallback(
|
||||
(usdtAmount) => {
|
||||
if (getBalanceNumber(usdtTokenBalance) <= usdtAmount) {
|
||||
toastWarning(t('Insufficient Balance'))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
[usdtTokenBalance],
|
||||
)
|
||||
return [onCheck]
|
||||
}
|
||||
|
||||
export const useCheckHccTokenBalance = () => {
|
||||
const { balance: hccTokenBalance } = useTokenBalance(getAddress(tokensList.hcc.address))
|
||||
const { toastWarning } = useToast()
|
||||
const { t } = useTranslation()
|
||||
const onCheck = useCallback(
|
||||
(hccAmount) => {
|
||||
if (getBalanceNumber(hccTokenBalance) <= hccAmount) {
|
||||
toastWarning(t('Insufficient Balance'))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
[hccTokenBalance],
|
||||
)
|
||||
return [onCheck]
|
||||
}
|
||||
|
||||
// nft盒子
|
||||
export const useGetList = () => {
|
||||
const data = async (page, size) => {
|
||||
const result = await getBoxPage({ page, size })
|
||||
return result
|
||||
const { content } = await getBoxPage({ page, size })
|
||||
const arr = content.map((item) => {
|
||||
const obj = item
|
||||
obj.num = 1
|
||||
obj.priceList = []
|
||||
|
||||
Object.keys(obj.price).forEach((childItem) => {
|
||||
obj.priceList.push({ label: childItem, value: obj.price[childItem] })
|
||||
})
|
||||
obj.price = undefined
|
||||
return obj
|
||||
})
|
||||
return arr
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
|
@ -37,7 +87,7 @@ export const useApproveUsdt = (tokenContract: Contract) => {
|
|||
|
||||
return { onApprove: handleApprove }
|
||||
}
|
||||
export const useApproveHccGiftNft = (tokenContract: Contract) => {
|
||||
export const useApproveHcc = (tokenContract: Contract) => {
|
||||
const handleApprove = useCallback(async () => {
|
||||
try {
|
||||
const tx = await tokenContract.approve(getBlindBoxAddress(), ethers.constants.MaxUint256)
|
||||
|
|
@ -51,13 +101,20 @@ export const useApproveHccGiftNft = (tokenContract: Contract) => {
|
|||
return { onApprove: handleApprove }
|
||||
}
|
||||
|
||||
// 购买
|
||||
export const useGetPurchase = () => {
|
||||
const data = async (id) => {
|
||||
const result = await getPurchase(id)
|
||||
return result
|
||||
// 购买合约
|
||||
export const useBuyTransaction = () => {
|
||||
const blindBoxFun = useBlindBox()
|
||||
const address = getBlindBoxAddress()
|
||||
const transaction = async (id, params) => {
|
||||
const result = await getPurchase(id, params)
|
||||
const { num, hccPrice, otherPaymentPrice, timestamp, code, type, sign, key } = result
|
||||
const mintParams = [address, num, hccPrice, otherPaymentPrice, timestamp, code, type, sign]
|
||||
const res = await blindBoxFun.mint(...mintParams)
|
||||
res.key = key
|
||||
res.code = code
|
||||
return res
|
||||
}
|
||||
return data
|
||||
return transaction
|
||||
}
|
||||
|
||||
export default useGetList
|
||||
|
|
|
|||
|
|
@ -1,20 +1,31 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import styled from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { useAccount } from 'state/userInfo/hooks'
|
||||
import { getAddress } from 'utils/addressHelpers'
|
||||
import { getAddress, getBlindBoxAddress } from 'utils/addressHelpers'
|
||||
import { fetchBlindBoxUserAllowances } from 'state/blindBox'
|
||||
import { useERC20 } from 'hooks/useContract'
|
||||
import UnlockButton from 'components/UnlockButton'
|
||||
import SwiperCore, { Keyboard, Mousewheel, Pagination } from 'swiper'
|
||||
import { Swiper, SwiperSlide } from 'swiper/react'
|
||||
import { Card, Text, Flex, Image, Button } from '@pancakeswap/uikit'
|
||||
import { Flex, Image, Button } from '@pancakeswap/uikit'
|
||||
import { checkBuyResult } from 'services/blindBox'
|
||||
import useRefresh from 'hooks/useRefresh'
|
||||
import useToast from 'hooks/useToast'
|
||||
import { UnOpenModel } from 'components/Modal'
|
||||
import tokens from 'config/constants/tokens'
|
||||
import { ListProp } from 'types/blindBox'
|
||||
import Header from './component/Header'
|
||||
import Operation from './component/Operation'
|
||||
import { useGetList, useApproveHccGiftNft } from './hooks'
|
||||
import {
|
||||
useGetList,
|
||||
useBuyTransaction,
|
||||
useApproveHcc,
|
||||
useApproveUsdt,
|
||||
useCheckHccTokenBalance,
|
||||
useCheckTokenBalance,
|
||||
} from './hooks'
|
||||
|
||||
import 'swiper/swiper.min.css'
|
||||
import 'swiper/components/pagination/pagination.min.css'
|
||||
|
|
@ -29,7 +40,7 @@ const MainFlex = styled(Flex)`
|
|||
`
|
||||
|
||||
const SwiperDiv = styled(Swiper)`
|
||||
height: 730px;
|
||||
height: 750px;
|
||||
position: relative;
|
||||
& > .swiper-wrapper > .swiper-slide > div > div {
|
||||
background: transparent;
|
||||
|
|
@ -38,15 +49,16 @@ const SwiperDiv = styled(Swiper)`
|
|||
.swiper-pagination-custom,
|
||||
.swiper-pagination-fraction {
|
||||
/* position: absolute; */
|
||||
bottom: 130px;
|
||||
bottom: 80px;
|
||||
}
|
||||
& > .swiper-pagination {
|
||||
bottom: 130px !important;
|
||||
display: ${(props) => props.color};
|
||||
bottom: 80px !important;
|
||||
${({ theme }) => theme.mediaQueries.xs} {
|
||||
bottom: 260px !important;
|
||||
bottom: 140px !important;
|
||||
}
|
||||
${({ theme }) => theme.mediaQueries.lg} {
|
||||
bottom: 130px !important;
|
||||
bottom: 80px !important;
|
||||
}
|
||||
& > .swiper-pagination-bullet {
|
||||
background: #fff;
|
||||
|
|
@ -144,29 +156,46 @@ const BuyButton = styled(Button)`
|
|||
}
|
||||
`
|
||||
const AuthorizationBtn = styled(Button)`
|
||||
width: 40%;
|
||||
margin: 20px auto 0px auto;
|
||||
border-radius: 50px;
|
||||
background: linear-gradient(180deg, #7be0fc 0%, #ac7bf1 100%);
|
||||
border: none;
|
||||
width: 500px;
|
||||
height: 45px;
|
||||
background: linear-gradient(180deg, #7be0fc 0%, #9961f0 100%);
|
||||
opacity: 1;
|
||||
border-radius: 23px;
|
||||
margin-top: 10px;
|
||||
${({ theme }) => theme.mediaQueries.xs} {
|
||||
width: 350px;
|
||||
}
|
||||
${({ theme }) => theme.mediaQueries.lg} {
|
||||
width: 500px;
|
||||
}
|
||||
`
|
||||
|
||||
const BlindBox: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [txId, setTxId] = useState()
|
||||
const [keyId, setKeyId] = useState()
|
||||
const [code, setCode] = useState()
|
||||
const [allowanceList, setAllowanceList] = useState({ usdt: 0, hcc: 0 })
|
||||
const [buyVisible, setBuyVisible] = useState(false)
|
||||
const { toastSuccess, toastError } = useToast()
|
||||
const { fastRefresh } = useRefresh()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const account = useAccount()
|
||||
const [blindBoxList, setBlindBoxList] = useState<ListProp[]>()
|
||||
const [buyNum, setBuyNum] = useState(0)
|
||||
const [buyNum, setBuyNum] = useState(1)
|
||||
|
||||
const usdtContract = useERC20(getAddress(tokens.usdt.address))
|
||||
const hccContract = useERC20(getAddress(tokens.hcc.address))
|
||||
const { onApprove: onUsdtApprove } = useApproveHccGiftNft(usdtContract)
|
||||
const { onApprove: onHccApprove } = useApproveHccGiftNft(hccContract)
|
||||
const { onApprove: onUsdtApprove } = useApproveHcc(usdtContract)
|
||||
const { onApprove: onHccApprove } = useApproveHcc(hccContract)
|
||||
|
||||
const getAllowances = async () => {
|
||||
const allowances = await fetchBlindBoxUserAllowances(account)
|
||||
if (allowances.usdt && allowances.hcc) {
|
||||
setBuyVisible(true)
|
||||
}
|
||||
|
||||
setAllowanceList({
|
||||
usdt: allowances.usdt,
|
||||
hcc: allowances.hcc,
|
||||
|
|
@ -187,39 +216,78 @@ const BlindBox: React.FC = () => {
|
|||
const getList = useGetList()
|
||||
|
||||
const getData = async () => {
|
||||
const { content } = await getList(1, 10)
|
||||
const arr = []
|
||||
content.forEach((item) => {
|
||||
const obj = item
|
||||
obj.num = 0
|
||||
obj.priceList = []
|
||||
Object.keys(obj.price).forEach((childItem) => {
|
||||
obj.priceList.push({ label: childItem, value: obj.price[childItem] })
|
||||
})
|
||||
obj.price = undefined
|
||||
arr.push(obj)
|
||||
})
|
||||
const arr = await getList(1, 10)
|
||||
setBlindBoxList(arr)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (account) {
|
||||
getAllowances()
|
||||
}
|
||||
}, [account])
|
||||
|
||||
const buyTransaction = useBuyTransaction()
|
||||
const [onCheckBalanceHcc] = useCheckHccTokenBalance()
|
||||
const [onCheckBalanceUsdt] = useCheckTokenBalance()
|
||||
const handleBuy = async (val) => {
|
||||
if (buyNum === 0) {
|
||||
toastError(t('Please select quantity'))
|
||||
return
|
||||
}
|
||||
let HccBalance = true
|
||||
val.priceList &&
|
||||
val.priceList.forEach((item) => {
|
||||
if (item.label === 'HCC') {
|
||||
HccBalance = onCheckBalanceHcc(Number(item.value))
|
||||
} else {
|
||||
HccBalance = onCheckBalanceUsdt(Number(item.value))
|
||||
}
|
||||
})
|
||||
if (!HccBalance) {
|
||||
return
|
||||
}
|
||||
setLoading(true)
|
||||
const res = await buyTransaction(val.id, {
|
||||
id: val.id,
|
||||
num: buyNum,
|
||||
})
|
||||
setTxId(res.hash)
|
||||
setKeyId(res.key)
|
||||
setCode(res.code)
|
||||
}
|
||||
const getTransactionResult = async () => {
|
||||
const res = await checkBuyResult({ tx: txId, key: keyId, boxId: code })
|
||||
if (res) {
|
||||
setLoading(false)
|
||||
setTxId(undefined)
|
||||
setKeyId(undefined)
|
||||
setCode(undefined)
|
||||
setBuyNum(1)
|
||||
toastSuccess(t('purchase succeeds'))
|
||||
getData()
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
if (txId && loading) {
|
||||
getTransactionResult()
|
||||
}
|
||||
}, [fastRefresh])
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, [])
|
||||
|
||||
const handleBuy = () => {
|
||||
console.log(buyNum)
|
||||
const swiperChange = () => {
|
||||
setBuyNum(1)
|
||||
}
|
||||
const getTime = (date) => {
|
||||
const date1 = dayjs()
|
||||
const date2 = dayjs(date)
|
||||
const time = date2.diff(date1)
|
||||
return time
|
||||
}
|
||||
|
||||
const renderContent = (): JSX.Element => {
|
||||
return (
|
||||
<MainFlex>
|
||||
{/* <UnOpenModel /> */}
|
||||
<SwiperDiv
|
||||
loop
|
||||
pagination={{ clickable: true }}
|
||||
spaceBetween={16}
|
||||
freeModeMomentumRatio={0.25}
|
||||
freeModeMomentumVelocityRatio={0.5}
|
||||
>
|
||||
<>
|
||||
{blindBoxList?.map((item) => {
|
||||
return (
|
||||
<SwiperSlide key={item.id}>
|
||||
|
|
@ -232,12 +300,30 @@ const BlindBox: React.FC = () => {
|
|||
<div className="ribbon1 limitTime">{t('time limit')}</div>
|
||||
)}
|
||||
</div>
|
||||
<Header detail={item} />
|
||||
<Image src={item.coverResource.url} width={500} height={460} marginTop="-40px" />
|
||||
<Operation detail={item} getNum={(v) => setBuyNum(v)} />
|
||||
</BlindBoxCard>
|
||||
{account ? <BuyButton onClick={handleBuy}>{t('Buy It Now')}</BuyButton> : <UnlockButtonDiv />}
|
||||
<Header detail={item} totalNumber={Number(item.total) - Number(item.purchased)} />
|
||||
<Flex justifyContent="center" marginTop={10}>
|
||||
<Image src={item.coverResource.url} width={410} height={370} />
|
||||
</Flex>
|
||||
|
||||
<Operation detail={item} stepNum={buyNum} getNum={(v) => setBuyNum(v)} />
|
||||
</BlindBoxCard>
|
||||
|
||||
{!account && <UnlockButtonDiv />}
|
||||
|
||||
{buyVisible && account && (
|
||||
<BuyButton
|
||||
disabled={
|
||||
new Date(item.beginTime).getTime() > new Date().getTime() ||
|
||||
(item.type === 'TIME_LIMIT' && getTime(item.endTime) <= 0) ||
|
||||
(item.type === 'QUANTITATIVE' && Number(item.total) - Number(item.purchased) <= 0)
|
||||
}
|
||||
onClick={() => handleBuy(item)}
|
||||
>
|
||||
{t('Buy It Now')}
|
||||
</BuyButton>
|
||||
)}
|
||||
|
||||
<Flex style={{ marginTop: '80px', width: '500px' }}>
|
||||
{!allowanceList.usdt && (
|
||||
<AuthorizationBtn
|
||||
disabled={loading}
|
||||
|
|
@ -259,10 +345,28 @@ const BlindBox: React.FC = () => {
|
|||
{t('Approve %coin% Contract', { coin: 'HCC' })}
|
||||
</AuthorizationBtn>
|
||||
)}
|
||||
</Flex>
|
||||
</BlindBoxFlex>
|
||||
</SwiperSlide>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<MainFlex>
|
||||
{/* <UnOpenModel /> */}
|
||||
<SwiperDiv
|
||||
color={blindBoxList?.length === 1 ? 'none' : ''}
|
||||
onSlideChange={swiperChange}
|
||||
loop
|
||||
pagination={{ clickable: true }}
|
||||
spaceBetween={16}
|
||||
freeModeMomentumRatio={0.25}
|
||||
freeModeMomentumVelocityRatio={0.5}
|
||||
>
|
||||
{renderContent()}
|
||||
</SwiperDiv>
|
||||
</MainFlex>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ import { Flex, Text } from '@pancakeswap/uikit'
|
|||
interface FlexProp {
|
||||
name?: string | number
|
||||
value?: string | number
|
||||
marginBottom?: string
|
||||
}
|
||||
|
||||
const FlexText: React.FC<FlexProp> = ({ name, value }) => {
|
||||
const FlexText: React.FC<FlexProp> = ({ name, value, marginBottom = '0px' }) => {
|
||||
return (
|
||||
<Flex justifyContent="space-between">
|
||||
<Flex justifyContent="space-between" style={{ marginBottom }}>
|
||||
<Text fontSize="12px">{name}</Text>
|
||||
<Text fontSize="12px">{value}</Text>
|
||||
</Flex>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
import React from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import styled from 'styled-components'
|
||||
import { Flex, Text, Button } from '@pancakeswap/uikit'
|
||||
import { provider as ProviderType } from 'web3-core'
|
||||
import { getAddress, getHolderPoolAddress } from 'utils/addressHelpers'
|
||||
import { usePriceHccUsdt } from 'state/hooks'
|
||||
import { getBalanceAmount } from 'utils/formatBalance'
|
||||
import { BIG_ZERO } from 'utils/bigNumber'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { useWithdraw } from '../../hooks/useHolderPoolBoard'
|
||||
import CardHeading from './CardHeading'
|
||||
import FlexText from './FlexText'
|
||||
|
||||
const FCard = styled.div`
|
||||
align-self: baseline;
|
||||
background: ${(props) => props.theme.card.background};
|
||||
border-radius: 32px;
|
||||
box-shadow: 0px 2px 30px 0px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
min-height: 410px;
|
||||
`
|
||||
const ContentDiv = styled.div`
|
||||
padding: 0 20px;
|
||||
`
|
||||
const InfoDiv = styled(Flex)`
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
`
|
||||
|
||||
const PriceCoin = styled.div`
|
||||
text-align: right;
|
||||
`
|
||||
|
||||
interface NodeCardProps {
|
||||
board: any
|
||||
removed: boolean
|
||||
provider?: ProviderType
|
||||
account?: string
|
||||
boardsData?: any
|
||||
}
|
||||
|
||||
const HolderPoolBoardCard: React.FC<NodeCardProps> = ({ board, account, boardsData }) => {
|
||||
const { t } = useTranslation()
|
||||
const hccPriceUsdt = usePriceHccUsdt()
|
||||
// const rawEarningsBalance = account ? getBalanceAmount(new BigNumber(board.estimatedProfit)).toNumber() : BIG_ZERO
|
||||
// const displayBalance = rawEarningsBalance.toFixed(3, BigNumber.ROUND_DOWN)
|
||||
|
||||
const withdraw = useWithdraw()
|
||||
const harvest = async () => {
|
||||
const res = await withdraw(account)
|
||||
console.log(res)
|
||||
}
|
||||
|
||||
return (
|
||||
<FCard>
|
||||
<CardHeading
|
||||
name={t(board.name)}
|
||||
img={board.img}
|
||||
tokenSymbol={board.tokenSymbol}
|
||||
amount={board.userData?.amount}
|
||||
/>
|
||||
<ContentDiv>
|
||||
{account && (
|
||||
<InfoDiv>
|
||||
<FlexText marginBottom="10px" name={t('NFT With the total')} value={board.amount as number} />
|
||||
<FlexText
|
||||
marginBottom="10px"
|
||||
name={t('The total amount of dividends')}
|
||||
value={board.receiveReward + board.estimatedProfit}
|
||||
/>
|
||||
<Flex justifyContent="space-between" alignItems="center">
|
||||
<Text fontSize="12px" color="#1FC7D4">
|
||||
{t('Unclaimed income')}
|
||||
</Text>
|
||||
<PriceCoin>
|
||||
<Text fontSize="16px" color="#1FC7D4">
|
||||
{board.estimatedProfit}
|
||||
</Text>
|
||||
<Text fontSize="12px" color="#9BE5EB">
|
||||
{hccPriceUsdt ? (hccPriceUsdt * board.estimatedProfit).toFixed(3) : 0} USDT
|
||||
</Text>
|
||||
</PriceCoin>
|
||||
</Flex>
|
||||
</InfoDiv>
|
||||
)}
|
||||
{/* disabled={Number(displayBalance) <= 0} */}
|
||||
<Button width="100%" onClick={harvest} disabled={board.estimatedProfit <= 0}>
|
||||
{t('Harvest')}
|
||||
</Button>
|
||||
</ContentDiv>
|
||||
</FCard>
|
||||
)
|
||||
}
|
||||
|
||||
export default HolderPoolBoardCard
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
import { useCallback } from 'react'
|
||||
import holderPoolABI from 'config/abi/holderPool.json'
|
||||
import { getHolderPoolAddress } from 'utils/addressHelpers'
|
||||
import { unstakeBoard, unstakeForceBoard } from 'utils/calls'
|
||||
import { useHolderPool } from 'hooks/useContract'
|
||||
import {
|
||||
getBalanceNumber,
|
||||
getDecimalAmount,
|
||||
formatDivNumber,
|
||||
getDecimalAmountNumber,
|
||||
formatTimeNumber,
|
||||
} from 'utils/formatBalance'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import multicall from 'utils/multicall'
|
||||
|
||||
// 获取信息
|
||||
export const useUserInfo = () => {
|
||||
const transaction = async (account) => {
|
||||
const holderPoolAddress = getHolderPoolAddress()
|
||||
const calls = [
|
||||
{
|
||||
address: holderPoolAddress,
|
||||
name: 'userInfo',
|
||||
params: [account],
|
||||
},
|
||||
{
|
||||
address: holderPoolAddress,
|
||||
name: 'pendingHCC',
|
||||
params: [account],
|
||||
},
|
||||
]
|
||||
|
||||
const [userInfo, estimatedProfit] = await multicall(holderPoolABI, calls)
|
||||
return {
|
||||
amount: new BigNumber(userInfo?.amount._hex).toNumber(),
|
||||
receiveReward: getBalanceNumber(userInfo?.receiveReward._hex),
|
||||
rewardDebt: new BigNumber(userInfo?.rewardDebt._hex).toNumber(),
|
||||
estimatedProfit: getBalanceNumber(estimatedProfit),
|
||||
}
|
||||
}
|
||||
return transaction
|
||||
}
|
||||
|
||||
export const useWithdraw = () => {
|
||||
const holderPool = useHolderPool()
|
||||
const transaction = async (account) => {
|
||||
const res = await holderPool.withdrawHCC(account)
|
||||
const receipt = await res.wait()
|
||||
return receipt.status
|
||||
}
|
||||
return transaction
|
||||
}
|
||||
|
||||
export default useUserInfo
|
||||
|
|
@ -2,6 +2,7 @@ import BigNumber from 'bignumber.js'
|
|||
import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react'
|
||||
import { Route, useRouteMatch, useLocation } from 'react-router-dom'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { Address } from 'config/constants/types'
|
||||
import boardsConfig from 'config/constants/boards'
|
||||
import tokens from 'config/constants/tokens'
|
||||
import { getAddress, getBoardAddress } from 'utils/addressHelpers'
|
||||
|
|
@ -21,9 +22,21 @@ import { fetchBoardUserDataAsync, fetchBoardsPublicDataAsync } from 'state/actio
|
|||
import { useAccount } from 'state/userInfo/hooks'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { UnOpenModel } from 'components/Modal'
|
||||
import { useUserInfo } from './hooks/useHolderPoolBoard'
|
||||
import BoardCard from './components/BoardCard/BoardCard'
|
||||
import HolderPoolBoardCard from './components/BoardCard/HolderPoolBoardCard'
|
||||
import HeaderItem from './components/HeaderItem'
|
||||
|
||||
interface userInfoProps {
|
||||
pid?: number
|
||||
name?: string
|
||||
amount?: number
|
||||
receiveReward?: number
|
||||
rewardDebt?: number
|
||||
tokenAddresses?: Address
|
||||
estimatedProfit?: number
|
||||
}
|
||||
|
||||
const PageContent = styled.div`
|
||||
background-image: url('/images/recommend/bg.svg');
|
||||
background-repeat: no-repeat;
|
||||
|
|
@ -75,6 +88,8 @@ const Boards: React.FC = () => {
|
|||
|
||||
const [boardsDataList, setBoardsDataList] = useState([])
|
||||
|
||||
const [nftHolder, setNftHolder] = useState<userInfoProps>({})
|
||||
|
||||
// 获取分红总额
|
||||
const fetchBoardShares = async () => {
|
||||
const boardsData = await Promise.all(
|
||||
|
|
@ -117,7 +132,21 @@ const Boards: React.FC = () => {
|
|||
setTotalAmount(total)
|
||||
setShareOutBonus(totalReward)
|
||||
}
|
||||
const userInfo = useUserInfo()
|
||||
const getUserInfo = async () => {
|
||||
const res = await userInfo(account)
|
||||
setNftHolder({
|
||||
pid: 3,
|
||||
name: 'NFT Holder',
|
||||
amount: res.amount,
|
||||
receiveReward: res.receiveReward,
|
||||
estimatedProfit: res.estimatedProfit,
|
||||
rewardDebt: res.rewardDebt,
|
||||
tokenAddresses: tokens.hcc.address,
|
||||
})
|
||||
}
|
||||
useEffect(() => {
|
||||
getUserInfo()
|
||||
dispatch(fetchBoardsPublicDataAsync())
|
||||
fetchBoardShares()
|
||||
if (account) {
|
||||
|
|
@ -132,6 +161,7 @@ const Boards: React.FC = () => {
|
|||
{boardsList.map((board, index) => (
|
||||
<BoardCard boardsData={boardsDataList[index]} key={board.pid} board={board} account={account} removed />
|
||||
))}
|
||||
{nftHolder.pid && <HolderPoolBoardCard board={nftHolder} account={account} removed />}
|
||||
</FlexLayout>
|
||||
</div>
|
||||
)
|
||||
|
|
@ -139,7 +169,7 @@ const Boards: React.FC = () => {
|
|||
|
||||
return (
|
||||
<PageContent>
|
||||
<UnOpenModel />
|
||||
{/* <UnOpenModel /> */}
|
||||
<Page>
|
||||
<Header>
|
||||
<HeadingText>{t('Total capital pool')}</HeadingText>
|
||||
|
|
|
|||
|
|
@ -164,7 +164,11 @@ const ExchangeCard: React.FC<Props> = ({ status, roundDetail, time }) => {
|
|||
{t('Immediately change')}
|
||||
</Button>
|
||||
) : (
|
||||
<Button width="100%" onClick={immediatelyChange} disabled={status !== 'proceed' || !hccPrice}>
|
||||
<Button
|
||||
width="100%"
|
||||
onClick={immediatelyChange}
|
||||
disabled={status !== 'proceed' || !hccPrice || Number(hccPrice) > roundDetail?.remaining}
|
||||
>
|
||||
{t('Immediately change')}
|
||||
</Button>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Flex, Button, Text, Image } from '@pancakeswap/uikit'
|
||||
import { getContract } from 'services/referral'
|
||||
import FlexCom from './FlexText'
|
||||
|
||||
interface DetailProps {
|
||||
detail: Detail
|
||||
}
|
||||
|
||||
interface Detail {
|
||||
address?: string
|
||||
createdAt?: string
|
||||
id?: string
|
||||
info?: InfoProps
|
||||
metadata?: any
|
||||
token?: string
|
||||
updatedAt?: string
|
||||
}
|
||||
interface InfoProps {
|
||||
coverResource?: CoverResourceProps
|
||||
grade?: string
|
||||
id?: string
|
||||
name?: string
|
||||
price?: any
|
||||
type?: string
|
||||
}
|
||||
interface CoverResourceProps {
|
||||
path?: string
|
||||
url?: string
|
||||
}
|
||||
|
||||
const DetailFlex = styled(Flex)`
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 380px;
|
||||
background-color: #f5ffff;
|
||||
border-radius: 20px;
|
||||
padding: 50px 30px;
|
||||
`
|
||||
const TitleText = styled(Text)`
|
||||
font-size: 28px;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
`
|
||||
const AssetsInfo: React.FC<DetailProps> = ({ detail }) => {
|
||||
const { t } = useTranslation()
|
||||
const [link, setLink] = useState('')
|
||||
|
||||
const getLinkAddress = async () => {
|
||||
const data = await getContract()
|
||||
setLink(data)
|
||||
}
|
||||
useEffect(() => {
|
||||
getLinkAddress()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<DetailFlex>
|
||||
<TitleText>{detail?.info.name}</TitleText>
|
||||
{detail?.info.grade === 'EPIC' && <FlexCom name={t('rarity')} value={t('epic')} />}
|
||||
{detail?.info.grade === 'LEGEND' && <FlexCom name={t('rarity')} value={t('legend')} />}
|
||||
{detail?.info.grade === 'RARE' && <FlexCom name={t('rarity')} value={t('uncommon')} />}
|
||||
{detail?.info.grade === 'NORMAL' && <FlexCom name={t('rarity')} value={t('common')} />}
|
||||
{detail?.info.type === 'PROPS' && <FlexCom name={t('category')} value={t('PROPS')} />}
|
||||
{detail?.info.type === 'GIVING' && <FlexCom name={t('category')} value={t('GIVING')} />}
|
||||
<FlexCom name="NFT TOKEN" value={`#${detail?.token}`} />
|
||||
<FlexCom
|
||||
name={t('Contract address')}
|
||||
typeLink={`https://bscscan.com/token/${link}`}
|
||||
value={`${link && link.substring(0, 6)}...${link && link.substring(link.length - 4, link.length)}`}
|
||||
/>
|
||||
<FlexCom name={t('Assets agreement')} value="ERC721" />
|
||||
<FlexCom name={t('Assets and chain')} value="BSC" />
|
||||
</DetailFlex>
|
||||
)
|
||||
}
|
||||
export default AssetsInfo
|
||||
|
|
@ -5,25 +5,12 @@ import { useTranslation } from 'contexts/Localization'
|
|||
import { Heading, Flex } from '@pancakeswap/uikit'
|
||||
import { useAccount } from 'state/userInfo/hooks'
|
||||
import useRefresh from 'hooks/useRefresh'
|
||||
import Empty from 'components/Empty'
|
||||
import { useGetSelfPage } from '../hooks'
|
||||
import ShopList from './ShopList'
|
||||
import NumMain from './NumMain'
|
||||
|
||||
const aaa = keyframes`
|
||||
0% {
|
||||
background-position: 0 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
`
|
||||
|
||||
const PageContent = styled.div`
|
||||
background: rgba(255, 255, 255, 0.39);
|
||||
padding: 30px 0;
|
||||
/* max-width: 70%; */
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
`
|
||||
|
|
@ -31,7 +18,6 @@ const StatusFlex = styled(Flex)`
|
|||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 30px;
|
||||
/* padding: 0 23px; */
|
||||
& > .active {
|
||||
background: linear-gradient(90deg, #1fd4b0 0%, #1fc9d3 100%);
|
||||
color: #fff;
|
||||
|
|
@ -83,42 +69,53 @@ const Shop = styled.div`
|
|||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
`
|
||||
const MainDiv = styled.div`
|
||||
/* padding: 0 35px; */
|
||||
`
|
||||
|
||||
const NftBox: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const list = [
|
||||
{ label: 'Cat goddess Emerald ', type: 1, id: 1 },
|
||||
{ label: 'Cat goddess Emerald ', type: 2, id: 2 },
|
||||
{ label: 'Cat goddess Emerald ', type: 3, id: 3 },
|
||||
{ label: 'Cat goddess Emerald ', type: 4, id: 4 },
|
||||
{ label: 'Cat goddess Emerald ', type: 1, id: 5 },
|
||||
]
|
||||
const [pageNum, setPage] = useState(1)
|
||||
const [count, setCount] = useState(undefined)
|
||||
|
||||
const [grade, setGrade] = useState('')
|
||||
const [list, setList] = useState([])
|
||||
const status = [
|
||||
{ label: t('All'), id: '1' },
|
||||
{ label: t('epic'), id: '2' },
|
||||
{ label: t('legend'), id: '3' },
|
||||
{ label: t('uncommon'), id: '4' },
|
||||
{ label: t('common'), id: '5' },
|
||||
{ label: t('All'), id: '1', grade: '' },
|
||||
{ label: t('common'), id: '5', grade: 'NORMAL' },
|
||||
{ label: t('uncommon'), id: '4', grade: 'RARE' },
|
||||
{ label: t('epic'), id: '2', grade: 'EPIC' },
|
||||
{ label: t('legend'), id: '3', grade: 'LEGEND' },
|
||||
]
|
||||
const [statusIndex, setStatusIndex] = useState(0)
|
||||
|
||||
const cutStatus = (index) => {
|
||||
setStatusIndex(index)
|
||||
setPage(1)
|
||||
setGrade(status[index].grade)
|
||||
}
|
||||
const pageChange = (event, page) => {
|
||||
console.log(event)
|
||||
console.log(page)
|
||||
setPage(page)
|
||||
}
|
||||
const getSelfPage = useGetSelfPage()
|
||||
const getData = async () => {
|
||||
const params = {
|
||||
page: pageNum,
|
||||
size: 8,
|
||||
grade,
|
||||
}
|
||||
const { size, total, content } = await getSelfPage(params)
|
||||
setList(content)
|
||||
setCount(getTotalPageNum(total, size))
|
||||
}
|
||||
const getTotalPageNum = (total, pageSize) => {
|
||||
const countTotal = ((Number(total) + Number(pageSize) - 1) / Number(pageSize)).toString()
|
||||
return parseInt(countTotal)
|
||||
}
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, [pageNum, grade])
|
||||
|
||||
return (
|
||||
<PageContent>
|
||||
<MainDiv>
|
||||
<NumMain quantity={100} withNumber={100} />
|
||||
</MainDiv>
|
||||
<StatusFlex>
|
||||
{status.map((item, index) => {
|
||||
return (
|
||||
|
|
@ -132,16 +129,19 @@ const NftBox: React.FC = () => {
|
|||
)
|
||||
})}
|
||||
</StatusFlex>
|
||||
<HeadingTitle scale="lg">{t('Did not have')}</HeadingTitle>
|
||||
<HeadingTitle scale="lg">{t('already owned')}</HeadingTitle>
|
||||
{/* 商品 */}
|
||||
<Shop>
|
||||
{list.map((item) => {
|
||||
return <ShopList item={item} />
|
||||
return <ShopList item={item} key={item.id} />
|
||||
})}
|
||||
</Shop>
|
||||
<Flex justifyContent="center">
|
||||
<Pagination count={10} onChange={pageChange} />
|
||||
{list.length > 0 && (
|
||||
<Flex justifyContent="center" padding={10}>
|
||||
<Pagination count={count} onChange={pageChange} page={pageNum} />
|
||||
</Flex>
|
||||
)}
|
||||
{list.length === 0 && <Empty />}
|
||||
</PageContent>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,15 @@
|
|||
import React from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Modal, Flex, Text, Image, Button } from '@pancakeswap/uikit'
|
||||
import FlexText from './FlexText'
|
||||
import { useGetNftDetails } from '../hooks'
|
||||
import AssetsInfo from './AssetsInfo'
|
||||
|
||||
interface DetailProp {
|
||||
item?: Detail
|
||||
token?: string
|
||||
onDismiss?: () => void
|
||||
}
|
||||
|
||||
interface Detail {
|
||||
label?: string
|
||||
type?: number | string
|
||||
id?: number | string
|
||||
}
|
||||
const Main = styled(Modal)`
|
||||
width: 1050px;
|
||||
background-color: #fff;
|
||||
|
|
@ -58,7 +54,6 @@ const MainFlex = styled(Flex)`
|
|||
}
|
||||
`
|
||||
const ShopItem = styled(Flex)`
|
||||
/* height: 358px; */
|
||||
border-radius: 20px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
|
@ -134,18 +129,6 @@ const DetailFlex = styled(Flex)`
|
|||
margin-top: 0px;
|
||||
}
|
||||
`
|
||||
const CardMain = styled.div`
|
||||
height: 380px;
|
||||
background-color: #f5ffff;
|
||||
border-radius: 20px;
|
||||
padding: 50px 30px;
|
||||
`
|
||||
|
||||
const TitleText = styled(Text)`
|
||||
font-size: 28px;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
`
|
||||
|
||||
const SellButton = styled(Button)`
|
||||
height: 60px;
|
||||
|
|
@ -160,55 +143,34 @@ const CenterDiv = styled.div`
|
|||
overflow-y: auto;
|
||||
`
|
||||
|
||||
const DetailModal: React.FC<DetailProp> = ({ item, onDismiss }) => {
|
||||
const DetailModal: React.FC<DetailProp> = ({ token, onDismiss }) => {
|
||||
const { t } = useTranslation()
|
||||
const getNftDetail = useGetNftDetails()
|
||||
const [detail, setDetail] = useState(undefined)
|
||||
|
||||
const getClassBcg = () => {
|
||||
let bcg = ''
|
||||
switch (item.type) {
|
||||
case 1:
|
||||
bcg = 'epicBcg'
|
||||
break
|
||||
case 2:
|
||||
bcg = 'legendBcg'
|
||||
break
|
||||
case 3:
|
||||
bcg = 'uncommonBcg'
|
||||
break
|
||||
case 4:
|
||||
bcg = 'commonBcg'
|
||||
break
|
||||
default:
|
||||
bcg = 'epicBcg'
|
||||
}
|
||||
return bcg
|
||||
const getDetail = async () => {
|
||||
const res = await getNftDetail(token, { token })
|
||||
setDetail(res)
|
||||
}
|
||||
useEffect(() => {
|
||||
getDetail()
|
||||
}, [token])
|
||||
|
||||
return (
|
||||
<Main title="" onDismiss={onDismiss}>
|
||||
<CenterDiv>
|
||||
<MainFlex>
|
||||
<ShopItem className={getClassBcg()}>
|
||||
<ShopItem>
|
||||
<div className="ribbon">
|
||||
{item.type === 1 && <div className="ribbon1 epic">{t('epic')}</div>}
|
||||
{item.type === 2 && <div className="ribbon1 legend">{t('legend')}</div>}
|
||||
{item.type === 3 && <div className="ribbon1 uncommon">{t('uncommon')}</div>}
|
||||
{item.type === 4 && <div className="ribbon1 common">{t('common')}</div>}
|
||||
{detail?.info.grade === 'EPIC' && <div className="ribbon1 epic">{t('epic')}</div>}
|
||||
{detail?.info.grade === 'LEGEND' && <div className="ribbon1 legend">{t('legend')}</div>}
|
||||
{detail?.info.grade === 'RARE' && <div className="ribbon1 uncommon">{t('uncommon')}</div>}
|
||||
{detail?.info.grade === 'NORMAL' && <div className="ribbon1 common">{t('common')}</div>}
|
||||
</div>
|
||||
{item.type === 1 && <Image src="/images/nft/epic-icon.svg" width={267} height={405} />}
|
||||
{item.type === 2 && <Image src="/images/nft/legend-icon.svg" width={267} height={405} />}
|
||||
{item.type === 3 && <Image src="/images/nft/uncommon-icon.svg" width={267} height={405} />}
|
||||
{item.type === 4 && <Image src="/images/nft/box.svg" width={267} height={405} />}
|
||||
<Image src={detail?.info.coverResource.url} width={400} height={510} />
|
||||
</ShopItem>
|
||||
<DetailFlex>
|
||||
<CardMain>
|
||||
<TitleText>Cat goddess Emerald</TitleText>
|
||||
<FlexText title={t('Total quantity of ownership')} value="10000" marginTop="58px" />
|
||||
<FlexText title="NFT TOKEN" value="10000" />
|
||||
<FlexText title={t('Contract address')} value="合约地址" />
|
||||
<FlexText title={t('Assets agreement')} value="资产协议" />
|
||||
<FlexText title={t('Assets and chain')} value="资产公链" />
|
||||
</CardMain>
|
||||
<AssetsInfo detail={detail} />
|
||||
<SellButton>{t('Selling immediately')}</SellButton>
|
||||
</DetailFlex>
|
||||
</MainFlex>
|
||||
|
|
|
|||
|
|
@ -1,29 +1,63 @@
|
|||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { useTranslation } from 'contexts/Localization'
|
||||
import { Text, Flex } from '@pancakeswap/uikit'
|
||||
import { Flex, Text, Link } from '@pancakeswap/uikit'
|
||||
|
||||
interface FlexProp {
|
||||
title: number | string
|
||||
value: number | string
|
||||
marginTop?: string
|
||||
fontSize?: string
|
||||
color?: string
|
||||
interface FlexProps {
|
||||
name: string
|
||||
value: string
|
||||
paddings?: string
|
||||
leftColor?: string
|
||||
rightColor?: string
|
||||
typeLink?: string
|
||||
size?: string
|
||||
textColor?: string
|
||||
rightSize?: string
|
||||
}
|
||||
|
||||
const MainFlex = styled(Flex)`
|
||||
font-size: 14px;
|
||||
color: #666666;
|
||||
align-items: center;
|
||||
const FlexDiv = styled(Flex)`
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 14px;
|
||||
& > .linkText:hover {
|
||||
color: #1fc7d4 !important;
|
||||
border-bottom: 1px solid #1fc7d4 !important;
|
||||
}
|
||||
`
|
||||
const TextLink = styled(Text)`
|
||||
cursor: pointer;
|
||||
`
|
||||
|
||||
const FlexText: React.FC<FlexProp> = ({ title, value, marginTop = '20px', color = '#666666', fontSize = '14px' }) => {
|
||||
const FlexCom: React.FC<FlexProps> = ({
|
||||
name,
|
||||
value,
|
||||
paddings = '0px',
|
||||
leftColor = '#666666',
|
||||
rightColor = 'textSubtle',
|
||||
typeLink,
|
||||
size = '14px',
|
||||
textColor = '#666666',
|
||||
rightSize = '14px',
|
||||
}) => {
|
||||
const openPage = () => {
|
||||
window.open(typeLink)
|
||||
}
|
||||
|
||||
return (
|
||||
<MainFlex style={{ marginTop }}>
|
||||
<Text style={{ fontSize, color }}>{title}</Text>
|
||||
<Text style={{ fontSize, color }}>{value}</Text>
|
||||
</MainFlex>
|
||||
<FlexDiv style={{ padding: paddings }}>
|
||||
<Text style={{ fontSize: size, color: leftColor }}>{name}</Text>
|
||||
{typeLink ? (
|
||||
<TextLink
|
||||
color={rightColor}
|
||||
style={{ color: textColor, borderBottom: `1px solid ${textColor}` }}
|
||||
onClick={openPage}
|
||||
className="linkText"
|
||||
>
|
||||
{value}
|
||||
</TextLink>
|
||||
) : (
|
||||
<Text style={{ color: textColor, fontSize: rightSize }}>{value}</Text>
|
||||
)}
|
||||
</FlexDiv>
|
||||
)
|
||||
}
|
||||
export default FlexText
|
||||
export default FlexCom
|
||||
|
|
|
|||
|
|
@ -59,28 +59,40 @@ interface ShopListItemProps {
|
|||
item?: Detail
|
||||
}
|
||||
interface Detail {
|
||||
label?: string
|
||||
type?: number | string
|
||||
id?: number | string
|
||||
address?: string
|
||||
createdAt?: string
|
||||
id?: string
|
||||
info: InfoProps
|
||||
token?: string
|
||||
updatedAt?: string
|
||||
}
|
||||
interface InfoProps {
|
||||
coverResource?: CoverResourceProps
|
||||
grade?: string
|
||||
id?: string
|
||||
name?: string
|
||||
price?: any
|
||||
type?: string
|
||||
}
|
||||
interface CoverResourceProps {
|
||||
path?: string
|
||||
url?: string
|
||||
}
|
||||
|
||||
const ShopList: React.FC<ShopListItemProps> = ({ item }) => {
|
||||
const { t } = useTranslation()
|
||||
const [onDetailModal] = useModal(<DetailModal item={item} />)
|
||||
const [onDetailModal] = useModal(<DetailModal token={item.token} />)
|
||||
|
||||
return (
|
||||
<ShopItem key={item.id} onClick={onDetailModal}>
|
||||
<div className="ribbon">
|
||||
{item.type === 1 && <div className="ribbon1 epic">{t('epic')}</div>}
|
||||
{item.type === 2 && <div className="ribbon1 legend">{t('legend')}</div>}
|
||||
{item.type === 3 && <div className="ribbon1 uncommon">{t('uncommon')}</div>}
|
||||
{item.type === 4 && <div className="ribbon1 common">{t('common')}</div>}
|
||||
{item.info.grade === 'EPIC' && <div className="ribbon1 epic">{t('epic')}</div>}
|
||||
{item.info.grade === 'LEGEND' && <div className="ribbon1 legend">{t('legend')}</div>}
|
||||
{item.info.grade === 'RARE' && <div className="ribbon1 uncommon">{t('uncommon')}</div>}
|
||||
{item.info.grade === 'NORMAL' && <div className="ribbon1 common">{t('common')}</div>}
|
||||
</div>
|
||||
{item.type === 1 && <Image src="/images/nft/epic.svg" width={278} height={280} />}
|
||||
{item.type === 2 && <Image src="/images/nft/legend.svg" width={278} height={280} />}
|
||||
{item.type === 3 && <Image src="/images/nft/uncommon.svg" width={278} height={280} />}
|
||||
{item.type === 4 && <Image src="/images/nft/common.svg" width={278} height={280} />}
|
||||
<ItemText>{item.label}</ItemText>
|
||||
<Image src={item.info.coverResource.url} width={278} height={302} />
|
||||
<ItemText>{item.info.name}</ItemText>
|
||||
</ShopItem>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
import { useCallback } from 'react'
|
||||
import { useBlindBox } from 'hooks/useContract'
|
||||
import { getAddress, getBlindBoxAddress } from 'utils/addressHelpers'
|
||||
import { getSelfPage, getNftDetails } from 'services/nftBox'
|
||||
import { ethers, Contract } from 'ethers'
|
||||
|
||||
export const useGetSelfPage = () => {
|
||||
const data = async (params) => {
|
||||
const result = await getSelfPage(params)
|
||||
return result
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// export const useGetNftDetail = () => {
|
||||
// const data = async (token, params) => {
|
||||
// const result = await getNftDetail(token, params)
|
||||
// console.log(result)
|
||||
// return result
|
||||
// }
|
||||
// return data
|
||||
// }
|
||||
|
||||
export const useGetNftDetails = () => {
|
||||
const data = async (token, params) => {
|
||||
const result = await getNftDetails(token, params)
|
||||
return result
|
||||
}
|
||||
return data
|
||||
}
|
||||
export default useGetSelfPage
|
||||
|
|
@ -6,8 +6,10 @@ import { UnOpenModel } from 'components/Modal'
|
|||
import Box from './components/Box'
|
||||
|
||||
const PageContent = styled.div`
|
||||
background: rgba(255, 255, 255, 0.39);
|
||||
min-height: calc(100vh - 64px);
|
||||
background-image: url('/images/home/bg.svg');
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
/* background-image: url('/images/page/nftBox.jpg');
|
||||
background-position: 50%;
|
||||
|
|
|
|||
Loading…
Reference in New Issue