mirror of
https://github.com/kremalicious/blog.git
synced 2024-11-22 01:46:51 +01:00
automatic network switching
This commit is contained in:
parent
d1315e7912
commit
cbbb81e391
@ -32,8 +32,15 @@ table[aria-disabled='true'] {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.table :global(.TokenLogo),
|
||||
.table :global(.TokenLogo) img {
|
||||
.table :global(.TokenLogo) {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.table :global(.TokenLogo) img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useAccount, useEnsName } from 'wagmi'
|
||||
import { useAccount, useChains, useEnsName } from 'wagmi'
|
||||
import styles from './Data.module.css'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { $amount, $selectedToken } from '@features/Web3/stores'
|
||||
@ -13,11 +13,17 @@ export function Data({
|
||||
ensResolved: string | null | undefined
|
||||
isDisabled: boolean
|
||||
}) {
|
||||
const { address: from, chain } = useAccount()
|
||||
const chains = useChains()
|
||||
const { address: from } = useAccount()
|
||||
const { data: ensFrom } = useEnsName({ address: from, chainId: 1 })
|
||||
|
||||
const selectedToken = useStore($selectedToken)
|
||||
const amount = useStore($amount)
|
||||
|
||||
const networkName = chains.filter(
|
||||
(chain) => chain.id === selectedToken?.chainId
|
||||
)[0].name
|
||||
|
||||
return (
|
||||
<table className={styles.table} aria-disabled={isDisabled}>
|
||||
<tbody>
|
||||
@ -54,7 +60,10 @@ export function Data({
|
||||
<tr>
|
||||
<td className={styles.label}>on</td>
|
||||
<td>
|
||||
<span className={styles.network}>{chain?.name}</span>
|
||||
<div className="TokenLogo">
|
||||
<img src={selectedToken?.chainLogo || ''} />
|
||||
</div>
|
||||
<span className={styles.network}>{networkName}</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -18,12 +18,6 @@ export function Preview() {
|
||||
|
||||
const { handleSend, isLoading, error } = useSend()
|
||||
|
||||
// TODO: Cancel flow if chain changes in preview as this can mess with token selection
|
||||
// useEffect(() => {
|
||||
// if (!chain?.id || $isInitSend.get() === false) return
|
||||
// $isInitSend.set(false)
|
||||
// }, [chain?.id])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Data to={to} ensResolved={ensResolved} isDisabled={isLoading} />
|
||||
|
@ -3,18 +3,12 @@
|
||||
}
|
||||
|
||||
.rainbowkit > div:first-child {
|
||||
display: flex;
|
||||
/* display: flex;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: space-between;
|
||||
justify-content: space-between; */
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
/* hide the account icon, and hope nothing else */
|
||||
|
||||
/* .rainbowkit button [aria-hidden] {
|
||||
display: none;
|
||||
} */
|
||||
|
||||
.rainbowkit [aria-label='Chain Selector'],
|
||||
.rainbowkit [data-testid='rk-account-button'] div {
|
||||
font-weight: var(--font-weight-base);
|
||||
|
@ -4,7 +4,7 @@ import styles from './RainbowKit.module.css'
|
||||
export function RainbowKit() {
|
||||
return (
|
||||
<div className={styles.rainbowkit}>
|
||||
<ConnectButton chainStatus="full" showBalance={false} />
|
||||
<ConnectButton chainStatus="none" showBalance={false} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -21,8 +21,8 @@
|
||||
}
|
||||
|
||||
.TokenLogo {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
margin-right: calc(var(--spacer) / 4);
|
||||
border: 1px solid var(--border-color);
|
||||
@ -30,15 +30,24 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: var(--font-size-mini);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.TokenLogo img {
|
||||
.TokenLogoImage {
|
||||
margin: 0;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.TokenChainLogo {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
bottom: -5px;
|
||||
right: -5px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--border-color);
|
||||
}
|
||||
|
||||
.TokenName,
|
||||
.TokenBalance {
|
||||
margin: 0;
|
||||
|
@ -41,10 +41,21 @@ export const Token = forwardRef<HTMLDivElement, SelectItemProps>(
|
||||
<Select.ItemText>
|
||||
<span className="TokenLogo">
|
||||
{token?.logo ? (
|
||||
<img src={token.logo} width="32" height="32" />
|
||||
<img
|
||||
src={token.logo}
|
||||
width="32"
|
||||
height="32"
|
||||
className="TokenLogoImage"
|
||||
/>
|
||||
) : (
|
||||
token?.symbol?.substring(0, 3)
|
||||
)}
|
||||
<img
|
||||
src={token?.chainLogo}
|
||||
width="20"
|
||||
height="20"
|
||||
className="TokenChainLogo"
|
||||
/>
|
||||
</span>
|
||||
</Select.ItemText>
|
||||
<div>
|
||||
|
@ -17,7 +17,7 @@ export function TokenSelect() {
|
||||
const selectedToken = useStore($selectedToken)
|
||||
|
||||
const items = tokens?.map((token) => (
|
||||
<Token key={token.address} token={token} />
|
||||
<Token key={`${token.address}-${token.chainId}`} token={token} />
|
||||
))
|
||||
|
||||
function handleValueChange(value: `0x${string}`) {
|
||||
@ -32,12 +32,12 @@ export function TokenSelect() {
|
||||
useEffect(() => {
|
||||
if (selectedToken?.address || !tokens || !tokens?.length) return
|
||||
|
||||
handleValueChange('0x0')
|
||||
// select ETH mainnet token
|
||||
handleValueChange('0x0-1')
|
||||
}, [tokens, selectedToken])
|
||||
|
||||
return tokens && address ? (
|
||||
<Select.Root
|
||||
// defaultValue={selectedToken?.address || tokens[0].address}
|
||||
value={selectedToken?.address}
|
||||
onValueChange={(value: `0x${string}`) => handleValueChange(value)}
|
||||
disabled={isLoading}
|
||||
|
@ -2,12 +2,13 @@ export type GetToken = {
|
||||
address: `0x${string}`
|
||||
balance: number | undefined
|
||||
chainId: number
|
||||
name: string | null
|
||||
symbol: string | null
|
||||
decimals: number | null
|
||||
logo: string | null
|
||||
chainLogo: string | undefined
|
||||
name: string | undefined
|
||||
symbol: string | undefined
|
||||
decimals: number | undefined
|
||||
logo: string | undefined
|
||||
price: {
|
||||
usd: number | null
|
||||
eur: number | null
|
||||
usd: number | undefined
|
||||
eur: number | undefined
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import useSWR, { type SWRResponse } from 'swr'
|
||||
import { useChainId, useAccount } from 'wagmi'
|
||||
import { useAccount, useChains } from 'wagmi'
|
||||
import type { GetToken } from './types'
|
||||
|
||||
const fetcher = (url: string) => fetch(url).then((res) => res.json())
|
||||
@ -10,26 +10,23 @@ const apiUrl = import.meta.env.PUBLIC_WEB3_API_URL
|
||||
// Wrapper for fetching user tokens with swr.
|
||||
//
|
||||
export function useFetchTokens(): SWRResponse<GetToken[] | undefined, Error> {
|
||||
const chainId = useChainId()
|
||||
const { address } = useAccount()
|
||||
// const { chains } = useConfig()
|
||||
|
||||
const chains = useChains()
|
||||
const [url, setUrl] = useState<string | undefined>()
|
||||
|
||||
const fetchResults = useSWR<GetToken[] | undefined>(url, fetcher)
|
||||
|
||||
// Set url only after we have all data loaded on client,
|
||||
// preventing initial fetch.
|
||||
useEffect(() => {
|
||||
if (!address || !chainId) {
|
||||
if (!address || !chains) {
|
||||
setUrl(undefined)
|
||||
return
|
||||
}
|
||||
|
||||
// const chainIds = chains.map((chain) => chain.id).join(',')
|
||||
const url = `${apiUrl}/balance?address=${address}&chainIds=${chainId}`
|
||||
const chainIds = chains.map((chain) => chain.id).join(',')
|
||||
const url = `${apiUrl}/balance?address=${address}&chainIds=${chainIds}`
|
||||
setUrl(url)
|
||||
}, [address, chainId])
|
||||
}, [address, chains])
|
||||
|
||||
return fetchResults
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ export async function send(
|
||||
) {
|
||||
if (!selectedToken?.decimals || !amount || !to) return
|
||||
|
||||
const isNative = selectedToken.address === '0x0'
|
||||
const isNative = selectedToken.address.startsWith('0x0')
|
||||
const requestNative = { chainId, to, value: parseEther(amount) }
|
||||
const requestErc20 = {
|
||||
chainId,
|
||||
|
@ -3,7 +3,7 @@ import { useStore } from '@nanostores/react'
|
||||
import { useState } from 'react'
|
||||
import { send } from './send'
|
||||
import { isUnhelpfulErrorMessage } from './isUnhelpfulErrorMessage'
|
||||
import { useAccount, useConfig, useEnsAddress } from 'wagmi'
|
||||
import { useAccount, useConfig, useEnsAddress, useSwitchChain } from 'wagmi'
|
||||
import siteConfig from '@config/blog.config'
|
||||
|
||||
export function useSend() {
|
||||
@ -13,17 +13,31 @@ export function useSend() {
|
||||
const { chainId } = useAccount()
|
||||
const { ens } = siteConfig.author.ether
|
||||
const { data: to } = useEnsAddress({ name: ens, chainId: 1 })
|
||||
const { switchChain } = useSwitchChain()
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [isError, setIsError] = useState(false)
|
||||
const [error, setError] = useState<string | undefined>()
|
||||
|
||||
async function handleSend() {
|
||||
if (!selectedToken || !amount || !to) return
|
||||
|
||||
// switch chains first
|
||||
if (chainId !== selectedToken.chainId) {
|
||||
switchChain({ chainId: selectedToken.chainId })
|
||||
}
|
||||
|
||||
try {
|
||||
setIsError(false)
|
||||
setError(undefined)
|
||||
setIsLoading(true)
|
||||
const hash = await send(config, selectedToken, amount, to, chainId)
|
||||
const hash = await send(
|
||||
config,
|
||||
selectedToken,
|
||||
amount,
|
||||
to,
|
||||
selectedToken.chainId
|
||||
)
|
||||
if (hash) $txHash.set(hash)
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = (error as Error).message
|
||||
|
Loading…
Reference in New Issue
Block a user