Skip to content

Commit

Permalink
Peer icon/count on the header widget
Browse files Browse the repository at this point in the history
  • Loading branch information
katspaugh committed Sep 26, 2023
1 parent 07a3a13 commit b30c87d
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 38 deletions.
28 changes: 25 additions & 3 deletions src/components/walletconnect/HeaderWidget/Icon.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
import { ButtonBase, SvgIcon } from '@mui/material'
import { Badge, ButtonBase, SvgIcon } from '@mui/material'

import WalletConnectIcon from '@/public/images/common/walletconnect.svg'
import SafeAppIconCard from '@/components/safe-apps/SafeAppIconCard'

const Icon = (props: { onClick: () => void }) => (
type IconProps = {
onClick: () => void
sessionCount: number
sessionInfo?: {
name: string
iconUrl: string
}
}

const Icon = ({ sessionCount, sessionInfo, ...props }: IconProps): React.ReactElement => (
<ButtonBase disableRipple onClick={props.onClick}>
<SvgIcon component={WalletConnectIcon} inheritViewBox />
<Badge
badgeContent={
sessionCount > 1
? sessionCount
: sessionInfo && <SafeAppIconCard alt={sessionInfo.name} src={sessionInfo.iconUrl} width={12} height={12} />
}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
>
<SvgIcon component={WalletConnectIcon} inheritViewBox fontSize="small" />
</Badge>
</ButtonBase>
)

Expand Down
15 changes: 13 additions & 2 deletions src/components/walletconnect/HeaderWidget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useCallback, useContext, useRef, useState } from 'react'
import { Badge, Box } from '@mui/material'

import { WalletConnectContext } from '@/services/walletconnect/WalletConnectContext'
import useWalletConnectSessions from '@/services/walletconnect/useWalletConnectSessions'
import Icon from './Icon'
import SessionManager from '../SessionManager'
import Popup from '../Popup'
Expand All @@ -10,18 +11,28 @@ const WalletConnectHeaderWidget = () => {
const { error } = useContext(WalletConnectContext)
const [popupOpen, setPopupOpen] = useState(false)
const iconRef = useRef<HTMLDivElement>(null)
const sessions = useWalletConnectSessions()

const onOpen = useCallback(() => setPopupOpen(true), [])
const onClose = useCallback(() => setPopupOpen(false), [])

return (
<Box display="flex">
<div ref={iconRef}>
<Icon onClick={onOpen} />
<Icon
onClick={onOpen}
sessionCount={sessions.length}
sessionInfo={
sessions[0]
? { name: sessions[0].peer.metadata.name, iconUrl: sessions[0].peer.metadata.icons[0] }
: undefined
}
/>
<Badge color="error" variant="dot" invisible={!error} />
</div>

<Popup anchorEl={iconRef.current} open={popupOpen} onClose={onClose}>
<SessionManager />
<SessionManager sessions={sessions} />
</Popup>
</Box>
)
Expand Down
10 changes: 5 additions & 5 deletions src/components/walletconnect/SessionManager/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,22 @@ import type { SessionTypes } from '@walletconnect/types'

import useSafeInfo from '@/hooks/useSafeInfo'
import { WalletConnectContext } from '@/services/walletconnect/WalletConnectContext'
import useWalletConnectSessions from '@/services/walletconnect/useWalletConnectSessions'
import { asError } from '@/services/exceptions/utils'
import ProposalForm from '../ProposalForm'
import WcInput from '../WcInput'
import ErrorMessage from '@/components/tx/ErrorMessage'
import SessionList from '../SessionList'

const SessionManager = () => {
const SessionManager = ({ sessions }: { sessions: SessionTypes.Struct[] }) => {
const { safe, safeAddress } = useSafeInfo()
const { chainId } = safe
const { walletConnect, error: walletConnectError } = useContext(WalletConnectContext)
const sessions = useWalletConnectSessions()
const [proposal, setProposal] = useState<Web3WalletTypes.SessionProposal>()
const [error, setError] = useState<Error>()

// On session approve
const onApprove = useCallback(async () => {
if (!chainId || !safeAddress || !proposal) return
if (!walletConnect || !chainId || !safeAddress || !proposal) return

try {
await walletConnect.approveSession(proposal, chainId, safeAddress)
Expand All @@ -35,7 +33,7 @@ const SessionManager = () => {

// On session reject
const onReject = useCallback(async () => {
if (!proposal) return
if (!walletConnect || !proposal) return

try {
await walletConnect.rejectSession(proposal)
Expand All @@ -49,6 +47,7 @@ const SessionManager = () => {

// On session disconnect
const onDisconnect = async (session: SessionTypes.Struct) => {
if (!walletConnect) return
try {
await walletConnect.disconnectSession(session)
} catch (error) {
Expand All @@ -58,6 +57,7 @@ const SessionManager = () => {

// Subscribe to session proposals
useEffect(() => {
if (!walletConnect) return
return walletConnect.onSessionPropose(setProposal)
}, [walletConnect])

Expand Down
37 changes: 23 additions & 14 deletions src/components/walletconnect/WcInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TextField, Typography } from '@mui/material'
import { useContext, useState } from 'react'
import { useCallback, useContext, useState } from 'react'
import type { ChangeEvent } from 'react'
import { TextField, Typography } from '@mui/material'

import { WalletConnectContext } from '@/services/walletconnect/WalletConnectContext'
import { asError } from '@/services/exceptions/utils'
Expand All @@ -10,18 +10,27 @@ const WcInput = () => {
const [error, setError] = useState<Error>()
const [connecting, setConnecting] = useState(false)

const onInput = async (e: ChangeEvent<HTMLInputElement>) => {
const uri = e.target.value

try {
await walletConnect.connect(uri)
} catch (e) {
setError(asError(e))
return
}

setConnecting(true)
}
const onInput = useCallback(
async (e: ChangeEvent<HTMLInputElement>) => {
if (!walletConnect) return

const uri = e.target.value
if (!uri) {
setError(undefined)
return
}

try {
await walletConnect.connect(uri)
} catch (e) {
setError(asError(e))
return
}

setConnecting(true)
},
[walletConnect],
)

return (
<>
Expand Down
32 changes: 18 additions & 14 deletions src/services/walletconnect/WalletConnectContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import WalletConnectWallet from './WalletConnectWallet'
import { asError } from '../exceptions/utils'
import { stripEip155Prefix } from './utils'

const walletConnect = new WalletConnectWallet()
const walletConnectSingleton = new WalletConnectWallet()

export const WalletConnectContext = createContext<{
walletConnect: WalletConnectWallet
walletConnect: WalletConnectWallet | null
error: Error | null
}>({
walletConnect,
walletConnect: null,
error: null,
})

Expand All @@ -21,31 +21,35 @@ export const WalletConnectProvider = ({ children }: { children: ReactNode }) =>
safe: { chainId },
safeAddress,
} = useSafeInfo()
const [walletConnect, setWalletConnect] = useState<WalletConnectWallet | null>(null)
const [error, setError] = useState<Error | null>(null)
const safeWalletProvider = useSafeWalletProvider()

// Init WalletConnect
useEffect(() => {
walletConnect.init().catch(setError)
walletConnectSingleton
.init()
.then(() => setWalletConnect(walletConnectSingleton))
.catch(setError)
}, [])

// Update chainId
useEffect(() => {
if (chainId) {
walletConnect.chainChanged(chainId).catch(setError)
}
}, [chainId])
if (!walletConnect || !chainId) return

walletConnect.chainChanged(chainId).catch(setError)
}, [walletConnect, chainId])

// Update accounts
useEffect(() => {
if (safeAddress && chainId) {
walletConnect.accountsChanged(chainId, safeAddress).catch(setError)
}
}, [chainId, safeAddress])
if (!walletConnect || !chainId || !safeAddress) return

walletConnect.accountsChanged(chainId, safeAddress).catch(setError)
}, [walletConnect, chainId, safeAddress])

// Subscribe to requests
useEffect(() => {
if (!safeWalletProvider || !chainId) return
if (!walletConnect || !safeWalletProvider || !chainId) return

return walletConnect.onRequest(async (event) => {
const { topic } = event
Expand All @@ -69,7 +73,7 @@ export const WalletConnectProvider = ({ children }: { children: ReactNode }) =>
setError(asError(e))
}
})
}, [chainId, safeWalletProvider])
}, [walletConnect, chainId, safeWalletProvider])

return <WalletConnectContext.Provider value={{ walletConnect, error }}>{children}</WalletConnectContext.Provider>
}
3 changes: 3 additions & 0 deletions src/services/walletconnect/useWalletConnectSessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ function useWalletConnectSessions(): SessionTypes.Struct[] {
const [sessions, setSessions] = useState<SessionTypes.Struct[]>([])

const updateSessions = useCallback(() => {
if (!walletConnect) return
setSessions(walletConnect.getActiveSessions())
}, [walletConnect])

Expand All @@ -15,11 +16,13 @@ function useWalletConnectSessions(): SessionTypes.Struct[] {

// On session add
useEffect(() => {
if (!walletConnect) return
return walletConnect.onSessionAdd(updateSessions)
}, [walletConnect, updateSessions])

// On session delete
useEffect(() => {
if (!walletConnect) return
return walletConnect.onSessionDelete(updateSessions)
}, [walletConnect, updateSessions])

Expand Down

0 comments on commit b30c87d

Please sign in to comment.