Commit 06a05bb0 authored by Max Alekseenko's avatar Max Alekseenko

add connect wallet button to header

parent dddbabdf
...@@ -17,6 +17,7 @@ import theme from 'theme'; ...@@ -17,6 +17,7 @@ import theme from 'theme';
import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary'; import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary';
import GoogleAnalytics from 'ui/shared/GoogleAnalytics'; import GoogleAnalytics from 'ui/shared/GoogleAnalytics';
import Layout from 'ui/shared/layout/Layout'; import Layout from 'ui/shared/layout/Layout';
import Web3ModalProvider from 'ui/shared/Web3ModalProvider';
import 'lib/setLocale'; import 'lib/setLocale';
...@@ -52,17 +53,19 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) { ...@@ -52,17 +53,19 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
{ ...ERROR_SCREEN_STYLES } { ...ERROR_SCREEN_STYLES }
onError={ handleError } onError={ handleError }
> >
<AppContextProvider pageProps={ pageProps }> <Web3ModalProvider>
<QueryClientProvider client={ queryClient }> <AppContextProvider pageProps={ pageProps }>
<ScrollDirectionProvider> <QueryClientProvider client={ queryClient }>
<SocketProvider url={ `${ config.api.socket }${ config.api.basePath }/socket/v2` }> <ScrollDirectionProvider>
{ getLayout(<Component { ...pageProps }/>) } <SocketProvider url={ `${ config.api.socket }${ config.api.basePath }/socket/v2` }>
</SocketProvider> { getLayout(<Component { ...pageProps }/>) }
</ScrollDirectionProvider> </SocketProvider>
<ReactQueryDevtools/> </ScrollDirectionProvider>
<GoogleAnalytics/> <ReactQueryDevtools/>
</QueryClientProvider> <GoogleAnalytics/>
</AppContextProvider> </QueryClientProvider>
</AppContextProvider>
</Web3ModalProvider>
</AppErrorBoundary> </AppErrorBoundary>
</ChakraProvider> </ChakraProvider>
); );
......
...@@ -10,6 +10,7 @@ import Transactions from 'ui/home/Transactions'; ...@@ -10,6 +10,7 @@ import Transactions from 'ui/home/Transactions';
import AdBanner from 'ui/shared/ad/AdBanner'; import AdBanner from 'ui/shared/ad/AdBanner';
import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop'; import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop';
import SearchBar from 'ui/snippets/searchBar/SearchBar'; import SearchBar from 'ui/snippets/searchBar/SearchBar';
import WalletMenuDesktop from 'ui/snippets/walletMenu/WalletMenuDesktop';
const Home = () => { const Home = () => {
return ( return (
...@@ -34,6 +35,7 @@ const Home = () => { ...@@ -34,6 +35,7 @@ const Home = () => {
</Heading> </Heading>
<Box display={{ base: 'none', lg: 'block' }}> <Box display={{ base: 'none', lg: 'block' }}>
{ config.features.account.isEnabled && <ProfileMenuDesktop isHomePage/> } { config.features.account.isEnabled && <ProfileMenuDesktop isHomePage/> }
<WalletMenuDesktop isHomePage/>
</Box> </Box>
</Flex> </Flex>
<LightMode> <LightMode>
......
...@@ -7,6 +7,8 @@ import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo'; ...@@ -7,6 +7,8 @@ import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo';
import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop'; import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop';
import ProfileMenuMobile from 'ui/snippets/profileMenu/ProfileMenuMobile'; import ProfileMenuMobile from 'ui/snippets/profileMenu/ProfileMenuMobile';
import SearchBar from 'ui/snippets/searchBar/SearchBar'; import SearchBar from 'ui/snippets/searchBar/SearchBar';
import WalletMenuDesktop from 'ui/snippets/walletMenu/WalletMenuDesktop';
import WalletMenuMobile from 'ui/snippets/walletMenu/WalletMenuMobile';
import Burger from './Burger'; import Burger from './Burger';
...@@ -42,7 +44,12 @@ const Header = ({ isHomePage, renderSearchBar }: Props) => { ...@@ -42,7 +44,12 @@ const Header = ({ isHomePage, renderSearchBar }: Props) => {
> >
<Burger/> <Burger/>
<NetworkLogo/> <NetworkLogo/>
{ config.features.account.isEnabled ? <ProfileMenuMobile/> : <Box boxSize={ 10 }/> } <Box display="flex">
{ config.features.account.isEnabled ? <ProfileMenuMobile/> : <Box boxSize={ 10 }/> }
<Box ml={ 2 }>
<WalletMenuMobile/>
</Box>
</Box>
</Flex> </Flex>
{ !isHomePage && searchBar } { !isHomePage && searchBar }
</Box> </Box>
...@@ -58,7 +65,10 @@ const Header = ({ isHomePage, renderSearchBar }: Props) => { ...@@ -58,7 +65,10 @@ const Header = ({ isHomePage, renderSearchBar }: Props) => {
<Box width="100%"> <Box width="100%">
{ searchBar } { searchBar }
</Box> </Box>
{ config.features.account.isEnabled && <ProfileMenuDesktop/> } <Box display="flex">
{ config.features.account.isEnabled && <ProfileMenuDesktop/> }
<WalletMenuDesktop/>
</Box>
</HStack> </HStack>
) } ) }
</Box> </Box>
......
import { Box, Button, Text, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
type Props = {
address?: string;
disconnect?: () => void;
};
const WalletMenuContent = ({ address, disconnect }: Props) => {
const primaryTextColor = useColorModeValue('blackAlpha.800', 'whiteAlpha.800');
return (
<Box>
<Text
fontSize="sm"
fontWeight={ 600 }
mb={ 1 }
color={ primaryTextColor }
{ ...getDefaultTransitionProps() }
>
My wallet
</Text>
<Text
fontSize="sm"
mb={ 5 }
fontWeight={ 400 }
color="gray.500"
{ ...getDefaultTransitionProps() }
>
Your wallet is used to interact with apps and contracts in the explorer.
</Text>
<AddressEntity
address={{ hash: address }}
noLink
noTooltip
truncation="dynamic"
fontSize="sm"
fontWeight={ 700 }
color={ primaryTextColor }
mb={ 6 }
/>
<Button size="sm" width="full" variant="outline" onClick={ disconnect }>
Disconnect
</Button>
</Box>
);
};
export default WalletMenuContent;
import type { ButtonProps } from '@chakra-ui/react';
import { Popover, PopoverContent, PopoverBody, PopoverTrigger, Button, useColorModeValue, Box, useBoolean } from '@chakra-ui/react';
import React from 'react';
import AddressIdenticon from 'ui/shared/entities/address/AddressIdenticon';
import HashStringShorten from 'ui/shared/HashStringShorten';
import useWallet from 'ui/snippets/walletMenu/useWallet';
import WalletMenuContent from 'ui/snippets/walletMenu/WalletMenuContent';
type Props = {
isHomePage?: boolean;
};
const WalletMenuDesktop = ({ isHomePage }: Props) => {
const { isWalletConnected, address, connect, disconnect, isModalOpening, isModalOpen } = useWallet();
const [ isPopoverOpen, setIsPopoverOpen ] = useBoolean(false);
const variant = React.useMemo(() => {
if (isWalletConnected) {
return 'subtle';
}
return isHomePage ? 'solid' : 'outline';
}, [ isWalletConnected, isHomePage ]);
let buttonStyles: Partial<ButtonProps> = {};
const themedBackground = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
const themedBorderColor = useColorModeValue('gray.300', 'gray.700');
const themedColor = useColorModeValue('blackAlpha.800', 'gray.400');
if (isWalletConnected) {
buttonStyles = {
bg: isHomePage ? '#EBF8FF' : themedBackground,
color: isHomePage ? 'blackAlpha.800' : themedColor,
_hover: {
color: isHomePage ? 'blackAlpha.800' : themedColor,
},
};
} else if (isHomePage) {
buttonStyles = {
color: '#FFFFFF',
};
} else {
buttonStyles = {
borderColor: themedBorderColor,
color: themedColor,
};
}
return (
<Popover
openDelay={ 300 }
placement="bottom-end"
gutter={ 10 }
isLazy
isOpen={ isPopoverOpen }
onClose={ setIsPopoverOpen.off }
>
<PopoverTrigger>
<Button
variant={ variant }
colorScheme="blue"
flexShrink={ 0 }
isLoading={ isModalOpening || isModalOpen }
loadingText="Connect wallet"
onClick={ isWalletConnected ? setIsPopoverOpen.on : connect }
ml={ 3 }
fontSize="sm"
{ ...buttonStyles }
>
{ isWalletConnected ? (
<>
<Box mr={ 2 }>
<AddressIdenticon size={ 20 } hash={ address }/>
</Box>
<HashStringShorten hash={ address } isTooltipDisabled/>
</>
) : 'Connect wallet' }
</Button>
</PopoverTrigger>
{ isWalletConnected && (
<PopoverContent w="235px">
<PopoverBody padding="24px 16px 16px 16px">
<WalletMenuContent address={ address } disconnect={ disconnect }/>
</PopoverBody>
</PopoverContent>
) }
</Popover>
);
};
export default WalletMenuDesktop;
import { Drawer, DrawerOverlay, DrawerContent, DrawerBody, useDisclosure, IconButton, useColorModeValue, Icon } from '@chakra-ui/react';
import React from 'react';
import walletIcon from 'icons/wallet.svg';
import AddressIdenticon from 'ui/shared/entities/address/AddressIdenticon';
import useWallet from 'ui/snippets/walletMenu/useWallet';
import WalletMenuContent from 'ui/snippets/walletMenu/WalletMenuContent';
const WalletMenuMobile = () => {
const { isOpen, onOpen, onClose } = useDisclosure();
const { isWalletConnected, address, connect, disconnect, isModalOpening, isModalOpen } = useWallet();
const themedBackground = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
const themedBorderColor = useColorModeValue('gray.300', 'gray.700');
const themedColor = useColorModeValue('blackAlpha.800', 'gray.400');
return (
<>
<IconButton
aria-label="wallet menu"
icon={ isWalletConnected ?
<AddressIdenticon size={ 20 } hash={ address }/> :
<Icon as={ walletIcon } boxSize={ 6 }/>
}
variant={ isWalletConnected ? 'subtle' : 'outline' }
colorScheme="gray"
boxSize="40px"
flexShrink={ 0 }
bg={ isWalletConnected ? themedBackground : undefined }
color={ themedColor }
borderColor={ !isWalletConnected ? themedBorderColor : undefined }
onClick={ isWalletConnected ? onOpen : connect }
isLoading={ isModalOpening || isModalOpen }
/>
{ isWalletConnected && (
<Drawer
isOpen={ isOpen }
placement="right"
onClose={ onClose }
autoFocus={ false }
>
<DrawerOverlay/>
<DrawerContent maxWidth="260px">
<DrawerBody p={ 6 }>
<WalletMenuContent address={ address } disconnect={ disconnect }/>
</DrawerBody>
</DrawerContent>
</Drawer>
) }
</>
);
};
export default WalletMenuMobile;
import { useWeb3Modal } from '@web3modal/react';
import React from 'react';
import { useAccount, useDisconnect } from 'wagmi';
import * as mixpanel from 'lib/mixpanel/index';
export default function useWallet() {
const { open, isOpen } = useWeb3Modal();
const { disconnect } = useDisconnect();
const [ isModalOpening, setIsModalOpening ] = React.useState(false);
const [ isClientLoaded, setIsClientLoaded ] = React.useState(false);
React.useEffect(() => {
setIsClientLoaded(true);
}, []);
const handleConnect = React.useCallback(async() => {
setIsModalOpening(true);
await open();
setIsModalOpening(false);
mixpanel.logEvent(mixpanel.EventTypes.WALLET_CONNECT, { Status: 'Started' });
}, [ open ]);
const handleAccountConnected = React.useCallback(({ isReconnected }: { isReconnected: boolean }) => {
!isReconnected && mixpanel.logEvent(mixpanel.EventTypes.WALLET_CONNECT, { Status: 'Connected' });
}, []);
const handleDisconnect = React.useCallback(() => {
disconnect();
}, [ disconnect ]);
const { address, isDisconnected } = useAccount({ onConnect: handleAccountConnected });
const isWalletConnected = isClientLoaded && !isDisconnected && address !== undefined;
return {
isWalletConnected,
address: address || '',
connect: handleConnect,
disconnect: handleDisconnect,
isModalOpening,
isModalOpen: isOpen,
};
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment