add isValidating behavior

This commit is contained in:
Matthias Kretschmann 2024-03-31 04:32:11 +01:00
parent 1aa4ee1afc
commit e5153b2730
Signed by: m
GPG Key ID: 606EEEF3C479A91F
10 changed files with 66 additions and 36 deletions

View File

@ -5,7 +5,7 @@ import styles from './CalculationBase.module.css'
import { usePrices } from '@/hooks' import { usePrices } from '@/hooks'
export function CalculationBase() { export function CalculationBase() {
const prices = usePrices() const { prices } = usePrices()
return ( return (
<ul className={styles.calculationBase}> <ul className={styles.calculationBase}>

View File

@ -13,7 +13,7 @@ export function FormAmount({
}: { }: {
amount: number amount: number
setAmount: Dispatch<SetStateAction<number>> setAmount: Dispatch<SetStateAction<number>>
token: Token token: Token | string
setToken?: Dispatch<SetStateAction<Token>> setToken?: Dispatch<SetStateAction<Token>>
isFiat?: boolean isFiat?: boolean
}) { }) {

View File

@ -8,7 +8,7 @@ export function InputToken({
setToken, setToken,
isFiat isFiat
}: { }: {
token: Token token: Token | string
isFiat?: boolean isFiat?: boolean
setToken?: Dispatch<SetStateAction<Token>> setToken?: Dispatch<SetStateAction<Token>>
}) { }) {

View File

@ -1 +1 @@
export type Token = 'ocean' | 'fet' | 'agix' | 'usd' | undefined export type Token = 'ocean' | 'fet' | 'agix' | undefined

View File

@ -56,3 +56,19 @@
filter: grayscale(1); filter: grayscale(1);
} }
} }
.isValidating {
animation: flicker 2s infinite ease-out forwards;
}
@keyframes flicker {
0% {
opacity: 0.25;
}
50% {
opacity: 1;
}
100% {
opacity: 0.25;
}
}

View File

@ -10,6 +10,7 @@ type Props = {
amountAsi: number amountAsi: number
amountFiat: number amountFiat: number
amountOriginalFiat?: number amountOriginalFiat?: number
isValidating: boolean
} }
export function Result({ export function Result({
@ -18,11 +19,16 @@ export function Result({
amount, amount,
amountAsi, amountAsi,
amountFiat, amountFiat,
amountOriginalFiat amountOriginalFiat,
isValidating
}: Props) { }: Props) {
return ( return (
<div className={styles.result}> <div className={styles.result}>
<div className={styles.resultLine}> <div
className={`${styles.resultLine} ${
isValidating ? styles.isValidating : ''
}`}
>
<span className={styles.logo} data-symbol={tokenSymbol}> <span className={styles.logo} data-symbol={tokenSymbol}>
<Image <Image
src={`https://tokens.1inch.io/${tokenAddress}.png`} src={`https://tokens.1inch.io/${tokenAddress}.png`}
@ -40,7 +46,11 @@ export function Result({
</span> </span>
) : null} ) : null}
</div> </div>
<div className={styles.resultLine}> <div
className={`${styles.resultLine} ${
isValidating ? styles.isValidating : ''
}`}
>
<ArrowRightIcon className={styles.iconArrow} /> <ArrowRightIcon className={styles.iconArrow} />
<strong title={`${amountAsi}`}> <strong title={`${amountAsi}`}>
{formatNumber(amountAsi || 0, 'ASI')} {formatNumber(amountAsi || 0, 'ASI')}

View File

@ -9,7 +9,7 @@ import { usePrices } from '@/hooks'
import { FormAmount } from '@/components/FormAmount' import { FormAmount } from '@/components/FormAmount'
export function Buy() { export function Buy() {
const prices = usePrices() const { prices, isValidating } = usePrices()
const [amount, setAmount] = useState(100) const [amount, setAmount] = useState(100)
const [debouncedAmount] = useDebounce(amount, 500) const [debouncedAmount] = useDebounce(amount, 500)
@ -32,6 +32,7 @@ export function Buy() {
? (debouncedAmount / prices.ocean) * ratioOceanToAsi * prices.asi ? (debouncedAmount / prices.ocean) * ratioOceanToAsi * prices.asi
: 0 : 0
} }
isValidating={isValidating}
/> />
<Result <Result
tokenSymbol="AGIX" tokenSymbol="AGIX"
@ -45,6 +46,7 @@ export function Buy() {
? (debouncedAmount / prices.agix) * ratioAgixToAsi * prices.asi ? (debouncedAmount / prices.agix) * ratioAgixToAsi * prices.asi
: 0 : 0
} }
isValidating={isValidating}
/> />
<Result <Result
tokenSymbol="FET" tokenSymbol="FET"
@ -58,6 +60,7 @@ export function Buy() {
? (debouncedAmount / prices.fet) * ratioFetToAsi * prices.asi ? (debouncedAmount / prices.fet) * ratioFetToAsi * prices.asi
: 0 : 0
} }
isValidating={isValidating}
/> />
</div> </div>
) )

View File

@ -16,20 +16,22 @@ import { usePrices } from '@/hooks'
import { FormAmount, type Token } from '@/components/FormAmount' import { FormAmount, type Token } from '@/components/FormAmount'
export function Swap() { export function Swap() {
const prices = usePrices() const { prices, isValidating: isValidatingPrices } = usePrices()
const [amount, setAmount] = useState(100) const [amount, setAmount] = useState(100)
const [debouncedAmount] = useDebounce(amount, 500) const [debouncedAmount] = useDebounce(amount, 500)
const [token, setToken] = useState<Token>('ocean') const [token, setToken] = useState<Token>('ocean')
const { data: dataSwapOceanToAgix } = useSWR( const { data: dataSwapOceanToAgix, isValidating: isValidatingOceanToAgix } =
`/api/quote/?tokenIn=${tokens[0]}&tokenOut=${tokens[2]}&amountIn=${debouncedAmount}`, useSWR(
fetcher `/api/quote/?tokenIn=${tokens[0]}&tokenOut=${tokens[2]}&amountIn=${debouncedAmount}`,
) fetcher
)
const { data: dataSwapOceanToFet } = useSWR( const { data: dataSwapOceanToFet, isValidating: isValidatingOceanToFet } =
`/api/quote/?tokenIn=${tokens[0]}&tokenOut=${tokens[1]}&amountIn=${debouncedAmount}`, useSWR(
fetcher `/api/quote/?tokenIn=${tokens[0]}&tokenOut=${tokens[1]}&amountIn=${debouncedAmount}`,
) fetcher
)
return ( return (
<div className={stylesShared.results}> <div className={stylesShared.results}>
@ -51,6 +53,11 @@ export function Swap() {
amountAsi={debouncedAmount * ratioOceanToAsi} amountAsi={debouncedAmount * ratioOceanToAsi}
amountFiat={debouncedAmount * ratioOceanToAsi * prices.asi} amountFiat={debouncedAmount * ratioOceanToAsi * prices.asi}
amountOriginalFiat={token ? debouncedAmount * prices[token] : undefined} amountOriginalFiat={token ? debouncedAmount * prices[token] : undefined}
isValidating={
isValidatingOceanToAgix ||
isValidatingOceanToFet ||
isValidatingPrices
}
/> />
<Result <Result
@ -74,6 +81,7 @@ export function Swap() {
(dataSwapOceanToAgix?.amountOut / (dataSwapOceanToAgix?.amountOut /
Number(`1e${dataSwapOceanToAgix?.decimals}`) || 0) * prices.agix Number(`1e${dataSwapOceanToAgix?.decimals}`) || 0) * prices.agix
} }
isValidating={isValidatingOceanToAgix || isValidatingPrices}
/> />
<Result <Result
@ -95,6 +103,7 @@ export function Swap() {
(dataSwapOceanToFet?.amountOut / (dataSwapOceanToFet?.amountOut /
Number(`1e${dataSwapOceanToFet?.decimals}`) || 0) * prices.asi Number(`1e${dataSwapOceanToFet?.decimals}`) || 0) * prices.asi
} }
isValidating={isValidatingOceanToFet || isValidatingPrices}
/> />
</div> </div>
) )

View File

@ -1,23 +1,12 @@
.results { .results {
border: 1px solid rgba(var(--foreground-rgb), 0.2); border: 1px solid rgba(var(--foreground-rgb), 0.2);
border-radius: var(--border-radius); border-radius: var(--border-radius);
padding: 1.25rem 1.5rem; padding: 1.5rem 2rem;
} }
/* .results form {
border-color: transparent;
}
.results input {
background: none;
}
.results:hover form {
border-color: rgba(var(--foreground-rgb), 0.2);
} */
.title { .title {
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
font-size: 1.2rem; font-size: 1.2rem;
color: rgb(var(--foreground-rgb-highlight)); color: rgb(var(--foreground-rgb-highlight));
min-height: 58px;
} }

View File

@ -4,16 +4,19 @@ import { tokens } from '@/constants'
import { fetcher } from '@/utils' import { fetcher } from '@/utils'
import useSWR from 'swr' import useSWR from 'swr'
export function usePrices(): { [key: string]: number } { export function usePrices(): {
const { data: dataPrices } = useSWR( prices: { ocean: number; fet: number; agix: number; asi: number }
isValidating: boolean
} {
const { data, isValidating } = useSWR(
`/api/prices/?tokens=${tokens.toString()}`, `/api/prices/?tokens=${tokens.toString()}`,
fetcher fetcher
) )
const ocean = dataPrices?.[tokens[0]]?.usd || 0 const ocean = data?.[tokens[0]]?.usd || 0
const fet = dataPrices?.[tokens[1]]?.usd || 0 const fet = data?.[tokens[1]]?.usd || 0
const agix = dataPrices?.[tokens[2]]?.usd || 0 const agix = data?.[tokens[2]]?.usd || 0
const asi = fet const asi = fet
return { ocean, fet, agix, asi } return { prices: { ocean, fet, agix, asi }, isValidating }
} }