Skip to content

[TASK-16321] Fix/pots fixes#1368

Merged
Zishan-7 merged 14 commits intopeanut-wallet-devfrom
fix/pots-fixes
Oct 29, 2025
Merged

[TASK-16321] Fix/pots fixes#1368
Zishan-7 merged 14 commits intopeanut-wallet-devfrom
fix/pots-fixes

Conversation

@Zishan-7
Copy link
Contributor

No description provided.

@vercel
Copy link

vercel bot commented Oct 28, 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 Oct 29, 2025 4:18pm

@notion-workspace
Copy link

🪲 Request pots bugs

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 28, 2025

Walkthrough

Adds input-preserving decimal formatting and exposes it to token inputs; enhances TokenAmountInput with device-aware autofocus, decorative caret, and default-slider props; exposes a programmatic "Pay with Peanut" trigger in request fulfillment context and wires Peanut-balance modal/flow; adds extra-small PerkIcon size, tweaks Slider init semantics, and a Tailwind blink animation.

Changes

Cohort / File(s) Summary
Formatting util
src/utils/general.utils.ts
formatTokenAmount signature changed to `(amount?: number
TokenAmountInput
src/components/Global/TokenAmountInput/index.tsx
Adds client directive, device-aware shouldAutoFocus, local isFocused + fake blinking caret UI, onFocus/onBlur handlers, dynamic decimal enforcement via formatTokenAmount, new public props defaultSliderValue? and defaultSliderSuggestedAmount?, and wiring to prefill slider/suggested amount.
Slider
src/components/Global/Slider/index.tsx
Initialization now prefers `defaultValue
Payment flow / Context
src/components/Payment/PaymentForm/index.tsx, src/context/RequestFulfillmentFlowContext.tsx
Expose triggerPayWithPeanut and setTriggerPayWithPeanut in context; PaymentForm listens to trigger to initiate Peanut payments, adds default slider value calculation and request-pot wiring, and adjusts init guards/dep arrays.
ActionList / Peanut modal
src/components/Common/ActionList.tsx
Adds Peanut balance check, "Use Peanut balance" modal, blocks/redirects request flow to Peanut payment when balance sufficient, and uses setTriggerPayWithPeanut to start Peanut payment from modal.
Request link init
src/components/Request/link/views/Create.request.link.view.tsx
Removes raw numeric param checks; uses memoized sanitizedAmount = formatTokenAmount(paramsAmount, 2, true) and initializes token value/display from sanitized value.
Transaction details UI
src/components/TransactionDetails/PerkIcon.tsx, src/components/TransactionDetails/TransactionCard.tsx
Add extra-small to PerkIcon sizes and adjust avatar/icon classes across TransactionCard branches (smaller sizes, removal/commenting of some inline StatusPill renderings).
Tailwind config
tailwind.config.js
Adds blink keyframes and blink animation alias (1.5s step-end infinite) used by the decorative caret.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

  • Areas needing extra attention:
    • src/utils/general.utils.ts — new forInput path, regex/partial-input preservation, NaN and numeric-flooring behavior, and callers relying on old signature.
    • src/components/Global/TokenAmountInput/index.tsx — autofocus behavior across devices, accessibility, caret animation, and slider-prefill wiring.
    • RequestFulfillmentFlowContext + PaymentForm + ActionList — race conditions and side-effect ordering around triggerPayWithPeanut and modal flows.
    • src/components/Global/Slider/index.tsx — change in initialization/sync semantics.

Possibly related PRs

Suggested reviewers

  • jjramirezn
  • kushagrasarathe

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 2 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title "[TASK-16321] Fix/pots fixes" uses vague terminology that does not clearly convey the specific nature of the changes. While "pots" aligns with the branch name and may refer to the "request-pot" feature, the term "fixes" lacks clarity about what is actually being fixed or improved. The changeset contains substantial feature additions including Peanut payment flow enhancements, token input improvements with slider defaults, balance awareness integration, and various UI refinements—none of which are meaningfully captured by the generic "fixes" terminology. Consider revising the title to be more specific and descriptive of the primary changes, such as "Add request-pot payment flow with Peanut balance awareness and slider defaults" or "Implement request-pot features with trigger-based Peanut payment." This would provide reviewers and future maintainers with a clear understanding of the PR's purpose without requiring them to examine the changeset details.
Description Check ❓ Inconclusive No pull request description was provided by the author. The description field is empty, which means there is no textual content to evaluate for relevance to the changeset. While an empty description is not explicitly off-topic, it represents the most extreme form of vagueness, providing zero information about the PR's intent, scope, or context to potential reviewers. Add a pull request description that summarizes the key changes and objectives. Given the scope of changes across multiple components (TokenAmountInput, PaymentForm, ActionList, context providers, and utilities), a brief description explaining the request-pot payment feature, Peanut balance integration, and any other significant functionality would help reviewers understand the PR's purpose and impact.
✨ 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 fix/pots-fixes

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

@coderabbitai coderabbitai bot added the enhancement New feature or request label Oct 28, 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: 4

🧹 Nitpick comments (3)
tailwind.config.js (1)

190-193: Blink animation: simplify keyframes and honor reduced motion

  • Consider replacing the 50.01% hack with steps timing or tighter keyframes, and ensure usage is wrapped with motion-safe/motion-reduce to respect user settings. Example usage: motion-safe:animate-blink motion-reduce:animate-none.

Apply if preferred:

-                blink: {
-                    '0%, 50%': { opacity: '1' },
-                    '50.01%, 100%': { opacity: '0' },
-                },
+                blink: {
+                    '0%, 49.99%': { opacity: '1' },
+                    '50%, 100%': { opacity: '0' },
+                },
-                blink: 'blink 1.5s step-end infinite',
+                blink: 'blink 1.5s steps(1, end) infinite',

Also applies to: 201-201

src/components/Request/link/views/Create.request.link.view.tsx (1)

46-50: Lean on the sanitizer; drop parseFloat pre-check

sanitizeDecimalInput already returns '' for invalid input. This reduces branches and keeps inputs like '123.' intact.

-    const sanitizedAmount = useMemo(() => {
-        if (!paramsAmount || isNaN(parseFloat(paramsAmount))) return ''
-        return sanitizeDecimalInput(paramsAmount, 2)
-    }, [paramsAmount])
+    const sanitizedAmount = useMemo(
+        () => sanitizeDecimalInput(paramsAmount ?? '', 2),
+        [paramsAmount]
+    )
src/components/TransactionDetails/PerkIcon.tsx (1)

4-4: Added 'extra-small' size looks consistent

Config and typing align with existing sizes. Consider using existing .icon-16 utility for consistency, but current approach is fine.

Also applies to: 12-15

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef52c8e and 2e054fb.

📒 Files selected for processing (7)
  • src/components/Global/TokenAmountInput/index.tsx (3 hunks)
  • src/components/Payment/PaymentForm/index.tsx (2 hunks)
  • src/components/Request/link/views/Create.request.link.view.tsx (2 hunks)
  • src/components/TransactionDetails/PerkIcon.tsx (1 hunks)
  • src/components/TransactionDetails/TransactionCard.tsx (2 hunks)
  • src/utils/general.utils.ts (1 hunks)
  • tailwind.config.js (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📚 Learning: 2024-10-07T15:25:45.170Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.

Applied to files:

  • src/components/Request/link/views/Create.request.link.view.tsx
📚 Learning: 2024-10-07T15:28:25.280Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.

Applied to files:

  • src/components/Request/link/views/Create.request.link.view.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Global/TokenAmountInput/index.tsx:23-30
Timestamp: 2024-10-29T12:19:41.968Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), when the 'Max' button is clicked, we intentionally set the input denomination to 'TOKEN' because we are setting the value as token.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/Link/Input.view.tsx:244-248
Timestamp: 2024-10-29T12:20:47.207Z
Learning: In the `TokenAmountInput` component within `src/components/Global/TokenAmountInput/index.tsx`, when `balance` is undefined, the `maxValue` prop should be set to an empty string `''`.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2025-08-22T07:25:59.304Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:596-600
Timestamp: 2025-08-22T07:25:59.304Z
Learning: The `TokenAmountInput` component in `src/components/Global/TokenAmountInput/` always returns decimal strings (e.g., "1,234.56"), not base units. When passing these values to external APIs like Daimo's `toUnits` prop, simply stripping commas with `.replace(/,/g, '')` is sufficient.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#413
File: src/context/tokenSelector.context.tsx:118-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the `TokenContextProvider` component within `src/context/tokenSelector.context.tsx`, in the TypeScript React application, when data changes and before calling `fetchAndSetTokenPrice`, it is necessary to reset `selectedTokenData`, `selectedTokenPrice`, `selectedTokenDecimals`, and `inputDenomination` to discard stale data.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2025-01-16T13:14:40.363Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#631
File: src/components/Create/Create.tsx:108-112
Timestamp: 2025-01-16T13:14:40.363Z
Learning: In the Peanut UI codebase, the `resetTokenContextProvider` function from `tokenSelectorContext` is a stable function reference that doesn't change, so it doesn't need to be included in useEffect dependencies.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2025-10-24T13:44:39.443Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.443Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
🧬 Code graph analysis (3)
src/components/Request/link/views/Create.request.link.view.tsx (1)
src/utils/general.utils.ts (1)
  • sanitizeDecimalInput (395-400)
src/components/Global/TokenAmountInput/index.tsx (2)
src/hooks/useGetDeviceType.ts (1)
  • useDeviceType (37-42)
src/utils/general.utils.ts (2)
  • formatAmountWithoutComma (486-492)
  • sanitizeDecimalInput (395-400)
src/components/TransactionDetails/TransactionCard.tsx (1)
src/components/TransactionDetails/PerkIcon.tsx (1)
  • PerkIcon (34-44)
🪛 ast-grep (0.39.6)
src/utils/general.utils.ts

[warning] 396-396: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^\\d*\\.?\\d{0,${maxDecimals}})
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

⏰ 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 (7)
src/components/Payment/PaymentForm/index.tsx (2)

651-652: Header title logic simplification LGTM

Clearer defaulting to 'Add Money'/'Pay'; matches flow semantics.


795-806: Render Contributors only when non‑empty

Good UX and avoids empty sections. LGTM.

src/components/Request/link/views/Create.request.link.view.tsx (1)

22-22: No action required; utils barrel correctly re-exports sanitizeDecimalInput.

Verification confirms sanitizeDecimalInput is exported from src/utils/general.utils.ts (line 395) and re-exported by the barrel at src/utils/index.ts via wildcard export. The import from @/utils is valid and will not cause build breaks.

src/components/Global/TokenAmountInput/index.tsx (2)

3-3: Import of sanitizeDecimalInput looks good.

No issues with the new utility import.


280-282: No changes needed; animate-blink is properly configured.

The search results confirm that animate-blink is explicitly defined in tailwind.config.js (lines 190 and 201) with the animation rule 'blink 1.5s step-end infinite'. The code at lines 280-282 correctly uses this custom animation. The original review comment's concern was based on a false premise—the animation is already present in the Tailwind configuration.

Likely an incorrect or invalid review comment.

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

137-137: Badge size change to "extra-small" — LGTM.

Consistent with reduced avatar footprint; no prop API issues observed.

Please eyeball alignment in dense lists on small screens.


118-118: No issues found—PerkIcon properly supports size="extra-small".

The verification confirms that sizeConfig['extra-small'] is defined at line 12 with a valid configuration (container: 'h-8 w-8', icon: { width: 16, height: 16 }), and the type definition includes 'extra-small' as a valid size option. The code at line 118 is safe and will not throw at runtime.

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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/context/RequestFulfillmentFlowContext.tsx (1)

60-71: Missing reset for triggerPayWithPeanut in resetFlow

The resetFlow callback resets all other state but doesn't include setTriggerPayWithPeanut(false). This could leave the trigger in a stale true state if the flow is reset, potentially causing unintended payment initiation.

Add to resetFlow:

 const resetFlow = useCallback(() => {
     setExternalWalletFulfillMethod(null)
     setShowExternalWalletFulfillMethods(false)
     setFlowStep(null)
     setShowRequestFulfilmentBankFlowManager(false)
     setSelectedCountry(null)
     setOnrampData(null)
     setShowVerificationModal(false)
     setRequesterDetails(null)
     setFulfillUsingManteca(false)
     setRegionalMethodType('mercadopago')
+    setTriggerPayWithPeanut(false)
 }, [])
♻️ Duplicate comments (2)
src/utils/general.utils.ts (1)

390-405: [Duplicate] Refactor to avoid dynamic RegExp and preserve trailing dots

This concern was already raised in a previous review. The dynamic RegExp constructor is flagged by static analysis (ReDoS risk) and the function lacks explicit handling for trailing dots during real-time input (e.g., "1.""1.5").

src/components/Global/TokenAmountInput/index.tsx (1)

60-60: [Duplicate] Unguarded window access still present

Line 60 still contains unguarded window.innerWidth access that will crash during SSR. This was flagged in a previous review but not fully resolved by adding the 'use client' directive alone.

Apply this fix:

-    const inputType = useMemo(() => (window.innerWidth < 640 ? 'text' : 'number'), [])
+    const inputType = useMemo(
+        () => (typeof window !== 'undefined' && window.innerWidth < 640 ? 'text' : 'number'),
+        []
+    )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e054fb and 9064824.

📒 Files selected for processing (8)
  • src/components/Common/ActionList.tsx (7 hunks)
  • src/components/Global/Slider/index.tsx (1 hunks)
  • src/components/Global/TokenAmountInput/index.tsx (5 hunks)
  • src/components/Payment/PaymentForm/index.tsx (11 hunks)
  • src/components/Request/link/views/Create.request.link.view.tsx (2 hunks)
  • src/components/TransactionDetails/TransactionCard.tsx (2 hunks)
  • src/context/RequestFulfillmentFlowContext.tsx (4 hunks)
  • src/utils/general.utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/Request/link/views/Create.request.link.view.tsx
  • src/components/TransactionDetails/TransactionCard.tsx
🧰 Additional context used
🧠 Learnings (12)
📚 Learning: 2024-12-02T17:19:18.532Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#551
File: src/components/Request/Create/Views/Initial.view.tsx:151-156
Timestamp: 2024-12-02T17:19:18.532Z
Learning: In the `InitialView` component at `src/components/Request/Create/Views/Initial.view.tsx`, when setting the default chain and token in the `useEffect` triggered by `isPeanutWallet`, it's acceptable to omit the setters from the dependency array and not include additional error handling for invalid defaults.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-07T13:42:00.443Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-05-19T19:40:43.138Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#868
File: src/components/Payment/PaymentForm/index.tsx:284-293
Timestamp: 2025-05-19T19:40:43.138Z
Learning: When converting between USD and token amounts, always check if the token price (divisor) is valid and non-zero before performing the division to prevent Infinity, NaN, or errors. Implementing validation like `if (!tokenPrice || isNaN(tokenPrice) || tokenPrice === 0)` before division operations is crucial for handling cases where price data might be unavailable.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-07T15:50:29.173Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-07T15:50:29.173Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-10-24T13:44:39.473Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Global/TokenAmountInput/index.tsx:23-30
Timestamp: 2024-10-29T12:19:41.968Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), when the 'Max' button is clicked, we intentionally set the input denomination to 'TOKEN' because we are setting the value as token.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/Link/Input.view.tsx:244-248
Timestamp: 2024-10-29T12:20:47.207Z
Learning: In the `TokenAmountInput` component within `src/components/Global/TokenAmountInput/index.tsx`, when `balance` is undefined, the `maxValue` prop should be set to an empty string `''`.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2025-08-22T07:25:59.304Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:596-600
Timestamp: 2025-08-22T07:25:59.304Z
Learning: The `TokenAmountInput` component in `src/components/Global/TokenAmountInput/` always returns decimal strings (e.g., "1,234.56"), not base units. When passing these values to external APIs like Daimo's `toUnits` prop, simply stripping commas with `.replace(/,/g, '')` is sufficient.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-29T14:44:08.745Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Cashout/Components/Initial.view.tsx:194-198
Timestamp: 2024-10-29T14:44:08.745Z
Learning: Using a fixed 6 decimal places for `floorFixed` is acceptable for token amounts in this codebase, even if tokens have varying decimal places.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#413
File: src/context/tokenSelector.context.tsx:118-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the `TokenContextProvider` component within `src/context/tokenSelector.context.tsx`, in the TypeScript React application, when data changes and before calling `fetchAndSetTokenPrice`, it is necessary to reset `selectedTokenData`, `selectedTokenPrice`, `selectedTokenDecimals`, and `inputDenomination` to discard stale data.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
🧬 Code graph analysis (3)
src/components/Payment/PaymentForm/index.tsx (1)
src/utils/general.utils.ts (1)
  • sanitizeDecimalInput (400-405)
src/components/Common/ActionList.tsx (2)
src/hooks/wallet/useWallet.ts (1)
  • useWallet (15-101)
src/constants/actionlist.consts.ts (1)
  • PaymentMethod (5-12)
src/components/Global/TokenAmountInput/index.tsx (3)
src/context/tokenSelector.context.tsx (1)
  • tokenSelectorContext (19-38)
src/hooks/useGetDeviceType.ts (1)
  • useDeviceType (37-42)
src/utils/general.utils.ts (1)
  • sanitizeDecimalInput (400-405)
🪛 ast-grep (0.39.6)
src/utils/general.utils.ts

[warning] 401-401: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^\\d*\\.?\\d{0,${maxDecimals}})
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

⏰ 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 (11)
src/components/Global/TokenAmountInput/index.tsx (4)

1-1: Good addition of 'use client' directive

The directive correctly marks this as a Client Component, resolving part of the SSR concern raised in previous reviews.


61-64: Device-aware autofocus improves mobile UX

Smart implementation that prevents disruptive autofocus on mobile devices (iOS/Android) while maintaining desktop convenience. The useDeviceType hook provides a clean abstraction.


258-263: Proper decimal clamping based on display mode

The dynamic maxDecimals logic correctly addresses the previous review concern: 2 decimals for USD/fiat/stablecoins, and up to decimals (bounded to 6) for token amounts. This prevents truncating valid token inputs while maintaining currency precision.

Based on learnings and previous review feedback.


251-289: Fake caret implementation for visual continuity

The decorative blinking caret when input is unfocused and empty provides good visual feedback for users. The implementation correctly uses pointer-events-none and Tailwind's animate-blink utility.

src/components/Common/ActionList.tsx (3)

155-158: Peanut balance gating improves UX

Smart flow that prompts users with sufficient Peanut balance before allowing them to proceed with external payment methods. The isUsePeanutBalanceModalShown guard prevents repeated prompts.


237-256: Disable interaction correctly while modal shown

The pointerEvents: 'none' inline style effectively disables the Daimo pay button when the Peanut balance modal should be shown, preventing accidental bypasses. Good defensive UX pattern.


314-338: Clear modal messaging and CTA

The "Use your Peanut balance instead" modal provides clear value proposition (instant, no delays) and triggers the Peanut payment flow via setTriggerPayWithPeanut(true) on CTA click.

src/context/RequestFulfillmentFlowContext.tsx (1)

39-40: Clean context extension for programmatic payment trigger

The triggerPayWithPeanut flag enables components like ActionList to programmatically initiate Peanut payments. Type-safe addition to the context API.

src/components/Payment/PaymentForm/index.tsx (2)

601-607: Clean trigger-based Peanut payment initiation

The effect correctly responds to triggerPayWithPeanut from the context, initiates payment, and resets the trigger to prevent repeated execution. Simple and effective pattern for programmatic payment flows.


246-256: Proper gating for request pot initial view

The showRequestPotInitialView flag correctly bypasses balance checks, wallet connection requirements, and payment initiation during the initial pot contribution view. The returnAfterChargeCreation flag ensures charges are created without immediate payment execution.

Also applies to: 335-341, 471-471

src/components/Global/Slider/index.tsx (1)

18-18: Remove the external value synchronization break in Slider component

The removal of the useEffect that synced external controlledValue changes breaks TokenAmountInput, which relies on updating the Slider's displayed value when tokenValue changes. When a user modifies the token amount input, sliderValue recalculates via useMemo, but the Slider ignores this update because there's no mechanism to sync the new controlledValue to internalValue. This causes the Slider to display a stale position while the input value updates.

Restore the useEffect to watch controlledValue and update internalValue when external changes occur, or refactor TokenAmountInput to not pass a dynamic value prop if the Slider is truly meant to be uncontrolled.

⛔ Skipped due to learnings
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.

@Zishan-7 Zishan-7 marked this pull request as ready for review October 29, 2025 11:55
@notion-workspace
Copy link

🪲 Request pots bugs

1 similar comment
@notion-workspace
Copy link

🪲 Request pots bugs

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9064824 and ff66afe.

📒 Files selected for processing (2)
  • src/components/Global/TokenAmountInput/index.tsx (6 hunks)
  • src/components/Payment/PaymentForm/index.tsx (11 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/Global/TokenAmountInput/index.tsx
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.

Applied to files:

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

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-07T13:42:00.443Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-05-19T19:40:43.138Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#868
File: src/components/Payment/PaymentForm/index.tsx:284-293
Timestamp: 2025-05-19T19:40:43.138Z
Learning: When converting between USD and token amounts, always check if the token price (divisor) is valid and non-zero before performing the division to prevent Infinity, NaN, or errors. Implementing validation like `if (!tokenPrice || isNaN(tokenPrice) || tokenPrice === 0)` before division operations is crucial for handling cases where price data might be unavailable.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-07T15:50:29.173Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-07T15:50:29.173Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-10-24T13:44:39.473Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.

Applied to files:

  • src/components/Payment/PaymentForm/index.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 (9)
src/components/Payment/PaymentForm/index.tsx (9)

27-34: LGTM!

The import of sanitizeDecimalInput is clean and the utility integration aligns with the PR's goal of adding decimal sanitization.


98-99: LGTM!

The new triggerPayWithPeanut state properly exposes programmatic payment initiation capability from the context.


176-200: LGTM!

The guard logic correctly skips initial setup when showRequestPotInitialView is true, and the dependency array is properly updated.


308-319: LGTM!

The guard correctly bypasses USD value calculations for the request pot initial view, maintaining consistency with the specialized flow.


340-349: LGTM!

The dependency array correctly includes showRequestPotInitialView which is used within the memo logic.


722-722: LGTM!

The title change from "Send" to "Pay" better reflects the payment action in the non-external-wallet flow.


784-785: LGTM!

The computed slider defaults are correctly passed to TokenAmountInput, enabling pre-populated slider behavior for request pots.


868-879: LGTM!

The contributors section is properly gated and correctly maps contributor data with appropriate positioning and keys.


672-714: Side effect issue resolved and pre-population working correctly.

The TokenAmountInput component properly handles the defaultSliderSuggestedAmount prop through a useEffect that sets both tokenValue and displayValue when the prop changes. The useMemo is now pure, follows React best practices, and the suggested amount correctly pre-fills the input field.

…andleInitiatePayment and setTriggerPayWithPeanut
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/Payment/PaymentForm/index.tsx (1)

672-714: Consider extracting slider suggestion logic to a utility function.

The defaultSliderValue useMemo spans 42 lines with complex branching logic. While the current implementation is correct and well-commented, extracting this to a separate utility function (e.g., calculateSuggestedContribution) would improve testability and make the component easier to scan.

This is purely an optional refactor—the existing code works correctly.

Example structure:

// In utils file
export function calculateSuggestedContribution(
    charges: Charge[] | undefined,
    totalAmount: number,
    totalCollected: number
): { percentage: number; suggestedAmount: number } {
    // Move lines 674-713 here
}

// In component
const defaultSliderValue = useMemo(() => {
    return calculateSuggestedContribution(
        requestDetails?.charges,
        requestDetails?.tokenAmount ? parseFloat(requestDetails.tokenAmount) : 0,
        totalAmountCollected
    )
}, [requestDetails?.charges, requestDetails?.tokenAmount, totalAmountCollected])
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff66afe and aba84f5.

📒 Files selected for processing (1)
  • src/components/Payment/PaymentForm/index.tsx (11 hunks)
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.

Applied to files:

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

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-07T13:42:00.443Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-05-19T19:40:43.138Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#868
File: src/components/Payment/PaymentForm/index.tsx:284-293
Timestamp: 2025-05-19T19:40:43.138Z
Learning: When converting between USD and token amounts, always check if the token price (divisor) is valid and non-zero before performing the division to prevent Infinity, NaN, or errors. Implementing validation like `if (!tokenPrice || isNaN(tokenPrice) || tokenPrice === 0)` before division operations is crucial for handling cases where price data might be unavailable.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-07T15:50:29.173Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-07T15:50:29.173Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-10-24T13:44:39.473Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
🔇 Additional comments (1)
src/components/Payment/PaymentForm/index.tsx (1)

27-34: Overall implementation looks solid; past issues successfully resolved.

The integration of request pot functionality with slider defaults and Pay with Peanut triggering is well-structured. Notably:

  • Side effect previously in useMemo has been eliminated—defaultSliderValue now returns a pure object
  • useEffect dependencies at lines 601-607 are complete (addressed per past review)
  • The sanitizeDecimalInput precision concern no longer applies (call removed from this context)
  • Conditional gating with showRequestPotInitialView is consistently applied throughout

The slider suggestion logic (lines 672-714) handles edge cases correctly: empty contributions, overfilled pots, and remaining amounts all have appropriate fallback behaviors.

Also applies to: 98-99, 177-177, 200-200, 309-309, 319-319, 341-341, 601-607, 672-714, 722-722, 784-785, 868-868

Copy link
Contributor

@kushagrasarathe kushagrasarathe left a comment

Choose a reason for hiding this comment

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

approvvveddd, please lmk when qns addressed

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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/components/Global/TokenAmountInput/index.tsx (2)

312-315: Remove all thousands separators before currency formatting.

Single replace removes only the first comma; use global replace to avoid blank/NaN outputs for large values.

-                            : formatCurrency(alternativeDisplayValue.replace(',', ''))}{' '}
+                            : formatCurrency(alternativeDisplayValue.replace(/,/g, ''))}{' '}

329-348: Sanitize toggled value for input and avoid commas in a type=number input.

When toggling, alternativeDisplayValue may contain commas; setting it directly can break a number input. Sanitize for the next mode and strip separators.

-                        const currentValue = displayValue
-                        if (!alternativeDisplayValue || alternativeDisplayValue === '0.00') {
-                            setDisplayValue('')
-                        } else {
-                            setDisplayValue(alternativeDisplayValue)
-                        }
-                        if (!currentValue) {
-                            setAlternativeDisplayValue('0.00')
-                        } else {
-                            setAlternativeDisplayValue(currentValue)
-                        }
-                        setIsInputUsd(!isInputUsd)
+                        const currentValue = displayValue
+                        const nextIsInputUsd = !isInputUsd
+                        const maxDecimals = nextIsInputUsd ? 2 : decimals
+                        const rawAlt = (alternativeDisplayValue || '').replace(/,/g, '')
+                        const nextDisplay = formatTokenAmount(rawAlt, maxDecimals, true) ?? ''
+                        setDisplayValue(nextDisplay)
+                        setAlternativeDisplayValue(currentValue || '0.00')
+                        setIsInputUsd(nextIsInputUsd)
src/components/Payment/PaymentForm/index.tsx (1)

300-313: Remove setInputTokenAmount(usdValue) to maintain consistent token units.

The effect sets inputTokenAmount to USD, contradicting its use as a token amount elsewhere (parsing, validations, conversions at lines 210, 317-321, 563-564, 612-622). Keep only setUsdValue(usdValue), or use the existing isInitialInputUsd prop to display USD initially without changing inputTokenAmount's unit.

-        const usdValue = formatAmount(tokenAmount * requestedTokenPriceData.price)
-        setInputTokenAmount(usdValue)
-        setUsdValue(usdValue)
+        const usdValue = formatAmount(tokenAmount * requestedTokenPriceData.price)
+        setUsdValue(usdValue)
♻️ Duplicate comments (1)
src/components/Global/TokenAmountInput/index.tsx (1)

62-62: Guard window access in render path.

Wrap window.innerWidth with a typeof check to avoid SSR crashes and hydration surprises.

-    const inputType = useMemo(() => (window.innerWidth < 640 ? 'text' : 'number'), [])
+    const inputType = useMemo(
+        () => (typeof window !== 'undefined' && window.innerWidth < 640 ? 'text' : 'number'),
+        []
+    )
🧹 Nitpick comments (1)
src/components/Global/TokenAmountInput/index.tsx (1)

358-362: Controlled vs uncontrolled Slider props.

With value={sliderValue}, defaultValue is ignored. Remove defaultValue or make the Slider uncontrolled.

-                    <Slider
-                        onValueChange={onSliderValueChange}
-                        value={sliderValue}
-                        defaultValue={[defaultSliderValue ? defaultSliderValue : 100]}
-                    />
+                    <Slider onValueChange={onSliderValueChange} value={sliderValue} />
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aba84f5 and 79849e2.

📒 Files selected for processing (4)
  • src/components/Global/TokenAmountInput/index.tsx (6 hunks)
  • src/components/Payment/PaymentForm/index.tsx (10 hunks)
  • src/components/Request/link/views/Create.request.link.view.tsx (2 hunks)
  • src/utils/general.utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/Request/link/views/Create.request.link.view.tsx
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:596-600
Timestamp: 2025-08-22T07:25:59.304Z
Learning: The `TokenAmountInput` component in `src/components/Global/TokenAmountInput/` always returns decimal strings (e.g., "1,234.56"), not base units. When passing these values to external APIs like Daimo's `toUnits` prop, simply stripping commas with `.replace(/,/g, '')` is sufficient.
📚 Learning: 2025-10-24T13:44:39.473Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Global/TokenAmountInput/index.tsx:23-30
Timestamp: 2024-10-29T12:19:41.968Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), when the 'Max' button is clicked, we intentionally set the input denomination to 'TOKEN' because we are setting the value as token.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/Link/Input.view.tsx:244-248
Timestamp: 2024-10-29T12:20:47.207Z
Learning: In the `TokenAmountInput` component within `src/components/Global/TokenAmountInput/index.tsx`, when `balance` is undefined, the `maxValue` prop should be set to an empty string `''`.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2025-08-22T07:25:59.304Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:596-600
Timestamp: 2025-08-22T07:25:59.304Z
Learning: The `TokenAmountInput` component in `src/components/Global/TokenAmountInput/` always returns decimal strings (e.g., "1,234.56"), not base units. When passing these values to external APIs like Daimo's `toUnits` prop, simply stripping commas with `.replace(/,/g, '')` is sufficient.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
  • src/utils/general.utils.ts
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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/Global/TokenAmountInput/index.tsx
  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-29T14:44:08.745Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Cashout/Components/Initial.view.tsx:194-198
Timestamp: 2024-10-29T14:44:08.745Z
Learning: Using a fixed 6 decimal places for `floorFixed` is acceptable for token amounts in this codebase, even if tokens have varying decimal places.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
  • src/utils/general.utils.ts
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#413
File: src/context/tokenSelector.context.tsx:118-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the `TokenContextProvider` component within `src/context/tokenSelector.context.tsx`, in the TypeScript React application, when data changes and before calling `fetchAndSetTokenPrice`, it is necessary to reset `selectedTokenData`, `selectedTokenPrice`, `selectedTokenDecimals`, and `inputDenomination` to discard stale data.

Applied to files:

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

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-07T13:42:00.443Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-05-19T19:40:43.138Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#868
File: src/components/Payment/PaymentForm/index.tsx:284-293
Timestamp: 2025-05-19T19:40:43.138Z
Learning: When converting between USD and token amounts, always check if the token price (divisor) is valid and non-zero before performing the division to prevent Infinity, NaN, or errors. Implementing validation like `if (!tokenPrice || isNaN(tokenPrice) || tokenPrice === 0)` before division operations is crucial for handling cases where price data might be unavailable.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-07T15:50:29.173Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-07T15:50:29.173Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
🧬 Code graph analysis (1)
src/components/Global/TokenAmountInput/index.tsx (3)
src/context/tokenSelector.context.tsx (1)
  • tokenSelectorContext (19-38)
src/hooks/useGetDeviceType.ts (1)
  • useDeviceType (37-42)
src/utils/general.utils.ts (1)
  • formatTokenAmount (451-495)
🪛 ast-grep (0.39.6)
src/utils/general.utils.ts

[warning] 463-463: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^\\d*\\.?\\d{0,${maxFractionDigits}}$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)


[warning] 466-466: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^\\d*\\.?\\d{0,${maxFractionDigits}})
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

🪛 GitHub Actions: Tests
src/components/Global/TokenAmountInput/index.tsx

[warning] 1-1: Code style issues found in this file. Run 'pnpm prettier --write' to fix.


[error] 1-1: Prettier formatting check failed. The run exited with code 1. Run 'pnpm prettier --write' to fix code style issues.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Deploy-Preview
🔇 Additional comments (2)
src/components/Payment/PaymentForm/index.tsx (2)

665-707: Default slider suggestion logic looks solid.

Good: returns both percentage and amount, caps at 100, handles empty/overfilled pots.

Optionally pass token decimals to any downstream sanitization to avoid truncation in low-liquidity tokens.


594-601: Nice: effect dependencies handled for programmatic “Pay with Peanut”.

Deps include handleInitiatePayment and setter; avoids stale closures.

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 (2)
src/components/Global/TokenAmountInput/index.tsx (1)

242-251: Preset via effect bypasses onChange and forces 2 decimals

This directly sets state and hardcodes 2 decimals, skipping conversions. Route through onChange and respect mode/token decimals.

-// Sync default slider suggested amount to the input
-useEffect(() => {
-    if (defaultSliderSuggestedAmount) {
-        const formattedAmount = formatTokenAmount(defaultSliderSuggestedAmount.toString(), 2)
-        if (formattedAmount) {
-            setTokenValue(formattedAmount)
-            setDisplayValue(formattedAmount)
-        }
-    }
-}, [defaultSliderSuggestedAmount])
+// Sync default slider suggested amount via normal onChange flow
+useEffect(() => {
+    if (defaultSliderSuggestedAmount === undefined) return
+    const maxDecimals =
+        displayMode === 'FIAT' || displayMode === 'STABLE' || isInputUsd ? 2 : decimals
+    const preset = formatTokenAmount(defaultSliderSuggestedAmount.toString(), maxDecimals, true)
+    if (preset !== undefined) onChange(preset, isInputUsd)
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+}, [defaultSliderSuggestedAmount])

Based on learnings

src/utils/general.utils.ts (1)

451-490: Clamp decimals and micro‑opt the floor

Add defensive clamping for maxFractionDigits and avoid recomputing Math.pow:

-export function formatTokenAmount(amount?: number | string, maxFractionDigits?: number, forInput: boolean = false) {
+export function formatTokenAmount(amount?: number | string, maxFractionDigits?: number, forInput: boolean = false) {
     if (amount === undefined) return undefined
-    maxFractionDigits = maxFractionDigits ?? 6
+    // Clamp 0..18 for safety and consistency
+    maxFractionDigits = Math.max(0, Math.min(18, Math.floor(maxFractionDigits ?? 6)))
@@
-    // floor the amount
-    const flooredAmount = Math.floor(amountNumber * Math.pow(10, maxFractionDigits)) / Math.pow(10, maxFractionDigits)
+    // floor the amount
+    const pow = 10 ** maxFractionDigits
+    const flooredAmount = Math.floor(amountNumber * pow) / pow
🧹 Nitpick comments (5)
src/components/Global/Slider/index.tsx (1)

18-25: Default vs controlled: avoid first‑paint flicker and ignored defaults

With internalValue initializing from defaultValue, but value also provided by parent, the effect immediately overwrites with controlledValue (often [0]), causing a jump and nullifying the default.

Prefer letting parent pass value that already falls back to the desired default when tokenValue is empty, and drop defaultValue here. Example parent change (TokenAmountInput):

-  <Slider
-      onValueChange={onSliderValueChange}
-      value={sliderValue}
-      defaultValue={[defaultSliderValue ? defaultSliderValue : 100]}
-  />
+  <Slider
+      onValueChange={onSliderValueChange}
+      value={!tokenValue ? [defaultSliderValue ?? 100] : sliderValue}
+  />

Also update sliderValue to use the default when !tokenValue:

-  if (!maxAmount || !tokenValue) return [0]
+  if (!maxAmount) return [0]
+  if (!tokenValue) return [defaultSliderValue ?? 100]

This preserves the intended preset without a visible snap.

src/components/Global/TokenAmountInput/index.tsx (4)

35-36: New props added cleanly

defaultSliderValue and defaultSliderSuggestedAmount extend the API as expected. Consider brief JSDoc to document precedence/units.


63-67: Drop window width check; always use type="text" + inputMode

type="number" prevents preserving partial inputs like 1. and the window.innerWidth branch is unnecessary. Keep inputMode="decimal" for the right keypad and use type="text" on all devices.

Apply in the input hunk below; you can then remove inputType and the window read.


264-305: Input: prefer type="text"; keep input-preserving path; minor cleanup

  • Set type="text" to preserve 1. inputs and remove desktop/mobile branching.
  • You can drop inputType and the window read.
-    <input
-        autoFocus={shouldAutoFocus}
+    <input
+        autoFocus={shouldAutoFocus}
         className={`h-12 w-[4ch] max-w-80 bg-transparent text-6xl font-black caret-primary-1 outline-none transition-colors placeholder:text-h1 placeholder:text-gray-1 focus:border-primary-1 dark:border-white dark:bg-n-1 dark:text-white dark:placeholder:text-white/75 dark:focus:border-primary-1`}
         placeholder={'0.00'}
@@
-        inputMode="decimal"
-        type={inputType}
+        inputMode="decimal"
+        type="text"
         value={displayValue}

Optional: consider early-returning when formattedAmount === '' so onChange('', …) can treat it as empty rather than 0 downstream.


358-362: Ensure slider default actually shows and avoid jump

Fold the default into value when there’s no tokenValue, and drop defaultValue to prevent immediate overwrite by controlled state.

-  <Slider
-      onValueChange={onSliderValueChange}
-      value={sliderValue}
-      defaultValue={[defaultSliderValue ? defaultSliderValue : 100]}
-  />
+  <Slider
+      onValueChange={onSliderValueChange}
+      value={!tokenValue ? [defaultSliderValue ?? 100] : sliderValue}
+  />

Also consider clamping sliderValue to [0, 120] to match slider bounds.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 79849e2 and a9cff36.

📒 Files selected for processing (3)
  • src/components/Global/Slider/index.tsx (1 hunks)
  • src/components/Global/TokenAmountInput/index.tsx (6 hunks)
  • src/utils/general.utils.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:596-600
Timestamp: 2025-08-22T07:25:59.304Z
Learning: The `TokenAmountInput` component in `src/components/Global/TokenAmountInput/` always returns decimal strings (e.g., "1,234.56"), not base units. When passing these values to external APIs like Daimo's `toUnits` prop, simply stripping commas with `.replace(/,/g, '')` is sufficient.
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.
📚 Learning: 2025-08-22T07:25:59.304Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:596-600
Timestamp: 2025-08-22T07:25:59.304Z
Learning: The `TokenAmountInput` component in `src/components/Global/TokenAmountInput/` always returns decimal strings (e.g., "1,234.56"), not base units. When passing these values to external APIs like Daimo's `toUnits` prop, simply stripping commas with `.replace(/,/g, '')` is sufficient.

Applied to files:

  • src/utils/general.utils.ts
  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-29T14:44:08.745Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Cashout/Components/Initial.view.tsx:194-198
Timestamp: 2024-10-29T14:44:08.745Z
Learning: Using a fixed 6 decimal places for `floorFixed` is acceptable for token amounts in this codebase, even if tokens have varying decimal places.

Applied to files:

  • src/utils/general.utils.ts
  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2025-10-24T13:44:39.473Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Global/TokenAmountInput/index.tsx:23-30
Timestamp: 2024-10-29T12:19:41.968Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), when the 'Max' button is clicked, we intentionally set the input denomination to 'TOKEN' because we are setting the value as token.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/Link/Input.view.tsx:244-248
Timestamp: 2024-10-29T12:20:47.207Z
Learning: In the `TokenAmountInput` component within `src/components/Global/TokenAmountInput/index.tsx`, when `balance` is undefined, the `maxValue` prop should be set to an empty string `''`.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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/Global/TokenAmountInput/index.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#413
File: src/context/tokenSelector.context.tsx:118-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the `TokenContextProvider` component within `src/context/tokenSelector.context.tsx`, in the TypeScript React application, when data changes and before calling `fetchAndSetTokenPrice`, it is necessary to reset `selectedTokenData`, `selectedTokenPrice`, `selectedTokenDecimals`, and `inputDenomination` to discard stale data.

Applied to files:

  • src/components/Global/TokenAmountInput/index.tsx
🧬 Code graph analysis (1)
src/components/Global/TokenAmountInput/index.tsx (3)
src/context/tokenSelector.context.tsx (1)
  • tokenSelectorContext (19-38)
src/hooks/useGetDeviceType.ts (1)
  • useDeviceType (37-42)
src/utils/general.utils.ts (1)
  • formatTokenAmount (451-490)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Deploy-Preview
🔇 Additional comments (3)
src/components/Global/TokenAmountInput/index.tsx (3)

1-2: Client directive added — good

Component correctly marked as a Client Component.


5-5: Import changes look good

Switch to formatTokenAmount aligns with input-preserving logic.


11-11: Device type hook integration — OK

Using useDeviceType for autofocus control is fine.

@Zishan-7 Zishan-7 merged commit 0583d3f into peanut-wallet-dev Oct 29, 2025
5 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Mar 20, 2026
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