mirror of
https://github.com/kremalicious/blog.git
synced 2024-12-23 01:30:01 +01:00
refactor, fetch abort
This commit is contained in:
parent
b9b0093a2e
commit
74f89bcb7e
@ -1,6 +1,6 @@
|
|||||||
import { type ReactElement } from 'react'
|
import { useEffect, type ReactElement, useState } from 'react'
|
||||||
import styles from './Conversion.module.css'
|
import styles from './Conversion.module.css'
|
||||||
import type { GetToken } from '../../api/getTokens'
|
import type { GetToken } from '../../hooks/useTokens'
|
||||||
|
|
||||||
export function Conversion({
|
export function Conversion({
|
||||||
amount,
|
amount,
|
||||||
@ -9,12 +9,25 @@ export function Conversion({
|
|||||||
amount: string
|
amount: string
|
||||||
token: GetToken | undefined
|
token: GetToken | undefined
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const dollar = token?.price?.usd
|
const [dollar, setDollar] = useState('0.00')
|
||||||
? (Number(amount) * token?.price?.usd).toFixed(2)
|
const [euro, setEuro] = useState('0.00')
|
||||||
: '0.00'
|
|
||||||
const euro = token?.price?.eur
|
useEffect(() => {
|
||||||
? (Number(amount) * token?.price?.eur).toFixed(2)
|
if (!token?.price || !amount) {
|
||||||
: '0.00'
|
setDollar('0.00')
|
||||||
|
setEuro('0.00')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const dollar = token?.price?.usd
|
||||||
|
? (Number(amount) * token?.price?.usd).toFixed(2)
|
||||||
|
: '0.00'
|
||||||
|
const euro = token?.price?.eur
|
||||||
|
? (Number(amount) * token?.price?.eur).toFixed(2)
|
||||||
|
: '0.00'
|
||||||
|
setDollar(dollar)
|
||||||
|
setEuro(euro)
|
||||||
|
}, [token?.price, amount])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.conversion}>
|
<div className={styles.conversion}>
|
||||||
|
@ -4,7 +4,7 @@ import { Conversion } from '../Conversion'
|
|||||||
import styles from './InputGroup.module.css'
|
import styles from './InputGroup.module.css'
|
||||||
import { TokenSelect } from '../Tokens'
|
import { TokenSelect } from '../Tokens'
|
||||||
import config from '@config/blog.config'
|
import config from '@config/blog.config'
|
||||||
import type { GetToken } from '../../api/getTokens'
|
import type { GetToken } from '../../hooks/useTokens'
|
||||||
|
|
||||||
export function InputGroup({
|
export function InputGroup({
|
||||||
amount,
|
amount,
|
||||||
@ -23,7 +23,10 @@ export function InputGroup({
|
|||||||
<>
|
<>
|
||||||
<div className={styles.inputGroup}>
|
<div className={styles.inputGroup}>
|
||||||
<div className={styles.token}>
|
<div className={styles.token}>
|
||||||
<TokenSelect setTokenSelected={setTokenSelected} />
|
<TokenSelect
|
||||||
|
selectedToken={token}
|
||||||
|
setTokenSelected={setTokenSelected}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { parseEther } from 'viem'
|
import { parseEther } from 'viem'
|
||||||
import { useContractWrite, usePrepareContractWrite } from 'wagmi'
|
import { useContractWrite, usePrepareContractWrite } from 'wagmi'
|
||||||
import siteConfig from '@config/blog.config'
|
import siteConfig from '@config/blog.config'
|
||||||
import { abi } from './abi'
|
import { abiErc20Transfer } from './abiErc20Transfer'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
export function SendErc20({
|
export function SendErc20({
|
||||||
@ -15,7 +15,7 @@ export function SendErc20({
|
|||||||
}) {
|
}) {
|
||||||
const { config } = usePrepareContractWrite({
|
const { config } = usePrepareContractWrite({
|
||||||
address: tokenAddress,
|
address: tokenAddress,
|
||||||
abi,
|
abi: abiErc20Transfer,
|
||||||
functionName: 'transfer',
|
functionName: 'transfer',
|
||||||
args: [siteConfig.author.ether, parseEther(amount)]
|
args: [siteConfig.author.ether, parseEther(amount)]
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export const abi = [
|
export const abiErc20Transfer = [
|
||||||
{
|
{
|
||||||
constant: false,
|
constant: false,
|
||||||
inputs: [
|
inputs: [
|
@ -3,7 +3,7 @@ import * as Select from '@radix-ui/react-select'
|
|||||||
import { formatCurrency } from '@coingecko/cryptoformat'
|
import { formatCurrency } from '@coingecko/cryptoformat'
|
||||||
import './Token.css'
|
import './Token.css'
|
||||||
import { Check } from '@images/components/react'
|
import { Check } from '@images/components/react'
|
||||||
import type { GetToken } from '../../api/getTokens'
|
import type { GetToken } from '../../hooks/useTokens'
|
||||||
|
|
||||||
interface SelectItemProps extends HTMLAttributes<HTMLDivElement> {
|
interface SelectItemProps extends HTMLAttributes<HTMLDivElement> {
|
||||||
token: GetToken | undefined
|
token: GetToken | undefined
|
||||||
|
@ -2,17 +2,22 @@ import * as Select from '@radix-ui/react-select'
|
|||||||
import './TokenSelect.css'
|
import './TokenSelect.css'
|
||||||
import { Token } from './Token'
|
import { Token } from './Token'
|
||||||
import { ChevronDown, ChevronsDown, ChevronsUp } from '@images/components/react'
|
import { ChevronDown, ChevronsDown, ChevronsUp } from '@images/components/react'
|
||||||
import { useTokens } from '../../hooks/useTokens'
|
import { useTokens } from '../../hooks/useTokens/useTokens'
|
||||||
import { TokenLoading } from './TokenLoading'
|
import { TokenLoading } from './TokenLoading'
|
||||||
import type { GetToken } from '../../api/getTokens'
|
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
import type { GetToken } from '../../hooks/useTokens'
|
||||||
|
import { useAccount, useNetwork } from 'wagmi'
|
||||||
|
|
||||||
export function TokenSelect({
|
export function TokenSelect({
|
||||||
|
selectedToken,
|
||||||
setTokenSelected
|
setTokenSelected
|
||||||
}: {
|
}: {
|
||||||
|
selectedToken: GetToken | undefined
|
||||||
setTokenSelected: React.Dispatch<React.SetStateAction<GetToken>>
|
setTokenSelected: React.Dispatch<React.SetStateAction<GetToken>>
|
||||||
}) {
|
}) {
|
||||||
const { data: tokens, isLoading } = useTokens()
|
const { data: tokens, isLoading } = useTokens()
|
||||||
|
const { chain } = useNetwork()
|
||||||
|
const { address } = useAccount()
|
||||||
|
|
||||||
const items = tokens?.map((token) => (
|
const items = tokens?.map((token) => (
|
||||||
<Token key={token.address} token={token} />
|
<Token key={token.address} token={token} />
|
||||||
@ -24,12 +29,16 @@ export function TokenSelect({
|
|||||||
setTokenSelected(token)
|
setTokenSelected(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
// set default token data
|
// Set default token data to native token
|
||||||
useEffect(() => handleValueChange('0x0'), [])
|
useEffect(() => {
|
||||||
|
if (!chain?.id || !address || !tokens) return
|
||||||
|
|
||||||
return tokens ? (
|
handleValueChange('0x0')
|
||||||
|
}, [chain?.id, address, tokens])
|
||||||
|
|
||||||
|
return (
|
||||||
<Select.Root
|
<Select.Root
|
||||||
defaultValue={tokens?.[0].address}
|
defaultValue={selectedToken?.address}
|
||||||
onValueChange={(value: `0x${string}`) => handleValueChange(value)}
|
onValueChange={(value: `0x${string}`) => handleValueChange(value)}
|
||||||
disabled={!tokens || isLoading}
|
disabled={!tokens || isLoading}
|
||||||
>
|
>
|
||||||
@ -63,5 +72,5 @@ export function TokenSelect({
|
|||||||
</Select.Content>
|
</Select.Content>
|
||||||
</Select.Portal>
|
</Select.Portal>
|
||||||
</Select.Root>
|
</Select.Root>
|
||||||
) : null
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,15 @@
|
|||||||
export type GetToken = {
|
import type { GetToken } from './types'
|
||||||
address: `0x${string}`
|
|
||||||
balance: number | undefined
|
|
||||||
chainId: number
|
|
||||||
name: string | null
|
|
||||||
symbol: string | null
|
|
||||||
decimals: number | null
|
|
||||||
logo: string | null
|
|
||||||
price: {
|
|
||||||
usd: number | null
|
|
||||||
eur: number | null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getTokens(
|
export async function getTokens(
|
||||||
address: `0x${string}`,
|
address: `0x${string}`,
|
||||||
chainId: number
|
chainId: number,
|
||||||
|
signal?: AbortSignal
|
||||||
): Promise<GetToken[]> {
|
): Promise<GetToken[]> {
|
||||||
if (!address || !chainId) return []
|
if (!address || !chainId) return []
|
||||||
|
|
||||||
// const url = `http://localhost:3000/api/balance?address=${address}&chainId=${chainId}`
|
// const url = `http://localhost:3000/api/balance?address=${address}&chainId=${chainId}`
|
||||||
const url = `https://web3.kremalicious.com/api/balance?address=${address}&chainId=${chainId}`
|
const url = `https://web3.kremalicious.com/api/balance?address=${address}&chainId=${chainId}`
|
||||||
const response = await fetch(url)
|
const response = await fetch(url, { signal })
|
||||||
const json: GetToken[] = await response.json()
|
const json: GetToken[] = await response.json()
|
||||||
|
|
||||||
if (!json) console.error(response.statusText)
|
if (!json) console.error(response.statusText)
|
@ -0,0 +1,2 @@
|
|||||||
|
export * from './useTokens'
|
||||||
|
export * from './types'
|
13
src/components/Sponsor/Web3Donation/hooks/useTokens/types.ts
Normal file
13
src/components/Sponsor/Web3Donation/hooks/useTokens/types.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export type GetToken = {
|
||||||
|
address: `0x${string}`
|
||||||
|
balance: number | undefined
|
||||||
|
chainId: number
|
||||||
|
name: string | null
|
||||||
|
symbol: string | null
|
||||||
|
decimals: number | null
|
||||||
|
logo: string | null
|
||||||
|
price: {
|
||||||
|
usd: number | null
|
||||||
|
eur: number | null
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { useAccount, useNetwork } from 'wagmi'
|
import { useAccount, useNetwork } from 'wagmi'
|
||||||
import { getTokens, type GetToken } from '../api/getTokens'
|
import { getTokens } from './getTokens'
|
||||||
|
import type { GetToken } from './types'
|
||||||
|
|
||||||
export function useTokens() {
|
export function useTokens() {
|
||||||
const { address } = useAccount()
|
const { address } = useAccount()
|
||||||
@ -11,23 +12,35 @@ export function useTokens() {
|
|||||||
const [isError, setIsError] = useState<boolean>()
|
const [isError, setIsError] = useState<boolean>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const abortController = new AbortController()
|
||||||
|
const { signal } = abortController
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
if (!address || !chain) return
|
if (!address || !chain?.id) return
|
||||||
|
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const tokens = await getTokens(address, chain.id)
|
const tokens = await getTokens(address, chain.id, signal)
|
||||||
setData(tokens)
|
setData(tokens)
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
setIsError(true)
|
setIsError(true)
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
console.error((error as Error).message)
|
if ((error as Error).name !== 'AbortError') {
|
||||||
|
console.error((error as Error).message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
init()
|
init()
|
||||||
}, [address, chain])
|
|
||||||
|
return () => {
|
||||||
|
abortController.abort()
|
||||||
|
setData(undefined)
|
||||||
|
setIsLoading(undefined)
|
||||||
|
setIsError(undefined)
|
||||||
|
}
|
||||||
|
}, [address, chain?.id])
|
||||||
|
|
||||||
return { data, isLoading, isError }
|
return { data, isLoading, isError }
|
||||||
}
|
}
|
@ -6,7 +6,7 @@ import Alert, { getTransactionMessage } from './components/Alert/Alert'
|
|||||||
import { InputGroup } from './components/Input'
|
import { InputGroup } from './components/Input'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { SendNative, SendErc20 } from './components/Send'
|
import { SendNative, SendErc20 } from './components/Send'
|
||||||
import type { GetToken } from './api/getTokens'
|
import type { GetToken } from './hooks/useTokens'
|
||||||
|
|
||||||
export default function Web3Donation(): ReactElement {
|
export default function Web3Donation(): ReactElement {
|
||||||
const { address: account } = useAccount()
|
const { address: account } = useAccount()
|
||||||
|
Loading…
Reference in New Issue
Block a user