-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from ar-io/PE-5967-wallet-connection-profile-me…
…nu-ar-connect PE-5967: wallet connection profile menu AR connect
- Loading branch information
Showing
26 changed files
with
748 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
20.9.0 | ||
20.12.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { useEffectOnce } from '@src/hooks/useEffectOnce'; | ||
import { useGlobalState } from '@src/store'; | ||
import { ReactElement, useEffect } from 'react'; | ||
|
||
const GlobalDataProvider = ({ | ||
children, | ||
}: { | ||
children: ReactElement; | ||
}) => { | ||
const twoMinutes = 120000; | ||
|
||
const setBlockHeight = useGlobalState((state) => state.setBlockHeight); | ||
const setCurrentEpoch = useGlobalState((state) => state.setCurrentEpoch); | ||
const arweave = useGlobalState((state) => state.arweave); | ||
const arioReadSDK = useGlobalState((state) => state.arIOReadSDK); | ||
|
||
useEffectOnce(() => { | ||
const update = async () => { | ||
const currentEpoch = await arioReadSDK.getCurrentEpoch(); | ||
setCurrentEpoch(currentEpoch); | ||
}; | ||
|
||
update(); | ||
}); | ||
|
||
useEffect(() => { | ||
const updateBlockHeight = async () => { | ||
const blockHeight = await (await arweave.blocks.getCurrent()).height; | ||
setBlockHeight(blockHeight); | ||
}; | ||
updateBlockHeight(); | ||
const interval = setInterval(updateBlockHeight, twoMinutes); | ||
|
||
return () => { | ||
clearInterval(interval); | ||
}; | ||
}); | ||
|
||
return <>{children}</>; | ||
}; | ||
|
||
export default GlobalDataProvider; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { Popover } from '@headlessui/react'; | ||
import { useGlobalState } from '@src/store'; | ||
import { formatBalance, formatWalletAddress } from '@src/utils'; | ||
import { forwardRef, useState } from 'react'; | ||
import Button, { ButtonType } from './Button'; | ||
import { | ||
ConnectIcon, | ||
GearIcon, | ||
LogoutIcon, | ||
StakingIcon, | ||
WalletIcon, | ||
} from './icons'; | ||
import ConnectModal from './modals/ConnectModal'; | ||
|
||
// eslint-disable-next-line react/display-name | ||
const CustomPopoverButton = forwardRef<HTMLButtonElement>((props, ref) => { | ||
return ( | ||
<Button | ||
forwardRef={ref} | ||
buttonType={ButtonType.PRIMARY} | ||
icon={<ConnectIcon />} | ||
title="Profile" | ||
{...props} | ||
/> | ||
); | ||
}); | ||
|
||
const Profile = () => { | ||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false); | ||
|
||
const walletStateInitialized = useGlobalState( | ||
(state) => state.walletStateInitialized, | ||
); | ||
|
||
const wallet = useGlobalState((state) => state.wallet); | ||
const balances = useGlobalState((state) => state.balances); | ||
const updateWallet = useGlobalState((state) => state.updateWallet); | ||
const walletAddress = useGlobalState((state) => state.walletAddress); | ||
|
||
return walletAddress ? ( | ||
<Popover className="relative"> | ||
<Popover.Button as={CustomPopoverButton} /> | ||
|
||
<Popover.Panel | ||
className="absolute right-0 z-10 mt-[10px] w-[240px] | ||
rounded-[12px] border border-grey-800 bg-grey-1000 px-[16px] text-sm shadow-md" | ||
> | ||
<div className="flex gap-[8px] py-[20px]"> | ||
<WalletIcon /> | ||
<div className="text-sm text-high"> | ||
{formatWalletAddress(walletAddress.toString())} | ||
</div> | ||
</div> | ||
<div className="rounded-[6px] border border-grey-800 py-[12px]"> | ||
<div className="px-[16px] text-xs text-low">IO Balance</div> | ||
<div className="border-b border-grey-800 px-[16px] pb-[12px] pt-[4px] text-high"> | ||
{formatBalance(balances.io)} | ||
</div> | ||
<div className="px-[16px] pt-[12px] text-xs text-low">AR Balance</div> | ||
<div className="px-[16px] pt-[4px] text-high"> | ||
{formatBalance(balances.ar)} | ||
</div> | ||
</div> | ||
<div className="flex flex-col gap-[12px] py-[12px] text-mid"> | ||
<button className="flex items-center gap-[8px]"> | ||
<GearIcon /> Gateway Management | ||
</button> | ||
<button className="flex items-center gap-[8px]"> | ||
<StakingIcon /> Delegated Staking | ||
</button> | ||
<button | ||
className="flex items-center gap-[8px]" | ||
title="Logout" | ||
onClick={async () => { | ||
await wallet?.disconnect(); | ||
updateWallet(undefined, undefined); | ||
}} | ||
> | ||
<LogoutIcon /> Logout | ||
</button> | ||
</div> | ||
</Popover.Panel> | ||
</Popover> | ||
) : walletStateInitialized ? ( | ||
<div> | ||
<Button | ||
buttonType={ButtonType.PRIMARY} | ||
icon={<ConnectIcon />} | ||
title="Connect" | ||
text="Connect" | ||
onClick={() => setIsModalOpen(true)} | ||
/> | ||
<ConnectModal open={isModalOpen} onClose={() => setIsModalOpen(false)} /> | ||
</div> | ||
) : ( | ||
<div></div> | ||
); | ||
}; | ||
export default Profile; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { useEffectOnce } from '@src/hooks/useEffectOnce'; | ||
import { ArConnectWalletConnector } from '@src/services/wallets/ArConnectWalletConnector'; | ||
import { useGlobalState } from '@src/store'; | ||
import { WALLET_TYPES } from '@src/types'; | ||
import { mioToIo } from '@src/utils'; | ||
import { ArweaveTransactionID } from '@src/utils/ArweaveTransactionId'; | ||
import Ar from 'arweave/web/ar'; | ||
import { ReactElement, useEffect } from 'react'; | ||
|
||
const AR = new Ar(); | ||
|
||
const WalletProvider = ({ children }: { children: ReactElement }) => { | ||
const blockHeight = useGlobalState((state) => state.blockHeight); | ||
const walletAddress = useGlobalState((state) => state.walletAddress); | ||
const setWalletStateInitialized = useGlobalState( | ||
(state) => state.setWalletStateInitialized, | ||
); | ||
const updateWallet = useGlobalState((state) => state.updateWallet); | ||
const setBalances = useGlobalState((state) => state.setBalances); | ||
const arweave = useGlobalState((state) => state.arweave); | ||
const arIOReadSDK = useGlobalState((state) => state.arIOReadSDK); | ||
|
||
useEffect(() => { | ||
window.addEventListener('arweaveWalletLoaded', updateIfConnected); | ||
|
||
return () => { | ||
window.removeEventListener('arweaveWalletLoaded', updateIfConnected); | ||
}; | ||
}); | ||
|
||
useEffectOnce(() => { | ||
setTimeout(() => { | ||
setWalletStateInitialized(true); | ||
}, 5000); | ||
}); | ||
|
||
useEffect(() => { | ||
if (walletAddress) { | ||
const updateBalances = async (address: ArweaveTransactionID) => { | ||
try { | ||
const [mioBalance, winstonBalance] = await Promise.all([ | ||
arIOReadSDK.getBalance({ address: address.toString() }), | ||
arweave.wallets.getBalance(address.toString()), | ||
]); | ||
|
||
const arBalance = +AR.winstonToAr(winstonBalance); | ||
const ioBalance = mioToIo(mioBalance); | ||
|
||
setBalances(arBalance, ioBalance); | ||
} catch (error) { | ||
// eventEmitter.emit('error', error); | ||
} | ||
}; | ||
|
||
updateBalances(walletAddress); | ||
} | ||
}, [walletAddress, blockHeight, arIOReadSDK, arweave, setBalances]); | ||
|
||
const updateIfConnected = async () => { | ||
const walletType = window.localStorage.getItem('walletType'); | ||
|
||
try { | ||
if (walletType === WALLET_TYPES.ARCONNECT) { | ||
const connector = new ArConnectWalletConnector(); | ||
const address = await connector?.getWalletAddress(); | ||
|
||
updateWallet(address, connector); | ||
} | ||
} catch (error) { | ||
// eventEmitter.emit('error', error); | ||
} finally { | ||
setWalletStateInitialized(true); | ||
} | ||
}; | ||
|
||
return <>{children}</>; | ||
}; | ||
|
||
export default WalletProvider; |
Oops, something went wrong.