fix: pull to refresh progress indicator on android#1424
fix: pull to refresh progress indicator on android#1424Hugo0 merged 20 commits intopeanut-wallet-devfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughRefactors pull-to-refresh into a cross-platform React hook (used in mobile and setup layouts), updates global CSS (overscroll prevention, color-scheme hint, expanded perkShake keyframes), replaces reloads with router.refresh plus haptics in wallet navigation, and adds display_override to the PWA manifest. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/app/(mobile-ui)/layout.tsx (1)
79-80: Clarify the purpose of resistanceFunction.The comment states this is to "prevent conflicts with native behavior," but the
resistanceFunctionactually controls the pull resistance curve/feel, not whether conflicts occur. The formulaMath.min(1, t / 2.5)creates a softer, less resistant pull compared to the default linear resistance.Consider updating the comment to reflect the actual purpose (e.g., "softer pull resistance for better UX on Android") and verify through testing that this resistance value provides the desired user experience.
- // prevent conflicts with native behavior - resistanceFunction: (t) => Math.min(1, t / 2.5), + // softer pull resistance for better mobile UX + resistanceFunction: (t) => Math.min(1, t / 2.5),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/app/(mobile-ui)/layout.tsx(2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (5)
src/app/(mobile-ui)/layout.tsx (5)
51-54: LGTM: Pull-to-refresh enabled for both mobile platforms.The platform detection logic correctly enables pull-to-refresh for both iOS and Android devices while skipping desktop browsers.
83-90: LGTM: Cleanup logic properly handles state restoration.The cleanup function correctly destroys the PullToRefresh instance and restores the original overscroll behavior for Android devices, preventing memory leaks and ensuring proper state management.
91-91: LGTM: Effect dependency correctly tracks device type changes.Adding
detectedDeviceTypeto the dependency array ensures the effect re-runs when the device type changes, properly reinitializing pull-to-refresh with the correct platform-specific configuration. The cleanup function will run before each re-initialization, preventing any resource leaks.
62-81: Implementation looks solid—verified all Android compatibility mitigations are in place.The code correctly implements the recommended practices from current web sources:
- CSS
overscroll-behavior: noneis applied on Android to prevent native PTR conflicts (lines 57–59)- Platform detection gates initialization to mobile-only (iOS and Android)
- Proper cleanup on unmount restores default behavior
shouldPullToRefreshchecks scroll position before allowing refreshSince this is a draft, ensure testing on real Android devices across Chrome versions (native PTR behavior varies). The pulltorefreshjs library (v0.1.22) is old, but the integration here follows current best practices and mitigates known conflicts.
56-60: No changes required—implementation is correct.CSS
overscroll-behavioris the standard way to stop Chrome Android's native pull-to-refresh, and your implementation correctly appliesoverscroll-behavior: 'none'to both the document root and body elements, which is the recommended approach. Additional viewport meta tags or touch-action CSS are not necessary for this purpose.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/app/manifest.ts(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/styles/globals.css (1)
29-31: Clarify redundant tap-highlight styling.The
-webkit-tap-highlight-color: transparentrule is duplicated: it's already applied to thebodyelement at line 22 (base layer), which cascades to all buttons. The new utilities-layer rule forbutton, [type='button'](line 29-31) repeats the same value.If this duplication is intentional to ensure button-level override specificity in certain contexts, document that. Otherwise, consider removing the redundant rule to keep the cascade clean.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/styles/globals.css(8 hunks)
🧰 Additional context used
🪛 GitHub Actions: Tests
src/styles/globals.css
[warning] 1-1: Code style issues found in the above file. Run Prettier with --write to fix.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (5)
src/styles/globals.css (5)
8-16: Core PR objective implemented correctly.The additions of
overscroll-behavior-y: containon html/body andcolor-scheme: light onlyon :root are the correct CSS-based approach to prevent browser pull-to-refresh on Android and enforce light mode rendering. The implementation is sound.However, the pipeline reports Prettier formatting issues in this file that need to be resolved. Please run Prettier with
--writeto fix the code style violations before merging.
90-95: Minor formatting alignment.The removal of whitespace around the child combinator (
.scroller > span→.scroller>span) is a stylistic change with no functional impact. This is consistent with stricter CSS formatting.
287-377: Perk animation enhancements are well-structured.The keyframe animations have been enriched with explicit 0%/100% blocks and consistent step delineation across all intensity levels (Weak, Medium, Strong, Intense). The progressive scaling of transform values and addition of Y-axis translation in Strong/Intense variants improves clarity and maintainability. These changes are sound.
491-494: Ensure end-of-file formatting compliance.The file should have proper trailing newline formatting per Prettier standards. Verify this is resolved when running Prettier fixes.
1-1: Note: Incomplete review scope — manifest file not provided.The PR summary mentions changes to
src/app/manifest.ts(addingdisplay_override: ['standalone']), but onlyglobals.csswas provided for review. The manifest changes work in conjunction with the CSS updates to fully support PWA standalone mode and pull-to-refresh prevention.Please ensure manifest.ts changes are also reviewed for correctness and completeness.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/styles/globals.css (1)
290-370: Consider consolidating perk shake keyframes.The expanded keyframes (10%, 20%, 30%, etc.) provide finer control but make the animations more verbose. If the visual difference is subtle, consider using CSS custom properties for the transform values to reduce duplication.
Example consolidation:
+:root { + --perk-shake-weak-x: 4px; + --perk-shake-weak-rotate: 0.5deg; +} + @keyframes perkShakeWeak { 0%, 100% { transform: translateX(0) rotate(0deg); } 10%, 30%, 50%, 70%, 90% { - transform: translateX(-4px) rotate(-0.5deg); + transform: translateX(calc(-1 * var(--perk-shake-weak-x))) rotate(calc(-1 * var(--perk-shake-weak-rotate))); } 20%, 40%, 60%, 80% { - transform: translateX(4px) rotate(0.5deg); + transform: translateX(var(--perk-shake-weak-x)) rotate(var(--perk-shake-weak-rotate)); } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/app/(mobile-ui)/layout.tsx(2 hunks)src/styles/globals.css(6 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-05-21T18:52:22.958Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 870
File: src/styles/globals.css:18-18
Timestamp: 2025-05-21T18:52:22.958Z
Learning: In the peanut-ui project, using `-webkit-tap-highlight-color: none` fixed an issue with blue highlights appearing when tapping inputs on mobile devices, even though `none` is not a technically valid value for this CSS property according to specifications. The valid alternative would be `transparent`.
Applied to files:
src/styles/globals.css
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
Applied to files:
src/app/(mobile-ui)/layout.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (3)
src/styles/globals.css (1)
11-15: Verify that overscroll disabling doesn't affect legitimate scrolling.The CSS correctly disables native pull-to-refresh on Android. However, ensure this doesn't interfere with normal vertical scrolling behavior, especially on pages with nested scrollable containers.
Test the following scenarios on Android devices:
- Normal page scrolling
- Nested scrollable divs (e.g., modals, drawers)
- Horizontal scrolling elements (carousels)
src/app/(mobile-ui)/layout.tsx (2)
51-52: PTR initialization correctly targets all mobile devices (iOS and Android).The logic change from iOS-only to all non-WEB devices is correct and verified across the codebase. Device detection via
useGetDeviceType.tsreliably distinguishes between WEB, IOS, and ANDROID. The pattern of checkingDeviceType.WEBto skip initialization is consistent with how device types are used in other components (e.g.,InstallPWA.tsx,AddWithdrawCountriesList.tsx). The dependency array change to[detectedDeviceType]is appropriate for re-initialization on device type changes.
76-76: The device type detection is immutable—the concerns are not valid.The
useDeviceTypehook initializesdeviceTypeviauseState(() => detectDeviceType())with no setter. The detection is synchronous (based on staticnavigator.userAgentandnavigator.maxTouchPointsproperties) and never changes during a session. This meansdetectedDeviceTypeis immutable, invalidating all stated concerns:
- Device type detection is not asynchronous
- Device type does not change during the session (navigator properties are static)
- Re-initialization does not occur, so race conditions are not a concern
The suggested ref-based workaround is unnecessary. The code functions correctly as-is, though the dependency array could be simplified to
[]since the value never changes. The review's reasoning is based on incorrect assumptions about when and how the device type changes.Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/app/(mobile-ui)/layout.tsx (1)
60-62: Accessibility concern persists with empty instruction strings.The empty instruction strings (
'') hide visual PTR prompts but may impact screen reader users as previously noted. This concern from the earlier review remains unaddressed.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/app/(mobile-ui)/layout.tsx(2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2025-07-24T10:57:15.315Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1000
File: src/components/og/ProfileCardOG.tsx:0-0
Timestamp: 2025-07-24T10:57:15.315Z
Learning: In `src/components/og/ProfileCardOG.tsx`, the scribble image should have an empty alt attribute (alt="") to prevent layout issues if the image fails to load. Since it's a decorative element positioned absolutely over the username text, showing alt text would interfere with the layout and username display.
Applied to files:
src/app/(mobile-ui)/layout.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (2)
src/app/(mobile-ui)/layout.tsx (2)
46-52: LGTM! Cross-platform PTR support correctly enabled.The guard logic change from iOS-only to mobile-only (excluding WEB) correctly enables pull-to-refresh on both iOS and Android devices as intended by the PR objectives.
77-77: LGTM! Proper dependency tracking.Adding
detectedDeviceTypeandrouterto the dependency array correctly ensures the pull-to-refresh instance is reinitialized when these values change, with proper cleanup of old instances.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/components/Global/WalletNavigation/index.tsx (1)
36-64: LGTM! Consider adding a clarifying comment.The implementation correctly uses
router.refresh()to refresh the current page when clicking on an already-active navigation link. This approach preserves client-side state while re-fetching server data, which is preferable to a full page reload.Optional improvement: Consider adding a brief comment explaining the refresh behavior for future maintainers:
onClick={() => { + // Refresh the page when clicking the current active link if (pathName === href) { router.refresh() } }}Verification needed: Given the PR title mentions addressing Android native pointer issues, please verify that this refresh mechanism works correctly on Android devices and doesn't conflict with any pull-to-refresh gestures.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/Global/WalletNavigation/index.tsx(3 hunks)
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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 used instead of `router.replace` in URL manipulation functions when immediate/synchronous URL updates are required for subsequent actions to read the updated URL parameters.
📚 Learning: 2025-09-05T07:31:11.396Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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.
Applied to files:
src/components/Global/WalletNavigation/index.tsx
📚 Learning: 2024-10-29T16:06:38.812Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.
Applied to files:
src/components/Global/WalletNavigation/index.tsx
📚 Learning: 2025-09-05T07:31:11.396Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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 used instead of `router.replace` in URL manipulation functions when immediate/synchronous URL updates are required for subsequent actions to read the updated URL parameters.
Applied to files:
src/components/Global/WalletNavigation/index.tsx
📚 Learning: 2025-07-05T16:58:25.340Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
Applied to files:
src/components/Global/WalletNavigation/index.tsx
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
Applied to files:
src/components/Global/WalletNavigation/index.tsx
🧬 Code graph analysis (1)
src/components/Global/WalletNavigation/index.tsx (1)
src/components/Global/Icons/Icon.tsx (1)
Icon(209-218)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (1)
src/components/Global/WalletNavigation/index.tsx (1)
11-11: LGTM!The
useRouterimport is correctly added to support the navigation refresh functionality.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/styles/globals.css (1)
1-1: Fix Prettier formatting issues.The pipeline reports code style issues in this file. Run Prettier to auto-fix:
npx prettier --write src/styles/globals.cssBased on pipeline failure logs.
♻️ Duplicate comments (1)
src/app/manifest.ts (1)
19-19: Redundantdisplay_overridepersists despite being marked as addressed.This line was flagged as redundant in a previous review and marked as "Addressed in commit ee4ea21", but it remains in the current code. Setting
display_override: ['standalone']whendisplayis already'standalone'provides no functional benefit.Apply this diff to remove the redundant property:
display: 'standalone', - display_override: ['standalone'], background_color: '#ffffff',Or, if fallback display modes are intended, provide actual alternatives:
- display_override: ['standalone'], + display_override: ['standalone', 'minimal-ui'],
🧹 Nitpick comments (1)
src/styles/globals.css (1)
91-91: Minor selector normalization—verify Prettier compliance.The child combinator spacing was normalized from
.scroller > spanto.scroller>span. While both are valid CSS, ensure this aligns with the project's Prettier configuration, as the pipeline reports formatting issues in this file.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/app/manifest.ts(1 hunks)src/styles/globals.css(8 hunks)
🧰 Additional context used
🪛 GitHub Actions: Tests
src/styles/globals.css
[warning] 1-1: Code style issues found in the above file. Run Prettier with --write to fix.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (2)
src/styles/globals.css (2)
12-16: Correct CSS approach to disable native pull-to-refresh on Android.The
overscroll-behavior-y: noneproperty onhtmlandbodyis the recommended CSS solution for disabling native pull-to-refresh behavior on mobile browsers, directly addressing the PR objective.
288-378: Perk animation changes appear unrelated to the PTR fix.The expansion of perk shake animation keyframes from condensed to explicit multi-step formats (
0%, 10%, 20%, ...) adds verbosity but doesn't materially change the animation behavior, since browsers automatically interpolate between defined keyframes. These changes seem outside the scope of fixing the pull-to-refresh indicator issue.Consider:
- Were these animation refinements intentional for this PR, or should they be moved to a separate change?
- If intentional, what specific animation improvement do the additional explicit keyframe steps provide?
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/styles/globals.css (1)
1-494: Fix prettier formatting issues.The pipeline reports code style issues in this file.
Run the following command to fix formatting:
pnpm prettier --write src/styles/globals.csssrc/components/0_Bruddle/Button.tsx (1)
193-207: Add missing dependencies to useCallback.The
handleClickcallback usesdisableHapticsandtriggerHapticbut doesn't include them in the dependency array. This violates React's exhaustive-deps rule and could cause stale closures ifdisableHapticschanges between renders.Apply this diff to fix the dependency array:
}, - [longPress, isLongPressed, onClick] + [longPress, isLongPressed, onClick, disableHaptics, triggerHaptic] )src/components/Global/QRScanner/index.tsx (2)
78-86: AddstopCamerato dependency array.The
closeScannercallback invokesstopCamerabut doesn't list it in dependencies. WhilestopCamerahas an empty dependency array (making it stable), omitting it violates the exhaustive-deps rule and reduces code clarity.Apply this diff:
- }, [onClose]) + }, [onClose, stopCamera])
87-107: Critical: Add missing dependencies tohandleQRScan.The callback references
onScanandtoastbut only includesprocessingQRin its dependency array. This creates stale closures—ifonScanchanges between renders, the callback continues using the outdated function.Apply this diff:
}, - [processingQR] + [processingQR, onScan, toast] )
🧹 Nitpick comments (6)
src/components/0_Bruddle/Button.tsx (1)
200-202: Consider adding error handling for haptic feedback.The
triggerHaptic()call is unguarded. Since this is an external library call within a core UI component, wrapping it in a try-catch would prevent the button from breaking if haptic feedback fails.Apply this diff to add defensive error handling:
- if (!disableHaptics) { - triggerHaptic() - } + if (!disableHaptics) { + try { + triggerHaptic() + } catch (error) { + // Silently fail - haptic feedback is non-critical + console.warn('Haptic feedback failed:', error) + } + }src/components/Payment/Views/Status.payment.view.tsx (1)
193-196: Consider aligning dependency array with "on mount" intent.The comment indicates this should run only on mount, but including
triggerHapticin the dependency array means it will also re-run iftriggerHaptic's identity changes. If the hook provides a stable reference (likely), this works as intended. However, for clarity you could use an empty array[]or add an ESLint disable comment if you want to be explicit about the mount-only behavior.src/components/Claim/Link/Onchain/Success.view.tsx (1)
168-171: Same dependency array consideration as Status.payment.view.tsx.The comment indicates "on mount" intent, but
triggerHapticin the dependency array could cause re-runs if its identity changes. This is consistent with the pattern in Status.payment.view.tsx (lines 193-196), but consider aligning the dependency array with the stated intent for clarity.src/components/Global/QRScanner/index.tsx (1)
252-258: Extract the close delay to a named constant.The 1500ms delay on line 254 is a magic number. Consider extracting it to a configuration constant (e.g.,
SCANNER_CLOSE_DELAY_MS) for clarity and maintainability.+const SCANNER_CLOSE_DELAY_MS = 1500 // Grace period before closing scanner + // ... later in the component: useEffect(() => { if (!isOpen) { - setTimeout(closeScanner, 1500) + setTimeout(closeScanner, SCANNER_CLOSE_DELAY_MS) } else {src/components/Home/HomeHistory.tsx (1)
65-72: Remove debug console.log before production.The KYC status refresh logic is correct and properly awaits
fetchUser()to update the user data. However, the console.log on line 68 should be removed or replaced with a proper logging mechanism for production code.onKycStatusUpdate: useCallback( async (newStatus: string) => { // refetch user data when kyc status changes so the status item appears immediately - console.log('KYC status updated via WebSocket:', newStatus) await fetchUser() }, [fetchUser] ),src/components/Profile/components/IdentityVerificationCountryList.tsx (1)
82-93: Make the chevron container non-interactive.This icon-only chevron is wrapped in
<Button>with no handler, leaving a focusable control that does nothing when activated. Please switch it to a non-interactive element (e.g., a<div>/<span>witharia-hidden) so keyboard and assistive-tech users don’t hit a dead end.- <Button - shadowSize="4" - size="small" - className="h-6 w-6 rounded-full p-0 shadow-[0.12rem_0.12rem_0_#000000]" - > - <div className="flex size-7 items-center justify-center"> - <Icon name="chevron-up" className="h-9 rotate-90" /> - </div> - </Button> + <div + className="flex h-6 w-6 items-center justify-center rounded-full shadow-[0.12rem_0.12rem_0_#000000]" + aria-hidden + > + <Icon name="chevron-up" className="h-4 rotate-90" /> + </div>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlsrc/assets/icons/europe-globe.svgis excluded by!**/*.svgsrc/assets/icons/latam-globe.svgis excluded by!**/*.svgsrc/assets/icons/north-america-globe.svgis excluded by!**/*.svgsrc/assets/icons/rest-of-world-globe.svgis excluded by!**/*.svg
📒 Files selected for processing (59)
next.config.js(1 hunks)package.json(3 hunks)src/app/(mobile-ui)/history/page.tsx(3 hunks)src/app/(mobile-ui)/home/page.tsx(4 hunks)src/app/(mobile-ui)/profile/identity-verification/[region]/[country]/page.tsx(1 hunks)src/app/(mobile-ui)/profile/identity-verification/[region]/page.tsx(1 hunks)src/app/(mobile-ui)/profile/identity-verification/layout.tsx(1 hunks)src/app/(mobile-ui)/profile/identity-verification/page.tsx(1 hunks)src/app/(mobile-ui)/qr/[code]/page.tsx(4 hunks)src/app/(mobile-ui)/withdraw/crypto/page.tsx(3 hunks)src/app/(mobile-ui)/withdraw/manteca/page.tsx(2 hunks)src/app/[...recipient]/client.tsx(4 hunks)src/assets/icons/index.ts(1 hunks)src/components/0_Bruddle/BaseInput.tsx(1 hunks)src/components/0_Bruddle/BaseSelect.tsx(1 hunks)src/components/0_Bruddle/Button.tsx(4 hunks)src/components/0_Bruddle/index.ts(1 hunks)src/components/ActionListCard/index.tsx(4 hunks)src/components/AddMoney/consts/index.ts(242 hunks)src/components/AddWithdraw/DynamicBankAccountForm.tsx(8 hunks)src/components/Claim/Claim.tsx(3 hunks)src/components/Claim/Link/Onchain/Confirm.view.tsx(1 hunks)src/components/Claim/Link/Onchain/Success.view.tsx(4 hunks)src/components/Common/CountryList.tsx(6 hunks)src/components/Global/DirectSendQR/index.tsx(3 hunks)src/components/Global/Icons/Icon.tsx(3 hunks)src/components/Global/Icons/globe-lock.tsx(1 hunks)src/components/Global/IframeWrapper/index.tsx(1 hunks)src/components/Global/QRCodeWrapper/index.tsx(2 hunks)src/components/Global/QRScanner/index.tsx(6 hunks)src/components/Global/TokenAmountInput/index.tsx(4 hunks)src/components/Global/UnsupportedBrowserModal/index.tsx(4 hunks)src/components/Global/WalletNavigation/index.tsx(4 hunks)src/components/Home/HomeCarouselCTA/CarouselCTA.tsx(3 hunks)src/components/Home/HomeHistory.tsx(5 hunks)src/components/Home/KycCompletedModal/index.tsx(1 hunks)src/components/IdentityVerification/StartVerificationModal.tsx(1 hunks)src/components/Invites/InvitesPage.tsx(2 hunks)src/components/Kyc/KycStatusItem.tsx(2 hunks)src/components/Payment/PaymentForm/index.tsx(3 hunks)src/components/Payment/Views/Confirm.payment.view.tsx(3 hunks)src/components/Payment/Views/Status.payment.view.tsx(4 hunks)src/components/Profile/components/CountryListSection.tsx(1 hunks)src/components/Profile/components/IdentityVerificationCountryList.tsx(1 hunks)src/components/Profile/index.tsx(2 hunks)src/components/Profile/views/IdentityVerification.view.tsx(5 hunks)src/components/Profile/views/RegionsPage.view.tsx(1 hunks)src/components/Profile/views/RegionsVerification.view.tsx(1 hunks)src/components/TransactionDetails/TransactionCard.tsx(2 hunks)src/constants/index.ts(1 hunks)src/constants/stateCodes.consts.ts(1 hunks)src/context/contextProvider.tsx(2 hunks)src/context/passkeySupportContext.tsx(1 hunks)src/hooks/useIdentityVerification.tsx(1 hunks)src/interfaces/interfaces.ts(1 hunks)src/styles/globals.css(9 hunks)src/utils/__mocks__/simplewebauthn-browser.ts(1 hunks)src/utils/identityVerification.tsx(1 hunks)tailwind.config.js(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/components/Claim/Link/Onchain/Confirm.view.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/Global/WalletNavigation/index.tsx
🧰 Additional context used
🧠 Learnings (65)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1396
File: src/app/(mobile-ui)/home/page.tsx:295-304
Timestamp: 2025-11-04T17:47:06.328Z
Learning: In src/app/(mobile-ui)/home/page.tsx, when closing the KycCompletedModal, updateUserById is called without awaiting to provide instant feedback to the user. This fire-and-forget pattern for modal dismissals and UI preference updates is intentional and consistent across the codebase—user experience with instant UI feedback takes priority over waiting for backend sync operations.
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 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
Repo: peanutprotocol/peanut-ui PR: 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".
📚 Learning: 2025-08-22T07:28:32.281Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.281Z
Learning: In `src/components/Payment/PaymentForm/index.tsx`, the `handleCompleteDaimoPayment` function is only for updating payment status in the backend after a successful Daimo payment. Payment success/failure is handled by Daimo itself, so try/catch error handling and error display are not needed for backend sync failures - users shouldn't see errors if payment succeeded but database update failed.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsxsrc/components/Payment/Views/Status.payment.view.tsxsrc/components/Payment/PaymentForm/index.tsxsrc/app/[...recipient]/client.tsx
📚 Learning: 2025-08-26T15:25:53.328Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.328Z
Learning: In `src/components/Common/ActionListDaimoPayButton.tsx`, the `handleCompleteDaimoPayment` function should not display error messages to users when DB update fails because the Daimo payment itself has succeeded - showing errors would be confusing since the payment was successful.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsxsrc/components/Payment/PaymentForm/index.tsxsrc/app/[...recipient]/client.tsx
📚 Learning: 2024-10-07T15:25:45.170Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsxsrc/components/Payment/Views/Status.payment.view.tsxsrc/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/components/Global/TokenAmountInput/index.tsxsrc/app/(mobile-ui)/withdraw/crypto/page.tsx
📚 Learning: 2024-10-07T15:28:25.280Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsxsrc/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/components/Global/TokenAmountInput/index.tsxsrc/app/(mobile-ui)/withdraw/crypto/page.tsx
📚 Learning: 2024-10-18T01:51:35.247Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 458
File: src/components/Offramp/Confirm.view.tsx:141-141
Timestamp: 2024-10-18T01:51:35.247Z
Learning: The `handleConfirm` function in `src/components/Create/Link/Confirm.view.tsx` is separate from the one in `src/components/Offramp/Confirm.view.tsx` and does not need to be renamed when refactoring `handleConfirm` in `src/components/Offramp/Confirm.view.tsx`.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsxsrc/components/Claim/Link/Onchain/Success.view.tsx
📚 Learning: 2024-10-23T09:38:27.670Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:27.670Z
Learning: In `src/app/request/pay/page.tsx`, if `linkRes` is not OK in the `generateMetadata` function, the desired behavior is to use the standard title and preview image without throwing an error.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsxsrc/components/Claim/Link/Onchain/Success.view.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsxsrc/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2024-10-07T13:42:07.299Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Pay.tsx:113-123
Timestamp: 2024-10-07T13:42:07.299Z
Learning: In the `PayRequestLink` component (`src/components/Request/Pay/Pay.tsx`), when resolving ENS names, handle errors by displaying an appropriate error message to the user if the ENS cannot be resolved.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsx
📚 Learning: 2024-10-22T18:11:36.864Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:32-49
Timestamp: 2024-10-22T18:11:36.864Z
Learning: In `src/app/request/pay/page.tsx`, the `id` parameter is accessed via `searchParams.id` in the `generateMetadata` function.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsxsrc/app/(mobile-ui)/profile/identity-verification/[region]/page.tsxsrc/components/Payment/PaymentForm/index.tsxsrc/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsxsrc/components/Payment/Views/Status.payment.view.tsxsrc/components/Claim/Link/Onchain/Success.view.tsx
📚 Learning: 2024-10-18T08:54:22.142Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 458
File: src/components/Offramp/Confirm.view.tsx:96-96
Timestamp: 2024-10-18T08:54:22.142Z
Learning: In the `src/components/Offramp/Confirm.view.tsx` file, it's acceptable to include crass or informal language in code comments.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsx
📚 Learning: 2025-10-02T15:23:01.513Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Applied to files:
src/components/Payment/Views/Confirm.payment.view.tsxsrc/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/app/(mobile-ui)/withdraw/crypto/page.tsxsrc/components/Claim/Link/Onchain/Success.view.tsxsrc/app/(mobile-ui)/home/page.tsxsrc/app/[...recipient]/client.tsx
📚 Learning: 2025-11-04T17:47:06.328Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1396
File: src/app/(mobile-ui)/home/page.tsx:295-304
Timestamp: 2025-11-04T17:47:06.328Z
Learning: In src/app/(mobile-ui)/home/page.tsx, when closing the KycCompletedModal, updateUserById is called without awaiting to provide instant feedback to the user. This fire-and-forget pattern for modal dismissals and UI preference updates is intentional and consistent across the codebase—user experience with instant UI feedback takes priority over waiting for backend sync operations.
Applied to files:
src/interfaces/interfaces.tssrc/components/Home/KycCompletedModal/index.tsxsrc/components/IdentityVerification/StartVerificationModal.tsxsrc/app/(mobile-ui)/history/page.tsxsrc/components/Profile/views/IdentityVerification.view.tsxsrc/app/(mobile-ui)/profile/identity-verification/layout.tsxsrc/app/(mobile-ui)/qr/[code]/page.tsxsrc/components/Profile/index.tsxsrc/app/(mobile-ui)/withdraw/crypto/page.tsxsrc/components/Kyc/KycStatusItem.tsxsrc/components/Home/HomeHistory.tsxsrc/app/(mobile-ui)/home/page.tsx
📚 Learning: 2024-10-25T11:33:46.776Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 484
File: src/components/Cashout/Components/Initial.view.tsx:273-274
Timestamp: 2024-10-25T11:33:46.776Z
Learning: In the `InitialCashoutView` component (`src/components/Cashout/Components/Initial.view.tsx`), linked bank accounts should not generate error states, and the `ValidatedInput` component will clear any error messages if needed. Therefore, it's unnecessary to manually clear the error state when selecting or clearing linked bank accounts.
Applied to files:
src/components/Home/KycCompletedModal/index.tsxsrc/components/AddWithdraw/DynamicBankAccountForm.tsxsrc/components/Profile/views/IdentityVerification.view.tsx
📚 Learning: 2025-08-20T09:08:19.266Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 1112
File: src/components/Claim/Link/views/BankFlowManager.view.tsx:336-343
Timestamp: 2025-08-20T09:08:19.266Z
Learning: In the KYC flow implementation, `setJustCompletedKyc` must be called after `await fetchUser()` in the `handleKycSuccess` callback. Setting `justCompletedKyc` before fetching the user would cause a re-fetching loop because `handleKycSuccess` is set in a useEffect inside the KYC hook, which would cause the UI flow to get stuck in one view.
Applied to files:
src/components/Home/KycCompletedModal/index.tsxsrc/app/(mobile-ui)/history/page.tsxsrc/components/Profile/views/IdentityVerification.view.tsxsrc/components/Profile/index.tsxsrc/components/Kyc/KycStatusItem.tsxsrc/components/Home/HomeHistory.tsxsrc/app/(mobile-ui)/home/page.tsx
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
Applied to files:
src/components/Home/KycCompletedModal/index.tsxsrc/app/(mobile-ui)/history/page.tsxsrc/components/Profile/views/IdentityVerification.view.tsxsrc/app/(mobile-ui)/profile/identity-verification/layout.tsxsrc/components/Global/QRCodeWrapper/index.tsxsrc/components/Global/UnsupportedBrowserModal/index.tsxsrc/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/components/Global/TokenAmountInput/index.tsxsrc/app/(mobile-ui)/withdraw/crypto/page.tsxsrc/app/(mobile-ui)/home/page.tsx
📚 Learning: 2024-12-02T17:19:18.532Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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.
Applied to files:
src/components/Payment/Views/Status.payment.view.tsxsrc/components/Global/QRCodeWrapper/index.tsxsrc/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/components/Claim/Link/Onchain/Success.view.tsx
📚 Learning: 2025-09-05T07:31:11.396Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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.
Applied to files:
src/components/Payment/Views/Status.payment.view.tsxsrc/components/Claim/Claim.tsxsrc/app/(mobile-ui)/history/page.tsxsrc/components/Global/TokenAmountInput/index.tsxsrc/components/Claim/Link/Onchain/Success.view.tsxsrc/components/Home/HomeHistory.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.
Applied to files:
src/components/Payment/Views/Status.payment.view.tsxsrc/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2025-07-24T13:26:10.290Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1014
File: src/components/Claim/Link/Initial.view.tsx:413-413
Timestamp: 2025-07-24T13:26:10.290Z
Learning: In the peanut-ui repository, the change from `${SQUID_API_URL}/route` to `${SQUID_API_URL}/v2/route` in src/components/Claim/Link/Initial.view.tsx was a typo fix, not an API migration, as the codebase was already using Squid API v2.
Applied to files:
src/components/Payment/Views/Status.payment.view.tsxsrc/components/Claim/Link/Onchain/Success.view.tsx
📚 Learning: 2025-07-24T10:57:15.315Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1000
File: src/components/og/ProfileCardOG.tsx:0-0
Timestamp: 2025-07-24T10:57:15.315Z
Learning: In `src/components/og/ProfileCardOG.tsx`, the scribble image should have an empty alt attribute (alt="") to prevent layout issues if the image fails to load. Since it's a decorative element positioned absolutely over the username text, showing alt text would interfere with the layout and username display.
Applied to files:
src/components/Payment/Views/Status.payment.view.tsx
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 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".
Applied to files:
src/components/Profile/views/RegionsPage.view.tsxsrc/components/IdentityVerification/StartVerificationModal.tsxsrc/components/Profile/components/IdentityVerificationCountryList.tsxsrc/components/Common/CountryList.tsxsrc/app/(mobile-ui)/profile/identity-verification/[region]/[country]/page.tsxsrc/components/AddWithdraw/DynamicBankAccountForm.tsxsrc/components/Profile/views/IdentityVerification.view.tsxsrc/app/(mobile-ui)/profile/identity-verification/page.tsxsrc/app/(mobile-ui)/profile/identity-verification/layout.tsxsrc/components/Profile/components/CountryListSection.tsxsrc/app/(mobile-ui)/profile/identity-verification/[region]/page.tsxsrc/components/Profile/views/RegionsVerification.view.tsxsrc/context/contextProvider.tsxsrc/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/app/(mobile-ui)/withdraw/crypto/page.tsxsrc/components/AddMoney/consts/index.ts
📚 Learning: 2025-05-02T19:14:25.010Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 828
File: src/app/(mobile-ui)/request/[...username]/page.tsx:17-17
Timestamp: 2025-05-02T19:14:25.010Z
Learning: In Next.js App Router, catch-all routes (like `/request/[...username]`) will only match URLs with at least one parameter segment, ensuring that the page component only renders when there is at least one value in the params array.
Applied to files:
src/components/Profile/views/RegionsPage.view.tsxsrc/app/(mobile-ui)/profile/identity-verification/[region]/page.tsx
📚 Learning: 2025-08-14T14:42:54.411Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/utils/withdraw.utils.ts:181-191
Timestamp: 2025-08-14T14:42:54.411Z
Learning: The countryCodeMap in src/components/AddMoney/consts/index.ts uses uppercase 3-letter country codes as keys (like 'AUT', 'BEL', 'CZE') that map to 2-letter country codes, requiring input normalization to uppercase for proper lookups.
Applied to files:
src/components/Profile/components/IdentityVerificationCountryList.tsxsrc/components/Common/CountryList.tsxsrc/components/AddWithdraw/DynamicBankAccountForm.tsxsrc/components/Profile/views/IdentityVerification.view.tsxsrc/utils/identityVerification.tsxsrc/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/constants/stateCodes.consts.tssrc/components/AddMoney/consts/index.ts
📚 Learning: 2025-08-13T18:22:01.941Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:0-0
Timestamp: 2025-08-13T18:22:01.941Z
Learning: In the DynamicBankAccountForm component, the countryName parameter from useParams will always resemble a country title, not a URL slug.
Applied to files:
src/components/Profile/components/IdentityVerificationCountryList.tsxsrc/components/AddWithdraw/DynamicBankAccountForm.tsxsrc/components/Profile/views/IdentityVerification.view.tsx
📚 Learning: 2025-10-07T10:19:20.077Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 1286
File: src/components/MultiStepBankAccountForm/FormInput.tsx:10-10
Timestamp: 2025-10-07T10:19:20.077Z
Learning: The codebase follows a strict policy of avoiding `any` types. Always use proper TypeScript types, particularly from libraries like react-hook-form (RegisterOptions, FieldErrors, UseFormSetValue, etc.) rather than using `any`.
Applied to files:
src/components/0_Bruddle/BaseSelect.tsx
📚 Learning: 2025-08-14T14:36:18.758Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/components/Claim/Link/views/BankFlowManager.view.tsx:0-0
Timestamp: 2025-08-14T14:36:18.758Z
Learning: Bridge API requires ISO3 country codes (3-letter codes like "USA", "GBR") while flag display components need ISO2 codes (2-letter codes like "US", "GB").
Applied to files:
src/components/Common/CountryList.tsxsrc/components/AddMoney/consts/index.ts
📚 Learning: 2025-08-26T17:38:37.055Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1132
File: src/components/Common/ActionList.tsx:153-156
Timestamp: 2025-08-26T17:38:37.055Z
Learning: In ActionList.tsx, when there are circular dependency concerns with ACTION_METHODS being imported by other components, the preferred solution is to move ACTION_METHODS to a separate constants file (like src/constants/actionlist.consts.ts) rather than using prop drilling. This centralizes constants management and creates a cleaner dependency graph.
Applied to files:
src/components/ActionListCard/index.tsx
📚 Learning: 2024-11-18T21:36:11.486Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.
Applied to files:
src/components/Claim/Claim.tsxsrc/app/(mobile-ui)/withdraw/crypto/page.tsxsrc/components/Claim/Link/Onchain/Success.view.tsx
📚 Learning: 2025-08-07T12:53:50.946Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1072
File: src/app/(setup)/setup/page.tsx:173-175
Timestamp: 2025-08-07T12:53:50.946Z
Learning: In the peanut-ui setup flow at `src/app/(setup)/setup/page.tsx`, when handling unsupported scenarios, both device not supported and browser not supported cases should show the same "Unsupported browser" message using the `UnsupportedBrowserModal` component, rather than having distinct messaging for each scenario.
Applied to files:
src/components/Invites/InvitesPage.tsxsrc/components/Global/UnsupportedBrowserModal/index.tsx
📚 Learning: 2025-10-08T17:13:13.155Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1299
File: src/app/(mobile-ui)/points/page.tsx:41-51
Timestamp: 2025-10-08T17:13:13.155Z
Learning: In `src/app/(mobile-ui)/points/page.tsx`, the icon name "invite-heart" is intentionally used (not "inviter-heart") when displaying who invited the current user, as this is a deliberate design choice despite semantic differences with UserHeader usage.
Applied to files:
src/components/Invites/InvitesPage.tsxsrc/components/Global/Icons/Icon.tsxsrc/app/(mobile-ui)/qr/[code]/page.tsxsrc/components/Profile/index.tsxsrc/app/(mobile-ui)/home/page.tsx
📚 Learning: 2025-05-15T14:47:26.891Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 857
File: src/hooks/useWebSocket.ts:77-82
Timestamp: 2025-05-15T14:47:26.891Z
Learning: The useWebSocket hook in src/hooks/useWebSocket.ts is designed to provide raw history entries, while the components using it (such as HomeHistory.tsx) are responsible for implementing deduplication logic based on UUID to prevent duplicate entries when combining WebSocket data with other data sources.
Applied to files:
src/app/(mobile-ui)/history/page.tsxsrc/components/Home/HomeHistory.tsx
📚 Learning: 2025-05-15T14:45:45.632Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 857
File: src/hooks/useWebSocket.ts:5-5
Timestamp: 2025-05-15T14:45:45.632Z
Learning: For the WebSocketStatus type in useWebSocket.ts, it was decided to keep it as a non-exported type until there's a specific need to export it. The team prefers to address potential issues when they become actual requirements rather than preemptively.
Applied to files:
src/app/(mobile-ui)/history/page.tsx
📚 Learning: 2025-08-11T10:35:02.715Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 1078
File: src/hooks/useKycFlow.ts:129-141
Timestamp: 2025-08-11T10:35:02.715Z
Learning: In the KYC flow implementation in `src/hooks/useKycFlow.ts`, when Terms of Service (ToS) is accepted, there will always be a KYC link available in the `apiResponse`. The system ensures this invariant, so defensive checks for missing KYC links after ToS acceptance are unnecessary.
Applied to files:
src/app/(mobile-ui)/history/page.tsxsrc/components/Profile/index.tsxsrc/components/Kyc/KycStatusItem.tsxsrc/app/(mobile-ui)/home/page.tsx
📚 Learning: 2025-09-11T17:46:12.507Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.507Z
Learning: Functions in Next.js that are not marked with "use server" and contain secrets are unsafe to import in client components, as they get bundled into the client JavaScript and can leak environment variables to the browser.
Applied to files:
src/app/(mobile-ui)/history/page.tsxsrc/components/Home/HomeHistory.tsx
📚 Learning: 2025-11-06T08:19:05.201Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1407
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:459-475
Timestamp: 2025-11-06T08:19:05.201Z
Learning: In src/components/AddWithdraw/DynamicBankAccountForm.tsx, the street address field has a 35-character maximum length limit because the backend provider enforces this constraint, applicable to both US and Mexican addresses.
Applied to files:
src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2024-11-26T12:06:11.603Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 545
File: src/components/Global/GeneralRecipientInput/index.tsx:118-126
Timestamp: 2024-11-26T12:06:11.603Z
Learning: For bank account input fields, use `autocomplete="bank-account-number"` when the recipient type is `'us'` or `'iban'`.
Applied to files:
src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2025-01-16T13:14:40.363Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 631
File: src/components/Create/Create.tsx:108-112
Timestamp: 2025-01-16T13:14:40.363Z
Learning: In the Peanut UI codebase, the `resetTokenContextProvider` function from `tokenSelectorContext` is a stable function reference that doesn't change, so it doesn't need to be included in useEffect dependencies.
Applied to files:
src/components/Global/QRCodeWrapper/index.tsxsrc/context/contextProvider.tsxsrc/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2025-08-14T12:46:10.706Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1089
File: src/components/LandingPage/noFees.tsx:282-285
Timestamp: 2025-08-14T12:46:10.706Z
Learning: In the peanutprotocol/peanut-ui project, loading states are implemented only after they have been properly designed by the design team to ensure consistency across the application.
Applied to files:
src/components/Global/QRCodeWrapper/index.tsx
📚 Learning: 2025-07-05T16:58:25.340Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
Applied to files:
src/components/Global/UnsupportedBrowserModal/index.tsxsrc/components/Global/TokenAmountInput/index.tsxsrc/components/Home/HomeHistory.tsx
📚 Learning: 2025-09-08T03:13:09.111Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page.
Applied to files:
src/app/(mobile-ui)/qr/[code]/page.tsxsrc/components/Global/DirectSendQR/index.tsx
📚 Learning: 2025-11-07T11:51:58.861Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1419
File: src/components/Global/BalanceWarningModal/index.tsx:94-94
Timestamp: 2025-11-07T11:51:58.861Z
Learning: In `src/components/Global/BalanceWarningModal/index.tsx`, the casual and congratulatory phrase "You're rich! Congrats on having a high balance." is intentional and by design.
Applied to files:
src/app/(mobile-ui)/qr/[code]/page.tsx
📚 Learning: 2025-09-08T03:13:09.111Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page after scanning MERCADO_PAGO or PIX QR codes.
Applied to files:
src/components/Global/DirectSendQR/index.tsxsrc/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2025-10-29T11:27:59.248Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1368
File: src/components/Common/ActionList.tsx:109-111
Timestamp: 2025-10-29T11:27:59.248Z
Learning: In `src/components/Common/ActionList.tsx`, the `balance` from `useWallet()` hook is always in USDC (as a formatted string), making it directly comparable to USD amounts without conversion. The comparison `Number(balance) >= amountInUsd` is intentional and correct.
Applied to files:
src/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/app/(mobile-ui)/withdraw/crypto/page.tsx
📚 Learning: 2025-10-24T13:44:39.473Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.
Applied to files:
src/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 495
File: src/components/Global/TokenAmountInput/index.tsx:23-30
Timestamp: 2024-10-29T12:19:41.968Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), when the 'Max' button is clicked, we intentionally set the input denomination to 'TOKEN' because we are setting the value as token.
Applied to files:
src/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 495
File: src/components/Create/Link/Input.view.tsx:244-248
Timestamp: 2024-10-29T12:20:47.207Z
Learning: In the `TokenAmountInput` component within `src/components/Global/TokenAmountInput/index.tsx`, when `balance` is undefined, the `maxValue` prop should be set to an empty string `''`.
Applied to files:
src/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2025-06-18T19:56:55.443Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 919
File: src/components/Withdraw/views/Initial.withdraw.view.tsx:87-87
Timestamp: 2025-06-18T19:56:55.443Z
Learning: In withdraw flows for Peanut Wallet, the PeanutActionDetailsCard should always display "USDC" as the token symbol because it shows the amount being withdrawn from the Peanut Wallet (which holds USDC), regardless of the destination token/chain selected by the user. The TokenSelector is used for choosing the withdrawal destination, not the source display.
Applied to files:
src/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2025-08-22T07:25:59.304Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1104
File: src/components/Payment/PaymentForm/index.tsx:596-600
Timestamp: 2025-08-22T07:25:59.304Z
Learning: The `TokenAmountInput` component in `src/components/Global/TokenAmountInput/` always returns decimal strings (e.g., "1,234.56"), not base units. When passing these values to external APIs like Daimo's `toUnits` prop, simply stripping commas with `.replace(/,/g, '')` is sufficient.
Applied to files:
src/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-07T13:42:00.443Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Applied to files:
src/app/(mobile-ui)/withdraw/manteca/page.tsxsrc/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 413
File: src/context/tokenSelector.context.tsx:118-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the `TokenContextProvider` component within `src/context/tokenSelector.context.tsx`, in the TypeScript React application, when data changes and before calling `fetchAndSetTokenPrice`, it is necessary to reset `selectedTokenData`, `selectedTokenPrice`, `selectedTokenDecimals`, and `inputDenomination` to discard stale data.
Applied to files:
src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-11T01:14:15.489Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 424
File: src/components/Global/TokenSelector/TokenSelector.tsx:197-211
Timestamp: 2024-10-11T01:14:15.489Z
Learning: In `src/components/Global/TokenSelector/TokenSelector.tsx`, when the calculation within functions like `byChainAndText` is not computationally expensive, it's acceptable to avoid using `useCallback` for memoization.
Applied to files:
src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-03T09:57:43.885Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 404
File: src/context/tokenSelector.context.tsx:121-121
Timestamp: 2024-10-03T09:57:43.885Z
Learning: In `TokenContextProvider` within `tokenSelector.context.tsx`, when token data is loaded from preferences, it's acceptable to set `isTokenPriceFetchingComplete` to `true` because the token data is already available.
Applied to files:
src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-29T16:06:38.812Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.
Applied to files:
src/components/Global/TokenAmountInput/index.tsxsrc/components/Claim/Link/Onchain/Success.view.tsxsrc/components/Home/HomeHistory.tsx
📚 Learning: 2025-05-19T19:40:43.138Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 868
File: src/components/Payment/PaymentForm/index.tsx:284-293
Timestamp: 2025-05-19T19:40:43.138Z
Learning: When converting between USD and token amounts, always check if the token price (divisor) is valid and non-zero before performing the division to prevent Infinity, NaN, or errors. Implementing validation like `if (!tokenPrice || isNaN(tokenPrice) || tokenPrice === 0)` before division operations is crucial for handling cases where price data might be unavailable.
Applied to files:
src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-24T12:38:32.793Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 478
File: src/components/Request/Create/Views/Initial.view.tsx:81-89
Timestamp: 2024-10-24T12:38:32.793Z
Learning: In `src/components/Request/Create/Views/Initial.view.tsx`, the function `getTokenDetails` is a simple function that does not fetch from the network or perform asynchronous operations.
Applied to files:
src/components/Claim/Link/Onchain/Success.view.tsx
📚 Learning: 2025-04-11T11:33:53.245Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 798
File: src/components/Home/HomeHistory.tsx:138-192
Timestamp: 2025-04-11T11:33:53.245Z
Learning: In the HomeHistory component, infinite scrolling is intentionally not implemented despite the presence of useInfiniteQuery and IntersectionObserver code. The component is designed to only display the first 5 entries with a "View all transactions" link for viewing the complete history.
Applied to files:
src/components/Home/HomeHistory.tsx
📚 Learning: 2025-09-11T17:46:12.507Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.507Z
Learning: In Next.js applications, functions marked with "use server" are server actions that are safe to import in client components. Next.js generates proxy stubs for these functions, ensuring the actual implementation and any secrets (like process.env variables) remain on the server and are not bundled into the client JavaScript.
Applied to files:
src/components/Home/HomeHistory.tsx
📚 Learning: 2025-09-15T17:25:12.198Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/hooks/useCreateOnramp.ts:47-49
Timestamp: 2025-09-15T17:25:12.198Z
Learning: Server Actions in Next.js are specifically designed to be called from Client Components. They are asynchronous functions marked with 'use server' that run on the server but can be imported and invoked directly from client-side code. This is a core feature of the Next.js App Router, eliminating the need to create separate API routes for server-side operations called from the client.
Applied to files:
src/components/Home/HomeHistory.tsx
📚 Learning: 2025-08-20T08:09:24.667Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1111
File: src/styles/globals.css:0-0
Timestamp: 2025-08-20T08:09:24.667Z
Learning: In the peanut-ui project, font variables from localFont (like --font-roboto-flex-bold) are applied to the <body> element in src/app/layout.tsx, not the <html> element. CSS custom properties are available throughout the DOM tree from the body level.
Applied to files:
src/styles/globals.css
📚 Learning: 2025-08-20T08:09:24.667Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1111
File: src/styles/globals.css:0-0
Timestamp: 2025-08-20T08:09:24.667Z
Learning: In the peanut-ui project (src/app/layout.tsx), font variables from localFont (like --font-roboto-flex-bold) are applied to the <body> element's className, not the <html> element. All font variables including robotoFlexBold.variable are properly loaded on the body, making CSS custom properties available throughout the DOM tree.
Applied to files:
src/styles/globals.css
📚 Learning: 2025-06-22T16:10:53.167Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 915
File: src/hooks/useKycFlow.ts:96-124
Timestamp: 2025-06-22T16:10:53.167Z
Learning: The `initiateKyc` function in `src/app/actions/users.ts` already includes comprehensive error handling with try-catch blocks and returns structured responses with either `{ data }` or `{ error }` fields, so additional try-catch blocks around its usage are not needed.
Applied to files:
src/app/(mobile-ui)/home/page.tsx
📚 Learning: 2025-09-03T12:23:31.845Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1173
File: src/components/Common/SavedAccountsView.tsx:86-87
Timestamp: 2025-09-03T12:23:31.845Z
Learning: In the CountryData interface from src/components/AddMoney/consts, the path field is required (not optional) for all country entries.
Applied to files:
src/components/AddMoney/consts/index.ts
📚 Learning: 2025-08-19T09:08:16.945Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1107
File: src/components/LandingPage/hero.tsx:160-160
Timestamp: 2025-08-19T09:08:16.945Z
Learning: In the Hero component at src/components/LandingPage/hero.tsx, the team prefers to keep the main heading as h2 (not h1) and does not want a heading prop parameter - the heading content should remain hardcoded in the component.
Applied to files:
src/components/Home/HomeCarouselCTA/CarouselCTA.tsx
🧬 Code graph analysis (23)
src/components/Home/KycCompletedModal/index.tsx (5)
src/context/authContext.tsx (1)
useAuth(192-198)src/components/AddMoney/consts/index.ts (3)
CountryData(155-165)MantecaSupportedExchanges(10-21)countryData(292-2710)src/hooks/useKycStatus.tsx (1)
useKycStatus(12-36)src/hooks/useIdentityVerification.tsx (1)
useIdentityVerification(97-272)src/components/Global/Icons/Icon.tsx (1)
IconName(70-136)
src/context/passkeySupportContext.tsx (1)
src/hooks/usePasskeySupport.ts (2)
PasskeySupportResult(6-13)usePasskeySupport(21-102)
src/components/Profile/views/RegionsPage.view.tsx (2)
src/hooks/useIdentityVerification.tsx (1)
useIdentityVerification(97-272)src/components/0_Bruddle/Button.tsx (1)
Button(80-279)
src/components/IdentityVerification/StartVerificationModal.tsx (3)
src/hooks/useIdentityVerification.tsx (1)
useIdentityVerification(97-272)src/components/AddMoney/consts/index.ts (1)
MantecaSupportedExchanges(10-21)src/components/Global/Icons/Icon.tsx (1)
Icon(212-221)
src/components/Profile/components/IdentityVerificationCountryList.tsx (5)
src/utils/identityVerification.tsx (1)
getCountriesForRegion(3-22)src/components/SearchInput/index.tsx (1)
SearchInput(14-51)src/components/Global/Icons/Icon.tsx (1)
Icon(212-221)src/components/AddMoney/consts/index.ts (1)
MantecaSupportedExchanges(10-21)src/components/0_Bruddle/Button.tsx (1)
Button(80-279)
src/components/0_Bruddle/BaseSelect.tsx (1)
src/components/Global/Icons/Icon.tsx (1)
Icon(212-221)
src/components/Common/CountryList.tsx (1)
src/hooks/useIdentityVerification.tsx (1)
useIdentityVerification(97-272)
src/app/(mobile-ui)/history/page.tsx (1)
src/context/authContext.tsx (1)
useAuth(192-198)
src/components/AddWithdraw/DynamicBankAccountForm.tsx (1)
src/constants/stateCodes.consts.ts (2)
MX_STATES(64-97)US_STATES(5-56)
src/components/Global/Icons/Icon.tsx (1)
src/components/Global/Icons/globe-lock.tsx (1)
GlobeLockIcon(3-16)
src/components/Profile/views/IdentityVerification.view.tsx (3)
src/hooks/useIdentityVerification.tsx (1)
useIdentityVerification(97-272)src/utils/general.utils.ts (2)
getRedirectUrl(792-794)clearRedirectUrl(796-800)src/components/AddMoney/consts/index.ts (1)
countryData(292-2710)
src/utils/identityVerification.tsx (1)
src/components/AddMoney/consts/index.ts (3)
ALL_COUNTRIES_ALPHA3_TO_ALPHA2(2794-2797)MEXICO_ALPHA3_TO_ALPHA2(2785-2787)countryData(292-2710)
src/app/(mobile-ui)/profile/identity-verification/layout.tsx (1)
src/hooks/useIdentityVerification.tsx (1)
useIdentityVerification(97-272)
src/components/Profile/components/CountryListSection.tsx (4)
src/components/AddMoney/consts/index.ts (1)
CountryData(155-165)src/components/Global/Icons/Icon.tsx (1)
Icon(212-221)src/components/Global/Card/index.tsx (1)
getCardPosition(14-19)src/components/ActionListCard/index.tsx (1)
ActionListCard(23-78)
src/components/Global/UnsupportedBrowserModal/index.tsx (1)
src/context/passkeySupportContext.tsx (1)
usePasskeySupportContext(12-16)
src/app/(mobile-ui)/qr/[code]/page.tsx (1)
src/components/Global/Icons/Icon.tsx (1)
Icon(212-221)
src/components/Profile/views/RegionsVerification.view.tsx (5)
src/hooks/useIdentityVerification.tsx (2)
useIdentityVerification(97-272)Region(11-16)src/components/Global/EmptyStates/EmptyState.tsx (1)
EmptyState(13-28)src/components/ActionListCard/index.tsx (1)
ActionListCard(23-78)src/components/Global/Card/index.tsx (1)
getCardPosition(14-19)src/components/Global/Icons/Icon.tsx (1)
Icon(212-221)
src/components/Global/QRScanner/index.tsx (1)
src/hooks/useGetDeviceType.ts (1)
useDeviceType(37-42)
src/context/contextProvider.tsx (2)
src/context/passkeySupportContext.tsx (1)
PasskeySupportProvider(7-10)src/context/QrCodeContext.tsx (1)
QrCodeProvider(12-15)
src/components/Profile/index.tsx (1)
src/hooks/useKycStatus.tsx (1)
useKycStatus(12-36)
src/components/Home/HomeHistory.tsx (1)
src/context/authContext.tsx (1)
useAuth(192-198)
src/app/(mobile-ui)/home/page.tsx (3)
src/context/authContext.tsx (1)
useAuth(192-198)src/hooks/useKycStatus.tsx (1)
useKycStatus(12-36)src/app/actions/users.ts (1)
updateUserById(12-35)
src/hooks/useIdentityVerification.tsx (3)
src/context/authContext.tsx (1)
useAuth(192-198)src/hooks/useKycStatus.tsx (1)
useKycStatus(12-36)src/components/AddMoney/consts/index.ts (3)
MantecaSupportedExchanges(10-21)countryData(292-2710)BRIDGE_ALPHA3_TO_ALPHA2(2741-2783)
🪛 GitHub Actions: Tests
src/styles/globals.css
[warning] 1-1: Code style issues found in the file. Run 'pnpm prettier --write' to fix.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/hooks/usePullToRefresh.ts (1)
30-32: Return the Promise fromrouter.refresh()so PTR waits for completion.The
router.refresh()call returns a Promise, but theonRefreshcallback doesn't return it. This causes the pull-to-refresh animation to end immediately without waiting for the refresh to complete, breaking the intended user experience.Fix by returning the Promise:
onRefresh: () => { - router.refresh() + return router.refresh() },Or use async/await:
-onRefresh: () => { - router.refresh() -}, +async onRefresh() { + await router.refresh() +},
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/app/(mobile-ui)/layout.tsx(2 hunks)src/app/(setup)/layout.tsx(2 hunks)src/hooks/usePullToRefresh.ts(1 hunks)src/styles/globals.css(6 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1396
File: src/app/(mobile-ui)/home/page.tsx:295-304
Timestamp: 2025-11-04T17:47:06.328Z
Learning: In src/app/(mobile-ui)/home/page.tsx, when closing the KycCompletedModal, updateUserById is called without awaiting to provide instant feedback to the user. This fire-and-forget pattern for modal dismissals and UI preference updates is intentional and consistent across the codebase—user experience with instant UI feedback takes priority over waiting for backend sync operations.
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
Applied to files:
src/app/(setup)/layout.tsxsrc/app/(mobile-ui)/layout.tsx
📚 Learning: 2025-07-24T10:57:15.315Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1000
File: src/components/og/ProfileCardOG.tsx:0-0
Timestamp: 2025-07-24T10:57:15.315Z
Learning: In `src/components/og/ProfileCardOG.tsx`, the scribble image should have an empty alt attribute (alt="") to prevent layout issues if the image fails to load. Since it's a decorative element positioned absolutely over the username text, showing alt text would interfere with the layout and username display.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2025-09-05T07:31:11.396Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2025-08-20T08:09:24.667Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1111
File: src/styles/globals.css:0-0
Timestamp: 2025-08-20T08:09:24.667Z
Learning: In the peanut-ui project, font variables from localFont (like --font-roboto-flex-bold) are applied to the <body> element in src/app/layout.tsx, not the <html> element. CSS custom properties are available throughout the DOM tree from the body level.
Applied to files:
src/styles/globals.css
📚 Learning: 2025-08-20T08:09:24.667Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1111
File: src/styles/globals.css:0-0
Timestamp: 2025-08-20T08:09:24.667Z
Learning: In the peanut-ui project (src/app/layout.tsx), font variables from localFont (like --font-roboto-flex-bold) are applied to the <body> element's className, not the <html> element. All font variables including robotoFlexBold.variable are properly loaded on the body, making CSS custom properties available throughout the DOM tree.
Applied to files:
src/styles/globals.css
📚 Learning: 2025-05-21T18:52:22.958Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 870
File: src/styles/globals.css:18-18
Timestamp: 2025-05-21T18:52:22.958Z
Learning: In the peanut-ui project, using `-webkit-tap-highlight-color: none` fixed an issue with blue highlights appearing when tapping inputs on mobile devices, even though `none` is not a technically valid value for this CSS property according to specifications. The valid alternative would be `transparent`.
Applied to files:
src/styles/globals.css
🧬 Code graph analysis (2)
src/app/(setup)/layout.tsx (1)
src/hooks/usePullToRefresh.ts (1)
usePullToRefresh(18-46)
src/app/(mobile-ui)/layout.tsx (1)
src/hooks/usePullToRefresh.ts (1)
usePullToRefresh(18-46)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (5)
src/styles/globals.css (3)
5-15: Solid CSS approach to fix Android native pull-to-refresh.The
overscroll-behavior-y: nonerule (lines 11–15) is the correct CSS mitigation for Android Chromium's native pull-to-refresh behavior. Combined with the iOS-only pulltorefreshjs initialization (per PR description), this provides a consistent UX across platforms. The color-scheme refinement from forcing to nudging (line 8) is also appropriate—it prefers light mode for native controls without override.Minor edge-case note: If your app uses nested scrollable containers (e.g., modals, collapsible panels), verify that
overscroll-behavior-y: noneonhtml, bodydoesn't accidentally suppress intended scroll behavior in child contexts. (CSSoverscroll-behaviorrespects the cascade, so this should be safe, but worth a smoke test on Android.)
291-305: Keyframe expansions enhance shake animation smoothness.Adding intermediate keyframes (10%, 20%, 30%, etc.) to all four
perkShake*animations (Weak, Medium, Strong, Intense) provides smoother visual interpolation over the same animation duration. This is solid visual polish—the proportional transform offsets scale correctly per intensity level, and the granularity improves perceived quality without performance impact.Also applies to: 313-326, 335-348, 357-370
432-434: No functional change to input-text utility.Line 433 appears to be a formatting reflow only; the
@applydeclaration and all Tailwind classes remain unchanged. Keeping or reverting this formatting is a style choice for your team.src/hooks/usePullToRefresh.ts (1)
18-45: Well-structured hook with good defaults and cleanup.The hook implementation is clean and reusable with sensible defaults. The effect properly cleans up pull-to-refresh instances, the dependencies are correctly specified, and the instruction strings provide good user feedback.
src/app/(setup)/layout.tsx (1)
37-37: LGTM! Clean integration of pull-to-refresh.The default pull-to-refresh behavior (triggered when
window.scrollY === 0) is appropriate for the setup layout.
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/app/(mobile-ui)/layout.tsx(2 hunks)src/hooks/usePullToRefresh.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/app/(mobile-ui)/layout.tsx
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (4)
src/hooks/usePullToRefresh.ts (4)
1-3: LGTM!The imports are appropriate for implementing pull-to-refresh functionality with Next.js routing.
5-11: LGTM!The interface design is clean and provides good flexibility with sensible optional parameters.
18-27: LGTM!The hook signature, SSR guard, and default behavior are well-implemented:
- Proper SSR guard prevents server-side execution
- Default
shouldPullToRefreshcorrectly restricts PTR to the top of the page- Sensible option defaults
13-17: Let me verify the context around this CSS rule to ensure it applies globally:Now let me verify the selector context for this CSS rule:
CSS rule confirmed—no issues found. The comment is accurate.
The
overscroll-behavior-y: noneCSS rule inglobals.csscorrectly disables native pull-to-refresh and overscroll glow effects, preventing conflicts with the pulltorefreshjs library. The JSDoc comment accurately reflects this setup.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/app/(mobile-ui)/layout.tsx (1)
41-42: Good optimization pattern.Caching the DOM element reference avoids repeated
querySelectorcalls during pull-to-refresh gesture detection.Optional: Clarify the comment
The comment mentions "scroll events" but the callback is actually invoked during touch/pointer events when the library checks if a pull-to-refresh gesture should be allowed. Consider updating for precision:
- // cache the scrollable content element to avoid DOM queries on every scroll event + // cache the scrollable content element to avoid DOM queries during pull-to-refresh gesture detection
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/app/(mobile-ui)/layout.tsx(2 hunks)src/hooks/usePullToRefresh.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/hooks/usePullToRefresh.ts
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2025-07-24T10:57:15.315Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1000
File: src/components/og/ProfileCardOG.tsx:0-0
Timestamp: 2025-07-24T10:57:15.315Z
Learning: In `src/components/og/ProfileCardOG.tsx`, the scribble image should have an empty alt attribute (alt="") to prevent layout issues if the image fails to load. Since it's a decorative element positioned absolutely over the username text, showing alt text would interfere with the layout and username display.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2025-09-05T07:31:11.396Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2024-10-29T16:06:38.812Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2024-10-11T01:14:15.489Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 424
File: src/components/Global/TokenSelector/TokenSelector.tsx:197-211
Timestamp: 2024-10-11T01:14:15.489Z
Learning: In `src/components/Global/TokenSelector/TokenSelector.tsx`, when the calculation within functions like `byChainAndText` is not computationally expensive, it's acceptable to avoid using `useCallback` for memoization.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2024-10-24T12:40:15.006Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 478
File: src/components/Request/Create/Views/Initial.view.tsx:48-128
Timestamp: 2024-10-24T12:40:15.006Z
Learning: When `handleOnNext` is deliberately refactored to avoid dependencies that change, it's acceptable to have an empty dependency array in `useCallback`.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2024-10-24T12:36:40.508Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 478
File: src/components/Dashboard/useDashboard.tsx:134-134
Timestamp: 2024-10-24T12:36:40.508Z
Learning: In the file `src/components/Dashboard/useDashboard.tsx`, memoization of the `getTokenSymbol` function is not necessary because it is lightweight and does not involve complex computations or network calls.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2025-10-02T15:23:01.513Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2025-01-16T13:13:48.615Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 631
File: src/context/kernelClient.context.tsx:88-124
Timestamp: 2025-01-16T13:13:48.615Z
Learning: In React useEffect hooks, when there's an early return condition and async operations, it's correct to have cleanup functions in both the early return and the final return to ensure proper cleanup in all scenarios.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.
Applied to files:
src/app/(mobile-ui)/layout.tsx
📚 Learning: 2025-01-16T13:14:40.363Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 631
File: src/components/Create/Create.tsx:108-112
Timestamp: 2025-01-16T13:14:40.363Z
Learning: In the Peanut UI codebase, the `resetTokenContextProvider` function from `tokenSelectorContext` is a stable function reference that doesn't change, so it doesn't need to be included in useEffect dependencies.
Applied to files:
src/app/(mobile-ui)/layout.tsx
🧬 Code graph analysis (1)
src/app/(mobile-ui)/layout.tsx (1)
src/hooks/usePullToRefresh.ts (1)
usePullToRefresh(23-65)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (3)
src/app/(mobile-ui)/layout.tsx (3)
12-12: LGTM! Appropriate imports for the refactored pull-to-refresh implementation.The additions of
useCallback,useRef, and theusePullToRefreshhook are necessary for the new optimization strategy that memoizes the callback and caches DOM element references.Also applies to: 22-22
51-67: Excellent implementation of the memoized callback.The
shouldPullToRefreshcallback is properly memoized withuseCallbackand an empty dependency array (correct since it only accesses ref.current and globals). The lazy-loading pattern efficiently caches the DOM element on first use, and the fallback towindow.scrollYprovides robustness.This fully addresses the previous concern about re-initialization on every render.
69-70: Perfect integration - all previous concerns have been resolved.The refactoring to use the
usePullToRefreshhook successfully addresses all three concerns raised in previous reviews:
✅ Accessibility: The hook implementation provides proper instruction strings (
'Pull down to refresh','Release to refresh','Refreshing...') visible to users and screen readers.✅ Promise handling: The hook correctly returns a Promise from the
onRefreshcallback (wrappingrouter.refresh()inPromise.resolve()), ensuring pulltorefreshjs can properly manage the loading animation.✅ Memoization: The
shouldPullToRefreshcallback is now properly memoized withuseCallback, preventing unnecessary re-initialization of the pull-to-refresh mechanism.The implementation enables pull-to-refresh for both iOS and Android as intended, with optimized DOM access and stable callback references.
|
@coderabbitai review one final time in depth. |
🧩 Analysis chain🏁 Script executed: Length of output: 19872 @Hugo0: Excellent work! This is a significantly improved implementation that addresses all the concerns from my previous review. Here's my final in-depth analysis: ✅ All Critical Issues Resolved1. Native Android PTR Now Properly Disabledhtml, body {
/* disable native pull-to-refresh on mobile devices - we use custom implementation */
overscroll-behavior-y: none;
}Perfect! This CSS solution prevents Android's native pull-to-refresh using the recommended approach. 2. Unified Pull-to-Refresh Across PlatformsThe new 🎯 Implementation StrengthsHook Architecture// ✅ Excellent use of refs to prevent re-initialization
const shouldPullToRefreshRef = useRef(shouldPullToRefresh)
// ✅ Proper cleanup
return () => {
PullToRefresh.destroyAll()
}
// ✅ router.refresh() wrapped correctly for pulltorefreshjs
onRefresh: () => {
router.refresh()
return Promise.resolve()
}Smart Scroll DetectionThe mobile-ui layout has intelligent scroll detection: // ✅ Cached element ref to avoid repeated DOM queries
const scrollableContentRef = useRef<Element | null>(null)
// ✅ Checks actual scrollable content, not window
const shouldPullToRefresh = useCallback(() => {
if (!scrollableContentRef.current) {
scrollableContentRef.current = document.querySelector('#scrollable-content')
}
// only allow pull-to-refresh when at the very top
return scrollableContentRef.current?.scrollTop === 0
}, [])This is crucial because your layout has:
By checking Configuration Constantsconst DIST_THRESHOLD = 70 // minimum pull distance to trigger refresh
const DIST_MAX = 120 // maximum pull distance (visual limit)
const DIST_RELOAD = 80 // distance at which refresh is triggered when releasedWell-tuned values that should provide good UX. 📱 PWA EnhancementsManifest Updatedisplay_override: ['standalone']Good addition! This ensures the PWA displays in standalone mode on supporting browsers, hiding browser UI chrome. router.refresh() UsageAppropriate for your use case:
🔍 Minor Observations (Non-Issues)
✅ Verification ChecklistBased on the code review, this implementation should:
🎉 Final VerdictThis is production-ready code. The implementation is:
The PR successfully fixes the Android pull-to-refresh progress indicator issue by:
Recommendation: Approve and merge. 🚀 Suggested PR Title Update (optional, for clarity): 🧠 Learnings used✅ Actions performedReview triggered.
|
Uh oh!
There was an error while loading. Please reload this page.