diff --git a/src/app/layout.tsx b/src/app/layout.tsx index a7d009019..fd0df8952 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,16 +2,16 @@ import '@/styles/index.scss'; import { Metadata, Viewport } from 'next'; +import StoreProvider from '@/Providers/StoreProvider'; +import { UnisatProvider } from '@/Providers/unisat-context'; +import { UserProvider } from '@/Providers/user-context'; +import { XVerseProvider } from '@/Providers/xverse-context'; +import Hydrated from '@/components/Hydrated'; +import ToastOverlay from '@/components/ToastOverlay'; import { MetadataConfig, ViewportConfig } from '@/config'; import chakraThemes from '@/themes/chakra-themes'; import { ChakraProvider } from '@chakra-ui/react'; -import Hydrated from '@/components/Hydrated'; import dynamic from 'next/dynamic'; -import StoreProvider from '@/Providers/StoreProvider'; -import { XVerseProvider } from '@/Providers/xverse-context'; -import { UnisatProvider } from '@/Providers/unisat-context'; -import ToastOverlay from '@/components/ToastOverlay'; -import { UserProvider } from '@/Providers/user-context'; export const metadata: Metadata = MetadataConfig; export const viewport: Viewport = ViewportConfig; @@ -31,19 +31,19 @@ export default function RootLayout({ return ( - - - - - - - {children} - - - - - - + + + + + + + {children} + + + + + + ); diff --git a/src/components/BaseModal/index.tsx b/src/components/BaseModal/index.tsx index b182154f2..20e132d5f 100644 --- a/src/components/BaseModal/index.tsx +++ b/src/components/BaseModal/index.tsx @@ -1,11 +1,15 @@ -import s from './styles.module.scss'; -import React, { PropsWithChildren } from 'react'; -import cs from 'classnames'; -import { CDN_URL_ICONS } from '@/config'; -import { Modal, ModalHeader, ModalBody, ModalOverlay, ModalContent } from '@chakra-ui/modal'; -import { Flex } from '@chakra-ui/react'; -import { size } from 'valibot'; import SvgInset from '@/components/SvgInset'; +import { + Modal, + ModalBody, + ModalContent, + ModalHeader, + ModalOverlay, +} from '@chakra-ui/modal'; +import { Flex } from '@chakra-ui/react'; +import cs from 'classnames'; +import React, { PropsWithChildren } from 'react'; +import s from './styles.module.scss'; export interface IBaseModalProps { isShow: boolean; @@ -17,7 +21,9 @@ export interface IBaseModalProps { headerClassName?: string; } -const BaseModal = (props: PropsWithChildren): React.ReactNode => { +const BaseModal = ( + props: PropsWithChildren, +): React.ReactNode => { const { isShow, onHide, @@ -26,40 +32,32 @@ const BaseModal = (props: PropsWithChildren): React.ReactNode = children, description, headerClassName, - size = "normal" + size = 'normal', } = props; return ( - - - - - - -

- {title} -

-
-
- - {!!description && ( -

- {description} -

- )} - {children} -
-
-
+ + + + + + +

{title}

+
+
+ + {!!description && ( +

{description}

+ )} + {children} +
+
+
); }; diff --git a/src/interfaces/leader-board-point.ts b/src/interfaces/leader-board-point.ts index 017e1d9b5..d36fe443b 100644 --- a/src/interfaces/leader-board-point.ts +++ b/src/interfaces/leader-board-point.ts @@ -43,4 +43,5 @@ export interface ILeaderBoardPoint { usdt_value?:string; bvm_percent?:string; coin_balances?:IContributionCoin[]; + deposit_id:string; } diff --git a/src/modules/PublicSale/AuthForBuy/index.tsx b/src/modules/PublicSale/AuthForBuy/index.tsx index 6c83319f5..9448d6a59 100644 --- a/src/modules/PublicSale/AuthForBuy/index.tsx +++ b/src/modules/PublicSale/AuthForBuy/index.tsx @@ -1,170 +1,19 @@ import BaseModal from '@/components/BaseModal'; import SvgInset from '@/components/SvgInset'; -import { BVM_API, PERP_NAKA_API_URL, TWITTER_CLIENT_ID } from '@/config'; -import { IAuthenCode } from '@/modules/Whitelist/steps'; -import { - generateTokenWithTwPost, - requestAuthenByShareCode, -} from '@/services/player-share'; -import { generateTokenWithOauth } from '@/services/public-sale'; -import { setBearerToken } from '@/services/whitelist'; import { useAppSelector } from '@/stores/hooks'; -import { requestReload } from '@/stores/states/common/reducer'; import { userSelector } from '@/stores/states/user/selector'; -import { getLink, getUuid } from '@/utils/helpers'; -import AuthenStorage from '@/utils/storage/authen.storage'; -import { - Box, - Button, - Center, - Flex, - Spinner, - Text, - useDisclosure, -} from '@chakra-ui/react'; +import { Button, Flex, useDisclosure } from '@chakra-ui/react'; import cs from 'classnames'; -import copy from 'copy-to-clipboard'; -import React, { - PropsWithChildren, - useEffect, - useMemo, - useRef, - useState, -} from 'react'; -import { useDispatch } from 'react-redux'; -import BuyAsGuest from './buyAsGuest'; -import s from './styles.module.scss'; -import DepositContent from '../depositModal/deposit.content'; -import BtnCreateGuest from './btnCreateGuest'; +import React, { PropsWithChildren, useMemo } from 'react'; import { GoogleReCaptchaProvider } from 'react-google-recaptcha-v3'; +import DepositContent from '../depositModal/deposit.content'; +import s from './styles.module.scss'; interface IAuthForBuy extends PropsWithChildren {} -const AuthForBuy: React.FC = ({ children }) => { +const AuthForBuy: React.FC = () => { const user = useAppSelector(userSelector); const { isOpen, onOpen, onClose } = useDisclosure(); - const token = AuthenStorage.getAuthenKey(); - const [authenCode, setAuthenCode] = useState(); - const timer = useRef(); - const [submitting, setSubmitting] = useState(false); - const dispatch = useDispatch(); - const [isCopy, setIsCopy] = useState(false); - const [isBuyGuest, setIsBuyGuest] = useState(false); - - const uuid = getUuid(); - - useEffect(() => { - if (authenCode?.public_code) { - setSubmitting(true); - timer.current = setInterval(async () => { - handleVerifyTwitter(); - }, 5000); - } - return () => { - clearInterval(timer.current); - }; - }, [authenCode?.public_code]); - - const handleVerifyTwitter = async (): Promise => { - try { - const result = await generateTokenWithTwPost( - authenCode?.secret_code as string, - ); - onVerifyTwSuccess(result); - } catch (err) { - console.log('handleVerifyTwitter', err); - } - }; - - const onVerifyTwSuccess = (result: any) => { - if (result) { - clearInterval(timer.current); - const twitterToken = AuthenStorage.getAuthenKey(); - if (!twitterToken || twitterToken !== result?.token) { - AuthenStorage.setAuthenKey(result?.token); - setBearerToken(result?.token); - } - setSubmitting(false); - dispatch(requestReload()); - // onClose(); - } - }; - - useEffect(() => { - if (!user?.twitter_id) { - timer.current = setInterval(async () => { - handleVerifyTwitterWithUUID(); - }, 2000); - } - return () => { - clearInterval(timer.current); - }; - }, [user]); - - const handleVerifyTwitterWithUUID = async (): Promise => { - try { - const result = await generateTokenWithOauth(uuid); - if (result) { - clearInterval(timer.current); - if (!token || token !== result?.token) { - onVerifyTwSuccess(result); - setTimeout(() => { - onOpen(); - }, 1000); - } - } - } catch (e) { - console.log('handleVerifyTwitter TwitterSignIn', e); - } - }; - - const getTwitterOauthUrl = () => { - const URL = `${window.location.origin}/public-sale`; - const rootUrl = 'https://twitter.com/i/oauth2/authorize'; - const options = { - redirect_uri: `${BVM_API}/twitter-api/oauth/twitter-bvm?callbackURL=${URL}&uuid=${uuid}`, - client_id: TWITTER_CLIENT_ID, - state: 'state', - response_type: 'code', - code_challenge: 'challenge', - code_challenge_method: 'plain', - scope: [ - 'users.read', - 'tweet.read', - 'follows.read', - 'offline.access', - ].join(' '), - }; - const qs = new URLSearchParams(options).toString(); - window.open(`${rootUrl}?${qs}`, '_self'); - }; - - const generateLinkTweet = async () => { - let code = ''; - if (!token) { - const res: any = await requestAuthenByShareCode(); - setAuthenCode(res); - code = `\n\n#${res?.public_code}`; - } - - const shareUrl = getLink(user?.referral_code || ''); - const content = `Welcome to the future of Bitcoin with @BVMnetwork\n\nBitcoin Virtual Machine is the first modular blockchain metaprotocol that lets you launch your Bitcoin L2 blockchain protocol in a few clicks\n\n$BVM public sale starting soon${code}\n\nJoin the allowlist`; - return `https://twitter.com/intent/tweet?url=${shareUrl}&text=${encodeURIComponent( - content, - )}`; - }; - - const handleShareTw = async () => { - setIsCopy(false); - const content = await generateLinkTweet(); - window.open(content, '_blank'); - }; - - const onCopy = async () => { - const content = await generateLinkTweet(); - setIsCopy(true); - copy(content); - }; const isSigned = useMemo(() => { if (user?.guest_code || user?.twitter_id) { @@ -173,10 +22,6 @@ const AuthForBuy: React.FC = ({ children }) => { return false; }, [user]); - // if (user?.twitter_id || user?.guest_code) { - // return children; - // } - return ( <> @@ -191,101 +36,72 @@ const AuthForBuy: React.FC = ({ children }) => { Back $BVM - - {isSigned ? ( + + + + {/* {isSigned ? ( <> ) : ( <> - {isBuyGuest ? ( - setIsBuyGuest(false)} /> - ) : ( - <> - - - - - - - Post to sign-in - - - Or - - - Authorize to sign-in - - - {/* - */} - - - - - )} + + + + + + + Post to sign-in + + + Or + + + Authorize to sign-in + + + + + - )} - + )} */} + + ); }; diff --git a/src/modules/PublicSale/depositModal/deposit.check.it.here.tsx b/src/modules/PublicSale/depositModal/deposit.check.it.here.tsx new file mode 100644 index 000000000..c80ac9d52 --- /dev/null +++ b/src/modules/PublicSale/depositModal/deposit.check.it.here.tsx @@ -0,0 +1,51 @@ +import { + FocusLock, + Popover, + PopoverArrow, + PopoverCloseButton, + PopoverContent, + PopoverTrigger, + useDisclosure, +} from '@chakra-ui/react'; +import React, { PropsWithChildren } from 'react'; +import DepositLoginMode from './deposit.login.mode'; +import { GoogleReCaptchaProvider } from 'react-google-recaptcha-v3'; +import DepositCheck from './deposit.check'; + +interface IDepositCheckItHere extends PropsWithChildren {} + +const DepositCheckItHere: React.FC = ({ children }) => { + const firstFieldRef = React.useRef(null); + const { onClose, onOpen, isOpen } = useDisclosure(); + return ( + + {children} + + + + + + + + + + + ); +}; + +export default DepositCheckItHere; diff --git a/src/modules/PublicSale/depositModal/deposit.claim.it.here.tsx b/src/modules/PublicSale/depositModal/deposit.claim.it.here.tsx new file mode 100644 index 000000000..fa1c0d155 --- /dev/null +++ b/src/modules/PublicSale/depositModal/deposit.claim.it.here.tsx @@ -0,0 +1,43 @@ +import { + FocusLock, + Popover, + PopoverArrow, + PopoverCloseButton, + PopoverContent, + PopoverTrigger, + useDisclosure, +} from '@chakra-ui/react'; +import React, { PropsWithChildren } from 'react'; +import DepositLoginMode from './deposit.login.mode'; + +interface IDepositClaimItHere extends PropsWithChildren {} + +const DepositClaimItHere: React.FC = ({ children }) => { + const firstFieldRef = React.useRef(null); + const { + onClose: onClose2, + onOpen: onOpen2, + isOpen: isOpen2, + } = useDisclosure(); + return ( + + {children} + + + + + + + + + ); +}; + +export default DepositClaimItHere; diff --git a/src/modules/PublicSale/depositModal/deposit.content.item.tsx b/src/modules/PublicSale/depositModal/deposit.content.item.tsx index 6e9ec3260..1b737415a 100644 --- a/src/modules/PublicSale/depositModal/deposit.content.item.tsx +++ b/src/modules/PublicSale/depositModal/deposit.content.item.tsx @@ -50,7 +50,7 @@ export const DepositContentItem2: React.FC = ({ onClick={() => onSelectToken?.(token)} > - {tokenInfo?.name} + {tokenInfo?.symbol} ); }; diff --git a/src/modules/PublicSale/depositModal/deposit.content.tsx b/src/modules/PublicSale/depositModal/deposit.content.tsx index a4ec79a42..30509f308 100644 --- a/src/modules/PublicSale/depositModal/deposit.content.tsx +++ b/src/modules/PublicSale/depositModal/deposit.content.tsx @@ -1,10 +1,16 @@ import AppLoading from '@/components/AppLoading'; import SvgInset from '@/components/SvgInset'; import { PublicSaleWalletTokenDeposit } from '@/interfaces/vc'; -import { getLocation, getPublicsaleWalletInfo } from '@/services/public-sale'; +import { + generateTOkenWithSecretCode, + getLocation, + getPublicsaleWalletInfo, +} from '@/services/public-sale'; import { useAppSelector } from '@/stores/hooks'; import { commonSelector } from '@/stores/states/common/selector'; +import { setGuestSecretCode } from '@/stores/states/user/reducer'; import { userSelector } from '@/stores/states/user/selector'; +import { generateRandomString } from '@/utils/encryption'; import { formatCurrency } from '@/utils/format'; import AuthenStorage from '@/utils/storage/authen.storage'; import { compareString } from '@/utils/string'; @@ -12,15 +18,9 @@ import { Box, Center, Flex, - FocusLock, Menu, MenuButton, MenuList, - Popover, - PopoverArrow, - PopoverCloseButton, - PopoverContent, - PopoverTrigger, Text, useDisclosure, } from '@chakra-ui/react'; @@ -28,12 +28,11 @@ import BigNumber from 'bignumber.js'; import copy from 'copy-to-clipboard'; import React, { useEffect, useMemo, useState } from 'react'; import { isMobile } from 'react-device-detect'; -import { GoogleReCaptchaProvider } from 'react-google-recaptcha-v3'; +import { useGoogleReCaptcha } from 'react-google-recaptcha-v3'; import toast from 'react-hot-toast'; import QRCode from 'react-qr-code'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import ImportOrCreate from '../AuthForBuy/importOrCreate'; -import DepositCheck from './deposit.check'; import DepositContentItem, { DepositContentItem2, } from './deposit.content.item'; @@ -48,6 +47,7 @@ const COUNTRY_BANNED: any[] = ['US']; const DepositContent: React.FC = ({ amount_usd, onHide }) => { const { onClose, onOpen, isOpen } = useDisclosure(); + const user = useAppSelector(userSelector); const [loading, setLoading] = useState(true); const [checkingLocation, setCheckingLocation] = useState(true); @@ -63,10 +63,54 @@ const DepositContent: React.FC = ({ amount_usd, onHide }) => { const coinPrices = useSelector(commonSelector).coinPrices; + const dispatch = useDispatch(); + const { executeRecaptcha } = useGoogleReCaptcha(); + const [generating, setGenerating] = useState(true); + + const isAuth = useMemo(() => user?.guest_code || user?.twitter_id, [user]); + + const createNewSecretCode = () => { + try { + if (isAuth) { + setGenerating(false); + return; + } + if (!executeRecaptcha) { + console.log('Execute recaptcha not yet available'); + throw Error('Execute recaptcha not yet available'); + } + executeRecaptcha('enquiryFormSubmit').then((gReCaptchaToken) => { + console.log(gReCaptchaToken, 'response Google reCaptcha server'); + + getToken(gReCaptchaToken); + }); + } catch (error) { + // + } + }; + + const getToken = async (captcha: string, code?: string) => { + try { + const _secretCode = generateRandomString(10); + + const rs = await generateTOkenWithSecretCode(_secretCode, captcha); + AuthenStorage.setGuestSecretKey(_secretCode); + AuthenStorage.setGuestAuthenKey(rs?.token); + dispatch(setGuestSecretCode(_secretCode)); + } catch (error) { + } finally { + setGenerating(false); + } + }; + useEffect(() => { checkLocation(); }, []); + useEffect(() => { + createNewSecretCode(); + }, [isAuth]); + useEffect(() => { getTokens(); }, [user]); @@ -118,7 +162,7 @@ const DepositContent: React.FC = ({ amount_usd, onHide }) => { return '0'; }, [coinPrices, amount_usd, selectToken]); - if (loading || checkingLocation) { + if (loading || checkingLocation || generating) { return (
@@ -127,12 +171,16 @@ const DepositContent: React.FC = ({ amount_usd, onHide }) => { } if (isBanned) { - return
Not Available in Your Region
+ return ( +
+ Not Available in Your Region +
+ ); } return ( - {secretCode && ( + {/* {secretCode && ( <> @@ -153,30 +201,20 @@ const DepositContent: React.FC = ({ amount_usd, onHide }) => { - )} + )} */} {isDepositAnotherAccount ? ( <> - - - - { - setIsDepositAnotherAccount(false); - }} - > - Back to deposit - - - + + + { + setIsDepositAnotherAccount(false); + }} + > + Back to deposit + + ) : ( <> @@ -264,42 +302,12 @@ const DepositContent: React.FC = ({ amount_usd, onHide }) => { svgUrl="/icons/ic-copy.svg" /> - - - - Already deposited? - - - - - - - - - - - - )} - {secretCode && !token && ( + + {/* {secretCode && !token && ( <> = ({ amount_usd, onHide }) => { - )} + )} */} )} @@ -324,4 +332,8 @@ DepositContent.defaultProps = { amount_usd: '0', }; -export default DepositContent; +const DepositContentContainer: React.FC = (props) => { + return ; +}; + +export default DepositContentContainer; diff --git a/src/modules/PublicSale/depositModal/deposit.login.mode.tsx b/src/modules/PublicSale/depositModal/deposit.login.mode.tsx new file mode 100644 index 000000000..90acb72cb --- /dev/null +++ b/src/modules/PublicSale/depositModal/deposit.login.mode.tsx @@ -0,0 +1,150 @@ +import { Button, Flex, Text } from '@chakra-ui/react'; +import React, { useEffect, useRef, useState } from 'react'; +import s from './styles.module.scss'; +import cs from 'classnames'; +import { useAppSelector } from '@/stores/hooks'; +import AuthenStorage from '@/utils/storage/authen.storage'; +import { BVM_API, TWITTER_CLIENT_ID } from '@/config'; +import { IAuthenCode } from '@/modules/Whitelist/steps'; +import { + generateTokenWithTwPost, + requestAuthenByShareCode, +} from '@/services/player-share'; +import { generateTokenWithOauth } from '@/services/public-sale'; +import { setBearerToken } from '@/services/whitelist'; +import { requestReload } from '@/stores/states/common/reducer'; +import { userSelector } from '@/stores/states/user/selector'; +import { getUuid, getLink } from '@/utils/helpers'; +import { useDispatch } from 'react-redux'; + +const DepositLoginMode = ({ onClose }: { onClose: any }) => { + const user = useAppSelector(userSelector); + const token = AuthenStorage.getAuthenKey(); + const [authenCode, setAuthenCode] = useState(); + const timer = useRef(); + const [submitting, setSubmitting] = useState(false); + const dispatch = useDispatch(); + const [isCopy, setIsCopy] = useState(false); + const [isBuyGuest, setIsBuyGuest] = useState(false); + const uuid = getUuid(); + + useEffect(() => { + if (authenCode?.public_code) { + setSubmitting(true); + timer.current = setInterval(async () => { + handleVerifyTwitter(); + }, 5000); + } + return () => { + clearInterval(timer.current); + }; + }, [authenCode?.public_code]); + + const handleVerifyTwitter = async (): Promise => { + try { + const result = await generateTokenWithTwPost( + authenCode?.secret_code as string, + ); + onVerifyTwSuccess(result); + } catch (err) { + console.log('handleVerifyTwitter', err); + } + }; + + const onVerifyTwSuccess = (result: any) => { + if (result) { + clearInterval(timer.current); + const twitterToken = AuthenStorage.getAuthenKey(); + if (!twitterToken || twitterToken !== result?.token) { + AuthenStorage.setAuthenKey(result?.token); + setBearerToken(result?.token); + } + setSubmitting(false); + dispatch(requestReload()); + onClose(); + } + }; + + useEffect(() => { + if (!user?.twitter_id) { + timer.current = setInterval(async () => { + handleVerifyTwitterWithUUID(); + }, 2000); + } + return () => { + clearInterval(timer.current); + }; + }, [user]); + + const handleVerifyTwitterWithUUID = async (): Promise => { + try { + const result = await generateTokenWithOauth(uuid); + if (result) { + clearInterval(timer.current); + if (!token || token !== result?.token) { + onVerifyTwSuccess(result); + } + } + } catch (e) { + console.log('handleVerifyTwitter TwitterSignIn', e); + } + }; + + const getTwitterOauthUrl = () => { + const URL = `${window.location.origin}/public-sale`; + const rootUrl = 'https://twitter.com/i/oauth2/authorize'; + const options = { + redirect_uri: `${BVM_API}/twitter-api/oauth/twitter-bvm?callbackURL=${URL}&uuid=${uuid}`, + client_id: TWITTER_CLIENT_ID, + state: 'state', + response_type: 'code', + code_challenge: 'challenge', + code_challenge_method: 'plain', + scope: [ + 'users.read', + 'tweet.read', + 'follows.read', + 'offline.access', + ].join(' '), + }; + const qs = new URLSearchParams(options).toString(); + window.open(`${rootUrl}?${qs}`, '_self'); + }; + + const generateLinkTweet = async () => { + let code = ''; + if (!token) { + const res: any = await requestAuthenByShareCode(); + setAuthenCode(res); + code = `\n\n#${res?.public_code}`; + } + + const shareUrl = getLink(user?.referral_code || ''); + const content = `Welcome to the future of Bitcoin with @BVMnetwork\n\nBitcoin Virtual Machine is the first modular blockchain metaprotocol that lets you launch your Bitcoin L2 blockchain protocol in a few clicks\n\n$BVM public sale starting soon${code}\n\nJoin the allowlist`; + return `https://twitter.com/intent/tweet?url=${shareUrl}&text=${encodeURIComponent( + content, + )}`; + }; + + const handleShareTw = async () => { + setIsCopy(false); + const content = await generateLinkTweet(); + window.open(content, '_blank'); + }; + + return ( + + + + + ); +}; + +export default DepositLoginMode; diff --git a/src/modules/PublicSale/depositModal/styles.module.scss b/src/modules/PublicSale/depositModal/styles.module.scss index 5a4e7c7d8..68b91d8f3 100644 --- a/src/modules/PublicSale/depositModal/styles.module.scss +++ b/src/modules/PublicSale/depositModal/styles.module.scss @@ -249,4 +249,27 @@ cursor: pointer; text-decoration: underline; } + &.haveBoost { + p { + color: white; + opacity: 0.7; + text-align: right; + } + } +} + +.btnTweetToSign { + border-radius: 0px !important; + background: #ffffff !important; + p { + color: #000000 !important; + font-weight: 400 !important; + line-height: 100% !important; + } + &.btnPrimary { + background: #fa4e0e !important; + p { + color: #ffffff !important; + } + } } diff --git a/src/modules/PublicSale/leaderBoardVisual/AvatarItem/index.tsx b/src/modules/PublicSale/leaderBoardVisual/AvatarItem/index.tsx index 42ad0670a..771af4ee8 100644 --- a/src/modules/PublicSale/leaderBoardVisual/AvatarItem/index.tsx +++ b/src/modules/PublicSale/leaderBoardVisual/AvatarItem/index.tsx @@ -31,44 +31,50 @@ const AvatarItem = forwardRef((props: IProps, ref: any) => { const add = animatedLatestContributors?.find(c => c.twitter_id === data.twitter_id); if(add) { - return Number(data.usdt_value) + Number(add.usdt_value); + return refMoney.current.value + Number(add.usdt_value); } else { - return Number(data.usdt_value); + return refMoney.current.value; } } else { - return Number(data.usdt_value); + return refMoney.current.value; } - }, [data, needCheckDeposit, animatedLatestContributors]); + }, [needCheckDeposit, JSON.stringify(animatedLatestContributors)]); useEffect(() => { if (!refInertMoney.current) return; if (newTotalMoney && refMoney.current.value !== newTotalMoney) { + const numberLoop = 5; + const duration = 19/24; gsap.to(refMoney.current, { - value: newTotalMoney, ease: 'power3.inOut', duration: 1, onUpdate: () => { + value: newTotalMoney, ease: 'power3.inOut', duration: numberLoop * duration, onUpdate: () => { if (refInertMoney.current) { refInertMoney.current.innerHTML = `$${formatCurrency(refMoney.current.value, 0, 0, '', true)}`; } }, }); + if (!lottieRef.current) return; + + lottieRef.current.setLoop(numberLoop); + lottieRef.current.play(); + + setIsLoopDone(false); + if(refTime.current) { + clearTimeout(refTime.current); + } + refTime.current = setTimeout(() => { + setIsLoopDone(true); + onCompleted && onCompleted(); + }, duration * numberLoop * 1000); } else { refInertMoney.current.innerHTML = `$${formatCurrency(refMoney.current.value, 0, 0, '', true)}`; } - - if (!lottieRef.current) return; - const numberLoop = 3; - - lottieRef.current.setLoop(3); - lottieRef.current.play(); - setIsLoopDone(false); - - const duration = lottieRef.current; - refTime.current = setTimeout(() => { - setIsLoopDone(true); - onCompleted && onCompleted(); - }, duration * numberLoop); - + return () => { + if(refTime.current) { + clearTimeout(refTime.current); + } + } }, [newTotalMoney]); const [error, setError] = useState(false); @@ -79,7 +85,6 @@ const AvatarItem = forwardRef((props: IProps, ref: any) => { src={'/images/mk-user.jpg'} alt={'user'} style={{ cursor: 'pointer' }} />; }; - return (
{
{ -
+
{ fetchLatestData(); const interval = setInterval(() => { fetchLatestData(); - dispatch(setNeedCheckDeposit(true)); }, 10000); + setTimeout(() => { + dispatch(setNeedCheckDeposit(true)); + }, 12000); + return () => { clearInterval(interval); }; @@ -107,14 +110,14 @@ const LeaderBoardVisual = (props: IProps) => { const oldContributors = latestContributors?.current; const newRes = res.filter( function( el ) { - return oldContributors?.findIndex(a => a.twitter_id === el.twitter_id) < 0; + return oldContributors?.findIndex(a => a.deposit_id === el.deposit_id) < 0; }); if(newRes?.length > 0) { latestContributors.current = [...newRes].concat(latestContributors.current); - animatedLatestContributors.current = newRes; - dispatch(setAnimatedLatestContributors(newRes)); } + animatedLatestContributors.current = newRes || []; + dispatch(setAnimatedLatestContributors(newRes || [])); }; useEffect(() => { diff --git a/src/modules/Whitelist/FAQContent/index.tsx b/src/modules/Whitelist/FAQContent/index.tsx index 0805564ef..83a100dc6 100644 --- a/src/modules/Whitelist/FAQContent/index.tsx +++ b/src/modules/Whitelist/FAQContent/index.tsx @@ -7,6 +7,8 @@ import { } from '@chakra-ui/react'; import s from './styles.module.scss'; import { CDN_URL } from '@/config'; +import DepositClaimItHere from '@/modules/PublicSale/depositModal/deposit.claim.it.here'; +import DepositCheckItHere from '@/modules/PublicSale/depositModal/deposit.check.it.here'; const FAQContent: React.FC = (): React.ReactElement => { return ( @@ -20,7 +22,9 @@ const FAQContent: React.FC = (): React.ReactElement => { <>

- What is the minimum and maximum contribution per wallet? + + What is the minimum and maximum contribution per wallet? +

- There is no hard cap for the public sale. It will be a crowdfunding event, allowing the public to determine the valuation of the BVM project. + There is no hard cap for the public sale. It will be a + crowdfunding event, allowing the public to determine the + valuation of the BVM project.

@@ -83,9 +89,7 @@ const FAQContent: React.FC = (): React.ReactElement => { -

- BRC-20 -

+

BRC-20

)} @@ -110,7 +114,9 @@ const FAQContent: React.FC = (): React.ReactElement => {

- $BVM serves as the native cryptocurrency within the BVM ecosystem, facilitating network fee payments and the creation of Bitcoin L2 blockchains. + $BVM serves as the native cryptocurrency within the BVM + ecosystem, facilitating network fee payments and the + creation of Bitcoin L2 blockchains.

@@ -136,7 +142,9 @@ const FAQContent: React.FC = (): React.ReactElement => {

- There is no vesting period for the public sale. All tokens will be distributed at TGE, which is expected to be around early March. + There is no vesting period for the public sale. All tokens + will be distributed at TGE, which is expected to be around + early March.

@@ -162,7 +170,8 @@ const FAQContent: React.FC = (): React.ReactElement => {

- 15% of the total supply will be allocated for the public sale. + 15% of the total supply will be allocated for the public + sale.

@@ -174,9 +183,7 @@ const FAQContent: React.FC = (): React.ReactElement => { <>

- - What is the boost? - + What is the boost?

- The boost is available only to allowlist members, with potential boosts of up to 30%. + The boost is available only to allowlist members, with + potential boosts of up to 30%.

- To clarify, the top 1% of the allowlist will receive a 30% boost, the next 9% will get a 20% boost, and the remaining 90% will receive a 10% boost. + To clarify, the top 1% of the allowlist will receive a 30% + boost, the next 9% will get a 20% boost, and the remaining + 90% will receive a 10% boost.

- If you have a boost, claim it here. + If you have a boost,{' '} + + claim it here + + .

@@ -220,7 +234,34 @@ const FAQContent: React.FC = (): React.ReactElement => {

- You can deposit nine different currencies, including BTC, ETH, TIA, OP, ARB, ORDI, SATS, USDT, USDC. + You can deposit nine different currencies, including BTC, + ETH, TIA, OP, ARB, ORDI, SATS, USDT, USDC. +

+
+ + )} + + + + {({ isExpanded }) => ( + <> +

+ + + How to check my contribution status? + + + +

+ +

+ Check it here.

@@ -246,7 +287,8 @@ const FAQContent: React.FC = (): React.ReactElement => {

- The TGE is expected to take place around March, coinciding with the exchange listings. + The TGE is expected to take place around March, coinciding + with the exchange listings.

diff --git a/src/modules/Whitelist/FAQContent/styles.module.scss b/src/modules/Whitelist/FAQContent/styles.module.scss index 45863d2e9..beb14e802 100644 --- a/src/modules/Whitelist/FAQContent/styles.module.scss +++ b/src/modules/Whitelist/FAQContent/styles.module.scss @@ -61,6 +61,7 @@ a { text-decoration: underline; + cursor: pointer; } &:not(:last-child) {