From 0386b93bb747da10b7dfeee16712e2622485fcd6 Mon Sep 17 00:00:00 2001 From: eericxu <2681350846@qq.com> Date: Thu, 12 Sep 2024 16:50:57 +0800 Subject: [PATCH] fix claim --- lib/http/types.d.ts | 1 + pages/user.tsx | 541 ++++++++++++++++++++++++-------------------- 2 files changed, 295 insertions(+), 247 deletions(-) diff --git a/lib/http/types.d.ts b/lib/http/types.d.ts index 00bcf8c7..7aeb718d 100644 --- a/lib/http/types.d.ts +++ b/lib/http/types.d.ts @@ -27,6 +27,7 @@ export interface DepositDTO { share_from: string, deposit_state: number,// 1 deposited, 2 pendingRedeem expire_timestamp: number, + expire_block_number: number, extrinsic_hash: string, } diff --git a/pages/user.tsx b/pages/user.tsx index bdfd77b7..08112dc1 100644 --- a/pages/user.tsx +++ b/pages/user.tsx @@ -1,302 +1,351 @@ -import classNames from 'classnames'; -import { format } from 'date-fns'; -import { toBlob } from 'html-to-image'; -import _ from 'lodash'; +import classNames from "classnames"; +import { format } from "date-fns"; +import { toBlob } from "html-to-image"; +import _ from "lodash"; import React, { useEffect, useMemo, useRef, useState } from "react"; -import { Loader } from 'semantic-ui-react'; +import { Loader } from "semantic-ui-react"; import styled from "styled-components"; -import { BindAirdrop } from '../components/BindAirdrop'; +import { BindAirdrop } from "../components/BindAirdrop"; import Btn from "../components/Btn"; -import { Badge } from '../components/effect/Badge'; -import { BadgeIcon1, BadgeIcon2 } from '../components/icons'; -import { ColFlex } from '../components/layout'; +import { Badge } from "../components/effect/Badge"; +import { BadgeIcon1, BadgeIcon2 } from "../components/icons"; +import { ColFlex } from "../components/layout"; import { MCard } from "../components/MCard"; -import PageUserSideLayout from '../components/PageUserSideLayout'; -import { useApp } from '../lib/AppContext'; -import { CrustWalletDownUrl } from '../lib/config'; +import PageUserSideLayout from "../components/PageUserSideLayout"; +import { useApp } from "../lib/AppContext"; +import { CrustWalletDownUrl } from "../lib/config"; import { useClaim, useDeposit } from "../lib/hooks/useDeposit"; import { useGet } from "../lib/hooks/useGet"; -import { useGetDepost } from '../lib/hooks/useGetDeposit'; -import { useSafeState } from '../lib/hooks/useSafeState'; +import { useGetDepost } from "../lib/hooks/useGetDeposit"; +import { useSafeState } from "../lib/hooks/useSafeState"; import { getAccountByNickName, getDepositAddress, getNft, getShareEarnConfig, saveNft } from "../lib/http/share_earn"; -import { BlobFile } from '../lib/types'; -import { useAuthGateway, useAuthPinner } from '../lib/useAuth'; -import { useUpload } from '../lib/useUpload'; -import { formatCRU, trimZero } from '../lib/utils'; -import { useContextWrapLoginUser } from '../lib/wallet/hooks'; -import { GetNickname } from '../components/GetNickname'; - +import { BlobFile } from "../lib/types"; +import { useAuthGateway, useAuthPinner } from "../lib/useAuth"; +import { useUpload } from "../lib/useUpload"; +import { formatCRU, trimZero } from "../lib/utils"; +import { useContextWrapLoginUser } from "../lib/wallet/hooks"; +import { GetNickname } from "../components/GetNickname"; +import { useCall } from "../lib/hooks/useCall"; +import { BlockNumber } from "@polkadot/types/interfaces/types"; export interface Props { - className?: string + className?: string; } function Index(props: Props) { - const { className } = props - const { alert, loading } = useApp() - const wUser = useContextWrapLoginUser() - const { isCrust, isPremiumUser, deposit, doGetDeposit, hasDeposit, user, loading: isLoadingDeposit } = useGetDepost() - const [nickStat, setNickStat] = useSafeState<{ error?: string, shareFrom?: string, checking: boolean }>({ checking: false }) - const [inputNickname, setInputNickname] = useState() - const _onChangeNickname = (e) => setInputNickname(e.target.value) + const { className } = props; + const { alert, loading, api } = useApp(); + const wUser = useContextWrapLoginUser(); + const { isCrust, isPremiumUser, deposit, doGetDeposit, hasDeposit, user, loading: isLoadingDeposit } = useGetDepost(); + const [nickStat, setNickStat] = useSafeState<{ error?: string; shareFrom?: string; checking: boolean }>({ checking: false }); + const [inputNickname, setInputNickname] = useState(); + const _onChangeNickname = (e) => setInputNickname(e.target.value); const doChangeNickname = useMemo(() => { return _.debounce((nickName: string) => { - setNickStat({ checking: true }) + setNickStat({ checking: true }); if (nickName) { getAccountByNickName(nickName) .then((account) => { if (account !== user.account) { - setNickStat({ checking: false, shareFrom: account }) + setNickStat({ checking: false, shareFrom: account }); } else { - setNickStat({ checking: false, error: `It can't be your own` }) + setNickStat({ checking: false, error: `It can't be your own` }); } }) - .catch(() => setNickStat({ checking: false, error: 'Not found' })) + .catch(() => setNickStat({ checking: false, error: "Not found" })); } else { - setNickStat({ checking: false }) + setNickStat({ checking: false }); } - }, 500) - }, [user.account]) + }, 500); + }, [user.account]); useEffect(() => { - setNickStat({ checking: true }) - doChangeNickname(inputNickname) - }, [inputNickname]) - + setNickStat({ checking: true }); + doChangeNickname(inputNickname); + }, [inputNickname]); + const bestNum = useCall(api?.derive?.chain?.bestNumber); + const bestNumber = bestNum && bestNum.toNumber(); // - const [value, setValue] = useState() - const [config, _doRegetConfig, isLoadingConfig] = useGet(() => getShareEarnConfig()) - const showBasePrice = config && config.showBase - const showDeposit = isCrust && !hasDeposit - const showClaim = isCrust && hasDeposit - const [dest, _doRegetDepositAddress, isLoadingDepositAddress] = useGet(() => getDepositAddress()) - const showPremiumLoading = isLoadingDeposit || wUser.isLoadingNickname || isLoadingConfig || isLoadingDepositAddress - const fValue = useMemo(() => formatCRU(value), [value]) - const cTime = useMemo(() => new Date().getTime() / 1000, []) + const [value, setValue] = useState(); + const [config, _doRegetConfig, isLoadingConfig] = useGet(() => getShareEarnConfig()); + const showBasePrice = config && config.showBase; + const showDeposit = isCrust && !hasDeposit; + const showClaim = isCrust && hasDeposit; + const [dest, _doRegetDepositAddress, isLoadingDepositAddress] = useGet(() => getDepositAddress()); + const showPremiumLoading = isLoadingDeposit || wUser.isLoadingNickname || isLoadingConfig || isLoadingDepositAddress; + const fValue = useMemo(() => formatCRU(value), [value]); + const cTime = useMemo(() => new Date().getTime() / 1000, []); const fCalimValue = useMemo(() => { - if (!hasDeposit) return '-' + if (!hasDeposit) return "-"; // 提前赎回 // if (deposit.deposit.expire_timestamp > cTime) { // return trimZero(deposit.deposit.claim_amount) // } - return trimZero(deposit.deposit.deposit_amount) - }, [hasDeposit, cTime]) - const guaranteeAmount = useMemo(() => formatCRU(config?.guaranteeAmount || ''), [config]) - const guaranteeDiscountWithReferer = useMemo(() => formatCRU(config?.guaranteeDiscountWithReferer || ''), [config]) - const baseGuaranteeAmount = useMemo(() => formatCRU(config?.baseGuaranteeAmount || ''), [config]) - const baseGuaranteeDiscountWithReferer = useMemo(() => formatCRU(config?.baseGuaranteeDiscountWithReferer || ''), [config]) - const days = useMemo(() => { - if (!config) return '-' - const s = new Number(config.guaranteePeriod).valueOf() - return Math.round(s / 60 / 60 / 24) - }, [config]) - const periodTime = useMemo(() => { - if (!hasDeposit) return '--:--:--' - return format(deposit.deposit.expire_timestamp * 1000, "yyyy-MM-dd") - }, [hasDeposit, deposit]) + return trimZero(deposit.deposit.deposit_amount); + }, [hasDeposit, cTime]); + const guaranteeAmount = useMemo(() => formatCRU(config?.guaranteeAmount || ""), [config]); + const guaranteeDiscountWithReferer = useMemo(() => formatCRU(config?.guaranteeDiscountWithReferer || ""), [config]); + const baseGuaranteeAmount = useMemo(() => formatCRU(config?.baseGuaranteeAmount || ""), [config]); + const baseGuaranteeDiscountWithReferer = useMemo(() => formatCRU(config?.baseGuaranteeDiscountWithReferer || ""), [config]); + const [periodTime, days] = useMemo(() => { + if (!hasDeposit || !bestNumber) return "--:--:--"; + const timeSecends = deposit.deposit.expire_block_number > bestNumber ? (deposit.deposit.expire_block_number - bestNumber) * 6 : 0; + const fmtTime = format((timeSecends > 0 ? cTime + timeSecends : deposit.deposit.expire_timestamp) * 1000, "yyyy-MM-dd"); + const fmtDays = Math.round(timeSecends / 60 / 60 / 24); + return [fmtTime, fmtDays]; + }, [hasDeposit, deposit, cTime, bestNumber]); useEffect(() => { - if (!config) return + if (!config) return; if (nickStat.shareFrom) { - setValue(config.guaranteeDiscountWithReferer) + setValue(config.guaranteeDiscountWithReferer); } else { - setValue(config.guaranteeAmount) + setValue(config.guaranteeAmount); } - }, [config, nickStat.shareFrom]) + }, [config, nickStat.shareFrom]); - const uDeposit = useDeposit(dest, value, nickStat.shareFrom) - const uClaim = useClaim() + const uDeposit = useDeposit(dest, value, nickStat.shareFrom); + const uClaim = useClaim(); useEffect(() => { - let task + let task; if (uDeposit.finish || uClaim.finish) { - let count = 3 + let count = 3; task = setInterval(() => { if (count <= 0) { - clearInterval(task) + clearInterval(task); return; } count -= 1; - doGetDeposit() - }, 5000) + doGetDeposit(); + }, 5000); } - return () => task && clearInterval(task) - }, [uDeposit.finish, uClaim.finish]) + return () => task && clearInterval(task); + }, [uDeposit.finish, uClaim.finish]); - const onGoingDeposit = uDeposit.finish || (deposit && deposit.depositOngoing) - const disabledDeposit = !uDeposit.ready || !value || onGoingDeposit || nickStat.checking - const onGoingClaim = uClaim.finish || (deposit && deposit.claimOngoing) - const disabledClaim = !uClaim.ready || onGoingClaim || (hasDeposit && deposit.deposit.expire_timestamp >= cTime) - const _onClickDownCrustWallet = () => window.open(CrustWalletDownUrl, '_blank') - const _onClickDeposit = () => { !disabledDeposit && uDeposit.start() } - const _onClickClaim = () => { !disabledClaim && uClaim.start() } + const onGoingDeposit = uDeposit.finish || (deposit && deposit.depositOngoing); + const disabledDeposit = !uDeposit.ready || !value || onGoingDeposit || nickStat.checking; + const onGoingClaim = uClaim.finish || (deposit && deposit.claimOngoing); + const disabledClaim = !uClaim.ready || onGoingClaim || (hasDeposit && bestNumber && deposit.deposit.expire_block_number > bestNumber); + const _onClickDownCrustWallet = () => window.open(CrustWalletDownUrl, "_blank"); + const _onClickDeposit = () => { + !disabledDeposit && uDeposit.start(); + }; + const _onClickClaim = () => { + !disabledClaim && uClaim.start(); + }; - const { endpoint } = useAuthGateway() - const { pinner } = useAuthPinner() + const { endpoint } = useAuthGateway(); + const { pinner } = useAuthPinner(); const { upload, error } = useUpload(user, { endpoint, - pinner - }) + pinner, + }); useEffect(() => { - if (error) alert.error(error) - }, [error]) + if (error) alert.error(error); + }, [error]); const badgeRef = useRef(); const diabledGetBadge = !isPremiumUser && !badgeRef.current; - const [nft, doGetNft, loadNft] = useGet(() => getNft(user.account), [isCrust, isPremiumUser, user.account]) - const badgeCID = _.get(nft, '0.cid') + const [nft, doGetNft, loadNft] = useGet(() => getNft(user.account), [isCrust, isPremiumUser, user.account]); + const badgeCID = _.get(nft, "0.cid"); const hasBadge = !!badgeCID; - const badgeEnpoint = endpoint.value - const badgeFileName = `badge_nft_${user.nickName}` + const badgeEnpoint = endpoint.value; + const badgeFileName = `badge_nft_${user.nickName}`; const _onClickGetBadge = () => { if (diabledGetBadge) return; - loading.show() + loading.show(); toBlob(badgeRef.current as any) - .then(blob => { - const badgeFile = (blob as BlobFile) - badgeFile.name = `badge_${user.nickName}.svg` - return badgeFile + .then((blob) => { + const badgeFile = blob as BlobFile; + badgeFile.name = `badge_${user.nickName}.svg`; + return badgeFile; }) - .then(file => upload({ file })) + .then((file) => upload({ file })) .then(([sf, params]) => { const perSignData = `crust-${params.msg}:${params.signature}`; const base64Signature = window.btoa(perSignData); - console.info('nft:', sf) - return saveNft(base64Signature, sf.Hash).then(() => doGetNft()) + console.info("nft:", sf); + return saveNft(base64Signature, sf.Hash).then(() => doGetNft()); }) .catch(console.error) - .then(loading.hide) - } - + .then(loading.hide); + }; - return -
-
{isPremiumUser ? 'You are Premium User' : 'You are Trial User'}
-
Web3 Identity Logged-in: {user.account}
-
-
-
{'Why Premium?'}
-
-
-
Premium User
- {/*
End-2-end File Encryption
*/} -
Maximum Upload Size of1GB
-
- Renew On-chain Storage Order & - Place {`"Permanent Storage Order"`} -
-
More Space
-
- Claim Rewards {`from "Share-and-Earn"`} -
-
- Priority access tofuture airdrops - and other exclusive benefits -
-
-
-
Trial User
- {/*
End-2-end File Encryption
*/} -
Maximum Upload Size of 40MB
-
Storage Order Expires in6 Months
-
Limited Space
-
CannotClaim Rewards {`from "Share-and-Earn"`}
-
Limited access to future airdrops or other exclusive benefits
+ return ( + +
+
{isPremiumUser ? "You are Premium User" : "You are Trial User"}
+
+ Web3 Identity Logged-in: {user.account}
-
- { - !isCrust && -
How to get Premium
-
Log in with Crust Wallet and Deposit CRU to get Premium.
-
- -
-
} - { - showDeposit && -
Get Premium
- { - showPremiumLoading ?
: - !wUser.nickName ? : - <> -
- { - showBasePrice ? <> - Deposit {baseGuaranteeAmount} CRU(now {guaranteeAmount} CRU for Discount!) to become a Premium User.
- Deposit {baseGuaranteeDiscountWithReferer} CRU(now {guaranteeDiscountWithReferer} CRU for Discount!) if you have an invitation code (the Nickname of your inviter).
- : <> - Deposit {guaranteeAmount} CRU to become a Premium User.
- Deposit {guaranteeDiscountWithReferer} CRU if you have an invitation code (the Nickname of your inviter).
- - } - The deposit can be redeemed {days} days after your deposit date. +
+
{"Why Premium?"}
+
+
+
Premium User
+ {/*
End-2-end File Encryption
*/} +
+ Maximum Upload Size of + 1GB
-
- - {nickStat.error && {nickStat.error}} -
- - How to deposit? +
+ + Renew On-chain Storage Order & + + + Place {`"Permanent Storage Order"`} +
- - } - } - { - showClaim && -
Redeem Your Deposit
-
- You can redeem your deposit after {days} days (est. on {periodTime}) after your initial deposit. -
- - {onGoingClaim &&
Redeem funds will be processed every Wednesday.
} -
} - { - isPremiumUser && !loadNft && - {/* */} -
My Badge Collection
-
- Collect your Achievement Badge here. +
More Space
+
+ Claim Rewards {`from "Share-and-Earn"`} +
+
+ Priority access to + future airdrops + and other exclusive benefits +
+
+
+
Trial User
+ {/*
End-2-end File Encryption
*/} +
+ Maximum Upload Size of + 40MB +
+
+ Storage Order Expires in + 6 Months +
+
+ Limited Space +
+
+ Cannot + Claim Rewards {`from "Share-and-Earn"`} +
+
+ Limited access to future airdrops or other exclusive benefits +
+
- { - hasBadge ?
- - - My Badge #1 -
- Badge Type: Premium User Badge
- Badge CID: {badgeCID} +
+ {!isCrust && ( + +
How to get Premium
+
Log in with Crust Wallet and Deposit CRU to get Premium.
+
+ +
+
+ )} + {showDeposit && ( + +
Get Premium
+ {showPremiumLoading ? ( +
+ +
+ ) : !wUser.nickName ? ( + + ) : ( + <> +
+ {showBasePrice ? ( + <> + Deposit {baseGuaranteeAmount} CRU + (now {guaranteeAmount} CRU for Discount!) to become a Premium User.
+ Deposit {baseGuaranteeDiscountWithReferer} CRU + (now {guaranteeDiscountWithReferer} CRU for Discount!) if you have an invitation code (the Nickname of your inviter). +
+ + ) : ( + <> + Deposit {guaranteeAmount} CRU to become a Premium User.
+ Deposit {guaranteeDiscountWithReferer} CRU if you have an invitation code (the Nickname of your inviter). +
+ + )} + The deposit can be redeemed {days} days after your deposit date.
-
- View full image - Check in IPFS Scan +
+ + {nickStat.error && {nickStat.error}} +
+ + + How to deposit? +
- -
: <> -
- -
-
- -
-
- - {!isPremiumUser && Become a Premium User to get this badge.} + + )} + + )} + {showClaim && ( + +
Redeem Your Deposit
+
+ You can redeem your deposit after {days} days (est. on{" "} + + {periodTime} + + ) after your initial deposit. +
+ + {onGoingClaim &&
Redeem funds will be processed every Wednesday.
} +
+ )} + {isPremiumUser && !loadNft && ( + + {/* */} +
My Badge Collection
+
Collect your Achievement Badge here.
+ {hasBadge ? ( +
+ + + My Badge #1 +
+ Badge Type: Premium User Badge +
+ Badge CID: {badgeCID} +
+ +
- - } - -
- } - - + ) : ( + <> +
+ +
+
+ +
+
+ + {!isPremiumUser && Become a Premium User to get this badge.} +
+ + )} + + )} + + + ); } export default React.memo(styled(Index)` - .mlink-btn{ + .mlink-btn { white-space: nowrap !important; margin-left: 0 !important; margin-right: 40px; @@ -305,7 +354,7 @@ export default React.memo(styled(Index)` font-size: 14px !important; line-height: 19px !important; } - .mcard{ + .mcard { a { font-size: 10px; text-decoration: underline; @@ -324,7 +373,7 @@ export default React.memo(styled(Index)` color: #999999; } .text > .origin { - font-family: 'OpenSans-SemiBold'; + font-family: "OpenSans-SemiBold"; color: var(--primary-color); &.isBase { color: var(--main-color); @@ -370,11 +419,12 @@ export default React.memo(styled(Index)` flex: 1; border-radius: 16px; overflow: hidden; - .t-title,.t-item { - padding: 0 24px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + .t-title, + .t-item { + padding: 0 24px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .t-title { line-height: 54px; @@ -399,10 +449,10 @@ export default React.memo(styled(Index)` color: var(--primary-color); margin-right: 6px; margin-left: 6px; - &:first-child{ + &:first-child { margin-left: 0; } - &:last-child{ + &:last-child { margin-right: 0; } } @@ -421,10 +471,10 @@ export default React.memo(styled(Index)` } } .premium { - background: #FFEEDA; + background: #ffeeda; margin-right: 32px; - .t-item:nth-child(2n + 1){ - background-color: rgba(255,255,255,0.45); + .t-item:nth-child(2n + 1) { + background-color: rgba(255, 255, 255, 0.45); } .t-title { background-color: var(--primary-color); @@ -433,8 +483,8 @@ export default React.memo(styled(Index)` .trial { background: #eeeeee; /* margin-right: 32px; */ - .t-item:nth-child(2n + 1){ - background-color: rgba(255,255,255,0.45); + .t-item:nth-child(2n + 1) { + background-color: rgba(255, 255, 255, 0.45); } .t-title { background-color: black; @@ -455,16 +505,13 @@ export default React.memo(styled(Index)` border-radius: 8px; padding-left: 16px; font-size: 10px; - &::placeholder{ + &::placeholder { color: #999999; } } .input-NickError { font-size: 10px; - color: #F37565; + color: #f37565; margin-left: 12px; } - - - -`) +`);