Skip to content

feat: extra test txn step during signup to validate passkey and account setup#1490

Merged
jjramirezn merged 11 commits intopeanut-walletfrom
feat/test-txn-step
Nov 22, 2025
Merged

feat: extra test txn step during signup to validate passkey and account setup#1490
jjramirezn merged 11 commits intopeanut-walletfrom
feat/test-txn-step

Conversation

@kushagrasarathe
Copy link
Contributor

No description provided.

@vercel
Copy link

vercel bot commented Nov 18, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
peanut-wallet Ready Ready Preview Comment Nov 22, 2025 0:10am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 18, 2025

Walkthrough

Replaces email collection with a test-transaction signing step in setup, removes automatic peanut-wallet creation on Home, adds account-setup redirect and finalize hooks, adjusts auth/logout and kernel client cleanup, introduces passkey debug tooling, and adds test-transaction UI handling in transaction details.

Changes

Cohort / File(s) Summary
Setup flow core
src/components/Setup/Setup.consts.tsx, src/components/Setup/Setup.types.ts, src/components/Setup/Views/index.ts
Replaced collect-email step with sign-test-transaction: updated step IDs, titles/descriptions, component imports/exports, and ScreenId/ScreenProps types.
New setup UI & removed email UI
src/components/Setup/Views/SignTestTransaction.tsx, src/components/Setup/Views/CollectEmail.tsx, src/components/Setup/Views/SetupPasskey.tsx
Added SignTestTransaction component (new passkey test flow); removed CollectEmail; simplified SetupPasskey by removing post-signup/account-creation side effects.
Setup finish page
src/app/(setup)/setup/finish/page.tsx
Added FinishSetupPage that renders SignTestTransaction within SetupWrapper and Suspense fallback.
Home & layout changes (mobile-ui)
src/app/(mobile-ui)/home/page.tsx, src/app/(mobile-ui)/layout.tsx
Removed peanut-wallet auto-create side effect and related address/addAccount usage on Home; added useAccountSetupRedirect invocation in mobile layout to gate routes until account-setup check completes.
Account setup hooks
src/hooks/useAccountSetup.ts, src/hooks/useAccountSetupRedirect.ts
Added useAccountSetup (finalizeAccountSetup, processing/error state, redirect handling) and useAccountSetupRedirect (computes needsRedirect and triggers router push to /setup/finish).
Auth & kernel client changes
src/context/authContext.tsx, src/context/kernelClient.context.tsx
Auth logout flow: clear webAuthnKey, remove web-authn cookie, invalidate React Query caches, reset Redux setup/zerodev state, fetch user and redirect to /setup; KernelClientProvider now clears webAuthnKey and kernel clients when no userId.
Guest login removal
src/components/Global/GuestLoginCta/index.tsx
Removed GuestLoginCta component and its props/interface.
Passkey debug utilities
src/utils/passkeyDebug.ts, src/utils/index.ts
Added capturePasskeyDebugInfo(context: string) to collect and report passkey/device capabilities; exported via utils barrel.
Login hook docs
src/hooks/useLogin.tsx
Minor comment/documentation edits only.
Transaction details / test-transaction UI
src/components/TransactionDetails/transactionTransformer.ts, src/components/TransactionDetails/TransactionCard.tsx, src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx, src/components/TransactionDetails/TransactionDetailsReceipt.tsx
Detect 0-amount deposits as test transactions: return "Enjoy Peanut!" titles/memos, show Peanut logo and "Setup" label, swap right-side icons, and render PasskeyDocsLink in receipt for test transactions; adjust transformer return type name.
Misc exports
src/utils/index.ts
Re-exported passkey debug utilities (export * from './passkeyDebug').

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

  • Pay extra attention to:
    • src/context/authContext.tsx — logout ordering, cache invalidation, and Redux resets.
    • src/hooks/useAccountSetup.ts and src/hooks/useAccountSetupRedirect.ts — redirect logic and race conditions that could cause loops.
    • src/components/Setup/Views/SignTestTransaction.tsx — signing flow, promise handling, and error capture (Sentry, passkey debug).
    • Transaction details changes (transactionTransformer.ts, header/card/receipt) — detection correctness and UI branching edge cases.

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive No pull request description was provided by the author; the description field is empty. Add a description explaining the motivation, changes, and testing approach for this feature to help reviewers understand the context and scope.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: adding a test transaction step during signup to validate passkey and account setup, which aligns with the substantial modifications across multiple files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/test-txn-step

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (5)
src/components/Setup/Setup.consts.tsx (1)

5-5: SignTestTransaction step swap looks consistent; consider centralizing copy

Replacing the final collect-email step with sign-test-transaction and wiring SignTestTransaction here is consistent with the new finish-setup flow and the page at setup/finish/page.tsx. The title/description are aligned with that page, which is good, but it does introduce duplicate copy/config across files—consider centralizing these strings or reusing this step definition from the finish page (or vice versa) to keep them in sync.

Also applies to: 90-99

src/utils/passkeyDebug.ts (1)

7-64: Guard capturePasskeyDebugInfo for non-browser environments

capturePasskeyDebugInfo assumes window and navigator exist; it’s fine for the current call sites, but a future server-side or test usage would throw. A small early guard would make this more defensive:

 export const capturePasskeyDebugInfo = async (context: string) => {
-    try {
+    try {
+        if (typeof window === 'undefined' || typeof navigator === 'undefined') {
+            // Not in a browser context; nothing to capture
+            return null
+        }

This keeps behavior unchanged in the browser while avoiding accidental crashes elsewhere.

src/components/Setup/Views/SignTestTransaction.tsx (1)

25-55: User prefetch and existing-account redirect behavior looks good

The first effect proactively fetches the user when missing, and the second redirects straight to /home when a PEANUT_WALLET account already exists, which matches the “finish-only-if-incomplete” intent. Consider adding router to the dependency array of the second effect if your hooks lint rule is strict, but functionally this logic is sound as-is given router’s stable identity.

src/hooks/useAccountSetup.ts (2)

26-46: Consider adding race condition guard.

The finalizeAccountSetup function can be called multiple times concurrently (e.g., double-click, rapid navigation). While isProcessing is tracked, it's not checked within this function to prevent duplicate addAccount calls, which could create race conditions or duplicate accounts.

Add an early return guard:

 const finalizeAccountSetup = async (address: string) => {
     console.log('[useAccountSetup] Starting account finalization', { address, userId: user?.user.userId })

     if (!user) {
         console.error('[useAccountSetup] No user found')
         setError('User not found. Please refresh the page.')
         return false
     }
+
+    if (isProcessing) {
+        console.log('[useAccountSetup] Already processing, skipping duplicate call')
+        return false
+    }

     setIsProcessing(true)
     setError(null)

76-86: Minor inconsistency: optional chaining when user is already verified.

Line 82 uses user?.user.userId but the user's existence is already verified at line 29. While functionally safe, this creates an inconsistency in how user is accessed throughout the function.

For consistency, since user is guaranteed to exist here:

-            clearAuthState(user?.user.userId)
+            clearAuthState(user.user.userId)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9f310ea and 3b9618d.

📒 Files selected for processing (17)
  • src/app/(mobile-ui)/home/page.tsx (2 hunks)
  • src/app/(mobile-ui)/layout.tsx (3 hunks)
  • src/app/(setup)/setup/finish/page.tsx (1 hunks)
  • src/components/Global/GuestLoginCta/index.tsx (0 hunks)
  • src/components/Setup/Setup.consts.tsx (2 hunks)
  • src/components/Setup/Setup.types.ts (2 hunks)
  • src/components/Setup/Views/CollectEmail.tsx (0 hunks)
  • src/components/Setup/Views/SetupPasskey.tsx (1 hunks)
  • src/components/Setup/Views/SignTestTransaction.tsx (1 hunks)
  • src/components/Setup/Views/index.ts (1 hunks)
  • src/context/authContext.tsx (4 hunks)
  • src/context/kernelClient.context.tsx (1 hunks)
  • src/hooks/useAccountSetup.ts (1 hunks)
  • src/hooks/useAccountSetupRedirect.ts (1 hunks)
  • src/hooks/useLogin.tsx (2 hunks)
  • src/utils/index.ts (1 hunks)
  • src/utils/passkeyDebug.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • src/components/Setup/Views/CollectEmail.tsx
  • src/components/Global/GuestLoginCta/index.tsx
🧰 Additional context used
🧠 Learnings (30)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:279-279
Timestamp: 2025-08-14T08:02:26.705Z
Learning: For hotfixes in the peanut-ui codebase, prefer generic error messages over specific validation error details until the copy can be reviewed with the team, even when the validation functions return detailed error messages.
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 845
File: src/components/Request/link/views/Create.request.link.view.tsx:81-81
Timestamp: 2025-05-13T10:05:24.057Z
Learning: In the peanut-ui project, pages that handle request flows (like Create.request.link.view.tsx) are only accessible to logged-in users who will always have a username, making null checks for user?.user.username unnecessary in these contexts.
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.
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: 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/Setup/Views/SignTestTransaction.tsx
  • src/app/(mobile-ui)/layout.tsx
  • src/app/(setup)/setup/finish/page.tsx
  • src/components/Setup/Views/SetupPasskey.tsx
  • src/app/(mobile-ui)/home/page.tsx
  • src/components/Setup/Setup.consts.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/Setup/Views/SignTestTransaction.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/app/(mobile-ui)/layout.tsx
  • src/hooks/useAccountSetupRedirect.ts
  • src/hooks/useLogin.tsx
  • src/app/(mobile-ui)/home/page.tsx
📚 Learning: 2025-05-13T10:05:24.057Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 845
File: src/components/Request/link/views/Create.request.link.view.tsx:81-81
Timestamp: 2025-05-13T10:05:24.057Z
Learning: In the peanut-ui project, pages that handle request flows (like Create.request.link.view.tsx) are only accessible to logged-in users who will always have a username, making null checks for user?.user.username unnecessary in these contexts.

Applied to files:

  • src/app/(mobile-ui)/layout.tsx
  • src/hooks/useAccountSetupRedirect.ts
  • src/hooks/useLogin.tsx
  • src/app/(mobile-ui)/home/page.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/app/(mobile-ui)/layout.tsx
  • src/hooks/useLogin.tsx
  • src/app/(mobile-ui)/home/page.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
  • src/hooks/useLogin.tsx
  • src/app/(mobile-ui)/home/page.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/app/(mobile-ui)/layout.tsx
  • src/app/(setup)/setup/finish/page.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/app/(mobile-ui)/layout.tsx
  • src/app/(setup)/setup/finish/page.tsx
  • src/hooks/useLogin.tsx
  • src/app/(mobile-ui)/home/page.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
  • src/hooks/useAccountSetupRedirect.ts
  • src/hooks/useLogin.tsx
  • src/context/authContext.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/app/(mobile-ui)/layout.tsx
  • src/hooks/useAccountSetupRedirect.ts
  • src/hooks/useAccountSetup.ts
  • src/components/Setup/Views/SetupPasskey.tsx
  • src/hooks/useLogin.tsx
  • src/app/(mobile-ui)/home/page.tsx
📚 Learning: 2025-08-12T17:44:04.268Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1089
File: src/components/LandingPage/dropLink.tsx:35-42
Timestamp: 2025-08-12T17:44:04.268Z
Learning: In the Peanut UI project, opening the `/setup` route in a new tab from landing page CTAs is intentional design behavior to keep users on the marketing page while they start the setup process.

Applied to files:

  • src/app/(setup)/setup/finish/page.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/hooks/useAccountSetupRedirect.ts
  • src/hooks/useAccountSetup.ts
📚 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/hooks/useAccountSetup.ts
📚 Learning: 2025-01-16T13:13:09.158Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 631
File: src/context/kernelClient.context.tsx:34-69
Timestamp: 2025-01-16T13:13:09.158Z
Learning: Error handling through try-catch blocks in the `createKernelClient` function in `src/context/kernelClient.context.tsx` is not required as per the team's preference.

Applied to files:

  • src/context/kernelClient.context.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/context/kernelClient.context.tsx
  • src/context/authContext.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/context/kernelClient.context.tsx
  • src/app/(mobile-ui)/home/page.tsx
📚 Learning: 2025-01-13T17:45:04.539Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 623
File: src/context/walletContext/zeroDevContext.context.tsx:106-123
Timestamp: 2025-01-13T17:45:04.539Z
Learning: The promise chain for creating passkey validator and kernel client from webAuthnKey in ZeroDevContext is designed to be reliable and should not error, as the webAuthnKey is already validated before being stored in localStorage.

Applied to files:

  • src/context/kernelClient.context.tsx
  • src/components/Setup/Views/SetupPasskey.tsx
📚 Learning: 2025-01-13T17:36:31.764Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 623
File: src/context/walletContext/zeroDevContext.context.tsx:91-93
Timestamp: 2025-01-13T17:36:31.764Z
Learning: In the peanut-ui project, the webAuthnKey stored in localStorage only contains public data and is safe to store there. This is used in the ZeroDevContext for passkey validation.

Applied to files:

  • src/context/kernelClient.context.tsx
  • src/components/Setup/Views/SetupPasskey.tsx
  • src/utils/passkeyDebug.ts
📚 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/Setup/Views/SetupPasskey.tsx
  • src/app/(mobile-ui)/home/page.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/hooks/useLogin.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/hooks/useLogin.tsx
📚 Learning: 2025-09-29T18:34:33.596Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1251
File: src/components/Invites/JoinWaitlistPage.tsx:41-55
Timestamp: 2025-09-29T18:34:33.596Z
Learning: In the JoinWaitlistPage component, after successfully accepting an invite via invitesApi.acceptInvite(), calling fetchUser() is sufficient to update the user state and automatically display the app. No manual navigation to /home or other pages is required since the user is already on the home page and the app will be displayed once user.hasAppAccess is updated.

Applied to files:

  • src/hooks/useLogin.tsx
📚 Learning: 2025-07-07T20:22:11.092Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 958
File: src/app/actions/tokens.ts:266-266
Timestamp: 2025-07-07T20:22:11.092Z
Learning: In `src/app/actions/tokens.ts`, within the `fetchWalletBalances` function, using the non-null assertion operator `!` on `process.env.MOBULA_API_KEY!` is intentional and correct, and should not be flagged for replacement with explicit validation.

Applied to files:

  • src/app/(mobile-ui)/home/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)/home/page.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/context/authContext.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/context/authContext.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/context/authContext.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/context/authContext.tsx
📚 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/context/authContext.tsx
🧬 Code graph analysis (8)
src/components/Setup/Views/SignTestTransaction.tsx (5)
src/hooks/useZeroDev.ts (1)
  • useZeroDev (50-231)
src/hooks/useAccountSetup.ts (1)
  • useAccountSetup (14-95)
src/redux/slices/setup-slice.ts (1)
  • setupActions (69-69)
src/constants/zerodev.consts.ts (2)
  • PEANUT_WALLET_TOKEN (20-20)
  • PEANUT_WALLET_CHAIN (18-18)
src/utils/passkeyDebug.ts (1)
  • capturePasskeyDebugInfo (7-64)
src/app/(mobile-ui)/layout.tsx (1)
src/hooks/useAccountSetupRedirect.ts (1)
  • useAccountSetupRedirect (11-35)
src/app/(setup)/setup/finish/page.tsx (2)
src/components/Setup/components/SetupWrapper.tsx (1)
  • SetupWrapper (168-255)
src/components/Global/PeanutLoading/index.tsx (1)
  • PeanutLoading (4-28)
src/hooks/useAccountSetupRedirect.ts (1)
src/context/authContext.tsx (1)
  • useAuth (227-233)
src/hooks/useAccountSetup.ts (4)
src/context/authContext.tsx (1)
  • useAuth (227-233)
src/utils/general.utils.ts (3)
  • getValidRedirectUrl (903-919)
  • getRedirectUrl (796-798)
  • clearRedirectUrl (800-804)
src/components/Global/PostSignupActionManager/post-signup-action.consts.ts (1)
  • POST_SIGNUP_ACTIONS (3-24)
src/utils/auth.utils.ts (1)
  • clearAuthState (13-33)
src/components/Setup/Views/SetupPasskey.tsx (2)
src/hooks/useZeroDev.ts (1)
  • useZeroDev (50-231)
src/utils/webauthn.utils.ts (2)
  • withWebAuthnRetry (34-95)
  • getWebAuthnErrorMessage (149-172)
src/app/(mobile-ui)/home/page.tsx (2)
src/hooks/wallet/useWallet.ts (1)
  • useWallet (15-101)
src/context/authContext.tsx (1)
  • useAuth (227-233)
src/context/authContext.tsx (2)
src/utils/general.utils.ts (3)
  • updateUserPreferences (471-490)
  • removeFromCookie (189-199)
  • clearRedirectUrl (800-804)
src/redux/slices/setup-slice.ts (1)
  • setupActions (69-69)
⏰ 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 (22)
src/context/kernelClient.context.tsx (1)

166-172: LGTM! Proper cleanup on logout.

The early-exit logic correctly resets kernel-related state when no user is present, ensuring webAuthnKey and kernel clients are cleared before any subsequent logic runs. This aligns well with the broader logout flow enhancements in this PR.

src/hooks/useLogin.tsx (2)

16-16: LGTM! Helpful documentation addition.

The comment clarifies that the mobile-ui layout now handles redirecting users without PEANUT_WALLET accounts to /setup/finish, which aligns with the new account setup flow introduced in this PR.


32-36: LGTM! Comment improvements.

The capitalization fixes and inline comment improve code readability without changing behavior.

src/app/(mobile-ui)/home/page.tsx (2)

53-53: LGTM! Removal aligns with new account setup flow.

The removal of address from the useWallet hook is appropriate since the auto-account-creation logic has been moved to the dedicated setup flow (via useAccountSetupRedirect).


66-66: LGTM! Simplified auth usage.

The removal of addAccount aligns with moving account creation out of the home page and into the dedicated setup flow.

src/hooks/useAccountSetupRedirect.ts (2)

17-22: LGTM! Well-structured redirect logic.

The memoized needsRedirect computation correctly checks for:

  1. User presence and fetch completion
  2. Current path to prevent redirect loops on /setup/finish
  3. PEANUT_WALLET account presence

The logic ensures users without a completed account setup are consistently redirected to finish the process.


25-32: LGTM! Proper redirect side effect.

The useEffect correctly performs the redirect only when needsRedirect becomes true, with appropriate logging and dependencies.

src/components/Setup/Views/index.ts (1)

3-3: LGTM! Export update aligns with setup flow refactor.

The export change from CollectEmail to SignTestTransaction is consistent with the broader refactor replacing email collection with test transaction signing in the account setup flow.

src/utils/index.ts (1)

11-11: LGTM! Consistent barrel export pattern.

Re-exporting the passkeyDebug module follows the established pattern and makes debugging utilities available alongside other utils.

src/app/(mobile-ui)/layout.tsx (3)

25-25: LGTM! New hook import for account setup gating.

The import of useAccountSetupRedirect enables the layout to gate protected paths until account setup is complete.


84-85: LGTM! Clear documentation of redirect behavior.

The comment and hook invocation clearly establish that logged-in users without a peanut wallet account will be redirected to complete setup.


104-105: LGTM! Comprehensive loading gate.

The extended loading condition now properly waits for account setup completion (via needsRedirect and isCheckingAccount) in addition to existing auth checks, ensuring users complete the setup flow before accessing protected content.

src/components/Setup/Setup.types.ts (2)

14-14: LGTM! Type update aligns with flow refactor.

The ScreenId change from 'collect-email' to 'sign-test-transaction' reflects the replacement of the CollectEmail component with SignTestTransaction.


34-34: LGTM! Consistent type mapping.

The ScreenProps update maintains type consistency with the renamed screen identifier.

src/app/(setup)/setup/finish/page.tsx (2)

15-26: FinishSetupPageContent configuration looks correct

SetupWrapper is correctly wired for the sign-test-transaction step (layout, image, copy, no back/skip), and embedding SignTestTransaction directly keeps the flow simple and focused on the passkey check.


30-35: Suspense fallback choice is appropriate

Wrapping the content in <Suspense> with a full-screen PeanutLoading fallback is a good fit here, ensuring a clean loading experience if any child starts suspending.

src/context/authContext.tsx (1)

5-8: Logout flow cleanup is thorough and correctly ordered

The enhanced logoutUser flow looks solid: you only proceed after a successful API logout, then clear WebAuthn preferences, cookies (including the dedicated WebAuthn cookie and JWT), redirect URL, invalidate React Query caches, reset both setup and zerodev redux state, clear user-specific caches, sessionStorage flags, and Crisp sessions before refetching the user and navigating to /setup. The guards around window, sessionStorage, and caches help avoid client-only API issues, and the existing try/catch around the whole block preserves robustness.

Also applies to: 57-62, 128-196

src/components/Setup/Views/SignTestTransaction.tsx (2)

122-143: Error path resets state correctly and surfaces a generic support message

On failure, you reset both local (isSigning) and global (setupActions.setLoading(false)) loading flags, capture additional debug info, and show a generic “contact support” error, which is appropriate for a passkey-related hotfix. The flow avoids leaving the UI stuck in a loading state and provides enough guidance without exposing internal error details.


146-179: Loading/disabled state and UI rendering are coherent

isLoading aggregates signing, account-setup processing, and user-fetching, and isDisabled additionally guards on !user, which prevents premature interaction while state is resolving. Reusing isFetchingUser ? 'Loading...' : 'Sign test transaction' keeps the CTA clear, and wiring displayError into a bold error line plus the Passkeys docs link is a good balance of guidance and escape hatch.

src/components/Setup/Views/SetupPasskey.tsx (2)

23-28: LGTM: Simplified post-registration flow.

The effect now cleanly moves to the next step once the address is available, removing complex redirect side effects. The dependency array correctly includes both address and handleNext.


40-60: Improved error handling with WebAuthn retry wrapper.

The error handling appropriately distinguishes between:

  • WebAuthn errors (user-cancelable, no state clearing needed)
  • Backend/network errors (clears auth state to prevent partial state corruption)

The use of withWebAuthnRetry for transient errors (NotReadableError, etc.) is a good pattern for the passkey registration issue mentioned in the PR title.

src/hooks/useAccountSetup.ts (1)

44-44: Potential runtime error: telegramHandle null/undefined check missing.

If telegramHandle is null or undefined, accessing .length will throw a TypeError and crash the account setup flow.

Apply this diff to add a safe check:

-                telegramHandle: telegramHandle.length > 0 ? telegramHandle : undefined,
+                telegramHandle: telegramHandle && telegramHandle.length > 0 ? telegramHandle : undefined,
⛔ Skipped due to learnings
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.
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.
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.
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-04T13:10:49.199Z
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.
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.

@kushagrasarathe
Copy link
Contributor Author

@coderabbitai review in depth.

Evaluate:

  • risk of introducing new bugs and breaking existing functionality
  • performance impact and latency
  • code quality and DRY

Also, write a very concise testing guide for QA

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 18, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch the PR diff to examine the actual changes
gh pr diff 1490 --repo peanutprotocol/peanut-ui > pr_diff.txt
head -n 500 pr_diff.txt

Length of output: 21138


🏁 Script executed:

#!/bin/bash
# Get the full list of changed files
gh pr view 1490 --repo peanutprotocol/peanut-ui --json files --jq '.files[].path'

Length of output: 877


🏁 Script executed:

#!/bin/bash
# Examine key new files: SignTestTransaction component
cat src/components/Setup/Views/SignTestTransaction.tsx

Length of output: 8036


🏁 Script executed:

#!/bin/bash
# Examine the new useAccountSetup hook
cat src/hooks/useAccountSetup.ts

Length of output: 3750


🏁 Script executed:

#!/bin/bash
# Examine the new useAccountSetupRedirect hook
cat src/hooks/useAccountSetupRedirect.ts

Length of output: 1351


🏁 Script executed:

#!/bin/bash
# Examine the passkey debug utility
cat src/utils/passkeyDebug.ts

Length of output: 2383


🏁 Script executed:

#!/bin/bash
# Check the modified layout file
cat src/app/\(mobile-ui\)/layout.tsx

Length of output: 7451


🏁 Script executed:

#!/bin/bash
# Check the modified home page
cat src/app/\(mobile-ui\)/home/page.tsx

Length of output: 18968


🏁 Script executed:

#!/bin/bash
# Check the modified auth context
cat src/context/authContext.tsx | head -n 300

Length of output: 8200


🏁 Script executed:

#!/bin/bash
# Check remaining part of auth context
cat src/context/authContext.tsx | tail -n 200

Length of output: 6960


🏁 Script executed:

#!/bin/bash
# Check the new finish setup page
cat src/app/\(setup\)/setup/finish/page.tsx

Length of output: 1281


🏁 Script executed:

#!/bin/bash
# Check setup constants for flow changes
cat src/components/Setup/Setup.consts.tsx

Length of output: 4149


@kushagrasarathe I've completed an in-depth review of PR #1490. Here's my analysis:

🔴 Risk Assessment: HIGH-MEDIUM

Critical Risks - Breaking Functionality

1. Race Condition in SignTestTransaction (Bug)

// Line 59-63 - Missing 'router' in dependency array
useEffect(() => {
    if (accountExists) {
        console.log('[SignTestTransaction] Account exists, redirecting to home')
        router.push('/home')
    }
}, [accountExists]) // ❌ Should include 'router'

2. Account Creation Failure Recovery Gap
The test transaction can succeed but account creation can fail, leaving users in an unrecoverable state:

// SignTestTransaction.tsx:110-118
const success = await finalizeAccountSetup(address)
if (!success) {
    // User is stuck - passkey works, but no account in DB
    // Redux loading state is cleared but no retry mechanism
    setError(setupError || 'Failed to complete account setup...')
    return
}

Recommendation: Add retry logic or allow users to retry the account creation step without re-signing.

3. Potential Redirect Loop

  • useAccountSetupRedirect (layout) checks if user has no peanut wallet → redirects to /setup/finish
  • /setup/finish renders SignTestTransaction which checks if account exists → redirects to /home
  • If somehow account exists but user lands on /setup/finish, the flow is unclear
  • Missing path guard: pathName === '/setup/finish' in useAccountSetupRedirect prevents infinite loop, but logic is fragile

4. Removed Legacy Account Auto-Creation

// Deleted from home/page.tsx:109-120
// This was fixing accounts for users who had incomplete signups
if (address && user && !user.accounts.some((a) => a.type === AccountType.PEANUT_WALLET)) {
    addAccount({...})
}

Impact: Users with incomplete accounts from previous bugs won't be auto-fixed anymore. Consider adding a one-time migration or keeping this as a safety net.

5. Production Debug Log

// HomeHistory.tsx:98
console.log('combinedEntries', combinedEntries) // ❌ Remove before merge

Medium Risks

6. User Fetch Without Error Boundary

// SignTestTransaction.tsx:34-37
if (!user && !isFetchingUser) {
    fetchUser() // No error handling if this fails
}

7. Multiple User Fetch Calls

  • SignTestTransaction fetches user on mount
  • useAccountSetupRedirect depends on user state
  • Could cause redundant API calls during signup flow

8. Complex State Management
Loading states spread across: isSigning, isProcessing, isFetchingUser, dispatch(setupActions.setLoading()). This makes it hard to track the actual loading state.

⚡ Performance Impact: LOW-MEDIUM

Additions

  • Test Transaction: Adds 1 blockchain call (~2-5s) during signup - acceptable trade-off for verifying passkey functionality
  • PasskeyDebugInfo: Runs only on errors, minimal overhead
  • Redirect Check: Runs on every protected route render in layout - negligible (simple memo check)

Concerns

  • Multiple fetchUser() calls could create redundant network requests
  • No debouncing or request deduplication visible in the code

Recommendation: Ensure React Query (already in use) has proper cache/deduplication settings.

🧹 Code Quality: MEDIUM (DRY Violations)

DRY Violations

1. Account Existence Check Duplicated

// SignTestTransaction.tsx:53
const accountExists = user?.accounts.some((a) => a.type === AccountType.PEANUT_WALLET)

// useAccountSetupRedirect.ts:17
const hasPeanutWalletAccount = user.accounts.some((a) => a.type === AccountType.PEANUT_WALLET)

Fix: Create a helper function hasPeanutWalletAccount(user) in utils.

2. Redirect Logic Scattered
Redirect logic appears in 3 places:

  • useAccountSetup (58-76)
  • SetupPasskey (removed but similar pattern)
  • useLogin hook

Consider consolidating into a single usePostAuthRedirect hook.

3. Loading State Management
Multiple boolean flags for loading (isSigning, isProcessing, isFetchingUser) could be unified into a state machine or single enum.

Positive Patterns

✅ Good separation of concerns with useAccountSetup hook
✅ Comprehensive logging for debugging
✅ Proper error capture with Sentry
✅ Clear comments explaining flow logic

🧪 Concise QA Testing Guide

Test Scenarios

1. New User Signup (Happy Path)

  1. Navigate to /setup
  2. Enter invite code → Enter username → Setup passkey → Sign test transaction
  3. Verify: Redirected to /home with account created
  4. Check: User can send/receive money immediately

2. Returning User Login (Happy Path)

  1. Already have account → Login with passkey
  2. Verify: Goes directly to /home (no test transaction)

3. Incomplete Signup Recovery

  1. User registered passkey but closed browser before test transaction
  2. Login again
  3. Verify: Redirected to /setup/finish → Complete test transaction → Go to /home

4. Test Transaction Failure

  1. Go through signup until test transaction step
  2. Reject the passkey prompt
  3. Verify: Error message shown, can retry
  4. Verify: No account created in DB until successful signature

5. Network Failure During Account Creation

  1. Sign test transaction successfully
  2. Simulate network failure (DevTools offline)
  3. Verify: Error message, auth state cleared, can start over
  4. Critical: User should not be stuck in limbo

6. Redirect URL Handling

  1. Access /send?redirect_uri=/send
  2. Complete signup
  3. Verify: Redirected back to /send after completion

7. Legacy User Without Account (Regression)

  1. Find user who somehow has no PEANUT_WALLET account
  2. Login
  3. Verify: Gets redirected to /setup/finish or handled gracefully

8. Concurrent Sessions

  1. Open two tabs, start signup in both
  2. Complete in one tab
  3. Verify: Other tab handles state correctly (redirects or errors gracefully)

Device-Specific Tests

  • iOS Safari: PWA install → Passkey → Test transaction
  • Android Chrome: PWA install → Passkey → Test transaction
  • Desktop: All flows work without PWA
  • Devices without passkey support: Should show unsupported browser screen

Performance Checks

  • Test transaction completes within 10 seconds
  • No visible lag during redirects
  • No infinite redirect loops (watch network tab)

Recommendations

  1. Add missing dependency: Include router in useEffect dependency array (SignTestTransaction:63)
  2. Remove debug log: Delete console.log('combinedEntries', combinedEntries) from HomeHistory.tsx
  3. Add retry mechanism: Allow users to retry account creation if test transaction succeeds but DB write fails
  4. Consider keeping legacy fix: The removed auto-account-creation in home/page.tsx was a safety net
  5. Consolidate DRY violations: Extract hasPeanutWalletAccount helper
  6. Add error boundary: Wrap user fetch with try-catch in SignTestTransaction
  7. Document migration plan: How to handle users mid-signup when this deploys?

This is a substantial refactoring with good intent (verifying passkey functionality), but needs careful testing of edge cases, especially around the account creation timing and redirect logic.


🧠 Learnings used
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 852
File: src/hooks/useTransactionHistory.ts:177-239
Timestamp: 2025-05-14T21:16:06.369Z
Learning: When reviewing code, pay attention to and resolve CodeRabbit comments as they can contain useful refactoring suggestions and insights.

Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 594
File: src/components/Request/Pay/Views/Initial.view.tsx:188-213
Timestamp: 2024-12-31T15:08:15.640Z
Learning: Always resolve coderabbit comments when reviewing code, since they can contain useful suggestions.

Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:279-279
Timestamp: 2025-08-14T08:02:26.705Z
Learning: For hotfixes in the peanut-ui codebase, prefer generic error messages over specific validation error details until the copy can be reviewed with the team, even when the validation functions return detailed error messages.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/components/Setup/Views/SignTestTransaction.tsx (1)

102-122: Let finalizeAccountSetup own navigation (avoid double redirect)

After a successful finalizeAccountSetup(address), this component unconditionally calls router.push('/home'). finalizeAccountSetup already handles routing (including redirect_uri and stored redirect URLs), so this extra push can cause double navigation and override custom redirects.

Recommended change: remove the explicit router.push('/home') in the !accountExists branch and just keep the failure handling:

-            if (!accountExists) {
-                console.log('[SignTestTransaction] Finalizing account setup')
-                const success = await finalizeAccountSetup(address)
-                if (!success) {
-                    console.error('[SignTestTransaction] Failed to finalize account setup')
-                    setError(setupError || 'Failed to complete account setup. Please try again.')
-                    setIsSigning(false)
-                    dispatch(setupActions.setLoading(false))
-                    return
-                }
-                // account added successfully, redirect to home
-                console.log('[SignTestTransaction] Account setup complete, redirecting to home')
-                router.push('/home')
-                // keep loading state active until redirect completes
-            } else {
+            if (!accountExists) {
+                console.log('[SignTestTransaction] Finalizing account setup')
+                const success = await finalizeAccountSetup(address)
+                if (!success) {
+                    console.error('[SignTestTransaction] Failed to finalize account setup')
+                    setError(setupError || 'Failed to complete account setup. Please try again.')
+                    setIsSigning(false)
+                    dispatch(setupActions.setLoading(false))
+                    return
+                }
+                console.log('[SignTestTransaction] Account setup complete')
+                // Navigation is handled inside finalizeAccountSetup
+            } else {

Keep the existing router.push('/home') in the accountExists branch if login flow should still redirect directly.

🧹 Nitpick comments (5)
src/components/Home/HomeHistory.tsx (1)

98-99: Consider removing debug console.log before merging.

This debugging statement should be removed before the code reaches production, or replaced with a proper conditional logging mechanism if debugging output is needed long-term.

-    console.log('combinedEntries', combinedEntries)
-
src/components/TransactionDetails/transactionTransformer.ts (1)

495-515: Consider normalizing usdAmount when detecting test deposits

isTestDeposit currently checks entry.extraData?.usdAmount === '0', while the actual amount parsing below uses a normalized string (String(...).replace(/[^\d.-]/g, '')parseFloat). If the backend ever sends '0.00' or '0 USD', the amount would be 0 but isTestDeposit would be false, and the special memo would not show.

You could align detection with parsing, e.g.:

-    const isTestDeposit =
-        entry.type === EHistoryEntryType.DEPOSIT && (String(entry.amount) === '0' || entry.extraData?.usdAmount === '0')
+    const normalizedUsdAmount =
+        entry.extraData?.usdAmount !== undefined
+            ? parseFloat(String(entry.extraData.usdAmount).replace(/[^\d.-]/g, ''))
+            : undefined
+
+    const isTestDeposit =
+        entry.type === EHistoryEntryType.DEPOSIT &&
+        (String(entry.amount) === '0' || normalizedUsdAmount === 0)

and reuse normalizedUsdAmount when computing amount to avoid double parsing.

src/components/TransactionDetails/TransactionDetailsReceipt.tsx (1)

66-66: Nice contextualization of support vs passkey docs for test transactions

The conditional transaction.userName === 'Enjoy Peanut!' cleanly swaps the generic support CTA for PasskeyDocsLink, matching the test‑deposit naming used in the transformer, and the class overrides (border-t-0 pt-0) work correctly with twMerge.

To reduce future copy‑drift, consider extracting 'Enjoy Peanut!' into a shared constant used by the transformer, card, header, and receipt.

Also applies to: 1388-1399

src/components/TransactionDetails/TransactionCard.tsx (1)

24-25: Test‑transaction card UX looks good; consider consolidating constants/imports

The card correctly special‑cases test transactions:

  • Uses PEANUTMAN_LOGO instead of user avatar/perk icon.
  • Suppresses the usual action icon and shows "Setup" as the label.
  • Leaves the amount/sign logic unchanged, so the row still conveys value.

Two minor follow‑ups:

  • The "Enjoy Peanut!" check is duplicated across multiple components; a shared TEST_TRANSACTION_NAME constant would make later copy changes safer.
  • PEANUTMAN_LOGO is imported from '@/assets/peanut' here but from '@/assets' in TransactionDetailsHeaderCard.tsx. It’s worth double‑checking that both exports exist and, if possible, standardizing on a single import path for consistency.

Also applies to: 92-116, 131-141, 180-183, 201-212

src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx (1)

16-17: Test‑transaction header branch is coherent; unify detection and avoid scattered magic strings

The header card now:

  • Detects test transactions via userName === 'Enjoy Peanut!'.
  • Suppresses direction icons via the isTestTransaction flag in getIcon.
  • Renders a compact header with PEANUTMAN_LOGO and “Enjoy Peanut!” instead of the usual avatar/title/status/amount block.

For this temporary side fix, that’s a reasonable UX, and it lines up with the card/receipt behavior.

A few small improvements you might queue up:

  • Detection of test transactions ('Enjoy Peanut!') is repeated here and also inside getTitle and other components. Consider a shared isTestTransaction helper or TEST_TRANSACTION_NAME constant to keep it in one place.
  • Since getTitle already computes an isTestTransaction boolean, you could pass a flag down from the component instead of recomputing based on displayName, which would simplify reasoning and avoid divergence if the naming ever changes.
  • If product/design later wants the amount or status visible for the test transaction header, it will be easy to reuse the existing non‑test branch markup with a conditional instead of a separate minimal block. For now, the current simplification is fine.

Also applies to: 52-84, 117-123, 152-180, 205-287

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3b9618d and dcf5421.

📒 Files selected for processing (6)
  • src/components/Home/HomeHistory.tsx (1 hunks)
  • src/components/Setup/Views/SignTestTransaction.tsx (1 hunks)
  • src/components/TransactionDetails/TransactionCard.tsx (4 hunks)
  • src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx (6 hunks)
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx (2 hunks)
  • src/components/TransactionDetails/transactionTransformer.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (17)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:279-279
Timestamp: 2025-08-14T08:02:26.705Z
Learning: For hotfixes in the peanut-ui codebase, prefer generic error messages over specific validation error details until the copy can be reviewed with the team, even when the validation functions return detailed error messages.
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1089
File: src/components/LandingPage/dropLink.tsx:35-42
Timestamp: 2025-08-12T17:44:04.268Z
Learning: In the Peanut UI project, opening the `/setup` route in a new tab from landing page CTAs is intentional design behavior to keep users on the marketing page while they start the setup process.
📚 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/TransactionDetails/TransactionDetailsReceipt.tsx
  • src/components/Setup/Views/SignTestTransaction.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/TransactionDetails/TransactionDetailsReceipt.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/TransactionDetails/TransactionDetailsHeaderCard.tsx
  • src/components/TransactionDetails/TransactionCard.tsx
  • src/components/Setup/Views/SignTestTransaction.tsx
📚 Learning: 2025-05-23T19:26:58.220Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 873
File: src/components/Withdraw/views/Initial.withdraw.view.tsx:95-95
Timestamp: 2025-05-23T19:26:58.220Z
Learning: The GeneralRecipientInput component supports username validation and resolution through the validateAndResolveRecipient function in src/lib/validation/recipient.ts. The function automatically detects usernames (inputs that don't contain '.' for ENS and don't start with '0x' for addresses), validates them via API HEAD request, fetches user data, and resolves them to Ethereum addresses from the user's PEANUT_WALLET account.

Applied to files:

  • src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx
📚 Learning: 2025-11-07T11:51:58.900Z
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.900Z
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/components/TransactionDetails/TransactionDetailsHeaderCard.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/TransactionDetails/TransactionDetailsHeaderCard.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/components/TransactionDetails/TransactionCard.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/TransactionDetails/TransactionCard.tsx
  • src/components/Setup/Views/SignTestTransaction.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/TransactionDetails/TransactionCard.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/TransactionDetails/TransactionCard.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/components/Setup/Views/SignTestTransaction.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/Setup/Views/SignTestTransaction.tsx
📚 Learning: 2025-08-12T17:44:04.268Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1089
File: src/components/LandingPage/dropLink.tsx:35-42
Timestamp: 2025-08-12T17:44:04.268Z
Learning: In the Peanut UI project, opening the `/setup` route in a new tab from landing page CTAs is intentional design behavior to keep users on the marketing page while they start the setup process.

Applied to files:

  • src/components/Setup/Views/SignTestTransaction.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/Setup/Views/SignTestTransaction.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/components/Home/HomeHistory.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
🧬 Code graph analysis (3)
src/components/TransactionDetails/TransactionDetailsReceipt.tsx (2)
src/components/Setup/Views/SignTestTransaction.tsx (1)
  • PasskeyDocsLink (183-196)
src/components/Global/Icons/Icon.tsx (1)
  • Icon (215-224)
src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx (2)
src/components/Global/Icons/Icon.tsx (2)
  • IconName (71-138)
  • Icon (215-224)
src/components/UserHeader/index.tsx (1)
  • VerifiedUserLabel (44-122)
src/components/Setup/Views/SignTestTransaction.tsx (6)
src/hooks/useZeroDev.ts (1)
  • useZeroDev (50-231)
src/hooks/useAccountSetup.ts (1)
  • useAccountSetup (14-95)
src/context/authContext.tsx (1)
  • useAuth (227-233)
src/redux/slices/setup-slice.ts (1)
  • setupActions (69-69)
src/constants/zerodev.consts.ts (2)
  • PEANUT_WALLET_TOKEN (20-20)
  • PEANUT_WALLET_CHAIN (18-18)
src/utils/passkeyDebug.ts (1)
  • capturePasskeyDebugInfo (7-64)
🪛 Biome (2.1.2)
src/components/TransactionDetails/transactionTransformer.ts

[error] 322-322: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

⏰ 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/Setup/Views/SignTestTransaction.tsx (1)

147-165: Test‑transaction flow + error surface look consistent

The loading flags (isSigning || isProcessing || isFetchingUser), disabled state, and combined displayError = error || setupError provide a clear UX, and the generic error copy is appropriate for this hotfix while detailed context is sent to Sentry/passkey debug.

Copy link
Contributor

@jjramirezn jjramirezn left a comment

Choose a reason for hiding this comment

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

Looks good, one question. Do not merge before testing in preview. Ideally with an user that is having issues

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/components/TransactionDetails/TransactionCard.tsx (3)

93-95: Avoid coupling test-transaction logic to a hard-coded display name

Using name === 'Enjoy Peanut!' to drive isTestTransaction is brittle (copy changes, localization, or backend naming tweaks will silently break this flow). The same flag is then used to override icon/text to "Setup".

Consider instead:

  • Deriving this from a dedicated field on transaction (e.g. transaction.extraDataForDrawer?.isTestTransaction), or
  • At least centralizing the magic string in a shared constant with a short comment explaining the contract with the backend.

This keeps the setup/test-transaction behavior robust to UI copy changes.

Also applies to: 181-184


132-142: Align avatar sizing for test transactions with other branches

In the test-transaction avatar branch, the wrapper uses size-7 while the inner image uses size-8, whereas other branches keep wrapper and image at size-8. This may cause subtle layout jitter or overflow compared to normal avatars.

If there’s no specific design requirement for a different size here, I’d align this branch with the others (same size-* on wrapper and image) for consistency.


191-202: Confirm UX: replacing amount block with InvitesIcon for test transactions

For isTestTransaction, the card hides the amount/currency block and shows only an InvitesIcon, even though displayAmount and currencyDisplayAmount are still computed and passed to the drawer.

If the product requirement is to avoid showing any monetary value for the setup/test transaction, this is fine; otherwise, you may want to:

  • Keep the amount visible alongside the InvitesIcon, or
  • Add a small label explaining that this is a setup check, not a real transfer.

Worth double-checking with design/PM so users don’t get confused by a transaction-like row with no visible amount.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dcf5421 and 6a926ad.

📒 Files selected for processing (2)
  • src/components/Setup/Views/SignTestTransaction.tsx (1 hunks)
  • src/components/TransactionDetails/TransactionCard.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/Setup/Views/SignTestTransaction.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 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/components/TransactionDetails/TransactionCard.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/components/TransactionDetails/TransactionCard.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 (1)
src/components/TransactionDetails/TransactionCard.tsx (1)

24-26: Nice addition of lazy loading + error boundary around the drawer

Importing LazyLoadErrorBoundary and wrapping the lazy TransactionDetailsDrawer with Suspense improves resilience to chunk-load failures without impacting the main list render.

Just ensure LazyLoadErrorBoundary has a user-friendly fallback for this context (e.g., silently failing to open the drawer vs. showing a generic error), but structurally this looks solid.

Also applies to: 207-217

@kushagrasarathe kushagrasarathe changed the title feat: temp side fix for passkey reg issue on some devices feat: extra test txn step during signup to validate passkey and account setup Nov 22, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/components/TransactionDetails/transactionTransformer.ts (1)

330-341: Wrap DEPOSIT case body in a block to fix noSwitchDeclarations

Declaring const isTestTransaction directly in the case EHistoryEntryType.DEPOSIT clause violates the noSwitchDeclarations rule and can leak the binding into other cases. Please wrap this case body in a block.

-        case EHistoryEntryType.DEPOSIT:
-            direction = 'add'
-            transactionCardType = 'add'
-            // check if this is a test transaction (0 amount deposit during account setup), ideally this should be handled in the backend, but for now we'll handle it here cuz its a quick fix, and in promisland of post devconnect this should be handled in the backend.
-            const isTestTransaction = String(entry.amount) === '0' || entry.extraData?.usdAmount === '0'
-            if (isTestTransaction) {
-                nameForDetails = 'Enjoy Peanut!'
-            } else {
-                nameForDetails = entry.senderAccount?.identifier || 'Deposit Source'
-            }
-            isPeerActuallyUser = false
-            break
+        case EHistoryEntryType.DEPOSIT: {
+            direction = 'add'
+            transactionCardType = 'add'
+            // check if this is a test transaction (0 amount deposit during account setup), ideally this should be handled in the backend, but for now we'll handle it here cuz its a quick fix, and in promisland of post devconnect this should be handled in the backend.
+            const isTestTransaction = String(entry.amount) === '0' || entry.extraData?.usdAmount === '0'
+            if (isTestTransaction) {
+                nameForDetails = 'Enjoy Peanut!'
+            } else {
+                nameForDetails = entry.senderAccount?.identifier || 'Deposit Source'
+            }
+            isPeerActuallyUser = false
+            break
+        }
🧹 Nitpick comments (3)
src/components/TransactionDetails/transactionTransformer.ts (1)

511-514: Centralize test‑deposit detection instead of re‑encoding the condition

isTestDeposit here repeats the same “amount/usdAmount is zero” condition already used in the DEPOSIT case (and related UI components infer test state from userName === 'Enjoy Peanut!'). This spreads the same business rule across multiple places and string literals.

Consider deriving a single isTestDeposit flag once in this mapper (based on amount/usdAmount), attaching it to transactionDetails (e.g., as extraDataForDrawer.isTestDeposit), and reusing that flag for:

  • Setting nameForDetails ('Enjoy Peanut!') in the DEPOSIT case.
  • Overriding memo here.
  • Driving the test‑transaction UI in TransactionCard and TransactionDetailsHeaderCard.

That will keep the behavior consistent if the underlying condition or display copy ever changes.

Also applies to: 532-532

src/components/TransactionDetails/TransactionCard.tsx (1)

25-26: Test‑transaction card UI is clear; avoid relying on the 'Enjoy Peanut!' magic string

The new test‑transaction branch (Peanut logo avatar, "Setup" label, and InvitesIcon on the right) looks consistent and doesn’t disturb existing paths. However, isTestTransaction is inferred via name === 'Enjoy Peanut!', and the same literal is used again in the header component; this is brittle if copy or localization changes.

Once you have a dedicated flag from the mapper (e.g., transaction.extraDataForDrawer.isTestDeposit), consider switching this check to that boolean (or at least centralizing the string in a shared constant) so card/header/test‑memo logic all stay in sync.

Also applies to: 95-97, 134-144, 183-186, 193-204

src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx (1)

16-16: Header test‑transaction UX works, but test detection should be centralized

The dedicated test‑transaction header (Peanut logo + “Enjoy Peanut!” title, no arrow icon) is a nice, clear treatment and getIcon correctly suppresses arrows for link or test transactions. However:

  • isTestTransaction is inferred twice: once inside getTitle via displayName === 'Enjoy Peanut!' and again in the component via userName === 'Enjoy Peanut!', while TransactionCard has its own name === 'Enjoy Peanut!' check.
  • That repeats the same magic string and slightly different inputs (displayName vs userName), and the TODO already notes this is a “bad check” temporary fix.

To reduce drift, consider driving all of this from a single boolean on the mapped transaction data (e.g., isTestDeposit) and optionally extracting a shared helper/constant for the label, so header, card, and memo behavior stay aligned when the backend or copy inevitably changes.

Also applies to: 83-86, 121-125, 154-182, 212-215, 226-295

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 892b7d2 and f220574.

📒 Files selected for processing (4)
  • src/components/TransactionDetails/TransactionCard.tsx (4 hunks)
  • src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx (6 hunks)
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx (2 hunks)
  • src/components/TransactionDetails/transactionTransformer.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx
🧰 Additional context used
🧠 Learnings (14)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1089
File: src/components/LandingPage/dropLink.tsx:35-42
Timestamp: 2025-08-12T17:44:04.268Z
Learning: In the Peanut UI project, opening the `/setup` route in a new tab from landing page CTAs is intentional design behavior to keep users on the marketing page while they start the setup process.
📚 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/TransactionDetails/TransactionCard.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/TransactionDetails/TransactionCard.tsx
  • src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx
📚 Learning: 2025-05-23T19:26:58.220Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 873
File: src/components/Withdraw/views/Initial.withdraw.view.tsx:95-95
Timestamp: 2025-05-23T19:26:58.220Z
Learning: The GeneralRecipientInput component supports username validation and resolution through the validateAndResolveRecipient function in src/lib/validation/recipient.ts. The function automatically detects usernames (inputs that don't contain '.' for ENS and don't start with '0x' for addresses), validates them via API HEAD request, fetches user data, and resolves them to Ethereum addresses from the user's PEANUT_WALLET account.

Applied to files:

  • src/components/TransactionDetails/TransactionCard.tsx
  • src/components/TransactionDetails/TransactionDetailsHeaderCard.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/components/TransactionDetails/TransactionCard.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/components/TransactionDetails/TransactionDetailsHeaderCard.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/TransactionDetails/TransactionDetailsHeaderCard.tsx
📚 Learning: 2025-11-07T11:51:58.900Z
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.900Z
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/components/TransactionDetails/TransactionDetailsHeaderCard.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/TransactionDetails/transactionTransformer.ts
📚 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/TransactionDetails/transactionTransformer.ts
📚 Learning: 2025-07-07T20:22:11.092Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 958
File: src/app/actions/tokens.ts:266-266
Timestamp: 2025-07-07T20:22:11.092Z
Learning: In `src/app/actions/tokens.ts`, within the `fetchWalletBalances` function, using the non-null assertion operator `!` on `process.env.MOBULA_API_KEY!` is intentional and correct, and should not be flagged for replacement with explicit validation.

Applied to files:

  • src/components/TransactionDetails/transactionTransformer.ts
📚 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/TransactionDetails/transactionTransformer.ts
📚 Learning: 2025-02-17T14:07:49.883Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 669
File: src/lib/validation/recipient.ts:21-56
Timestamp: 2025-02-17T14:07:49.883Z
Learning: In the peanut-ui repository, wrapping switch case blocks in braces to comply with linter rules and avoid variable leakage is considered a non-blocking style improvement.

Applied to files:

  • src/components/TransactionDetails/transactionTransformer.ts
📚 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/TransactionDetails/transactionTransformer.ts
🧬 Code graph analysis (1)
src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx (2)
src/components/Global/Icons/Icon.tsx (2)
  • IconName (71-138)
  • Icon (215-224)
src/components/UserHeader/index.tsx (1)
  • VerifiedUserLabel (46-124)
🪛 Biome (2.1.2)
src/components/TransactionDetails/transactionTransformer.ts

[error] 334-334: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

⏰ 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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/components/TransactionDetails/transactionTransformer.ts (1)

512-515: Consider centralizing test-deposit detection and normalizing usdAmount

You’re effectively detecting “test deposits” twice: once via isTestTransaction in the DEPOSIT branch and again via isTestDeposit here with the same condition. That can drift over time and makes behavior harder to reason about.

Two concrete tweaks to consider:

  • Compute a single const isTestDeposit = /* condition */ once (outside the switch or just above) and reuse it in both the DEPOSIT case (for nameForDetails) and here (for memo).
  • Instead of entry.extraData?.usdAmount === '0', normalize as you already do for amount, e.g. parseFloat(String(entry.extraData?.usdAmount ?? '').replace(/[^\d.-]/g, '')) === 0, so numeric 0 or "0.00" are also treated as test deposits.

This keeps the “test transaction” behavior consistent and more robust if the backend ever changes the formatting of usdAmount.

Also applies to: 533-533

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f220574 and d7dbb22.

📒 Files selected for processing (1)
  • src/components/TransactionDetails/transactionTransformer.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1089
File: src/components/LandingPage/dropLink.tsx:35-42
Timestamp: 2025-08-12T17:44:04.268Z
Learning: In the Peanut UI project, opening the `/setup` route in a new tab from landing page CTAs is intentional design behavior to keep users on the marketing page while they start the setup process.
📚 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/TransactionDetails/transactionTransformer.ts
📚 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/TransactionDetails/transactionTransformer.ts
📚 Learning: 2025-07-07T20:22:11.092Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 958
File: src/app/actions/tokens.ts:266-266
Timestamp: 2025-07-07T20:22:11.092Z
Learning: In `src/app/actions/tokens.ts`, within the `fetchWalletBalances` function, using the non-null assertion operator `!` on `process.env.MOBULA_API_KEY!` is intentional and correct, and should not be flagged for replacement with explicit validation.

Applied to files:

  • src/components/TransactionDetails/transactionTransformer.ts
📚 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/TransactionDetails/transactionTransformer.ts
📚 Learning: 2025-02-17T14:07:49.883Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 669
File: src/lib/validation/recipient.ts:21-56
Timestamp: 2025-02-17T14:07:49.883Z
Learning: In the peanut-ui repository, wrapping switch case blocks in braces to comply with linter rules and avoid variable leakage is considered a non-blocking style improvement.

Applied to files:

  • src/components/TransactionDetails/transactionTransformer.ts
📚 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/TransactionDetails/transactionTransformer.ts
⏰ 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/TransactionDetails/transactionTransformer.ts (1)

330-342: DEPOSIT case scoping and test-transaction label look correct

Wrapping the EHistoryEntryType.DEPOSIT case body in a block correctly scopes isTestTransaction and satisfies the noSwitchDeclarations rule, and the zero-amount check cleanly switches the label to "Enjoy Peanut!" without affecting non-test deposits.

@jjramirezn jjramirezn merged commit 68a395b into peanut-wallet Nov 22, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants