[TASK-16321] Fix/pots fixes#1368
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds 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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 2 inconclusive)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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
sanitizeDecimalInputalready 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 consistentConfig and typing align with existing sizes. Consider using existing
.icon-16utility for consistency, but current approach is fine.Also applies to: 12-15
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 LGTMClearer defaulting to 'Add Money'/'Pay'; matches flow semantics.
795-806: Render Contributors only when non‑emptyGood 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-exportssanitizeDecimalInput.Verification confirms
sanitizeDecimalInputis exported fromsrc/utils/general.utils.ts(line 395) and re-exported by the barrel atsrc/utils/index.tsvia wildcard export. The import from@/utilsis 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-blinkis explicitly defined intailwind.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.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/context/RequestFulfillmentFlowContext.tsx (1)
60-71: Missing reset for triggerPayWithPeanut in resetFlowThe
resetFlowcallback resets all other state but doesn't includesetTriggerPayWithPeanut(false). This could leave the trigger in a staletruestate 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 dotsThis concern was already raised in a previous review. The dynamic
RegExpconstructor 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 presentLine 60 still contains unguarded
window.innerWidthaccess 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
📒 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.tsxsrc/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' directiveThe 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 UXSmart implementation that prevents disruptive autofocus on mobile devices (iOS/Android) while maintaining desktop convenience. The
useDeviceTypehook provides a clean abstraction.
258-263: Proper decimal clamping based on display modeThe dynamic
maxDecimalslogic correctly addresses the previous review concern: 2 decimals for USD/fiat/stablecoins, and up todecimals(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 continuityThe decorative blinking caret when input is unfocused and empty provides good visual feedback for users. The implementation correctly uses
pointer-events-noneand Tailwind'sanimate-blinkutility.src/components/Common/ActionList.tsx (3)
155-158: Peanut balance gating improves UXSmart flow that prompts users with sufficient Peanut balance before allowing them to proceed with external payment methods. The
isUsePeanutBalanceModalShownguard prevents repeated prompts.
237-256: Disable interaction correctly while modal shownThe
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 CTAThe "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 triggerThe
triggerPayWithPeanutflag 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 initiationThe effect correctly responds to
triggerPayWithPeanutfrom 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 viewThe
showRequestPotInitialViewflag correctly bypasses balance checks, wallet connection requirements, and payment initiation during the initial pot contribution view. ThereturnAfterChargeCreationflag 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 componentThe removal of the
useEffectthat synced externalcontrolledValuechanges breaksTokenAmountInput, which relies on updating the Slider's displayed value whentokenValuechanges. When a user modifies the token amount input,sliderValuerecalculates viauseMemo, but the Slider ignores this update because there's no mechanism to sync the newcontrolledValuetointernalValue. This causes the Slider to display a stale position while the input value updates.Restore the
useEffectto watchcontrolledValueand updateinternalValuewhen external changes occur, or refactorTokenAmountInputto not pass a dynamicvalueprop 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.
…ate PaymentForm to utilize it
1 similar comment
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (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
sanitizeDecimalInputis clean and the utility integration aligns with the PR's goal of adding decimal sanitization.
98-99: LGTM!The new
triggerPayWithPeanutstate properly exposes programmatic payment initiation capability from the context.
176-200: LGTM!The guard logic correctly skips initial setup when
showRequestPotInitialViewis 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
showRequestPotInitialViewwhich 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
TokenAmountInputcomponent properly handles thedefaultSliderSuggestedAmountprop through auseEffectthat sets bothtokenValueanddisplayValuewhen 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
There was a problem hiding this comment.
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
defaultSliderValueuseMemo 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
📒 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
useMemohas been eliminated—defaultSliderValuenow returns a pure objectuseEffectdependencies at lines 601-607 are complete (addressed per past review)- The
sanitizeDecimalInputprecision concern no longer applies (call removed from this context)- Conditional gating with
showRequestPotInitialViewis consistently applied throughoutThe 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
kushagrasarathe
left a comment
There was a problem hiding this comment.
approvvveddd, please lmk when qns addressed
There was a problem hiding this comment.
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,
alternativeDisplayValuemay contain commas; setting it directly can break anumberinput. 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: RemovesetInputTokenAmount(usdValue)to maintain consistent token units.The effect sets
inputTokenAmountto USD, contradicting its use as a token amount elsewhere (parsing, validations, conversions at lines 210, 317-321, 563-564, 612-622). Keep onlysetUsdValue(usdValue), or use the existingisInitialInputUsdprop to display USD initially without changinginputTokenAmount'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.innerWidthwith 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},defaultValueis ignored. RemovedefaultValueor 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
📒 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.tsxsrc/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.tsxsrc/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.tsxsrc/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.tsxsrc/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
handleInitiatePaymentand setter; avoids stale closures.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
src/components/Global/TokenAmountInput/index.tsx (1)
242-251: Preset via effect bypasses onChange and forces 2 decimalsThis directly sets state and hardcodes 2 decimals, skipping conversions. Route through
onChangeand 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 floorAdd defensive clamping for
maxFractionDigitsand avoid recomputingMath.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 defaultsWith
internalValueinitializing fromdefaultValue, butvaluealso provided by parent, the effect immediately overwrites withcontrolledValue(often[0]), causing a jump and nullifying the default.Prefer letting parent pass
valuethat already falls back to the desired default whentokenValueis empty, and dropdefaultValuehere. Example parent change (TokenAmountInput):- <Slider - onValueChange={onSliderValueChange} - value={sliderValue} - defaultValue={[defaultSliderValue ? defaultSliderValue : 100]} - /> + <Slider + onValueChange={onSliderValueChange} + value={!tokenValue ? [defaultSliderValue ?? 100] : sliderValue} + />Also update
sliderValueto 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
defaultSliderValueanddefaultSliderSuggestedAmountextend 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 like1.and thewindow.innerWidthbranch is unnecessary. KeepinputMode="decimal"for the right keypad and usetype="text"on all devices.Apply in the input hunk below; you can then remove
inputTypeand thewindowread.
264-305: Input: prefertype="text"; keep input-preserving path; minor cleanup
- Set
type="text"to preserve1.inputs and remove desktop/mobile branching.- You can drop
inputTypeand thewindowread.- <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 === ''soonChange('', …)can treat it as empty rather than0downstream.
358-362: Ensure slider default actually shows and avoid jumpFold the default into
valuewhen there’s notokenValue, and dropdefaultValueto 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
sliderValueto[0, 120]to match slider bounds.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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.tssrc/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.tssrc/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 — goodComponent correctly marked as a Client Component.
5-5: Import changes look goodSwitch to
formatTokenAmountaligns with input-preserving logic.
11-11: Device type hook integration — OKUsing
useDeviceTypefor autofocus control is fine.
No description provided.