diff --git a/package.json b/package.json index 39d7cb4c..df4bdc64 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zkbob-ui", - "version": "2.1.0", + "version": "2.2.0", "private": true, "dependencies": { "@dicebear/avatars": "^4.10.2", diff --git a/src/components/AccountSetUpModal/Generate/index.js b/src/components/AccountSetUpModal/Generate/index.js index e4b6f6c1..6b260494 100644 --- a/src/components/AccountSetUpModal/Generate/index.js +++ b/src/components/AccountSetUpModal/Generate/index.js @@ -3,7 +3,7 @@ import styled from 'styled-components'; import WalletConnectors from 'components/WalletConnectors'; -export default ({ generate, isCreation }) => { +export default ({ next, isCreation }) => { return ( @@ -12,7 +12,7 @@ export default ({ generate, isCreation }) => { : 'Select the wallet you used to create your zkAccount' } - + ); }; diff --git a/src/components/AccountSetUpModal/Sign/index.js b/src/components/AccountSetUpModal/Sign/index.js index 41599dd1..d953ab84 100644 --- a/src/components/AccountSetUpModal/Sign/index.js +++ b/src/components/AccountSetUpModal/Sign/index.js @@ -1,18 +1,32 @@ -import React from 'react'; +import React, { useState, useCallback } from 'react'; import styled from 'styled-components'; import Spinner from 'components/Spinner'; +import Button from 'components/Button'; + +export default ({ isCreation, sign }) => { + const [isLoading, setIsLoading] = useState(false); + + const onClick = useCallback(async () => { + setIsLoading(true); + try { + await sign(); + } catch (error) { + console.error(error); + } + setIsLoading(false); + }, [sign]); -export default ({ isCreation }) => { return ( - + {isLoading && } {isCreation ? 'Your zkAccount is being created based on the connected wallet.' : 'Accessing your zkAccount with your connected wallet.' } + {!isLoading && } ); }; diff --git a/src/components/AccountSetUpModal/index.js b/src/components/AccountSetUpModal/index.js index 611a469f..34d89813 100644 --- a/src/components/AccountSetUpModal/index.js +++ b/src/components/AccountSetUpModal/index.js @@ -103,20 +103,12 @@ export default ({ isOpen, onClose, saveZkAccountMnemonic, closePasswordModal }) }, []); const generate = useCallback(async () => { - const nextStep = step === STEP.CREATE_WITH_WALLET - ? STEP.SING_MESSAGE_TO_CREATE - : STEP.SING_MESSAGE_TO_RESTORE; - setStep(nextStep); - try { - const message = 'Access zkBob account.\n\nOnly sign this message for a trusted client!'; - const signedMessage = await signMessageAsync({ message }); - const newMnemonic = ethers.utils.entropyToMnemonic(md5.array(signedMessage)); - setConfirmedMnemonic(newMnemonic); - setStep(STEP.CREATE_PASSWORD); - } catch (error) { - setStep(step); - } - }, [signMessageAsync, step]); + const message = 'Access zkBob account.\n\nOnly sign this message for a trusted client!'; + const signedMessage = await signMessageAsync({ message }); + const newMnemonic = ethers.utils.entropyToMnemonic(md5.array(signedMessage)); + setConfirmedMnemonic(newMnemonic); + setStep(STEP.CREATE_PASSWORD); + }, [signMessageAsync]); const confirmPassword = useCallback(password => { const isNewAccount = !!newMnemonic; @@ -148,7 +140,7 @@ export default ({ isOpen, onClose, saveZkAccountMnemonic, closePasswordModal }) break; case STEP.CREATE_WITH_WALLET: title = 'Create new zkAccount'; - component = ; + component = setStep(STEP.SING_MESSAGE_TO_CREATE)} />; prevStep = STEP.CREATE_OPTIONS; break; case STEP.CREATE_WITH_SECRET: @@ -158,7 +150,7 @@ export default ({ isOpen, onClose, saveZkAccountMnemonic, closePasswordModal }) break; case STEP.RESTORE_WITH_WALLET: title = 'Login to your zkAccount'; - component = ; + component = setStep(STEP.SING_MESSAGE_TO_RESTORE)} />; prevStep = STEP.RESTORE_OPTIONS; break; case STEP.RESTORE_WITH_SECRET: @@ -173,13 +165,13 @@ export default ({ isOpen, onClose, saveZkAccountMnemonic, closePasswordModal }) break; case STEP.SING_MESSAGE_TO_CREATE: title = 'Sign the message to create your zkAccount'; - component = ; - prevStep = null; + component = ; + prevStep = STEP.CREATE_WITH_WALLET; break; case STEP.SING_MESSAGE_TO_RESTORE: title = 'Sign the message to login to your zkAccount'; - component = ; - prevStep = null; + component = ; + prevStep = STEP.RESTORE_WITH_WALLET; break; case STEP.CREATE_PASSWORD: title = 'Create password'; diff --git a/src/components/Button/index.js b/src/components/Button/index.js index 39eb351a..a2b49a6e 100644 --- a/src/components/Button/index.js +++ b/src/components/Button/index.js @@ -4,15 +4,16 @@ import styled from 'styled-components'; import SpinnerDefault from 'components/Spinner'; export default props => { + const { loading, ...otherProps } = props; switch(props.type) { case 'link': - return ; + return ; case 'pripary': default: return ( - @@ -22,9 +23,9 @@ export default props => { const Button = styled.button` background: ${props => - props.theme.button.primary.background[props.disabled ? (props.$contrast ? 'contrast' : 'disabled') : 'default'] + props.theme.button.primary.background[props.disabled ? (props.contrast ? 'contrast' : 'disabled') : 'default'] }; - color: ${props => props.theme.button.primary.text.color[props.disabled && props.$contrast ? 'contrast' : 'default']}; + color: ${props => props.theme.button.primary.text.color[props.disabled && props.contrast ? 'contrast' : 'default']}; font-size: ${props => props.theme.button.primary.text.size[props.small ? 'small' : 'default']}; font-weight: ${props => props.theme.button.primary.text.weight[props.small ? 'small' : 'default']}; padding: ${props => props.small ? '8px 16px' : '0'}; diff --git a/src/components/Dropdown/index.js b/src/components/Dropdown/index.js index 824704c7..0ea41c30 100644 --- a/src/components/Dropdown/index.js +++ b/src/components/Dropdown/index.js @@ -5,6 +5,7 @@ import 'rc-tooltip/assets/bootstrap.css'; const GlobalStyle = createGlobalStyle` .dropdown { + top: 55px !important; @media only screen and (max-width: 560px) { left: calc(100% - 58px) !important; transform: translateX(-100%) !important; diff --git a/src/components/Footer/index.js b/src/components/Footer/index.js index 2df1662c..b14ed5d5 100644 --- a/src/components/Footer/index.js +++ b/src/components/Footer/index.js @@ -18,8 +18,8 @@ export default () => { const resources = [ { icon: TwitterIcon, href: 'https://twitter.com/zkBob_' }, - { icon: TelegramIcon, href: 'https://t.me/zkbob_news' }, - { icon: MirrorIcon, href: 'https://mirror.xyz/0x6132eB883e88CD4E007552b871A6444Bfc34E837' }, + { icon: TelegramIcon, href: 'https://t.me/zkbobcommunity' }, + { icon: MirrorIcon, href: 'https://blog.zkbob.com/' }, { icon: GithubIcon, href: 'https://github.com/zkBob' }, ]; diff --git a/src/components/Header/index.js b/src/components/Header/index.js index 7c77146e..03d9fb6e 100644 --- a/src/components/Header/index.js +++ b/src/components/Header/index.js @@ -151,8 +151,8 @@ export default ({ ) : ( + {isLoadingZkAccount ? ( + + ) : ( + + )} ); -const InProgressScreen = () => { - const [text, setText] = useState(texts[0]); +const InProgressScreen = ({ supportId }) => { + const [progress, setProgress] = useState(0); useEffect(() => { - let counter = 0; const intervalId = setInterval(() => { - counter++; - const index = counter % texts.length; - setText(texts[index]); - }, 5000); // 5 seconds + setProgress(progress => progress + 1); + }, 600); return () => clearInterval(intervalId); }, []); return ( <> - {text} - + + + {Math.min(progress, 99)}% + + + Transferring tokens to your zkAccount + + {progress > 99 && ( + <> + + The process takes longer than usual. If the process does not complete within a few seconds,{' '} + contact our support team + + + + )} ); } -const CompletedScreen = () => ( +const CompletedScreen = ({ close }) => ( <> - - Your BOB tokens were claimed.
- Check your account balance. + + + Your BOB is on the way - + + Your tokens will be delivered during the next 1-2 minutes.{' '} + Check the transaction status on the History tab + + ); -const FailedScreen = () => ( - <> - - The tokens have already
been claimed -
- - -); +const FailedScreen = ({ error, supportId }) => { + const isClaimed = error?.message?.includes('Insufficient funds'); + return ( + <> + + + {isClaimed ? 'This gift card has already been used' : 'Something went wrong'} + + {!isClaimed && + + Please contact our support team to resolve this problem. Use Support ID in your request. + + } + + {!isClaimed && + + } + + ); +}; export default ({ isOpen, onClose, giftCard, redeemGiftCard, - zkAccount, isLoadingZkAccount, + zkAccount, isLoadingZkAccount, supportId, setUpAccount, isNewUser, currentPool, }) => { const [step, setStep] = useState(START); + const [error, setError] = useState(null); const redeem = useCallback(async () => { setStep(IN_PROGRESS); @@ -125,6 +190,7 @@ export default ({ await redeemGiftCard(); setStep(COMPLETED); } catch (error) { + setError(error); setStep(FAILED); } }, [redeemGiftCard]); @@ -140,8 +206,12 @@ export default ({ useEffect(() => { if (isOpen && !zkAccount && !isLoadingZkAccount) { setStep(CREATE_ACCOUNT); + } else if (isOpen && !giftCard && ![COMPLETED, FAILED].includes(step)) { + setStep(LOADING); + } else if (isOpen && giftCard && step === LOADING) { + setStep(START); } - }, [isOpen, zkAccount, isLoadingZkAccount]); + }, [isOpen, zkAccount, isLoadingZkAccount, giftCard, step]); const openCreateAccount = useCallback(() => { setUpAccount(); @@ -156,11 +226,13 @@ export default ({ return ( {(() => { switch(step) { + case LOADING: + return ; case CREATE_ACCOUNT: return ; case SWITCH_NETWORK: @@ -173,11 +245,11 @@ export default ({ isLoadingZkAccount={isLoadingZkAccount} />; case IN_PROGRESS: - return ; + return ; case COMPLETED: - return ; + return ; case FAILED: - return ; + return ; } })()} @@ -235,15 +307,53 @@ const StatusTitle = styled.span` text-align: center; `; -const CheckIcon = styled(CheckIconDefault)` - margin-bottom: 16px; +const CheckCircleIcon = styled(CheckCircleIconDefault)` + margin-bottom: 20px; + margin-top: -24px; `; const CrossIcon = styled(CrossIconDefault)` - margin-bottom: 16px; + margin-bottom: 20px; + margin-top: -24px; `; const Button = styled(ButtonDefault)` width: 100%; margin-top: 20px; `; + +const SpinnerContainer = styled.div` + position: relative; + margin-bottom: 20px; + margin-top: -24px; +`; + +const ProgressText = styled.span` + font-size: 20px; + color: ${({ theme }) => theme.text.color.primary}; + font-weight: ${({ theme }) => theme.text.weight.bold}; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +`; + +const CopyIcon = styled(CopyIconDefault)` + width: 16px; + height: 16px; +`; + +const CheckIcon = styled(CheckIconDefault)` + width: 16px; + height: 16px; +`; + +const SupportIdContainer = styled.div` + text-align: center; + cursor: pointer; + &:hover ${CopyIcon} { + path { + fill: ${props => props.theme.color.purple}; + } + } +`; diff --git a/src/components/Tabs/index.js b/src/components/Tabs/index.js index 20e8e620..520394a0 100644 --- a/src/components/Tabs/index.js +++ b/src/components/Tabs/index.js @@ -1,7 +1,7 @@ import React from 'react'; import styled from 'styled-components'; -export default ({ tabs, activeTab, onTabClick }) => { +export default ({ tabs, activeTab, onTabClick, showBadge }) => { return ( {tabs.map((tab, index) => @@ -9,7 +9,8 @@ export default ({ tabs, activeTab, onTabClick }) => { key={index} active={activeTab === index} onClick={() => onTabClick(index)} - >{tab} + $showBadge={showBadge && tab.badge} + >{tab.name} )} ); @@ -37,6 +38,7 @@ const Tabs = styled.div` `; const Tab = styled.div` + position: relative; border-radius: 10px; padding: 8px 16px; background-color: ${props => props.theme.tab.background[props.active ? 'active' : 'default']}; @@ -50,4 +52,14 @@ const Tab = styled.div` padding: 8px 10px; text-align: center; } + &::after { + content: ''; + display: ${props => props.$showBadge ? 'block' : 'none'}; + position: absolute; + top: 8px; + right: 8px; + width: 6px; + height: 6px; + border-radius: 50%; + background-color: #E53E3E; `; diff --git a/src/config/index.js b/src/config/index.js index 5b4a3663..134f56e2 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -86,4 +86,4 @@ const config = { } }; -export default config[process.env.REACT_APP_CONFIG]; +export default config[process.env.REACT_APP_CONFIG || 'dev']; diff --git a/src/containers/AccountSetUpButton/index.js b/src/containers/AccountSetUpButton/index.js index 5c1453a4..eb251160 100644 --- a/src/containers/AccountSetUpButton/index.js +++ b/src/containers/AccountSetUpButton/index.js @@ -9,8 +9,8 @@ export default () => { const { isLoadingZkAccount } = useContext(ZkAccountContext); return ( if (!zkAccount) return - else if (isLoadingState || isLoadingLimits) return + else if (isLoadingState || isLoadingLimits) return else if (amount.isZero()) return else if (amount.lt(minTxAmount)) return else if (amount.gt(balance)) return diff --git a/src/pages/Transfer/MultiTransfer/index.js b/src/pages/Transfer/MultiTransfer/index.js index 6f5121e1..d8326423 100644 --- a/src/pages/Transfer/MultiTransfer/index.js +++ b/src/pages/Transfer/MultiTransfer/index.js @@ -156,7 +156,7 @@ export default forwardRef((props, ref) => { } {(() => { if (!zkAccount) return - else if (isLoadingState) return + else if (isLoadingState) return else if (!data) return else return ; })()} diff --git a/src/pages/Transfer/SingleTransfer/index.js b/src/pages/Transfer/SingleTransfer/index.js index 50cfcd97..7710dc8f 100644 --- a/src/pages/Transfer/SingleTransfer/index.js +++ b/src/pages/Transfer/SingleTransfer/index.js @@ -56,7 +56,7 @@ export default () => { let button = null; if (zkAccount) { if (isLoadingState) { - button = ; + button = ; } else if (amount.isZero()) { button = ; } else if (amount.lt(minTxAmount)) { diff --git a/src/pages/Withdraw/index.js b/src/pages/Withdraw/index.js index 1f8311e8..32f39ab2 100644 --- a/src/pages/Withdraw/index.js +++ b/src/pages/Withdraw/index.js @@ -66,7 +66,7 @@ export default () => { let button = null; if (zkAccount) { if (isLoadingState || isLoadingLimits) { - button = ; + button = ; } else if (amount.isZero()) { button = ; } else if (amount.lt(minTxAmount)) { diff --git a/src/pages/index.js b/src/pages/index.js index 7f604b40..973f419a 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -86,7 +86,7 @@ const Routes = ({ showWelcome, params }) => ( - + );