Skip to content

Commit

Permalink
chore: replace effects with react query callbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
slavastartsev committed Nov 15, 2024
1 parent 80c3415 commit 534c403
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 83 deletions.
16 changes: 14 additions & 2 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,21 @@ import { CSSReset, BOBUIProvider, bobTheme } from '../packages/ui/src';
import { WagmiProvider } from '../packages/wagmi/src';
import { SatsWagmiConfig } from '../packages/sats-wagmi/src';
import './style.css';
import { QueryClient, QueryClientProvider } from '../packages/react-query/src';
import { QueryCache, QueryClient, QueryClientProvider } from '../packages/react-query/src';

const queryClient = new QueryClient();
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error, query) => {
if (typeof query.meta?.onError === 'function') query.meta.onError(error, query);
},
onSuccess(data, query) {
if (typeof query.meta?.onSuccess === 'function') query.meta.onSuccess(data, query);
},
onSettled(data, error, query) {
if (typeof query.meta?.onSettled === 'function') query.meta.onSettled(data, error, query);
}
})
});

const preview: Preview = {
parameters: {
Expand Down
84 changes: 37 additions & 47 deletions apps/bob-pay/src/app/[lang]/send/Send.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { t, Trans } from '@lingui/macro';
import { useLingui } from '@lingui/react';
import { mergeProps } from '@react-aria/utils';
import Big from 'big.js';
import { useEffect, useMemo, useState } from 'react';
import { useMemo, useState } from 'react';
import { Address, encodeFunctionData, erc20Abi, isAddress } from 'viem';

import { ScannerModal, TokenButtonGroup } from './components';
Expand Down Expand Up @@ -66,7 +66,15 @@ const Send = ({ ticker: tickerProp = 'WBTC', recipient }: SendProps): JSX.Elemen
const [isGroupAmount, setGroupAmount] = useState(false);

const { getPrice } = usePrices();
const { getBalance, isPending } = useBalances(CHAIN);
const { getBalance } = useBalances(CHAIN, {
meta: {
onSettled: () => {
if (form.values[TRANSFER_TOKEN_AMOUNT]) {
form.validateField(TRANSFER_TOKEN_AMOUNT);
}
}
}
});

const { data: tokens } = useTokens(CHAIN);

Expand Down Expand Up @@ -137,8 +145,7 @@ const Send = ({ ticker: tickerProp = 'WBTC', recipient }: SendProps): JSX.Elemen
const {
data: eoaTransferTx,
mutate: eoaTransfer,
isPending: isEOATransferPending,
error: eoaTransferError
isPending: isEOATransferPending
} = useMutation({
mutationKey: ['eoa-transfer', amount, form.values[TRANSFER_TOKEN_RECIPIENT]],
mutationFn: async ({
Expand Down Expand Up @@ -184,39 +191,33 @@ const Send = ({ ticker: tickerProp = 'WBTC', recipient }: SendProps): JSX.Elemen
});

return txid;
},
onError(error) {
toast.error(error.message);
// eslint-disable-next-line no-console
console.log(error);
}
});

const { isLoading: isWaitingEoaTransferTxConfirmation, data: eoaTransferTransactionReceipt } =
useWaitForTransactionReceipt({
hash: eoaTransferTx
});

useEffect(() => {
if (eoaTransferTransactionReceipt?.status === 'success') {
toast.success(t(i18n)`Successfully sent ${amount} ${token?.currency.symbol}`);

form.resetForm();
setAmount('');
setGroupAmount(false);
setTicker(tickerProp);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [eoaTransferTransactionReceipt]);
const { isLoading: isWaitingEoaTransferTxConfirmation } = useWaitForTransactionReceipt({
hash: eoaTransferTx,
query: {
meta: {
onSuccess: (data: { status: 'success' }) => {
if (data?.status === 'success') {
toast.success(t(i18n)`Successfully sent ${amount} ${token?.currency.symbol}`);

useEffect(() => {
if (eoaTransferError) {
toast.error(eoaTransferError.message);
// eslint-disable-next-line no-console
console.log(eoaTransferError);
form.resetForm();
setAmount('');
setGroupAmount(false);
setTicker(tickerProp);
}
}
}
}
}, [eoaTransferError]);
});

const {
mutate: smartAccountTransfer,
isPending: isSmartAccountTransferPending,
error: smartAccountTransferError
} = useMutation({
const { mutate: smartAccountTransfer, isPending: isSmartAccountTransferPending } = useMutation({
mutationKey: ['smart-account-transfer', amount, form.values[TRANSFER_TOKEN_RECIPIENT]],
onSuccess: (tx, variables) => {
if (!tx) {
Expand All @@ -234,6 +235,11 @@ const Send = ({ ticker: tickerProp = 'WBTC', recipient }: SendProps): JSX.Elemen
setGroupAmount(false);
setTicker(tickerProp);
},
onError(error) {
toast.error(t(i18n)`Failed to submit transaction`);
// eslint-disable-next-line no-console
console.log(error);
},
mutationFn: async ({
recipient,
currencyAmount
Expand Down Expand Up @@ -317,22 +323,6 @@ const Send = ({ ticker: tickerProp = 'WBTC', recipient }: SendProps): JSX.Elemen
}
});

useEffect(() => {
if (smartAccountTransferError) {
toast.error(t(i18n)`Failed to submit transaction`);
// eslint-disable-next-line no-console
console.log(smartAccountTransferError);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [smartAccountTransferError]);

useEffect(() => {
if (!isPending && form.values[TRANSFER_TOKEN_AMOUNT]) {
form.validateField(TRANSFER_TOKEN_AMOUNT);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isPending]);

const tokenInputItems = useMemo(
() =>
tokens?.map((token) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Flex, Span, useCurrencyFormatter, useLocale } from '@gobob/ui';
import { Item } from '@react-stately/collections';
import { Currency, CurrencyAmount } from '@gobob/currency';
import { usePrices } from '@gobob/react-query';
import { useEffect, useMemo, useState } from 'react';
import { useMemo, useState } from 'react';
import Big from 'big.js';

import { ButtonGroup } from '../ButtonGroup';
Expand All @@ -25,12 +25,14 @@ const TokenButtonGroup = ({ isSelected, currency, balance, onSelectionChange }:
const { getPrice, data: pricesData } = usePrices();

const [key, setKey] = useState<string>();
const [prevIsSelected, setPrevIsSelected] = useState(false);

useEffect(() => {
if (!isSelected) {
setKey(undefined);
}
}, [isSelected]);
if (!prevIsSelected && isSelected) setPrevIsSelected(true);

if (prevIsSelected && !isSelected) {
setKey(undefined);
setPrevIsSelected(false);
}

const amounts = useMemo(() => {
if (currency.symbol === 'WBTC') {
Expand Down
5 changes: 3 additions & 2 deletions apps/bob-pay/src/hooks/useBalances.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ChainId } from '@gobob/chains';
import { CurrencyAmount, ERC20Token, Ether } from '@gobob/currency';
import { INTERVAL, useQuery } from '@gobob/react-query';
import { DefinedInitialDataOptions, INTERVAL, useQuery } from '@gobob/react-query';
import { useCallback, useMemo } from 'react';
import { Address, erc20Abi } from 'viem';
import { usePublicClient } from 'wagmi';
Expand All @@ -10,7 +10,7 @@ import { useTokens } from './useTokens';

type Balances = Record<Address, CurrencyAmount<ERC20Token | Ether>>;

const useBalances = (chainId: ChainId) => {
const useBalances = (chainId: ChainId, query?: Pick<DefinedInitialDataOptions, 'meta'>) => {
const publicClient = usePublicClient({ chainId });
const address = useDynamicAddress();

Expand All @@ -20,6 +20,7 @@ const useBalances = (chainId: ChainId) => {
const native = useMemo(() => tokens.find((token) => token.currency.isNative), [tokens]);

const { data: balances, ...queryResult } = useQuery({
...query,
queryKey: ['balances', chainId, address],
enabled: Boolean(address && publicClient && tokens),
queryFn: async () => {
Expand Down
16 changes: 14 additions & 2 deletions apps/bob-pay/src/lib/react-query/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { QueryClient } from '@gobob/react-query';
import { QueryCache, QueryClient } from '@gobob/react-query';

const queryClient = new QueryClient();
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error, query) => {
if (typeof query.meta?.onError === 'function') query.meta.onError(error, query);
},
onSuccess(data, query) {
if (typeof query.meta?.onSuccess === 'function') query.meta.onSuccess(data, query);
},
onSettled(data, error, query) {
if (typeof query.meta?.onSettled === 'function') query.meta.onSettled(data, error, query);
}
})
});

export { queryClient };
21 changes: 21 additions & 0 deletions apps/bob-pay/src/lib/react-query/react-query.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import '@gobob/react-query';
import { DefaultError, Query } from '@gobob/react-query';

// https://tanstack.com/query/latest/docs/framework/react/typescript#typing-meta
interface CustomQueryMeta<TQueryFnData = unknown> extends Record<string, unknown> {
onSuccess?: ((data: TQueryFnData, query: Query<TQueryFnData, unknown, unknown>) => void) | undefined;
onError?: ((error: DefaultError, query: Query<TQueryFnData, unknown, unknown>) => void) | undefined;
onSettled?:
| ((
data: TQueryFnData | undefined,
error: DefaultError | null,
query: Query<TQueryFnData, unknown, unknown>
) => void)
| undefined;
}

declare module '@gobob/react-query' {
interface Register extends Record<string, unknown> {
queryMeta: CustomQueryMeta;
}
}
25 changes: 15 additions & 10 deletions apps/evm/src/app/[lang]/(bridge)/hooks/useGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import { toast } from '@gobob/ui';
import { Address, useAccount } from '@gobob/wagmi';
import { t } from '@lingui/macro';
import { useLingui } from '@lingui/react';
import { Dispatch, SetStateAction, useCallback, useMemo, useState } from 'react';
import * as Sentry from '@sentry/nextjs';
import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from 'react';
import { DebouncedState, useDebounceValue } from 'usehooks-ts';
import { isAddress } from 'viem';

Expand Down Expand Up @@ -213,9 +213,16 @@ const useGateway = ({ params, onError, onMutate, onSuccess }: UseGatewayLiquidit
}
});

const estimateFeeErrorMessage = t(i18n)`Failed to get estimated fee`;

const feeRatesQueryResult = useSatsFeeRate({
query: {
select: feeRatesSelect
select: feeRatesSelect,
meta: {
onError() {
toast.error(estimateFeeErrorMessage);
}
}
}
});

Expand All @@ -227,17 +234,15 @@ const useGateway = ({ params, onError, onMutate, onSuccess }: UseGatewayLiquidit
feeRate: feeRate,
query: {
enabled: Boolean(satsBalance && satsBalance.total > 0n && evmAddress),
select: (data) => CurrencyAmount.fromRawAmount(BITCOIN, data.amount)
select: (data) => CurrencyAmount.fromRawAmount(BITCOIN, data.amount),
meta: {
onError() {
toast.error(estimateFeeErrorMessage);
}
}
}
});

useEffect(() => {
if (feeEstimateQueryResult.error || feeRatesQueryResult.error) {
toast.error(t(i18n)`Failed to get estimated fee`);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [feeRatesQueryResult.error, feeEstimateQueryResult.error]);

const balance = useMemo(
() => getBalanceAmount(satsBalance?.total, feeEstimateQueryResult.data, liquidityQueryResult.data?.liquidityAmount),
[liquidityQueryResult.data?.liquidityAmount, satsBalance?.total, feeEstimateQueryResult.data]
Expand Down
16 changes: 14 additions & 2 deletions apps/evm/src/lib/react-query/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import { QueryClient } from '@gobob/react-query';
import { QueryCache, QueryClient } from '@gobob/react-query';

const queryClient = new QueryClient();
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error, query) => {
if (typeof query.meta?.onError === 'function') query.meta.onError(error, query);
},
onSuccess(data, query) {
if (typeof query.meta?.onSuccess === 'function') query.meta.onSuccess(data, query);
},
onSettled(data, error, query) {
if (typeof query.meta?.onSettled === 'function') query.meta.onSettled(data, error, query);
}
})
});

export { queryClient };
export * from './keys';
21 changes: 21 additions & 0 deletions apps/evm/src/lib/react-query/react-query.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import '@gobob/react-query';
import { DefaultError, Query } from '@gobob/react-query';

// https://tanstack.com/query/latest/docs/framework/react/typescript#typing-meta
interface CustomQueryMeta<TQueryFnData = unknown> extends Record<string, unknown> {
onSuccess?: ((data: TQueryFnData, query: Query<TQueryFnData, unknown, unknown>) => void) | undefined;
onError?: ((error: DefaultError, query: Query<TQueryFnData, unknown, unknown>) => void) | undefined;
onSettled?:
| ((
data: TQueryFnData | undefined,
error: DefaultError | null,
query: Query<TQueryFnData, unknown, unknown>
) => void)
| undefined;
}

declare module '@gobob/react-query' {
interface Register extends Record<string, unknown> {
queryMeta: CustomQueryMeta;
}
}
16 changes: 14 additions & 2 deletions apps/evm/src/test-utils/wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import { QueryClient, QueryClientProvider } from '@gobob/react-query';
import { QueryCache, QueryClient, QueryClientProvider } from '@gobob/react-query';
import { BOBUIProvider } from '@gobob/ui';
import { WagmiProvider } from '@gobob/wagmi';
import { PropsWithChildren } from 'react';

import { LinguiClientProvider } from '@/i18n/provider';

export const wrapper = ({ children }: PropsWithChildren) => {
const queryClient = new QueryClient();
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error, query) => {
if (typeof query.meta?.onError === 'function') query.meta.onError(error, query);
},
onSuccess(data, query) {
if (typeof query.meta?.onSuccess === 'function') query.meta.onSuccess(data, query);
},
onSettled(data, error, query) {
if (typeof query.meta?.onSettled === 'function') query.meta.onSettled(data, error, query);
}
})
});

return (
<LinguiClientProvider initialLocale='en' initialMessages={{}}>
Expand Down
21 changes: 21 additions & 0 deletions packages/react-query/react-query.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import '@tanstack/react-query';
import { DefaultError, Query } from '@tanstack/react-query';

// https://tanstack.com/query/latest/docs/framework/react/typescript#typing-meta
interface CustomQueryMeta<TQueryFnData = unknown> extends Record<string, unknown> {
onSuccess?: ((data: TQueryFnData, query: Query<TQueryFnData, unknown, unknown>) => void) | undefined;
onError?: ((error: DefaultError, query: Query<TQueryFnData, unknown, unknown>) => void) | undefined;
onSettled?:
| ((
data: TQueryFnData | undefined,
error: DefaultError | null,
query: Query<TQueryFnData, unknown, unknown>
) => void)
| undefined;
}

declare module '@tanstack/react-query' {
interface Register extends Record<string, unknown> {
queryMeta: CustomQueryMeta;
}
}
Loading

0 comments on commit 534c403

Please sign in to comment.