Skip to content

Commit

Permalink
feat: Add back in Figure Wallet support
Browse files Browse the repository at this point in the history
  • Loading branch information
jarrydallison committed Oct 23, 2024
1 parent cd0eeff commit ea9957f
Show file tree
Hide file tree
Showing 10 changed files with 637 additions and 52 deletions.
418 changes: 415 additions & 3 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@cosmos-kit/react": "2.20.0",
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
"@interchain-ui/react": "1.25.3",
"@provenanceio/walletconnect-js": "3.10.2",
"@provlabs/provenancejs": "0.0.6",
"@reduxjs/toolkit": "1.8.1",
"@reown/appkit": "1.0.7",
Expand Down
15 changes: 14 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useEffect } from 'react';
import { ThemeProvider } from 'styled-components';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import { useAssets, useColorScheme } from '../src/redux/hooks';
import { useWalletConnect } from '@provenanceio/walletconnect-js';
import { useAssets, useColorScheme, useApp } from '../src/redux/hooks';
import { Navigation, Footer, SpriteSheet, BaseStyle } from '../src/Components';
import { GlobalStyle } from '../src/theme';
import { isProd } from '../src/consts';
Expand Down Expand Up @@ -42,6 +43,12 @@ import {
const App = () => {
const { activeTheme } = useColorScheme();

const { setAuthToken } = useApp();

const {
walletConnectState: { signedJWT },
} = useWalletConnect();

const { assetMetadata, assetMetadataLoading, getAssetMetadata, assetMetadataFailed } =
useAssets();

Expand All @@ -51,6 +58,12 @@ const App = () => {
}
}, [assetMetadata, assetMetadataLoading, getAssetMetadata, assetMetadataFailed]);

useEffect(() => {
if (signedJWT) {
setAuthToken(signedJWT);
}
}, [setAuthToken, signedJWT]);

return (
<BrowserRouter basename={import.meta.env.PUBLIC_URL || ''}>
<GlobalStyle theme={activeTheme} />
Expand Down
191 changes: 168 additions & 23 deletions src/Components/UserAccount/UserAccount.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { useEffect, useState } from 'react';
import styled, { useTheme } from 'styled-components';
import { wallets } from '@cosmos-kit/leap-extension';
import { QRCodeModal, useWalletConnect } from '@provenanceio/walletconnect-js';
import { Link as BaseLink } from 'react-router-dom';
// @ts-ignore
import useOnClickOutside from 'react-tiny-hooks/use-on-click-outside';
// @ts-ignore
Expand All @@ -8,13 +11,16 @@ import useOnEscape from 'react-tiny-hooks/use-on-escape';
import useToggle from 'react-tiny-hooks/use-toggle';
import { useChain } from '@cosmos-kit/react';
import { cosmos } from '@provlabs/provenancejs';
import { maxLength } from '../../utils';
import { signJWT } from '../../utils/jwt';
import { CHAIN_NAME } from '../../config';
import { ICON_NAMES } from '../../consts';
import { breakpoints, ICON_NAMES, isProd } from '../../consts';
import { useApp } from '../../redux/hooks';
import { PopupNote } from '../../Components/PopupNote';
import Button from '../Button';
import Sprite from '../Sprite';
import Modal from '../../Components/Modal';
import figureWallet from '../../assets/figureMobileWalletIcon.png';

const Container = styled.div`
position: relative;
Expand All @@ -30,59 +36,128 @@ const AccountBtn = styled(Button)<{ isLoggedIn?: boolean }>`
animation-iteration-count: ${({ isLoggedIn }) => (isLoggedIn ? 0 : 2)};
`;

const PopupTxt = styled.p`
text-align: center;
@media ${breakpoints.up('md')} {
white-space: nowrap;
}
`;

const LogoutButton = styled(Button)`
float: right;
`;

const Link = styled(BaseLink)`
&&& {
:hover {
opacity: 1;
text-decoration: underline;
}
:visited {
color: ${({ theme }) => theme.FONT_NAV_VISITED};
}
color: ${({ theme }) => theme.FONT_NAV};
}
`;

const ModalContent = styled.div`
display: grid;
grid-template-columns: 1fr;
justify-content: center;
justify-items: center;
grid-auto-columns: max-content;
@media ${breakpoints.up('md')} {
grid-template-columns: 1fr 1fr;
}
`;

const ModalTitle = styled.div`
font-weight: ${({ theme }) => theme.FONT_WEIGHT_BOLD};
margin: 5px 0 10px 0;
font-size: 1.063rem;
`;

const ModalWalletButton = styled.div`
padding: 0 20px 20px 20px;
border-radius: 8px;
font-size: 1rem;
width: 100%;
font-weight: ${({ theme }) => theme.FONT_WEIGHT_BOLD};
display: flex;
flex-direction: column;
text-align: center;
justify-items: center;
justify-content: center;
max-width: 200px;
cursor: pointer;
:hover {
background-color: ${({ theme }) => theme.BACKGROUND_LIGHT};
}
`;

const WalletTitle = styled.p`
margin-bottom: 4px;
`;

const UserAccount = ({ isMobile }: { isMobile: boolean }) => {
const { isLoggedIn, setIsLoggedIn, setWalletAddress } = useApp();
const { isLoggedIn, setIsLoggedIn, setWalletAddress, setAuthToken, authToken, setWalletUrl } = useApp();
const theme = useTheme();
const position = isMobile ? 'above' : 'left';
const [visible, setVisible] = useState(false);

const [, , , deactivateShowPopup] = useToggle();
const [showPopup, toggleShowPopup, , deactivateShowPopup] = useToggle();
const containerRef = useOnClickOutside(deactivateShowPopup);
useOnEscape(deactivateShowPopup);

const { status, connect, address, signArbitrary, getSigningStargateClient, getAccount, wallet } =
useChain(CHAIN_NAME);
const { setAuthToken, authToken } = useApp();
// This is the old Figure Wallet stuff
const { walletConnectService: wcs, walletConnectState } = useWalletConnect();
// This is Leap
const {
status,
connect,
address,
signArbitrary,
isWalletDisconnected,
wallet,
getSigningStargateClient,
getAccount,
} = useChain(CHAIN_NAME);
const provJWT = localStorage.getItem('provenanceJWT');
const jwtInfo = provJWT ? JSON.parse(provJWT) : '';
const signedJWT = jwtInfo.expires < Date.now() / 1000 ? '' : jwtInfo.jwt;

useEffect(() => {
if (status === 'Disconnected') {
if (isWalletDisconnected && !walletConnectState.connected) {
localStorage.removeItem('provenanceJWT');
setIsLoggedIn(false);
setAuthToken('');
setWalletAddress('');
}
}, [setAuthToken, setWalletAddress, status, setIsLoggedIn]);
}, [setAuthToken, setWalletAddress, status, isWalletDisconnected, setIsLoggedIn, walletConnectState]);

useEffect(() => {
if (jwtInfo && jwtInfo.expires < Date.now() / 1000) {
localStorage.removeItem('provenanceJWT');
setIsLoggedIn(false);
setAuthToken('');
setWalletAddress('');
setIsLoggedIn(false);
}
}, [jwtInfo, setAuthToken, setIsLoggedIn, setWalletAddress]);
}, [jwtInfo, setIsLoggedIn, setWalletAddress]);

useEffect(() => {
if (signedJWT) {
if (signedJWT && status === 'Connected') {
setAuthToken(signedJWT);
}
}, [setAuthToken, signedJWT]);
}, [setAuthToken, signedJWT, status]);

useEffect(() => {
setIsLoggedIn(status === 'Connected');
if (address) {
setWalletAddress(address);
setIsLoggedIn(status === 'Connected' || walletConnectState.status === 'connected');
if (address || walletConnectState.address) {
setWalletAddress(address || walletConnectState.address);
}
}, [status, address, setIsLoggedIn, setWalletAddress]);
}, [status, address, setIsLoggedIn, setWalletAddress, walletConnectState]);

// This is the effect that signs the local JWT to access the explorer service
// This only occurs when connecting to Leap wallets
useEffect(() => {
const initialSigningEvent = async () => {
if (
!authToken &&
status === 'Connected' &&
address &&
wallet &&
Expand Down Expand Up @@ -161,9 +236,24 @@ const UserAccount = ({ isMobile }: { isMobile: boolean }) => {
]);

const handleLoginClick = () => {
connect();
if (wallet?.name.includes('leap')) {
connect()
} else {
toggleShowPopup();
wcs.connect();
}
};

const handleLogoutFigureWallet = () => {
setWalletAddress('')
setWalletUrl('')
setIsLoggedIn(false)
wcs.disconnect();
setVisible(false);
}

const [openSelectWalletModal, setOpenSelectWalletModal] = useState(false);

return (
<Container
ref={containerRef}
Expand All @@ -173,13 +263,68 @@ const UserAccount = ({ isMobile }: { isMobile: boolean }) => {
<PopupNote show={!isLoggedIn && visible} position={position} zIndex="201">
Login
</PopupNote>
<AccountBtn onClick={handleLoginClick} isLoggedIn={isLoggedIn}>
<AccountBtn
onClick={isLoggedIn ? handleLoginClick : () => setOpenSelectWalletModal(true)}
isLoggedIn={isLoggedIn}
>
<Sprite
icon={isLoggedIn ? ICON_NAMES.ACCOUNT : ICON_NAMES.KEY}
color={theme.FONT_NAV}
size="20px"
/>
</AccountBtn>
{isLoggedIn && (
<PopupNote show={showPopup} position={position} delay={0} zIndex="201">
<PopupTxt>You are currently logged in as</PopupTxt>
<PopupTxt>
<Link to={`/accounts/${walletConnectState.address}`}>
{isMobile ? maxLength(walletConnectState.address, 11, '3') : walletConnectState.address}
</Link>
</PopupTxt>
<LogoutButton color="secondary" onClick={handleLogoutFigureWallet} icon={ICON_NAMES.LOGOUT}>
Sign Out
</LogoutButton>
</PopupNote>
)}
<Modal isOpen={openSelectWalletModal} onClose={() => setOpenSelectWalletModal(false)}>
<div>
<ModalTitle>Select a Wallet Provider</ModalTitle>
<ModalContent>
<ModalWalletButton
onClick={() => {
setOpenSelectWalletModal(false);
connect();
}}
>
<WalletTitle>Leap Wallet</WalletTitle>
<img src={wallets[0].walletInfo.logo as string} alt="Leap Wallet" />
</ModalWalletButton>
<ModalWalletButton
onClick={() => {
setOpenSelectWalletModal(false);
wcs.connect();
}}
>
<WalletTitle>Figure Wallet</WalletTitle>
<img src={figureWallet} alt="Figure Wallet" />
</ModalWalletButton>
</ModalContent>
</div>
</Modal>
<QRCodeModal
walletConnectService={wcs}
title="Scan the QRCode with your mobile Provenance Blockchain Wallet."
className="QR-Code-Modal"
devWallets={[
'figure_mobile_test',
'figure_hosted_test',
// @ts-ignore
'provenance_extension',
// @ts-ignore
'provenance_mobile',
]}
hideWallets={isProd ? ['figure_hosted_test'] : ['figure_hosted']}
/>
</Container>
);
};
Expand Down
Loading

0 comments on commit ea9957f

Please sign in to comment.