mango-v4-ui/components/wallet/EnhancedWalletProvider.tsx

201 lines
5.1 KiB
TypeScript

import { SolanaMobileWalletAdapter } from '@solana-mobile/wallet-adapter-mobile'
import { WalletName, WalletReadyState } from '@solana/wallet-adapter-base'
import { useWallet, Wallet } from '@solana/wallet-adapter-react'
import { StandardWalletAdapter } from '@solana/wallet-standard-wallet-adapter-base'
import { useTranslation } from 'next-i18next'
import React, {
createContext,
ReactNode,
useCallback,
useContext,
useEffect,
useMemo,
} from 'react'
import mangoStore from '@store/mangoStore'
import { notify } from 'utils/notifications'
import { useLocalStorageStringState } from 'hooks/useLocalStorageState'
interface EnhancedWalletContextState {
displayedWallets: Wallet[]
preselectedWalletName: string | null
handleSelect: (name: WalletName | null) => void
handleConnect: () => Promise<void>
handleDisconnect: () => Promise<void>
}
const EnhancedWalletContext = createContext<EnhancedWalletContextState>(
{} as EnhancedWalletContextState
)
export function useEnhancedWallet(): EnhancedWalletContextState {
return useContext(EnhancedWalletContext)
}
export default function EnhancedWalletProvider({
children,
}: {
children: ReactNode
}) {
const { wallets, select, wallet, connect, disconnect } = useWallet()
const { t } = useTranslation(['common', 'profile'])
const set = mangoStore((s) => s.set)
const displayedWallets = useMemo(
() =>
wallets.slice().sort(({ adapter: a }, { adapter: b }) => {
if (a instanceof SolanaMobileWalletAdapter) {
if (b instanceof SolanaMobileWalletAdapter) return 0
return -1
} else if (b instanceof SolanaMobileWalletAdapter) {
return 1
}
if (a instanceof StandardWalletAdapter) {
if (b instanceof StandardWalletAdapter) return 0
return -1
} else if (b instanceof StandardWalletAdapter) {
return 1
}
if (a.readyState === b.readyState) return 0
if (a.readyState === WalletReadyState.Installed) return -1
if (b.readyState === WalletReadyState.Installed) return 1
return 0
}),
[wallets]
)
const [preselectedWalletName, setPreselectedWalletName] =
useLocalStorageStringState(
'preselectedWalletName',
wallet?.adapter.name || null
)
useEffect(() => {
const adapter = wallets.find(
({ adapter }) => adapter.name === preselectedWalletName
)?.adapter
if (adapter) {
select(adapter.name)
}
}, [preselectedWalletName, select, wallets])
useEffect(() => {
if (wallet) {
setPreselectedWalletName(wallet.adapter.name)
return
}
if (preselectedWalletName) return
for (const { adapter } of displayedWallets) {
if (
adapter.readyState === WalletReadyState.Installed ||
adapter.readyState === WalletReadyState.Loadable
) {
setPreselectedWalletName(adapter.name)
return
}
}
}, [
wallet,
setPreselectedWalletName,
select,
preselectedWalletName,
displayedWallets,
])
const handleSelect = useCallback(
(name: WalletName | null) => {
setPreselectedWalletName(name)
select(name)
},
[setPreselectedWalletName, select]
)
// const handleConnect = useCallback(async () => {
// setConnecting(true)
// const group = mangoStore.getState().group
// try {
// if (wallet && group) {
// await handleWalletConnect(wallet)
// }
// } catch (e) {
// console.error(e)
// } finally {
// setConnecting(false)
// }
// }, [wallet])
const handleConnect = useCallback(async () => {
if (wallet) {
try {
console.log('connecting')
await connect()
} catch (e) {
// Error will be handled by WalletProvider#onError
select(null)
}
} else if (preselectedWalletName) {
const adapter = wallets.find(
({ adapter }) => adapter.name === preselectedWalletName
)?.adapter
if (!adapter) {
setPreselectedWalletName(null)
return
}
if (
adapter.readyState === WalletReadyState.Installed ||
adapter.readyState === WalletReadyState.Loadable
) {
select(adapter.name)
} else {
notify({
title: `${adapter.name} Error`,
type: 'error',
description: `Please install ${adapter.name} and then reload this page.`,
})
if (typeof window !== 'undefined') {
window.open(adapter.url, '_blank')
}
}
}
}, [
wallets,
select,
wallet,
connect,
preselectedWalletName,
setPreselectedWalletName,
])
const handleDisconnect = useCallback(async () => {
set((state) => {
state.mangoAccounts = []
state.mangoAccount.current = undefined
})
notify({
type: 'info',
title: t('wallet-disconnected'),
})
await disconnect()
}, [set, t, disconnect])
return (
<EnhancedWalletContext.Provider
value={{
displayedWallets,
preselectedWalletName,
handleSelect,
handleConnect,
handleDisconnect,
}}
>
{children}
</EnhancedWalletContext.Provider>
)
}