diff --git a/src/features/payments/flows/direct-send/useDirectSendFlow.ts b/src/features/payments/flows/direct-send/useDirectSendFlow.ts index 81cf02930..34002956d 100644 --- a/src/features/payments/flows/direct-send/useDirectSendFlow.ts +++ b/src/features/payments/flows/direct-send/useDirectSendFlow.ts @@ -51,7 +51,14 @@ export function useDirectSendFlow() { const { user } = useAuth() const { createCharge, isCreating: isCreatingCharge } = useChargeManager() const { recordPayment, isRecording } = usePaymentRecorder() - const { isConnected, address: walletAddress, sendMoney, formattedBalance, hasSufficientBalance } = useWallet() + const { + isConnected, + address: walletAddress, + sendMoney, + formattedBalance, + hasSufficientBalance, + isFetchingBalance, + } = useWallet() const isLoggedIn = !!user?.user?.userId @@ -84,9 +91,18 @@ export function useDirectSendFlow() { }, [amount, hasSufficientBalance]) // check if should show insufficient balance error + // gate on !isFetchingBalance to avoid flash while balance is still loading const isInsufficientBalance = useMemo(() => { - return isLoggedIn && !!amount && !hasEnoughBalance && !isLoading && !isCreatingCharge && !isRecording - }, [isLoggedIn, amount, hasEnoughBalance, isLoading, isCreatingCharge, isRecording]) + return ( + isLoggedIn && + !!amount && + !hasEnoughBalance && + !isFetchingBalance && + !isLoading && + !isCreatingCharge && + !isRecording + ) + }, [isLoggedIn, amount, hasEnoughBalance, isFetchingBalance, isLoading, isCreatingCharge, isRecording]) // execute the payment (called from input view) const executePayment = useCallback(async () => { diff --git a/src/features/payments/flows/semantic-request/useSemanticRequestFlow.ts b/src/features/payments/flows/semantic-request/useSemanticRequestFlow.ts index dc43176f8..82775c0b6 100644 --- a/src/features/payments/flows/semantic-request/useSemanticRequestFlow.ts +++ b/src/features/payments/flows/semantic-request/useSemanticRequestFlow.ts @@ -84,6 +84,7 @@ export function useSemanticRequestFlow() { sendTransactions, formattedBalance, hasSufficientBalance, + isFetchingBalance, } = useWallet() // use token selector context for ui integration @@ -174,11 +175,13 @@ export function useSemanticRequestFlow() { }, [amount, hasSufficientBalance]) // check if should show insufficient balance error + // gate on !isFetchingBalance to avoid flash while balance is still loading const isInsufficientBalance = useMemo(() => { return ( isLoggedIn && !!amount && !hasEnoughBalance && + !isFetchingBalance && !isLoading && !isCreatingCharge && !isFetchingCharge && @@ -189,6 +192,7 @@ export function useSemanticRequestFlow() { isLoggedIn, amount, hasEnoughBalance, + isFetchingBalance, isLoading, isCreatingCharge, isFetchingCharge, diff --git a/src/features/payments/shared/components/SendWithPeanutCta.tsx b/src/features/payments/shared/components/SendWithPeanutCta.tsx index 644937bc8..62656a627 100644 --- a/src/features/payments/shared/components/SendWithPeanutCta.tsx +++ b/src/features/payments/shared/components/SendWithPeanutCta.tsx @@ -44,10 +44,15 @@ export default function SendWithPeanutCta({ const { user, isFetchingUser } = useAuth() const isLoggedIn = !!user?.user?.userId + // assume logged in while fetching to prevent "Join Peanut" flash + const showAsLoggedIn = isFetchingUser || isLoggedIn const handleClick = (e: React.MouseEvent) => { + // don't act while auth is still resolving + if (isFetchingUser) return + // if auth is required and user is not logged in, redirect to login - if (requiresAuth && !user?.user?.userId && !isFetchingUser) { + if (requiresAuth && !isLoggedIn) { saveRedirectUrl() router.push('/setup') return @@ -66,14 +71,14 @@ export default function SendWithPeanutCta({ } const icon = useMemo((): IconName | undefined => { - if (!isLoggedIn) { + if (!showAsLoggedIn) { return undefined } if (insufficientBalance) { return 'arrow-down' } return 'arrow-up-right' - }, [isLoggedIn, insufficientBalance]) + }, [showAsLoggedIn, insufficientBalance]) const peanutLogo = useMemo((): React.ReactNode => { return ( @@ -94,7 +99,7 @@ export default function SendWithPeanutCta({ onClick={handleClick} {...props} > - {!isLoggedIn ? ( + {!showAsLoggedIn ? (
Join
{peanutLogo}