Files
tom goriunovandGitHub 401dc58402 Smart wallet auth (#3220)
* basic login button implementation

* refactoring and add dynamic auth button to the other pages

* connect wallet without authenticating an user

* login and logout user in blockscout account

* refactoring and RPC overrides

* authenticate user with connected wallet

* add ENS to profile button

* override evm chains and fix contract write with waas wallet

* disconnect wallet and fix docker build

* add dynamic imports to components that use web3 wallet packages

* refactor user profile directory

* clean up

* tweaks

* update pw ci script

* fix "connect wallet" button behavior

* handle linking email to profile with dynamic provider

* fix test

* async loading web3 hooks and remove dynamic loading from components that use them

* fix pw tests

* add account navigation in horizontal layout when auth provider is dynamic

* fix address verification modal

* review fixes

* spelling fixes
2026-02-18 19:42:44 +01:00

101 lines
3.3 KiB
TypeScript

import type { ButtonProps } from '@chakra-ui/react';
import { Box, HStack } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react';
import type { UserInfo } from 'types/api/account';
import { useMarketplaceContext } from 'lib/contexts/marketplace';
import useIsMobile from 'lib/hooks/useIsMobile';
import shortenString from 'lib/shortenString';
import useWeb3AccountWithDomain from 'lib/web3/useAccountWithDomain';
import { Button } from 'toolkit/chakra/button';
import { Tooltip } from 'toolkit/chakra/tooltip';
import IconSvg from 'ui/shared/IconSvg';
import UserIdenticon from '../../UserIdenticon';
import { getUserHandle } from '../common/utils';
interface Props {
profileQuery: UseQueryResult<UserInfo, unknown>;
size?: ButtonProps['size'];
variant?: ButtonProps['variant'];
onClick: () => void;
isPending?: boolean;
}
const UserProfileButton = ({ profileQuery, size, variant, onClick, isPending, ...rest }: Props, ref: React.ForwardedRef<HTMLButtonElement>) => {
const [ isFetched, setIsFetched ] = useState(false);
const isMobile = useIsMobile();
const { data, isLoading } = profileQuery;
const web3AccountWithDomain = useWeb3AccountWithDomain(true);
const { isAutoConnectDisabled } = useMarketplaceContext();
React.useEffect(() => {
if (!isLoading) {
setIsFetched(true);
}
}, [ isLoading ]);
const handleFocus = useCallback((e: React.FocusEvent<HTMLButtonElement>) => {
e.preventDefault();
}, []);
const isButtonLoading = isPending || !isFetched || web3AccountWithDomain.isLoading;
const dataExists = !isButtonLoading && (Boolean(data) || Boolean(web3AccountWithDomain.address));
const content = (() => {
if (web3AccountWithDomain.address && !isButtonLoading) {
return (
<HStack gap={ 2 }>
<UserIdenticon address={ web3AccountWithDomain.address } isAutoConnectDisabled={ isAutoConnectDisabled }/>
<Box display={{ base: 'none', md: 'block' }} maxW="200px" overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap">
{ web3AccountWithDomain.domain || shortenString(web3AccountWithDomain.address) }
</Box>
</HStack>
);
}
if (!data || isButtonLoading) {
return 'Log in';
}
return (
<HStack gap={ 2 }>
<IconSvg name="profile" boxSize={ 5 }/>
<Box display={{ base: 'none', md: 'block' }}>{ data.email ? getUserHandle(data.email) : 'My profile' }</Box>
</HStack>
);
})();
return (
<Tooltip
content={ <span>Sign in to My Account to add tags,<br/>create watchlists, access API keys and more</span> }
disabled={ isMobile || isLoading || Boolean(data) }
openDelay={ 500 }
disableOnMobile
>
<span>
<Button
ref={ ref }
size={ size }
variant={ variant }
onClick={ onClick }
onFocus={ handleFocus }
selected={ dataExists }
highlighted={ isAutoConnectDisabled }
px={{ base: 2.5, lg: 3 }}
fontWeight={ dataExists ? 700 : 600 }
loading={ isButtonLoading }
{ ...rest }
>
{ content }
</Button>
</span>
</Tooltip>
);
};
export default React.forwardRef(UserProfileButton);