diff --git a/.env.example b/.env.example index c5f0ec770..f1453ab21 100644 --- a/.env.example +++ b/.env.example @@ -33,6 +33,7 @@ export NEXT_PUBLIC_ZERO_DEV_PAYMASTER_URL="" export NEXT_PUBLIC_ZERO_DEV_PASSKEY_SERVER_URL="" export NEXT_PUBLIC_POLYGON_PAYMASTER_URL="" export NEXT_PUBLIC_POLYGON_BUNDLER_URL="" +export NEXT_PUBLIC_BALANCE_WARNING_THRESHOLD=1 export NEXT_PUBLIC_INFURA_API_KEY="" diff --git a/src/app/(mobile-ui)/home/page.tsx b/src/app/(mobile-ui)/home/page.tsx index 78178bcc8..4b5a728b8 100644 --- a/src/app/(mobile-ui)/home/page.tsx +++ b/src/app/(mobile-ui)/home/page.tsx @@ -24,7 +24,12 @@ import { useEffect, useMemo, useState } from 'react' import { twMerge } from 'tailwind-merge' import { useAccount } from 'wagmi' import AddMoneyPromptModal from '@/components/Home/AddMoneyPromptModal' +import BalanceWarningModal from '@/components/Global/BalanceWarningModal' import { AccountType } from '@/interfaces' +import { formatUnits } from 'viem' +import { PEANUT_WALLET_TOKEN_DECIMALS } from '@/constants' + +const BALANCE_WARNING_THRESHOLD = parseInt(process.env.NEXT_PUBLIC_BALANCE_WARNING_THRESHOLD ?? '500') export default function Home() { const { balance, address, isFetchingBalance, isFetchingRewardBalance } = useWallet() @@ -43,6 +48,7 @@ export default function Home() { const [showIOSPWAInstallModal, setShowIOSPWAInstallModal] = useState(false) const [showAddMoneyPromptModal, setShowAddMoneyPromptModal] = useState(false) + const [showBalanceWarningModal, setShowBalanceWarningModal] = useState(false) const userFullName = useMemo(() => { if (!user) return @@ -97,6 +103,28 @@ export default function Home() { } }, [user?.hasPwaInstalled]) + // effect for showing balance warning modal + useEffect(() => { + if (typeof window !== 'undefined' && !isFetchingBalance) { + const hasSeenBalanceWarningThisSession = sessionStorage.getItem('hasSeenBalanceWarningThisSession') + const balanceInUsd = Number(formatUnits(balance, PEANUT_WALLET_TOKEN_DECIMALS)) + + // show if: + // 1. balance is above the threshold + // 2. user hasn't seen this warning in the current session + // 3. no other modals are currently active + if ( + balanceInUsd > BALANCE_WARNING_THRESHOLD && + !hasSeenBalanceWarningThisSession && + !showIOSPWAInstallModal && + !showAddMoneyPromptModal + ) { + setShowBalanceWarningModal(true) + sessionStorage.setItem('hasSeenBalanceWarningThisSession', 'true') + } + } + }, [balance, isFetchingBalance, showIOSPWAInstallModal, showAddMoneyPromptModal]) + // effect for showing add money prompt modal useEffect(() => { if (typeof window !== 'undefined' && !isFetchingBalance) { @@ -106,14 +134,20 @@ export default function Home() { // 1. balance is zero. // 2. user hasn't seen this prompt in the current session. // 3. the iOS PWA install modal is not currently active. + // 4. the balance warning modal is not currently active. // this allows the modal on any device (iOS/Android) and in any display mode (PWA/browser), // as long as the PWA modal (which is iOS & browser-specific) isn't taking precedence. - if (balance === 0n && !hasSeenAddMoneyPromptThisSession && !showIOSPWAInstallModal) { + if ( + balance === 0n && + !hasSeenAddMoneyPromptThisSession && + !showIOSPWAInstallModal && + !showBalanceWarningModal + ) { setShowAddMoneyPromptModal(true) sessionStorage.setItem('hasSeenAddMoneyPromptThisSession', 'true') } } - }, [balance, isFetchingBalance, showIOSPWAInstallModal]) + }, [balance, isFetchingBalance, showIOSPWAInstallModal, showBalanceWarningModal]) if (isLoading) { return @@ -174,6 +208,12 @@ export default function Home() { {/* Add Money Prompt Modal */} setShowAddMoneyPromptModal(false)} /> + + {/* Balance Warning Modal */} + setShowBalanceWarningModal(false)} + /> ) } diff --git a/src/app/(mobile-ui)/layout.tsx b/src/app/(mobile-ui)/layout.tsx index 771495bdb..29a5238c1 100644 --- a/src/app/(mobile-ui)/layout.tsx +++ b/src/app/(mobile-ui)/layout.tsx @@ -1,6 +1,9 @@ 'use client' -import { GenericBanner } from '@/components/Global/Banner' +import { MarqueeWrapper } from '@/components/Global/MarqueeWrapper' +import { useRouter } from 'next/navigation' +import { HandThumbsUp } from '@/assets' +import Image from 'next/image' import GuestLoginModal from '@/components/Global/GuestLoginModal' import PeanutLoading from '@/components/Global/PeanutLoading' import TopNavbar from '@/components/Global/TopNavbar' @@ -22,6 +25,7 @@ const publicPathRegex = /^\/(request\/pay|claim|pay\/.+$)/ const Layout = ({ children }: { children: React.ReactNode }) => { const pathName = usePathname() + const router = useRouter() const { isFetchingUser, user } = useAuth() const [isReady, setIsReady] = useState(false) const [hasToken, setHasToken] = useState(false) @@ -99,10 +103,17 @@ const Layout = ({ children }: { children: React.ReactNode }) => { {/* Main content area */}
- + {/* Only show banner if not on landing page */} + {pathName !== '/' && ( + + )} {/* Fixed top navbar */} {showFullPeanutWallet && (
diff --git a/src/app/(mobile-ui)/support/page.tsx b/src/app/(mobile-ui)/support/page.tsx index 0fd00a6cd..d9ec886cf 100644 --- a/src/app/(mobile-ui)/support/page.tsx +++ b/src/app/(mobile-ui)/support/page.tsx @@ -4,7 +4,7 @@ const SupportPage = () => { return (