1
0
mirror of https://github.com/kremalicious/blog.git synced 2025-02-14 21:10:25 +01:00

move selected token to nanostore

This commit is contained in:
Matthias Kretschmann 2023-10-29 22:51:31 +00:00
parent 7c82ec79be
commit 039757c671
Signed by: m
GPG Key ID: 606EEEF3C479A91F
6 changed files with 53 additions and 58 deletions

View File

@ -1,33 +1,28 @@
import { useEffect, type ReactElement, useState } 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 '../../hooks/useTokens' import { $selectedToken } from '../../stores/selectedToken'
import { useStore } from '@nanostores/react'
export function Conversion({ amount }: { amount: string }): ReactElement {
const selectedToken = useStore($selectedToken)
export function Conversion({
amount,
token
}: {
amount: string
token: GetToken | undefined
}): ReactElement {
const [dollar, setDollar] = useState('0.00') const [dollar, setDollar] = useState('0.00')
const [euro, setEuro] = useState('0.00') const [euro, setEuro] = useState('0.00')
useEffect(() => { useEffect(() => {
if (!token?.price || !amount) { if (!selectedToken?.price || !amount) {
setDollar('0.00') setDollar('0.00')
setEuro('0.00') setEuro('0.00')
return return
} }
const dollar = token?.price?.usd const { eur, usd } = selectedToken.price
? (Number(amount) * token?.price?.usd).toFixed(2)
: '0.00' const dollar = usd ? (Number(amount) * usd).toFixed(2) : '0.00'
const euro = token?.price?.eur const euro = eur ? (Number(amount) * eur).toFixed(2) : '0.00'
? (Number(amount) * token?.price?.eur).toFixed(2)
: '0.00'
setDollar(dollar) setDollar(dollar)
setEuro(euro) setEuro(euro)
}, [token?.price, amount]) }, [selectedToken?.price, amount])
return ( return (
<div className={styles.conversion}> <div className={styles.conversion}>

View File

@ -6,19 +6,17 @@ import Alert from '../Alert/Alert'
import { InputGroup } from '../Input' import { InputGroup } from '../Input'
import styles from './index.module.css' import styles from './index.module.css'
import { SendNative, SendErc20 } from '../Send' import { SendNative, SendErc20 } from '../Send'
import type { GetToken } from '../../hooks/useTokens' import { useSend } from '../../hooks/useSend'
import { useSend } from '@features/Web3/hooks/useSend'
import type { SendFormData } from './types' import type { SendFormData } from './types'
import { $selectedToken } from '../../stores/selectedToken'
import { useStore } from '@nanostores/react'
export default function Web3Form(): ReactElement { export default function Web3Form(): ReactElement {
const { address: account } = useAccount() const { address: account } = useAccount()
const selectedToken = useStore($selectedToken)
const [amount, setAmount] = useState('') const [amount, setAmount] = useState('')
const [debouncedAmount] = useDebounce(amount, 500) const [debouncedAmount] = useDebounce(amount, 500)
const [tokenSelected, setTokenSelected] = useState<GetToken>({
address: '0x0'
} as any)
const [sendFormData, setSendFormData] = useState<SendFormData>() const [sendFormData, setSendFormData] = useState<SendFormData>()
const { data, send } = sendFormData || {} const { data, send } = sendFormData || {}
@ -31,7 +29,7 @@ export default function Web3Form(): ReactElement {
className={styles.web3} className={styles.web3}
onSubmit={async (e) => { onSubmit={async (e) => {
e.preventDefault() e.preventDefault()
if (!send || amount === '' || amount === '0') return if (!send || debouncedAmount === '' || debouncedAmount === '0') return
await send() await send()
}} }}
> >
@ -42,24 +40,18 @@ export default function Web3Form(): ReactElement {
) : ( ) : (
<InputGroup <InputGroup
amount={amount} amount={amount}
token={tokenSelected}
setAmount={setAmount} setAmount={setAmount}
setTokenSelected={setTokenSelected}
isDisabled={isDisabled} isDisabled={isDisabled}
/> />
)} )}
{tokenSelected?.address === '0x0' ? ( {selectedToken?.address === '0x0' ? (
<SendNative <SendNative
amount={debouncedAmount} amount={debouncedAmount}
setSendFormData={setSendFormData} setSendFormData={setSendFormData}
/> />
) : ( ) : (
<SendErc20 <SendErc20 amount={debouncedAmount} setSendFormData={setSendFormData} />
amount={debouncedAmount}
tokenAddress={tokenSelected?.address}
setSendFormData={setSendFormData}
/>
)} )}
</form> </form>
) )

View File

@ -4,29 +4,21 @@ import { Conversion } from '../Conversion'
import styles from './InputGroup.module.css' import styles from './InputGroup.module.css'
import { TokenSelect } from '../TokenSelect' import { TokenSelect } from '../TokenSelect'
import config from '@config/blog.config' import config from '@config/blog.config'
import type { GetToken } from '../../hooks/useTokens'
export function InputGroup({ export function InputGroup({
amount, amount,
token,
isDisabled, isDisabled,
setAmount, setAmount
setTokenSelected
}: { }: {
amount: string amount: string
token: GetToken | undefined
isDisabled: boolean isDisabled: boolean
setAmount: React.Dispatch<React.SetStateAction<string>> setAmount: React.Dispatch<React.SetStateAction<string>>
setTokenSelected: React.Dispatch<React.SetStateAction<GetToken>>
}): ReactElement { }): ReactElement {
return ( return (
<> <>
<div className={styles.inputGroup}> <div className={styles.inputGroup}>
<div className={styles.token}> <div className={styles.token}>
<TokenSelect <TokenSelect />
selectedToken={token}
setTokenSelected={setTokenSelected}
/>
</div> </div>
<Input <Input
type="text" type="text"
@ -45,7 +37,7 @@ export function InputGroup({
Make it rain Make it rain
</button> </button>
</div> </div>
<Conversion amount={amount} token={token} /> <Conversion amount={amount} />
<div className={styles.disclaimer}> <div className={styles.disclaimer}>
This form sends tokens to my account <code>{config.author.ether}</code> This form sends tokens to my account <code>{config.author.ether}</code>
</div> </div>

View File

@ -1,23 +1,28 @@
import { parseEther } from 'viem' import { parseUnits } 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 { abiErc20Transfer } from './abiErc20Transfer' import { abiErc20Transfer } from './abiErc20Transfer'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useStore } from '@nanostores/react'
import { $selectedToken } from '@features/Web3/stores/selectedToken'
export function SendErc20({ export function SendErc20({
amount, amount,
tokenAddress,
setSendFormData setSendFormData
}: { }: {
amount: string amount: string
tokenAddress: `0x${string}` | undefined
setSendFormData: any setSendFormData: any
}) { }) {
const selectedToken = useStore($selectedToken)
const { config } = usePrepareContractWrite({ const { config } = usePrepareContractWrite({
address: tokenAddress, address: selectedToken.address,
abi: abiErc20Transfer, abi: abiErc20Transfer,
functionName: 'transfer', functionName: 'transfer',
args: [siteConfig.author.ether, parseEther(amount)] args: [
siteConfig.author.ether,
parseUnits(amount, selectedToken?.decimals || 18)
]
}) })
const { const {

View File

@ -4,17 +4,14 @@ import { Token } from './Token'
import { ChevronDown, ChevronsDown, ChevronsUp } from '@images/components/react' import { ChevronDown, ChevronsDown, ChevronsUp } from '@images/components/react'
import { TokenLoading } from './TokenLoading' import { TokenLoading } from './TokenLoading'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useTokens, type GetToken } from '../../hooks/useTokens' import { useTokens } from '../../hooks/useTokens'
import { useAccount, useNetwork } from 'wagmi' import { useAccount, useNetwork } from 'wagmi'
import { $selectedToken, $setSelectedToken } from '../../stores/selectedToken'
import { useStore } from '@nanostores/react'
export function TokenSelect({ export function TokenSelect() {
selectedToken,
setTokenSelected
}: {
selectedToken: GetToken | undefined
setTokenSelected: React.Dispatch<React.SetStateAction<GetToken>>
}) {
const { data: tokens, isLoading } = useTokens() const { data: tokens, isLoading } = useTokens()
const selectedToken = useStore($selectedToken)
const { chain } = useNetwork() const { chain } = useNetwork()
const { address } = useAccount() const { address } = useAccount()
@ -25,21 +22,22 @@ export function TokenSelect({
function handleValueChange(value: `0x${string}`) { function handleValueChange(value: `0x${string}`) {
const token = tokens?.find((token) => token.address === value) const token = tokens?.find((token) => token.address === value)
if (!token) return if (!token) return
setTokenSelected(token) $setSelectedToken(token)
} }
// Set default token data to native token // Set default token data to native token
useEffect(() => { useEffect(() => {
if (!chain?.id || !address || !tokens) return if (!chain?.id || !address || !tokens) return
handleValueChange('0x0') if (!selectedToken || !selectedToken?.address) handleValueChange('0x0')
}, [chain?.id, address, tokens]) }, [chain?.id, address, tokens, selectedToken])
return ( return (
<Select.Root <Select.Root
defaultValue={selectedToken?.address} defaultValue={selectedToken?.address}
onValueChange={(value: `0x${string}`) => handleValueChange(value)} onValueChange={(value: `0x${string}`) => handleValueChange(value)}
disabled={!tokens || isLoading} disabled={!tokens || isLoading}
value={selectedToken?.address}
> >
<Select.Trigger <Select.Trigger
className="SelectTrigger" className="SelectTrigger"

View File

@ -0,0 +1,13 @@
import { action, map } from 'nanostores'
import type { GetToken } from '../hooks/useTokens'
export const $selectedToken = map<GetToken>()
export const $setSelectedToken = action(
$selectedToken,
'setSelectedToken',
(store, token: GetToken) => {
store.set(token)
return store.get()
}
)