Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds documentation files and gitignore entry; bumps @headlessui/react. Implements points integration across UI: prefetching, gating queries, pluralized displays, and showing points in transaction receipts/types. Introduces accessibility titles in drawers. Adjusts confetti origin based on element position. Tweaks orientation locking, disables AppKit analytics, and adds minor UI/title updates. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
This is the final PR Bugbot will review for you during this billing cycle
Your free Bugbot reviews will reset on November 8
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
|
|
||
| if (isLoading || isTierInfoLoading) { | ||
|
|
||
| if (isLoading || isTierInfoLoading || !tierInfo?.data) { |
There was a problem hiding this comment.
Bug: Loading Spinner Fails to Resolve
The !tierInfo?.data condition in the loading check incorrectly triggers an indefinite loading spinner when tierInfo.data is null. This prevents the component from displaying either an error state (if the API failed) or the intended UI (if the API succeeded with empty data).
| usdAmount && | ||
| chargeDetails?.uuid && | ||
| ((flow === 'request_pay' && currentView === 'CONFIRM') || (flow === 'direct_pay' && currentView === 'STATUS')) | ||
|
|
There was a problem hiding this comment.
Bug: Direct Pay Points Calculation Issues
For direct_pay flows, points calculation has two issues. The shouldFetchPoints condition, relying on currentView === 'STATUS', prevents points from being fetched because the query enables before the view updates. Also, the PointsAction.P2P_REQUEST_PAYMENT action type used for calculation might be incorrect for direct_pay transactions.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (7)
src/config/wagmi.config.tsx (1)
58-58: Analytics disabled correctly; consider refining the comment.The change correctly disables AppKit analytics. However, the comment uses informal language ("plz").
Consider this more professional alternative:
- analytics: false, // no app-kit analytics plz + analytics: false, // Disable AppKit analyticsdocs/CHANGELOG.md (1)
1-1: Consider adding actual changelog content.This file contains only a placeholder. Consider documenting the changes introduced in this PR or establishing a changelog format for future releases.
WARP.md (1)
1-1: Consider clarifying the purpose of this file.The content ".cursorrules" suggests this might be a reference to another file or configuration. Consider adding documentation explaining the purpose of this file or whether it should contain the actual rules instead of just a reference.
.cursorrules (1)
5-6: Clarify the crash warnings.The phrasing "it crashes you" is ambiguous. Does this crash the cursor/IDE, the system, or cause another issue? Consider rephrasing for clarity.
Apply this diff to clarify the warnings:
-- never open SVG files, it crashes you. Only read jpeg, png, gif, or webp. -- never run jq command, it crashes you. +- never open SVG files as it may crash the IDE. Only read jpeg, png, gif, or webp. +- never run jq command as it may crash the IDE.src/components/Home/AddMoneyPromptModal/index.tsx (1)
54-54: Redundant dark mode class.The
dark:text-blackclass is redundant sincetext-blackalready forces black text in both light and dark modes. The!prefix ensures it overrides any inherited styles.Apply this diff to remove the redundant class:
- titleClassName="!text-lg !font-bold text-black dark:text-black" + titleClassName="!text-lg !font-bold text-black"src/components/Payment/Views/Status.payment.view.tsx (1)
173-181: Consider adding window dimension guards.The calculation uses
window.innerWidthandwindow.innerHeightwithout checking if they exist. While these are typically available in browser contexts, adding guards would make the code more defensive.Apply this diff to add defensive checks:
useEffect(() => { - if (points && pointsDivRef.current) { + if (points && pointsDivRef.current && typeof window !== 'undefined') { // Calculate position of points div relative to viewport const rect = pointsDivRef.current.getBoundingClientRect() const x = (rect.left + rect.width / 2) / window.innerWidth const y = (rect.top + rect.height / 2) / window.innerHeight shootDoubleStarConfetti({ origin: { x, y } }) } }, [points])src/components/Claim/Link/Onchain/Success.view.tsx (1)
147-155: Consider adding window dimension guards.Similar to the other confetti implementation in Status.payment.view.tsx, this code uses
window.innerWidthandwindow.innerHeightwithout checking if they exist. Consider adding the same defensive checks for consistency.Apply this diff to add defensive checks:
useEffect(() => { - if (pointsData?.estimatedPoints && pointsDivRef.current) { + if (pointsData?.estimatedPoints && pointsDivRef.current && typeof window !== 'undefined') { // Calculate position of points div relative to viewport const rect = pointsDivRef.current.getBoundingClientRect() const x = (rect.left + rect.width / 2) / window.innerWidth const y = (rect.top + rect.height / 2) / window.innerHeight shootDoubleStarConfetti({ origin: { x, y } }) } }, [pointsData?.estimatedPoints])
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (24)
.cursorrules(1 hunks).gitignore(1 hunks)WARP.md(1 hunks)docs/CHANGELOG.md(1 hunks)package.json(1 hunks)src/app/(mobile-ui)/points/page.tsx(5 hunks)src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx(1 hunks)src/app/[...recipient]/client.tsx(1 hunks)src/components/AddMoney/components/CryptoMethodDrawer.tsx(2 hunks)src/components/Claim/Link/Onchain/Success.view.tsx(3 hunks)src/components/Global/ErrorSuppressor.tsx(1 hunks)src/components/Global/ScreenOrientationLocker.tsx(1 hunks)src/components/Global/SupportDrawer/index.tsx(1 hunks)src/components/Global/TokenSelector/TokenSelector.tsx(2 hunks)src/components/Home/AddMoneyPromptModal/index.tsx(2 hunks)src/components/Kyc/KycStatusDrawer.tsx(2 hunks)src/components/Payment/Views/Status.payment.view.tsx(3 hunks)src/components/TransactionDetails/TransactionDetailsDrawer.tsx(2 hunks)src/components/TransactionDetails/TransactionDetailsReceipt.tsx(4 hunks)src/components/TransactionDetails/transaction-details.utils.ts(2 hunks)src/components/TransactionDetails/transactionTransformer.ts(2 hunks)src/config/wagmi.config.tsx(1 hunks)src/hooks/useTransactionHistory.ts(1 hunks)src/services/points.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-10-02T15:23:01.513Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Applied to files:
src/app/[...recipient]/client.tsxsrc/app/(mobile-ui)/withdraw/[country]/bank/page.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/TokenSelector/TokenSelector.tsx
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
Applied to files:
src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".
Applied to files:
src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx
🧬 Code graph analysis (12)
src/components/TransactionDetails/TransactionDetailsDrawer.tsx (1)
src/components/Global/Drawer/index.tsx (1)
DrawerTitle(89-89)
src/components/TransactionDetails/TransactionDetailsReceipt.tsx (1)
src/components/Payment/PaymentInfoRow.tsx (1)
PaymentInfoRow(7-81)
src/components/Global/SupportDrawer/index.tsx (2)
src/context/SupportModalContext.tsx (1)
useSupportModalContext(22-28)src/components/Global/Drawer/index.tsx (2)
Drawer(81-81)DrawerTitle(89-89)
src/components/Kyc/KycStatusDrawer.tsx (1)
src/components/Global/Drawer/index.tsx (2)
DrawerContent(86-86)DrawerTitle(89-89)
src/services/points.ts (1)
src/services/services.types.ts (1)
TierInfo(327-336)
src/components/Claim/Link/Onchain/Success.view.tsx (1)
src/utils/confetti.ts (1)
shootDoubleStarConfetti(49-67)
src/app/[...recipient]/client.tsx (1)
src/services/points.ts (1)
pointsApi(6-86)
src/components/AddMoney/components/CryptoMethodDrawer.tsx (1)
src/components/Global/Drawer/index.tsx (1)
DrawerTitle(89-89)
src/components/Global/TokenSelector/TokenSelector.tsx (1)
src/components/Global/Drawer/index.tsx (1)
DrawerTitle(89-89)
src/app/(mobile-ui)/points/page.tsx (1)
src/components/Global/Card/index.tsx (1)
getCardPosition(14-19)
src/components/Payment/Views/Status.payment.view.tsx (2)
src/constants/query.consts.ts (1)
TRANSACTIONS(2-2)src/utils/confetti.ts (1)
shootDoubleStarConfetti(49-67)
src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx (1)
src/services/points.ts (1)
pointsApi(6-86)
🪛 Biome (2.1.2)
src/app/(mobile-ui)/points/page.tsx
[error] 79-79: Expected corresponding JSX closing tag for 'div'.
Opening tag
closing tag
(parse)
[error] 71-71: Expected corresponding JSX closing tag for 'Card'.
Opening tag
closing tag
(parse)
[error] 70-70: Expected corresponding JSX closing tag for 'section'.
Opening tag
closing tag
(parse)
🪛 GitHub Actions: Tests
src/components/Global/ErrorSuppressor.tsx
[warning] 1-1: Code style check reported a warning in this file. Error occurred when checking code style in the above file.
src/app/(mobile-ui)/points/page.tsx
[error] 79-79: SyntaxError: JSX element 'div' has no corresponding closing tag. Prettier check failed. Command: 'pnpm prettier --check .'
⏰ 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: Cursor Bugbot
🔇 Additional comments (16)
src/components/Global/SupportDrawer/index.tsx (1)
2-2: LGTM! Excellent accessibility improvement.The addition of DrawerTitle with
sr-onlyclass provides an accessible label for screen readers without affecting the visual layout. This follows ARIA best practices and is consistent with the pattern used across other drawers in this PR.Also applies to: 9-9
.gitignore (1)
5-6: LGTM!Standard gitignore entry to exclude PR.md from version control.
src/components/Global/TokenSelector/TokenSelector.tsx (1)
28-28: LGTM! Excellent accessibility enhancement.The addition of DrawerTitle with descriptive text "Select Token and Network" provides clear context for screen reader users while remaining visually hidden. This aligns with WCAG guidelines and the consistent pattern established across other drawers.
Also applies to: 577-577
src/components/AddMoney/components/CryptoMethodDrawer.tsx (1)
5-5: LGTM! Proper accessibility implementation.The DrawerTitle provides appropriate context for assistive technologies. The text "Select a deposit method" accurately describes the drawer's purpose and aligns with the visible heading below.
Also applies to: 27-27
package.json (1)
32-32: Verify Headless UI v2 migration
- Major v2 release includes breaking API changes: update Transition usage to the new data-attribute API; rename PopoverOverlay→PopoverBackdrop and add DialogBackdrop; adapt form components and focus-management changes; adjust renamed/removed props on Menu, Listbox, Combobox, Tabs, Switch, RadioGroup, Checkbox, etc.
- Manually audit and test all HeadlessUI-based components in this PR: SupportDrawer, TokenSelector, TransactionDetailsDrawer, KycStatusDrawer, CryptoMethodDrawer.
.cursorrules (2)
15-15: LGTM!Good guidance on separating business logic from the interface for improved readability, debugging, and testability.
19-20: LGTM!Colocating tests with the code they test is a good practice that improves maintainability and discoverability.
src/components/Kyc/KycStatusDrawer.tsx (1)
123-126: LGTM!The addition of a screen-reader-only
DrawerTitleimproves accessibility by providing context for assistive technologies without altering the visual presentation. This aligns with the broader accessibility enhancements across drawer components in this PR.src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx (1)
47-56: Verify the intentional caching behavior change.Based on the learnings from PR #1266, the points calculation previously used
crypto.randomUUID()in the queryKey to intentionally bypass React Query caching and ensure fresh estimates on every render. The current implementation now enables caching with a stable queryKey.If this behavior change is intentional and you want caching enabled, the implementation looks correct. However, if you still need fresh estimates on every render, consider adding back the random component to the queryKey.
Based on learnings.
src/components/Payment/Views/Status.payment.view.tsx (1)
254-256: LGTM!The pluralization logic correctly handles singular/plural forms of "point/points" based on the count.
src/components/Claim/Link/Onchain/Success.view.tsx (1)
197-198: LGTM!The pluralization logic and spacing between the number and unit are correctly implemented.
src/components/Global/ScreenOrientationLocker.tsx (2)
8-11: LGTM!The addition of client-side and
window.screenguards prevents potential runtime errors in SSR or environments where the Screen API is unavailable.
19-26: LGTM!Replacing Sentry error reporting with
console.debugis appropriate here, as orientation lock failures are expected behavior on desktop browsers and environments that don't support this API. The comment clearly explains why this isn't treated as an error.src/services/points.ts (3)
10-12: LGTM!Adding error logging for missing JWT tokens improves observability and helps diagnose authentication issues.
68-75: LGTM!The detailed error logging including
response.status,response.statusText, andactionTypeprovides excellent context for debugging API failures. Including the action type is particularly helpful for tracking which specific point calculations are failing.
81-84: LGTM!Preserving the original error type when rethrowing ensures stack traces and error details are maintained while providing a fallback generic error message for non-Error objects.
| <div className="flex w-full items-center gap-2"> | ||
| {tierInfo?.data.currentTier} | ||
| <div className="w-full"> | ||
| <div className="relative h-1.5 w-full overflow-hidden rounded-full bg-grey-2"> | ||
| <div | ||
| className="h-full animate-pulse rounded-full bg-primary-1 transition-all duration-300" | ||
| style={{ | ||
| width: `${(tierInfo.data.totalPoints / tierInfo.data.nextTierThreshold) * 100}%`, | ||
| }} | ||
| /> | ||
| </div> | ||
| {tierInfo?.data.currentTier + 1} | ||
| </div> | ||
|
|
||
| <p className="text-sm text-grey-1"> | ||
| {tierInfo.data.pointsToNextTier} points needed for the next tier | ||
| </p> | ||
| </Card> | ||
| )} | ||
| <p className="text-sm text-grey-1"> | ||
| {tierInfo.data.pointsToNextTier} {tierInfo.data.pointsToNextTier === 1 ? 'point' : 'points'}{' '} | ||
| needed for the next tier | ||
| </p> | ||
| </Card> |
There was a problem hiding this comment.
Unclosed div breaks JSX compilation
The flex wrapper opened for the progress row (Line 79) never closes before the <p> tag, so the JSX fails to compile (see Prettier/static-analysis failure). Add the missing </div> to restore balanced markup.
<div className="flex w-full items-center gap-2">
{tierInfo?.data.currentTier}
<div className="w-full">
<div className="relative h-1.5 w-full overflow-hidden rounded-full bg-grey-2">
<div
className="h-full animate-pulse rounded-full bg-primary-1 transition-all duration-300"
style={{
width: `${(tierInfo.data.totalPoints / tierInfo.data.nextTierThreshold) * 100}%`,
}}
/>
</div>
{tierInfo?.data.currentTier + 1}
</div>
+ </div>
<p className="text-sm text-grey-1">
{tierInfo.data.pointsToNextTier} {tierInfo.data.pointsToNextTier === 1 ? 'point' : 'points'} needed for the next tier
</p>🧰 Tools
🪛 Biome (2.1.2)
[error] 79-79: Expected corresponding JSX closing tag for 'div'.
Opening tag
closing tag
(parse)
🪛 GitHub Actions: Tests
[error] 79-79: SyntaxError: JSX element 'div' has no corresponding closing tag. Prettier check failed. Command: 'pnpm prettier --check .'
🤖 Prompt for AI Agents
In src/app/(mobile-ui)/points/page.tsx around lines 79 to 97, the opening <div
className="flex w-full items-center gap-2"> for the progress row is not closed,
which breaks JSX compilation; add the missing closing </div> immediately after
the inner block that renders the progress bar and the next-tier label (i.e.
close the flex wrapper before the <p> tag), verify all other divs remain
balanced, and run the linter/Prettier to confirm compilation succeeds.
| @@ -0,0 +1 @@ | |||
|
No newline at end of file |
|||
There was a problem hiding this comment.
Remove the empty file or implement the component.
This empty file causes a code style pipeline failure. Either implement the ErrorSuppressor component or remove this file entirely.
To remove the file:
#!/bin/bash
# Verify if ErrorSuppressor is imported anywhere
rg -nP '\bErrorSuppressor\b' --type=ts --type=tsx -g '!**/node_modules/**'🧰 Tools
🪛 GitHub Actions: Tests
[warning] 1-1: Code style check reported a warning in this file. Error occurred when checking code style in the above file.
🤖 Prompt for AI Agents
In src/components/Global/ErrorSuppressor.tsx at lines 1-1 the file is empty and
causes the style pipeline to fail; either delete this file and ensure no imports
reference it (run rg -nP '\bErrorSuppressor\b' --type=ts --type=tsx -g
'!**/node_modules/**' and remove any imports) or implement a minimal component
that satisfies the linter by exporting a default React component (e.g., a
functional component that returns null) and update any existing imports to use
it; keep the implementation minimal and add an export so the project builds.
most of UI FE logic included here