Skip to content

Commit

Permalink
Merge pull request #30 from vechainfoundation/carpini/isolate-component
Browse files Browse the repository at this point in the history
feat: isolate button component
  • Loading branch information
davidecarpini authored Oct 27, 2023
2 parents f1044af + 69d9f37 commit fc03020
Show file tree
Hide file tree
Showing 15 changed files with 459 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import type { HTMLChakraProps } from '@chakra-ui/react';
import { Button, Icon, useDisclosure } from '@chakra-ui/react';
import { WalletIcon } from '@heroicons/react/24/solid';
import { useDisclosure } from '@chakra-ui/react';
import React from 'react';
import { useWallet } from '@vechain/react-wallet-kit';
import { ConnectWalletButton, useWallet } from '@vechain/react-wallet-kit';
import { AccountDetailModal } from './AccountDetailModal';
import { AddressButton } from './AddressButton';
import { ConnectWalletModal } from './ConnectWalletModal';

interface ConnectWalletButtonProps {
interface SwitchWalletButtonProps {
buttonProps?: HTMLChakraProps<'button'>;
}

export const ConnectWalletButton: React.FC<ConnectWalletButtonProps> = ({
export const SwitchWalletButton: React.FC<SwitchWalletButtonProps> = ({
buttonProps,
}): React.ReactElement => {
const { isOpen, onOpen, onClose } = useDisclosure();
Expand All @@ -38,16 +36,5 @@ export const ConnectWalletButton: React.FC<ConnectWalletButtonProps> = ({
</>
);

return (
<>
<ConnectWalletModal isOpen={isOpen} onClose={onClose} />
<Button
{...buttonProps}
leftIcon={<Icon as={WalletIcon} />}
onClick={onOpen}
>
Connect Wallet
</Button>
</>
);
return <ConnectWalletButton buttonProps={buttonProps} />;
};
2 changes: 1 addition & 1 deletion apps/sample-react-app/src/Components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ export * from './AccountDetailBody';
export * from './AccountDetailModal';
export * from './AddressButton';
export * from './AddressIcon';
export * from './ConnectWalletButton';
export * from './SwitchWalletButton';
export * from './ConnectWalletModal';
export * from './WalletSourceRadio';
6 changes: 3 additions & 3 deletions apps/sample-react-app/src/Components/layout/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { Bars3Icon } from '@heroicons/react/24/solid';
import { useWallet } from '@vechain/react-wallet-kit';
import { VechainLogo } from '../../Logos';
import { AccountDetailBody } from '../AccountDetailBody';
import { ConnectWalletButton } from '../ConnectWalletButton';
import { SwitchWalletButton } from '../SwitchWalletButton';

export const NavBar = (): JSX.Element => {
const bg = useColorModeValue('gray.50', 'gray.900');
Expand Down Expand Up @@ -101,7 +101,7 @@ const MobileNavBarDrawer = ({
source={accountState.source}
/>
) : (
<ConnectWalletButton />
<SwitchWalletButton />
)}
</VStack>
</VStack>
Expand All @@ -114,7 +114,7 @@ const MobileNavBarDrawer = ({
const NavBarWalletConnect = (): JSX.Element => {
return (
<HStack spacing={4}>
<ConnectWalletButton />
<SwitchWalletButton />
</HStack>
);
};
4 changes: 2 additions & 2 deletions apps/sample-react-app/src/Screens/components/Welcome.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Button, Heading, HStack, Link, Text, VStack } from '@chakra-ui/react';
import type { JSX } from 'react';
import { StyledCard } from '../../Components/shared';
import { ConnectWalletButton } from '../../Components';
import { SwitchWalletButton } from '../../Components';

export const Welcome = (): JSX.Element => {
return (
Expand All @@ -18,7 +18,7 @@ export const Welcome = (): JSX.Element => {
w="full"
wrap="wrap"
>
<ConnectWalletButton />
<SwitchWalletButton />
<Link
href="https://github.com/vechainfoundation/veworld-dapp"
isExternal
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
],
"scripts": {
"build": "turbo run build",
"build-react-kit": "turbo run build --filter='@vechain/react-wallet-kit'",
"build:deps": "turbo build --no-daemon --filter='@vechain/*'",
"clean": "npx turbo@latest run clean && rm -rf node_modules .turbo",
"dev": "turbo run dev --no-daemon",
Expand Down
3 changes: 3 additions & 0 deletions packages/react-wallet-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
"lint": "eslint src --ext .js,.jsx,.ts,.tsx"
},
"dependencies": {
"@chakra-ui/react": "^2.8.1",
"@heroicons/react": "^2.0.18",
"@vechain/connex": "2.1.0",
"@vechain/connex-framework": "2.1.0",
"@vechain/picasso": "^2.1.1",
"@vechain/wallet-connect": "*",
"@vechain/wallet-kit": "*",
"thor-devkit": "^2.0.9"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import {
Alert,
AlertIcon,
Box,
Button,
Flex,
HStack,
Icon,
Spinner,
Text,
VStack,
} from '@chakra-ui/react';
import { LinkIcon, WalletIcon } from '@heroicons/react/24/solid';
import React, { useCallback, useState } from 'react';
import { Certificate } from 'thor-devkit';
import { useConnex, useWallet } from '../../ConnexProvider';
import { Dialog } from './Dialog';
import { WalletSourceRadio } from './WalletSourceRadio';

interface ConnectedWalletDialogProps {
isOpen: boolean;
onClose: () => void;
}

export const ConnectWalletModal: React.FC<ConnectedWalletDialogProps> = ({
isOpen,
onClose,
}) => {
const header = (
<HStack spacing={2}>
<Icon as={WalletIcon} />
<Text>Connect Wallet</Text>
</HStack>
);

return (
<Dialog
body={<ConnectedWalletBody onClose={onClose} />}
header={header}
isOpen={isOpen}
onClose={onClose}
/>
);
};

interface ConnectedWalletBodyProps {
onClose: () => void;
}

const ConnectedWalletBody: React.FC<ConnectedWalletBodyProps> = ({
onClose,
}) => {
const { setAccount } = useWallet();
const { vendor } = useConnex();

const [connectionLoading, setConnectionLoading] = useState(false);
const [connectionError, setConnectionError] = useState('');

const connectToWalletHandler =
useCallback(async (): Promise<Certificate> => {
const message: Connex.Vendor.CertMessage = {
purpose: 'identification',
payload: {
type: 'text',
content: 'Sign a certificate to prove your identity',
},
};

if (!vendor) throw new Error('Vendor not available');

const certResponse = await vendor.sign('cert', message).request();

const cert: Certificate = {
purpose: message.purpose,
payload: message.payload,
domain: certResponse.annex.domain,
timestamp: certResponse.annex.timestamp,
signer: certResponse.annex.signer,
signature: certResponse.signature,
};

Certificate.verify(cert);

return cert;
}, [vendor]);

const onSuccessfullConnection = useCallback(
(cert: Certificate): void => {
setAccount(cert.signer);
onClose();
},
[setAccount, onClose],
);

const connectHandler = useCallback(async () => {
try {
setConnectionError('');
setConnectionLoading(true);

const cert = await connectToWalletHandler();

onSuccessfullConnection(cert);
} catch (e) {
if (e instanceof Error) {
setConnectionError(e.message);
} else {
setConnectionError('Failed to connect to wallet');
}
} finally {
setConnectionLoading(false);
}
}, [
onSuccessfullConnection,
setConnectionError,
setConnectionLoading,
connectToWalletHandler,
]);

const connect = useCallback(() => {
connectHandler().catch((e) => {
throw e;
});
}, [connectHandler]);

return (
<>
<Flex direction="column" gap={8}>
<Box>
<Text mb="8px">Wallet</Text>
<WalletSourceRadio />
</Box>
</Flex>
<VStack mt={8} spacing={4} w="full">
{connectionLoading ? (
<Alert status="warning">
<AlertIcon />
Waiting for wallet approval...
</Alert>
) : null}
{connectionError ? (
<Alert status="error">
<AlertIcon />
{connectionError}
</Alert>
) : null}

<Button
colorScheme="blue"
disabled={connectionLoading}
leftIcon={
connectionLoading ? <Spinner /> : <Icon as={LinkIcon} />
}
onClick={connect}
w="full"
>
{connectionLoading ? 'Connecting...' : 'Connect'}
</Button>
</VStack>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { HTMLChakraProps } from '@chakra-ui/react';
import {
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
} from '@chakra-ui/react';
import React from 'react';

interface DialogProps {
isOpen: boolean;
onClose: () => void;
header?: React.ReactNode;
headerStyle?: HTMLChakraProps<'header'>;
body?: React.ReactNode;
footer?: React.ReactNode;
showCloseButton?: boolean;
closeButtonStyle?: HTMLChakraProps<'button'>;
}

export const Dialog: React.FC<DialogProps> = ({
isOpen,
onClose,
header,
headerStyle = {},
body,
footer,
showCloseButton = true,
closeButtonStyle = {},
}) => {
return (
<Modal isOpen={isOpen} onClose={onClose} trapFocus={false}>
<ModalOverlay />
<ModalContent>
{header ? (
<ModalHeader {...headerStyle}>{header}</ModalHeader>
) : null}
{showCloseButton ? (
<ModalCloseButton {...closeButtonStyle} />
) : null}
{body ? <ModalBody>{body}</ModalBody> : null}
{footer ? <ModalFooter>{footer}</ModalFooter> : null}
</ModalContent>
</Modal>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { HTMLChakraProps } from '@chakra-ui/react';
import { Box, Button, Flex, HStack } from '@chakra-ui/react';
import React from 'react';

interface RadioCardProps extends HTMLChakraProps<'button'> {
children: React.ReactNode;
selected: boolean;
onClick: () => void;
}

export const RadioCard: React.FC<RadioCardProps> = ({
children,
selected,
onClick,
...props
}) => {
return (
<Button
shadow={selected ? 'outline' : 'none'}
variant="outline"
w="full"
{...props}
>
<HStack
justify="space-between"
onClick={onClick}
spacing={2}
w="full"
>
{children}
<RadioCircle filled={selected} />
</HStack>
</Button>
);
};

interface RadioCircleProps extends HTMLChakraProps<'div'> {
filled?: boolean;
}

const RadioCircle: React.FC<RadioCircleProps> = ({
filled = false,
...props
}) => {
return (
<Flex
align="center"
border="1px solid"
borderColor="lightgray"
justify="center"
p={1}
rounded="full"
{...props}
>
<Box
bg={filled ? 'blue.500' : 'transparent'}
display="block"
h={2.5}
margin="auto"
minW={2.5}
rounded="full"
w={2.5}
/>
</Flex>
);
};
Loading

0 comments on commit fc03020

Please sign in to comment.