Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/(mobile-ui)/qr-pay/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { useWallet } from '@/hooks/wallet/useWallet'
import { clearRedirectUrl, getRedirectUrl, isTxReverted } from '@/utils/general.utils'
import ErrorAlert from '@/components/Global/ErrorAlert'
import { PEANUT_WALLET_TOKEN_DECIMALS } from '@/constants'
import { MANTECA_DEPOSIT_ADDRESS } from '@/constants/manteca.consts'
import { formatUnits, parseUnits } from 'viem'
import { useTransactionDetailsDrawer } from '@/hooks/useTransactionDetailsDrawer'
import { TransactionDetailsDrawer } from '@/components/TransactionDetails/TransactionDetailsDrawer'
Expand All @@ -30,7 +31,6 @@ import ActionModal from '@/components/Global/ActionModal'
import { saveRedirectUrl } from '@/utils/general.utils'
import { MantecaGeoSpecificKycModal } from '@/components/Kyc/InitiateMantecaKYCModal'

const MANTECA_DEPOSIT_ADDRESS = '0x959e088a09f61aB01cb83b0eBCc74b2CF6d62053'
const MAX_QR_PAYMENT_AMOUNT = '200'

export default function QRPayPage() {
Expand Down
8 changes: 6 additions & 2 deletions src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,14 @@ export default function WithdrawBankPage() {
)?.currencyCode

useEffect(() => {
if (!bankAccount) {
if (!bankAccount && !amountToWithdraw) {
// If no bank account AND no amount, go back to main page
router.replace('/withdraw')
} else if (!bankAccount && amountToWithdraw) {
// If amount is set but no bank account, go to country method selection
router.replace(`/withdraw/${country}`)
}
}, [bankAccount, router])
}, [bankAccount, router, amountToWithdraw, country])

const destinationDetails = (account: Account) => {
let countryId: string
Expand Down
11 changes: 5 additions & 6 deletions src/app/(mobile-ui)/withdraw/crypto/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,10 @@ export default function WithdrawCryptoPage() {
}, [dispatch, resetPaymentInitiator])

useEffect(() => {
if (!amountToWithdraw) {
console.error('Amount not available in WithdrawFlowContext for withdrawal, redirecting.')
router.push('/withdraw')
return
if (amountToWithdraw) {
clearErrors()
dispatch(paymentActions.setChargeDetails(null))
}
clearErrors()
dispatch(paymentActions.setChargeDetails(null))
}, [amountToWithdraw])

useEffect(() => {
Expand Down Expand Up @@ -318,6 +315,8 @@ export default function WithdrawCryptoPage() {
}, [xChainRoute])

if (!amountToWithdraw) {
// Redirect to main withdraw page for amount input
router.push('/withdraw')
return <PeanutLoading />
}
Comment on lines +318 to 321
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Sep 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid router.push during render; move redirect to an effect.

Side-effects in render can cause hydration issues and double navigations.

-    if (!amountToWithdraw) {
-        // Redirect to main withdraw page for amount input
-        router.push('/withdraw')
-        return <PeanutLoading />
-    }
+    // Redirect to main withdraw page for amount input
+    useEffect(() => {
+        if (!amountToWithdraw) {
+            router.replace('/withdraw')
+        }
+    }, [amountToWithdraw, router])
+
+    if (!amountToWithdraw) {
+        return <PeanutLoading />
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Redirect to main withdraw page for amount input
router.push('/withdraw')
return <PeanutLoading />
}
// Redirect to main withdraw page for amount input
useEffect(() => {
if (!amountToWithdraw) {
router.replace('/withdraw')
}
}, [amountToWithdraw, router])
if (!amountToWithdraw) {
return <PeanutLoading />
}
🤖 Prompt for AI Agents
In src/app/(mobile-ui)/withdraw/crypto/page.tsx around lines 318-321, the code
calls router.push('/withdraw') during render which causes side-effects in render
and hydration/double-navigation issues; move the redirect into a client-side
effect: convert this component to a client component if not already (add "use
client" at the top), get router from useRouter(), and perform
router.push('/withdraw') inside a useEffect hook that runs on mount; meanwhile
return <PeanutLoading /> from render so the redirect runs only after the
component mounts.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks relevant

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Zishan-7 Yes, this is definitely a relevant issue that should be addressed.

Calling router.push() during render violates React's rules about side effects and can cause:

  • Hydration mismatches between server and client
  • Double navigation issues
  • Potential infinite re-render loops

The fix I suggested moves the redirect logic into a useEffect hook, which is the proper place for side effects like navigation. I also recommended using router.replace() instead of router.push() since we don't want users to navigate back to a page that would immediately redirect them again.

This pattern aligns with React best practices and is consistent with how similar redirect logic is handled elsewhere in the codebase.


🧠 Learnings used
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".

Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".

Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is preferred over `router.replace` when immediate/synchronous URL parameter updates are required, as `router.replace` is asynchronous and doesn't guarantee instant URL changes that subsequent code can rely on. This pattern is used consistently across usePaymentInitiator.ts, Confirm.payment.view.tsx, and useClaimLink.tsx.

Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#551
File: src/components/Request/Create/Views/Initial.view.tsx:151-156
Timestamp: 2024-12-02T17:19:18.532Z
Learning: In the `InitialView` component at `src/components/Request/Create/Views/Initial.view.tsx`, when setting the default chain and token in the `useEffect` triggered by `isPeanutWallet`, it's acceptable to omit the setters from the dependency array and not include additional error handling for invalid defaults.


Expand Down
Loading
Loading