Skip to content

QR Payment Points & Savings Features#1392

Merged
Hugo0 merged 18 commits intopeanut-wallet-devfrom
chore/points-and-card-savings
Nov 3, 2025
Merged

QR Payment Points & Savings Features#1392
Hugo0 merged 18 commits intopeanut-wallet-devfrom
chore/points-and-card-savings

Conversation

@Hugo0
Copy link
Contributor

@Hugo0 Hugo0 commented Nov 1, 2025

Summary of Changes

  • QR Payment Points: Added "You've earned X points!" display after Manteca and SimpleFi QR payments complete, with confetti animation
  • QR Payment Savings: Added "If you had paid with card, it'd have cost you ~X more!" message for Argentina Manteca QR payments only (5% savings, shows cents <$1, dollars >=$1)
  • Manteca Withdraw Points: Added points display to Manteca withdraw success view
  • Utility Functions: Created qr-payment.utils.ts with savings calculation and Argentina detection logic
  • Performance: Points fetched early via useQuery with 5min cache to avoid latency penalty
  • Home Page UI: Added Points link in header (icon + text + chevron), Profile menu includes Points item with star icon, UserHeader button uses shadowSize="3"

Risks

  • Low risk: All changes additive, backward compatible
  • Backend dependency: Requires points API to support MANTECA_QR_PAYMENT action type (already in use)
  • Conditional rendering: Savings message only shows for Argentina Manteca QR payments (MERCADO_PAGO/ARGENTINA_QR3), not Brazil PIX or SimpleFi

QA Guidelines

  • QR Payment Manteca (Argentina): Verify points display + savings message appear after payment
  • QR Payment Manteca (Brazil/PIX): Verify points display appears, savings message does NOT
  • QR Payment SimpleFi: Verify points display appears + confetti triggers
  • Manteca Withdraw: Verify points display appears in success view
  • Edge cases: Test with $0.01 (shows "1 cent"), $1.00 (shows "$1.00"), $10.00 (shows "~$10.00")
  • Perk flow: Verify points show even when perk is claimed (separate rewards)
  • Home page: Verify Points link in header navigates to /points, Profile menu shows Points item

@vercel
Copy link

vercel bot commented Nov 1, 2025

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

Project Deployment Preview Comments Updated (UTC)
peanut-wallet Ready Ready Preview Comment Nov 3, 2025 6:12pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 1, 2025

Walkthrough

Swap HomeBanners for HomeCarouselCTA, add carousel constants and hook rename, integrate points calculation/confetti and Argentina savings messaging across QR-pay and withdraw flows, remove banner/notification components, add number formatting and QR-payment utilities, and update Crisp support proxy and related hooks/components.

Changes

Cohort / File(s) Summary
Mobile home page
src/app/(mobile-ui)/home/page.tsx
Replaced HomeBanners with HomeCarouselCTA; adjusted Add Money Prompt session persistence (guarded writes and dedicated effect) and minor spacing tweaks.
QR-pay (points & savings)
src/app/(mobile-ui)/qr-pay/page.tsx
Added usePointsCalculation prefetch and usePointsConfetti; integrated calculateSavingsInCents/getSavingsMessage; updated success/balance flows and effect deps.
Withdraw flows
src/app/(mobile-ui)/withdraw/manteca/page.tsx, src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx
Introduced flowId (useId), replaced direct queries with usePointsCalculation (uniqueId/flowId), added confetti hook usage and Points UI blocks; widened effect dependencies.
Carousel CTA components & hook
src/components/Home/HomeCarouselCTA/CarouselCTA.tsx, src/components/Home/HomeCarouselCTA/index.tsx, src/hooks/useHomeCarouselCTAs.tsx
Added CarouselCTA and HomeCarouselCTA wrapper; renamed useBannersuseHomeCarouselCTAs, BannerCarouselCTA, migrated generator to memoized callback and renamed state from bannerscarouselCTAs.
Removed banner/notification components
src/components/Home/HomeBanners/BannerCard.tsx, src/components/Home/HomeBanners/index.tsx, src/components/Notifications/NotificationBanner.tsx
Deleted BannerCard, HomeBanners module, and NotificationBanner component and their props/types.
Points hook
src/hooks/usePointsCalculation.ts
New hook fetching cached points via pointsApi.calculatePoints, returns { pointsData, pointsDivRef }, enabled by user + positive amount + flag, accepts uniqueId/otherUserId.
Crisp support & proxy
src/app/crisp-proxy/page.tsx, src/components/CrispChat.tsx, src/components/Global/SupportDrawer/index.tsx, src/hooks/useCrispProxyUrl.ts, src/hooks/useCrispEmbedUrl.ts, src/hooks/useCrispUserData.ts, src/utils/crisp.ts, src/app/(mobile-ui)/support/page.tsx
Introduced Crisp proxy page, proxy URL hooks, expanded Crisp user/session data, reset helpers, switched SupportDrawer to proxy iframe with postMessage readiness, replaced CrispChat with CrispButton, and updated support page to use proxy + loading state.
Constants & exports
src/constants/carousel.consts.ts, src/constants/index.ts, src/constants/crisp.ts, src/constants/support.ts
Added carousel styling constants and re-export; added CRISP_WEBSITE_ID and support-related base URLs.
Utilities
src/utils/general.utils.ts, src/utils/qr-payment.utils.ts
Added formatNumberForDisplay(valueStr, options) and QR-payment utilities: calculateSavingsInCents, isArgentinaMantecaQrPayment, getSavingsMessage.
UI tweaks & small components
src/components/Profile/components/ProfileHeader.tsx, src/components/UserHeader/index.tsx, src/components/Home/InvitesIcon.tsx, src/components/Common/ActionList.tsx, src/components/Global/Slider/index.tsx, src/components/index.ts
ProfileHeader: added CopyToClipboard; UserHeader: increased button padding; InvitesIcon: changed animation class; ActionList: renders SupportCTA for guest 'claim' flow; Slider: updated second SNAP_POINTS to 100/3; components index comment tweak.
Tailwind config
tailwind.config.js
Added starPulsateWiggle keyframes and star-pulsate-wiggle animation alias.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Heterogeneous changes across UI, hooks, utils, and support/Crisp integration.
  • Areas needing extra attention:
    • usePointsCalculation: queryKey composition (uniqueId/flowId) and enabled conditions.
    • pointsDivRef timing and confetti triggering to avoid race conditions.
    • All call sites updated for hook/name changes: useBanners → useHomeCarouselCTAs and renamed return shape.
    • Ensure no residual imports/usages of removed BannerCard/NotificationBanner remain.
    • Crisp proxy messaging and session reset logic (resetCrispProxySessions) and logout integration.

Possibly related PRs

Suggested reviewers

  • jjramirezn
  • kushagrasarathe

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'QR Payment Points & Savings Features' accurately and clearly summarizes the main changes: addition of points display and savings messaging for QR payments.
Description check ✅ Passed The pull request description is comprehensive and directly related to the changeset, covering QR payment points, savings calculations, Manteca withdraw points, utility functions, performance considerations, and UI updates.
✨ 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 chore/points-and-card-savings

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

@Hugo0
Copy link
Contributor Author

Hugo0 commented Nov 1, 2025

@coderabbitai review in depth. See .cursorrules for guidelines.

@coderabbitai coderabbitai bot added the enhancement New feature or request label Nov 1, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 1, 2025

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the .cursorrules file to understand review guidelines
cat .cursorrules

Length of output: 2589


🏁 Script executed:

#!/bin/bash
# Get the list of files changed in this PR
gh pr view 1392 --json files --jq '.files[] | .path'

Length of output: 540


🏁 Script executed:

#!/bin/bash
# Get the PR diff
gh pr diff 1392

Length of output: 37192


🏁 Script executed:

#!/bin/bash
# Check if usePointsConfetti hook exists in codebase
fd -t f "usePointsConfetti" --exec cat {}

Length of output: 1151


🏁 Script executed:

#!/bin/bash
# Check imports in qr-pay/page.tsx to see full context
head -50 src/app/(mobile-ui)/qr-pay/page.tsx

Length of output: 131


🏁 Script executed:

#!/bin/bash
# Check if there are any existing tests for utils
fd -e test.ts -e test.tsx -e spec.ts -e spec.tsx . src/utils/

Length of output: 205


🏁 Script executed:

#!/bin/bash
# Check backend points API to understand MANTECA_QR_PAYMENT support
rg -n "MANTECA_QR_PAYMENT" --type ts

Length of output: 1065


🏁 Script executed:

#!/bin/bash
# Check the Profile header to understand the copy to clipboard change
cat src/components/Profile/components/ProfileHeader.tsx | head -80

Length of output: 3400


🏁 Script executed:

#!/bin/bash
# Check if CopyToClipboard is used elsewhere
rg -n "CopyToClipboard" --type tsx --type ts -C2

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Look at the Slider component to understand snap points context
cat src/components/Global/Slider/index.tsx

Length of output: 4475


🏁 Script executed:

#!/bin/bash
# Check if qr-payment.utils.ts functions are tested anywhere
rg -n "calculateSavingsInCents|isArgentinaMantecaQrPayment|getSavingsMessage" --type ts -g "**/*.test.*" -g "**/*.spec.*"

Length of output: 0


@Hugo0, I've completed an in-depth review according to .cursorrules. Here's my analysis:

🚨 Critical Issues

1. DRY Violation - Points Display Duplicated 3x

The points display JSX is duplicated in three places in qr-pay/page.tsx:

  • Lines 1016-1023 (after payment card)
  • Lines 1085-1096 (after perk banner)
  • Lines 1222-1234 (SimpleFi success)

Recommended Fix: Extract to a reusable component:

// src/components/QrPay/PointsEarned.tsx
interface PointsEarnedProps {
    points: number
    divRef: React.RefObject<HTMLDivElement>
}

export const PointsEarned: React.FC<PointsEarnedProps> = ({ points, divRef }) => (
    <div ref={divRef} className="flex justify-center gap-2">
        <Image src={STAR_STRAIGHT_ICON} alt="star" width={20} height={20} />
        <p className="text-sm font-medium text-black">
            You&apos;ve earned {points} {points === 1 ? 'point' : 'points'}!
        </p>
    </div>
)

Then use: {pointsData?.estimatedPoints && <PointsEarned points={pointsData.estimatedPoints} divRef={pointsDivRef} />}

2. Missing Tests for New Utils

qr-payment.utils.ts has no tests. Per .cursorrules: "Test new code - where tests make sense, test new code." These utils have clear inputs/outputs perfect for unit testing.

Recommended: Create src/utils/__tests__/qr-payment.utils.test.ts:

import { calculateSavingsInCents, isArgentinaMantecaQrPayment, getSavingsMessage } from '../qr-payment.utils'
import { EQrType } from '@/components/Global/DirectSendQR/utils'

describe('qr-payment.utils', () => {
    describe('calculateSavingsInCents', () => {
        it('should calculate 5% savings correctly', () => {
            expect(calculateSavingsInCents('10.00')).toBe(50) // 5% of $10 = $0.50 = 50 cents
            expect(calculateSavingsInCents('0.20')).toBe(1) // 5% of $0.20 = $0.01 = 1 cent
        })

        it('should return 0 for invalid input', () => {
            expect(calculateSavingsInCents(null)).toBe(0)
            expect(calculateSavingsInCents(undefined)).toBe(0)
            expect(calculateSavingsInCents('')).toBe(0)
        })
    })

    describe('isArgentinaMantecaQrPayment', () => {
        it('should return true for Argentina Manteca payments', () => {
            expect(isArgentinaMantecaQrPayment(EQrType.MERCADO_PAGO, 'MANTECA')).toBe(true)
            expect(isArgentinaMantecaQrPayment(EQrType.ARGENTINA_QR3, 'MANTECA')).toBe(true)
        })

        it('should return false for SimpleFi or Brazil PIX', () => {
            expect(isArgentinaMantecaQrPayment(EQrType.PIX, 'MANTECA')).toBe(false)
            expect(isArgentinaMantecaQrPayment(EQrType.MERCADO_PAGO, 'SIMPLEFI')).toBe(false)
        })
    })

    describe('getSavingsMessage', () => {
        it('should format cents for amounts < $1', () => {
            expect(getSavingsMessage(1)).toContain('1 cent')
            expect(getSavingsMessage(50)).toContain('50 cents')
        })

        it('should format dollars for amounts >= $1', () => {
            expect(getSavingsMessage(100)).toContain('$1.00')
            expect(getSavingsMessage(1050)).toContain('$10.50')
        })

        it('should return empty string for 0 or negative', () => {
            expect(getSavingsMessage(0)).toBe('')
            expect(getSavingsMessage(-10)).toBe('')
        })
    })
})

⚠️ Scope Questions

3. ProfileHeader CopyToClipboard Change

The addition of username copy-to-clipboard in ProfileHeader.tsx (lines 45-58) is not mentioned in PR objectives. Is this intentional or should it be in a separate PR?

4. Slider Snap Points Change

Line 7 in Slider/index.tsx changed from hardcoded 33 to 100/3 for precision. Not in PR objectives but makes sense for equal 3-person splits. Confirm this is intentional?

✅ What's Done Well

Performance ⚡

  • Excellent caching strategy: Points fetched early with useQuery and 5min staleTime to avoid latency
  • Simultaneous fetches: No sequential awaits where not needed
  • Conditional queries: enabled flags prevent unnecessary requests

Separation of Concerns 📦

  • New qr-payment.utils.ts properly separates business logic
  • usePointsConfetti hook cleanly encapsulates animation logic
  • Carousel refactoring from HomeBanners to HomeCarouselCTA improves naming clarity

Bug Fix 🐛

  • home/page.tsx (lines 202-227): Good fix for sessionStorage race condition by separating state update from storage write

Accessibility 🌐

  • CarouselCTA.tsx includes proper aria-label with descriptive text (lines 54-67)

📋 Minor Observations

  1. Carousel Constants: Good extraction to carousel.consts.ts for reusability
  2. useHomeCarouselCTAs Hook: Properly memoized with useCallback to prevent unnecessary re-renders
  3. Conditional Rendering: Savings message correctly only shows for Argentina Manteca payments
  4. JSDoc Comments: Good documentation in general.utils.ts (lines 217-230) and qr-payment.utils.ts

🔍 No Breaking Changes Detected

  • MANTECA_QR_PAYMENT already exists in backend (services.types.ts:451)
  • All changes are additive and backward compatible
  • Query key changes won't affect existing queries

📝 Summary

Must Fix:

  1. Extract duplicated points display to component (DRY principle)
  2. Add unit tests for qr-payment.utils.ts

Clarify:
3. Is ProfileHeader copy-to-clipboard change in scope?
4. Is Slider precision change intentional?

Great Work:

  • Performance optimizations with caching
  • Clean separation of concerns
  • Proper accessibility considerations

Would you like me to generate the complete test file and component extraction?


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

Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 823
File: src/context/kernelClient.context.tsx:79-86
Timestamp: 2025-04-29T19:36:38.121Z
Learning: When Hugo0 asks to "resolve coderabbit comments", they want to acknowledge the comment without necessarily implementing the suggested changes, as the current implementation might be intentional for their specific use case.

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

Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 942
File: src/components/AddMoney/consts/index.ts:2151-2162
Timestamp: 2025-06-30T10:44:08.048Z
Learning: Hugo0 often agrees with refactoring suggestions but defers implementation due to time constraints, preferring to track improvements as follow-up issues when they're part of larger architectural changes.

Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.

Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page after scanning MERCADO_PAGO or PIX QR codes.

@notion-workspace
Copy link

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/app/(mobile-ui)/qr-pay/page.tsx (1)

1065-1080: Consider extracting points display to a reusable component.

The points display JSX (lines 1072-1080) appears to follow a pattern that might be duplicated elsewhere. To improve maintainability and reduce duplication, consider extracting it to a reusable component.

Example component:

const PointsEarned = ({ points, elementRef }: { points: number; elementRef?: React.RefObject<HTMLDivElement> }) => (
    <div ref={elementRef} className="flex justify-center gap-2">
        <Image src={STAR_STRAIGHT_ICON} alt="star" width={20} height={20} />
        <p className="text-sm font-medium text-black">
            You&apos;ve earned {points} {points === 1 ? 'point' : 'points'}!
        </p>
    </div>
)

Usage:

-{pointsData?.estimatedPoints && (
-    <div ref={pointsDivRef} className="flex justify-center gap-2">
-        <Image src={STAR_STRAIGHT_ICON} alt="star" width={20} height={20} />
-        <p className="text-sm font-medium text-black">
-            You&apos;ve earned {pointsData.estimatedPoints}{' '}
-            {pointsData.estimatedPoints === 1 ? 'point' : 'points'}!
-        </p>
-    </div>
-)}
+{pointsData?.estimatedPoints && (
+    <PointsEarned points={pointsData.estimatedPoints} elementRef={pointsDivRef} />
+)}

Based on learnings

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d807a1 and 11e2105.

📒 Files selected for processing (1)
  • src/app/(mobile-ui)/qr-pay/page.tsx (9 hunks)
🧰 Additional context used
🧠 Learnings (14)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 942
File: src/components/AddMoney/consts/index.ts:2151-2162
Timestamp: 2025-06-30T10:44:08.048Z
Learning: Hugo0 often agrees with refactoring suggestions but defers implementation due to time constraints, preferring to track improvements as follow-up issues when they're part of larger architectural changes.
📚 Learning: 2025-10-02T15:23:01.513Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-09-08T03:13:09.111Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page after scanning MERCADO_PAGO or PIX QR codes.

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2024-10-07T15:25:45.170Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.

Applied to files:

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

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-10-29T11:27:59.248Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1368
File: src/components/Common/ActionList.tsx:109-111
Timestamp: 2025-10-29T11:27:59.248Z
Learning: In `src/components/Common/ActionList.tsx`, the `balance` from `useWallet()` hook is always in USDC (as a formatted string), making it directly comparable to USD amounts without conversion. The comparison `Number(balance) >= amountInUsd` is intentional and correct.

Applied to files:

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

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-09-08T03:13:09.111Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page.

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-09-08T03:11:00.114Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:31-41
Timestamp: 2025-09-08T03:11:00.114Z
Learning: In QR payment flows, the `createPayment` API call for payment tracking can be non-awaited when called after successful transaction execution, as it's a non-blocking logging operation and doesn't affect the user's success state.

Applied to files:

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

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-08-26T15:25:53.328Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.328Z
Learning: In `src/components/Common/ActionListDaimoPayButton.tsx`, the `handleCompleteDaimoPayment` function should not display error messages to users when DB update fails because the Daimo payment itself has succeeded - showing errors would be confusing since the payment was successful.

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-08-22T07:28:32.281Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.281Z
Learning: In `src/components/Payment/PaymentForm/index.tsx`, the `handleCompleteDaimoPayment` function is only for updating payment status in the backend after a successful Daimo payment. Payment success/failure is handled by Daimo itself, so try/catch error handling and error display are not needed for backend sync failures - users shouldn't see errors if payment succeeded but database update failed.

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
🧬 Code graph analysis (1)
src/app/(mobile-ui)/qr-pay/page.tsx (4)
src/services/points.ts (1)
  • pointsApi (6-131)
src/hooks/usePointsConfetti.ts (1)
  • usePointsConfetti (9-28)
src/constants/query.consts.ts (1)
  • TRANSACTIONS (2-2)
src/utils/qr-payment.utils.ts (3)
  • calculateSavingsInCents (9-13)
  • isArgentinaMantecaQrPayment (21-27)
  • getSavingsMessage (35-49)
⏰ 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/app/(mobile-ui)/qr-pay/page.tsx (7)

21-21: LGTM: Clean import organization and ref setup.

The new imports for points calculation, savings utilities, React Query, and the confetti hook are well-organized. The pointsDivRef is correctly typed as HTMLDivElement for anchoring the confetti animation.

Also applies to: 41-41, 45-47, 99-99


321-334: Verify SimpleFi points requirement.

The query is enabled only for MANTECA payments, and the comment states "Only Manteca QR payments give points (SimpleFi does not)". However, the PR objectives mention "points + confetti for SimpleFi", which appears inconsistent with this implementation.

Please clarify whether SimpleFi QR payments should earn points. If they should, the query enabled condition needs to be updated:

-enabled: !!(user?.user.userId && usdAmount && Number(usdAmount) > 0 && paymentProcessor === 'MANTECA'),
+enabled: !!(user?.user.userId && usdAmount && Number(usdAmount) > 0 && (paymentProcessor === 'MANTECA' || paymentProcessor === 'SIMPLEFI')),

And the action type would need to handle SimpleFi payments appropriately.


738-762: LGTM: Correct handling of balance check on success screen.

Skipping the balance check when isSuccess is true prevents confusing false-positive "insufficient balance" errors on the success screen, since the blockchain state may not have updated yet. The dependency array correctly includes isSuccess.


764-765: LGTM: Correct unconditional hook invocation.

The usePointsConfetti hook is correctly called unconditionally per React's Rules of Hooks, with conditional logic properly contained within the argument expression.


767-771: LGTM: Correct dependency array update.

Adding queryClient to the dependency array follows React's exhaustive-deps rule and is technically correct, even though queryClient is typically stable.


979-982: LGTM: Correct Argentina-specific savings calculation.

The savings calculation correctly uses the utility functions and is properly scoped to Argentina Manteca QR payments only (MERCADO_PAGO / ARGENTINA_QR3), as specified in the PR objectives.


1181-1261: Verify SimpleFi points display requirement.

The SimpleFi success view (lines 1181-1261) does not include points or savings display UI, which appears inconsistent with the PR objectives that mention "points + confetti for SimpleFi." However, the code comment at line 323 explicitly states "Only Manteca QR payments give points (SimpleFi does not)", and the points query is only enabled for MANTECA.

Please clarify:

  1. Should SimpleFi QR payments display earned points?
  2. If yes, the points display UI should be added after the payment card (around line 1207), similar to the Manteca success view (lines 1072-1080).

If SimpleFi should display points, you would need to:

  1. Update the query enabling condition (line 331) to include SimpleFi
  2. Add the points/savings display UI blocks in the SimpleFi success view
  3. Ensure the appropriate action type is used for SimpleFi in the points calculation

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.

one suggestion on abstraction of points fetching

if (!isUserKycApproved && !isUserBridgeKycUnderReview) {
_banners.push({
id: 'kyc-banner',
_carouselCTAs.push({
Copy link
Contributor

Choose a reason for hiding this comment

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

thank you hugo 🙏


{/* Points Display */}
{pointsData?.estimatedPoints && (
<div ref={pointsDivRef} className="flex justify-center gap-2">
Copy link
Contributor

Choose a reason for hiding this comment

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

qn non blocking: why is ref neded?

// Fetch points early to avoid latency penalty - fetch as soon as we have usdAmount
// This way points are cached by the time success view shows
// Only Manteca QR payments give points (SimpleFi does not)
const { data: pointsData } = useQuery({
Copy link
Contributor

Choose a reason for hiding this comment

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

could have been a hook, used two times

@Hugo0
Copy link
Contributor Author

Hugo0 commented Nov 3, 2025

@coderabbitai review new changes in depth and evaluate if PR is ready to merge

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 3, 2025

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the latest commits on the PR to see what changed since initial review
gh pr view 1392 --json commits --jq '.commits[] | {author: .authors[0].login, message: .messageHeadline, committedDate: .committedDate}'

Length of output: 730


🏁 Script executed:

#!/bin/bash
# Check if PointsEarned component was created to fix DRY violation
fd -t f "PointsEarned" --exec echo "Found: {}" \; --exec head -30 {}

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if unit tests were added for qr-payment.utils.ts
fd -e test.ts -e test.tsx -e spec.ts -e spec.tsx "qr-payment" --exec echo "Found: {}" \; --exec cat {}

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check current state of qr-pay/page.tsx to see if duplication still exists
rg -n "You've earned.*points" src/app/\(mobile-ui\)/qr-pay/page.tsx -A 2 -B 2

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Get the full current diff to see all latest changes
gh pr diff 1392 | head -1000

Length of output: 42748


🏁 Script executed:

#!/bin/bash
# Check if usePointsConfetti hook exists
fd -t f "usePointsConfetti" --exec echo "Found: {}" \; --exec cat {}

Length of output: 1191


🏁 Script executed:

#!/bin/bash
# Look at the full current qr-pay/page.tsx to see all instances of points display
rg -n "pointsData\?.estimatedPoints" src/app/\(mobile-ui\)/qr-pay/page.tsx -A 8 -B 2

Length of output: 1177


🏁 Script executed:

#!/bin/bash
# Check what test files exist in the codebase to understand testing patterns
fd -e test.ts -e test.tsx -e spec.ts -e spec.tsx . src/ | head -20

Length of output: 755


🏁 Script executed:

#!/bin/bash
# Review the new usePointsCalculation hook more carefully
cat src/hooks/usePointsCalculation.ts

Length of output: 1577


🏁 Script executed:

#!/bin/bash
# Check if there are any other new hooks or components added
git diff origin/peanut-wallet-dev --name-status | grep "^A"

Length of output: 204


🏁 Script executed:

#!/bin/bash
# Check for points display duplication in withdraw/manteca/page.tsx
rg -n "pointsData\?.estimatedPoints" src/app/\(mobile-ui\)/withdraw/manteca/page.tsx -A 8 -B 2

Length of output: 1158


🏁 Script executed:

#!/bin/bash
# List all files changed in the PR to see what's new
gh pr view 1392 --json files --jq '.files[] | select(.additions > 0) | .path' | sort

Length of output: 613


🏁 Script executed:

#!/bin/bash
# Check if qr-payment.utils.ts has any test coverage by searching for imports
rg -n "from.*qr-payment.utils" --type ts --type tsx

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Look at the exact structure of points display to count duplications
ast-grep --pattern $'<div ref={$_} className="flex justify-center gap-2">
  <Image src={STAR_STRAIGHT_ICON} alt="star" width={20} height={20} />
  <p className="text-sm font-medium text-black">
    You&apos;ve earned {$_}{" "}
    {$_ === 1 ? "point" : "points"}!
  </p>
</div>'

Length of output: 0


@Hugo0, I've reviewed the new changes. Here's my assessment:

✅ Excellent Progress Made

New Hooks Created (Great refactoring! 🎉):

  • usePointsCalculation - Cleanly encapsulates points fetching logic with proper caching, conditional enabling, and JSDoc
  • usePointsConfetti - Separates animation concerns with ref-based positioning and one-time trigger guard
  • ✅ Carousel refactoring (HomeCarouselCTA) - Clean component structure with proper accessibility

Other Improvements:

  • Good use of uniqueId parameter to prevent cache collisions
  • Proper requestAnimationFrame usage for confetti timing
  • Well-documented code with JSDoc comments

🚨 PR NOT Ready to Merge - 2 Critical Issues Remain

1. DRY Violation Still Exists

The points display JSX is still duplicated in 2 locations:

Location 1: src/app/(mobile-ui)/qr-pay/page.tsx (lines 1065-1073)

{pointsData?.estimatedPoints && (
    <div ref={pointsDivRef} className="flex justify-center gap-2">
        <Image src={STAR_STRAIGHT_ICON} alt="star" width={20} height={20} />
        <p className="text-sm font-medium text-black">
            You&apos;ve earned {pointsData.estimatedPoints}{' '}
            {pointsData.estimatedPoints === 1 ? 'point' : 'points'}!
        </p>
    </div>
)}

Location 2: src/app/(mobile-ui)/withdraw/manteca/page.tsx (lines 340-348)

{pointsData?.estimatedPoints && (
    <div ref={pointsDivRef} className="flex justify-center gap-2">
        <Image src={STAR_STRAIGHT_ICON} alt="star" width={20} height={20} />
        <p className="text-sm font-medium text-black">
            You&apos;ve earned {pointsData.estimatedPoints}{' '}
            {pointsData.estimatedPoints === 1 ? 'point' : 'points'}!
        </p>
    </div>
)}

Fix Required: Extract to a reusable component as suggested in my initial review.

2. Missing Unit Tests

src/utils/qr-payment.utils.ts still has no test coverage. Per .cursorrules: "Test new code - where tests make sense, test new code."

Testing patterns exist in the codebase at src/utils/__tests__/, but no qr-payment.utils.test.ts was created.


🎯 Action Required Before Merge

  1. Create src/components/QrPay/PointsEarned.tsx component (or similar location)
  2. Create src/utils/__tests__/qr-payment.utils.test.ts with test cases

Would you like me to generate both files for you? I can provide:

  • Complete PointsEarned component with proper TypeScript types
  • Complete test file following the existing test patterns in your codebase (Jest/Vitest)

Let me know and I'll generate them immediately! 🚀


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

Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.

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

Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.

Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 942
File: src/components/AddMoney/consts/index.ts:2151-2162
Timestamp: 2025-06-30T10:44:08.048Z
Learning: Hugo0 often agrees with refactoring suggestions but defers implementation due to time constraints, preferring to track improvements as follow-up issues when they're part of larger architectural changes.

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 11e2105 and 54cbee4.

📒 Files selected for processing (8)
  • src/app/(mobile-ui)/home/page.tsx (5 hunks)
  • src/app/(mobile-ui)/qr-pay/page.tsx (9 hunks)
  • src/app/(mobile-ui)/withdraw/manteca/page.tsx (4 hunks)
  • src/components/Home/InvitesIcon.tsx (1 hunks)
  • src/components/UserHeader/index.tsx (1 hunks)
  • src/hooks/usePointsCalculation.ts (1 hunks)
  • src/utils/qr-payment.utils.ts (1 hunks)
  • tailwind.config.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/utils/qr-payment.utils.ts
🧰 Additional context used
🧠 Learnings (24)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 942
File: src/components/AddMoney/consts/index.ts:2151-2162
Timestamp: 2025-06-30T10:44:08.048Z
Learning: Hugo0 often agrees with refactoring suggestions but defers implementation due to time constraints, preferring to track improvements as follow-up issues when they're part of larger architectural changes.
📚 Learning: 2025-10-08T17:13:13.155Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1299
File: src/app/(mobile-ui)/points/page.tsx:41-51
Timestamp: 2025-10-08T17:13:13.155Z
Learning: In `src/app/(mobile-ui)/points/page.tsx`, the icon name "invite-heart" is intentionally used (not "inviter-heart") when displaying who invited the current user, as this is a deliberate design choice despite semantic differences with UserHeader usage.

Applied to files:

  • src/app/(mobile-ui)/home/page.tsx
  • src/components/UserHeader/index.tsx
  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
  • src/components/Home/InvitesIcon.tsx
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.

Applied to files:

  • src/app/(mobile-ui)/home/page.tsx
  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-07-24T13:26:10.290Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1014
File: src/components/Claim/Link/Initial.view.tsx:413-413
Timestamp: 2025-07-24T13:26:10.290Z
Learning: In the peanut-ui repository, the change from `${SQUID_API_URL}/route` to `${SQUID_API_URL}/v2/route` in src/components/Claim/Link/Initial.view.tsx was a typo fix, not an API migration, as the codebase was already using Squid API v2.

Applied to files:

  • src/components/UserHeader/index.tsx
📚 Learning: 2025-10-02T15:23:01.513Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
  • src/app/(mobile-ui)/qr-pay/page.tsx
  • src/hooks/usePointsCalculation.ts
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2025-10-29T11:27:59.248Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1368
File: src/components/Common/ActionList.tsx:109-111
Timestamp: 2025-10-29T11:27:59.248Z
Learning: In `src/components/Common/ActionList.tsx`, the `balance` from `useWallet()` hook is always in USDC (as a formatted string), making it directly comparable to USD amounts without conversion. The comparison `Number(balance) >= amountInUsd` is intentional and correct.

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
  • src/app/(mobile-ui)/qr-pay/page.tsx
  • src/hooks/usePointsCalculation.ts
📚 Learning: 2025-07-05T16:58:25.340Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-09-11T17:46:12.507Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.507Z
Learning: Functions in Next.js that are not marked with "use server" and contain secrets are unsafe to import in client components, as they get bundled into the client JavaScript and can leak environment variables to the browser.

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2025-09-11T17:46:12.507Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.507Z
Learning: In Next.js applications, functions marked with "use server" are server actions that are safe to import in client components. Next.js generates proxy stubs for these functions, ensuring the actual implementation and any secrets (like process.env variables) remain on the server and are not bundled into the client JavaScript.

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2024-10-29T16:06:38.812Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2025-05-15T14:47:26.891Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 857
File: src/hooks/useWebSocket.ts:77-82
Timestamp: 2025-05-15T14:47:26.891Z
Learning: The useWebSocket hook in src/hooks/useWebSocket.ts is designed to provide raw history entries, while the components using it (such as HomeHistory.tsx) are responsible for implementing deduplication logic based on UUID to prevent duplicate entries when combining WebSocket data with other data sources.

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2024-11-18T21:36:11.486Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2025-08-22T07:28:32.281Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.281Z
Learning: In `src/components/Payment/PaymentForm/index.tsx`, the `handleCompleteDaimoPayment` function is only for updating payment status in the backend after a successful Daimo payment. Payment success/failure is handled by Daimo itself, so try/catch error handling and error display are not needed for backend sync failures - users shouldn't see errors if payment succeeded but database update failed.

Applied to files:

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

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-06-22T16:10:53.167Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 915
File: src/hooks/useKycFlow.ts:96-124
Timestamp: 2025-06-22T16:10:53.167Z
Learning: The `initiateKyc` function in `src/app/actions/users.ts` already includes comprehensive error handling with try-catch blocks and returns structured responses with either `{ data }` or `{ error }` fields, so additional try-catch blocks around its usage are not needed.

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2025-06-18T19:56:55.443Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 919
File: src/components/Withdraw/views/Initial.withdraw.view.tsx:87-87
Timestamp: 2025-06-18T19:56:55.443Z
Learning: In withdraw flows for Peanut Wallet, the PeanutActionDetailsCard should always display "USDC" as the token symbol because it shows the amount being withdrawn from the Peanut Wallet (which holds USDC), regardless of the destination token/chain selected by the user. The TokenSelector is used for choosing the withdrawal destination, not the source display.

Applied to files:

  • src/app/(mobile-ui)/withdraw/manteca/page.tsx
📚 Learning: 2024-10-07T15:25:45.170Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.

Applied to files:

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

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-09-08T03:13:09.111Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page after scanning MERCADO_PAGO or PIX QR codes.

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-09-08T03:13:09.111Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page.

Applied to files:

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

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2025-08-26T15:25:53.328Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.328Z
Learning: In `src/components/Common/ActionListDaimoPayButton.tsx`, the `handleCompleteDaimoPayment` function should not display error messages to users when DB update fails because the Daimo payment itself has succeeded - showing errors would be confusing since the payment was successful.

Applied to files:

  • src/app/(mobile-ui)/qr-pay/page.tsx
🧬 Code graph analysis (3)
src/app/(mobile-ui)/withdraw/manteca/page.tsx (3)
src/hooks/usePointsCalculation.ts (1)
  • usePointsCalculation (15-37)
src/hooks/usePointsConfetti.ts (1)
  • usePointsConfetti (9-28)
src/constants/query.consts.ts (1)
  • TRANSACTIONS (2-2)
src/app/(mobile-ui)/qr-pay/page.tsx (3)
src/hooks/usePointsCalculation.ts (1)
  • usePointsCalculation (15-37)
src/hooks/usePointsConfetti.ts (1)
  • usePointsConfetti (9-28)
src/utils/qr-payment.utils.ts (3)
  • calculateSavingsInCents (9-13)
  • isArgentinaMantecaQrPayment (21-27)
  • getSavingsMessage (35-49)
src/hooks/usePointsCalculation.ts (2)
src/context/authContext.tsx (1)
  • useAuth (185-191)
src/services/points.ts (1)
  • pointsApi (6-131)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Deploy-Preview
🔇 Additional comments (1)
src/components/UserHeader/index.tsx (1)

28-28: LGTM — minor spacing refinement.

The increased horizontal padding improves visual consistency with the broader UI polish effort described in the PR objectives.

@Hugo0
Copy link
Contributor Author

Hugo0 commented Nov 3, 2025

@coderabbitai review in depth again.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 3, 2025

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get latest PR commits to see what changed
gh pr view 1392 --json commits --jq '.commits[-5:] | .[] | {sha: .oid[0:7], author: .authors[0].login, message: .messageHeadline, date: .committedDate}'

echo "---"

# Check if PointsEarned component was created
echo "Checking for PointsEarned component:"
fd -t f -e tsx -e ts "PointsEarned"

echo "---"

# Check if qr-payment.utils test file was created
echo "Checking for qr-payment utils tests:"
fd -t f -e ts -e tsx "qr-payment" | grep -i test

echo "---"

# Check current state of qr-pay page for duplication
echo "Checking qr-pay page for points display duplication:"
rg -n "You've earned.*point" src/app/\(mobile-ui\)/qr-pay/page.tsx -A 3 -B 1 || echo "No matches found"

echo "---"

# Check manteca withdraw page for duplication
echo "Checking manteca page for points display duplication:"
rg -n "You've earned.*point" src/app/\(mobile-ui\)/withdraw/manteca/page.tsx -A 3 -B 1 || echo "No matches found"

echo "---"

# List all new files in the PR
echo "All files changed in PR:"
gh pr view 1392 --json files --jq '.files[] | .path' | sort

Length of output: 1541


🏁 Script executed:

#!/bin/bash
# Check how points are being displayed now in qr-pay page
echo "Current points display implementation in qr-pay/page.tsx:"
rg -n "pointsData\?.estimatedPoints" src/app/\(mobile-ui\)/qr-pay/page.tsx -A 8 -B 2

echo "---"

# Check how points are being displayed in manteca page
echo "Current points display implementation in manteca/page.tsx:"
rg -n "pointsData\?.estimatedPoints" src/app/\(mobile-ui\)/withdraw/manteca/page.tsx -A 8 -B 2

echo "---"

# Check if usePointsCalculation is being used
echo "usePointsCalculation usage in qr-pay:"
rg -n "usePointsCalculation" src/app/\(mobile-ui\)/qr-pay/page.tsx -A 3

echo "---"

# Check the qr-payment utils file to see current state
echo "Current qr-payment.utils.ts functions:"
cat src/utils/qr-payment.utils.ts

echo "---"

# Check if any test files exist in utils directory
echo "Existing test files in utils:"
fd -t f -e test.ts -e spec.ts . src/utils/

Length of output: 5051


@Hugo0, I've completed an in-depth review of the latest changes. Here's my assessment:

🚨 PR Still NOT Ready to Merge - Same 2 Critical Issues Remain

✅ Good Progress on Refactoring

You've done great work with the hooks:

  • usePointsCalculation is properly implemented and being used
  • usePointsConfetti is properly implemented and being used
  • ✅ Clean separation of concerns

❌ Critical Issue #1: DRY Violation Still Exists

The exact same 9 lines of points display JSX are still duplicated in 2 files:

File 1: src/app/(mobile-ui)/qr-pay/page.tsx (lines 1065-1073)

{pointsData?.estimatedPoints && (
    <div ref={pointsDivRef} className="flex justify-center gap-2">
        <Image src={STAR_STRAIGHT_ICON} alt="star" width={20} height={20} />
        <p className="text-sm font-medium text-black">
            You&apos;ve earned {pointsData.estimatedPoints}{' '}
            {pointsData.estimatedPoints === 1 ? 'point' : 'points'}!
        </p>
    </div>
)}

File 2: src/app/(mobile-ui)/withdraw/manteca/page.tsx (lines 340-348)

{pointsData?.estimatedPoints && (
    <div ref={pointsDivRef} className="flex justify-center gap-2">
        <Image src={STAR_STRAIGHT_ICON} alt="star" width={20} height={20} />
        <p className="text-sm font-medium text-black">
            You&apos;ve earned {pointsData.estimatedPoints}{' '}
            {pointsData.estimatedPoints === 1 ? 'point' : 'points'}!
        </p>
    </div>
)}

❌ Critical Issue #2: Missing Unit Tests

src/utils/qr-payment.utils.ts has no test coverage. Your codebase has an established test pattern in src/utils/__tests__/ with files like:

  • bridge.utils.test.ts
  • format.utils.test.ts
  • general.utils.test.ts

But qr-payment.utils.test.ts was not created.


🎯 Would you like me to generate both files?

I can immediately provide:

  1. src/components/Points/PointsEarned.tsx - Reusable component with proper types
  2. src/utils/__tests__/qr-payment.utils.test.ts - Complete unit tests following your codebase patterns

Just confirm and I'll generate both files with complete, ready-to-use code! 🚀


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

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

Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 942
File: src/components/AddMoney/consts/index.ts:2151-2162
Timestamp: 2025-06-30T10:44:08.048Z
Learning: Hugo0 often agrees with refactoring suggestions but defers implementation due to time constraints, preferring to track improvements as follow-up issues when they're part of larger architectural changes.

Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.

- Extract hardcoded URLs and IDs to constants files (DRY)
- Remove unused useCrispInitialization hook and CrispChat default component
- Clean up unused imports (resetCrispSession)
- Add clarifying comments for wallet address source
- Move Grafana/Arbiscan URLs to constants/support.ts
- Move CRISP_WEBSITE_ID to constants/crisp.ts (was duplicated 3x)
@notion-workspace
Copy link

Fix points

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/hooks/useCrispEmbedUrl.ts (1)

22-24: Simplify redundant fallback in user_nickname.

The condition on Line 22 already ensures either userData.fullName or userData.username exists, so the fallback || userData.username || '' on Line 23 is redundant. The expression can be simplified.

Apply this diff:

-        if (userData.fullName || userData.username) {
-            params.append('user_nickname', userData.fullName || userData.username || '')
-        }
+        const nickname = userData.fullName || userData.username
+        if (nickname) {
+            params.append('user_nickname', nickname)
+        }
src/app/crisp-proxy/page.tsx (1)

97-104: Potential race: fallback may double-notify parent.

The session:loaded event listener (Line 98) and the fallback timeout (Line 101) can both trigger notifyParentReady(), leading to duplicate CRISP_READY messages. While likely harmless in this context, consider tracking whether the notification has been sent to avoid unnecessary postMessages.

+        let hasNotified = false
+        const notifyOnce = () => {
+            if (!hasNotified) {
+                hasNotified = true
+                notifyParentReady()
+            }
+        }
+
-        window.$crisp.push(['on', 'session:loaded', notifyParentReady])
-        setTimeout(notifyParentReady, 1500)
+        window.$crisp.push(['on', 'session:loaded', notifyOnce])
+        setTimeout(notifyOnce, 1500)
src/hooks/useCrispProxyUrl.ts (1)

22-24: Simplify redundant fallback in user_nickname.

The condition on Line 22 already ensures either userData.fullName or userData.username exists, making the fallback || userData.username || '' on Line 23 redundant.

Apply this diff:

-        if (userData.fullName || userData.username) {
-            params.append('user_nickname', userData.fullName || userData.username || '')
-        }
+        const nickname = userData.fullName || userData.username
+        if (nickname) {
+            params.append('user_nickname', nickname)
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fb3f548 and f243f3d.

📒 Files selected for processing (12)
  • src/app/(mobile-ui)/support/page.tsx (1 hunks)
  • src/app/crisp-proxy/page.tsx (1 hunks)
  • src/components/CrispChat.tsx (1 hunks)
  • src/components/Global/SupportDrawer/index.tsx (1 hunks)
  • src/components/index.ts (1 hunks)
  • src/constants/crisp.ts (1 hunks)
  • src/constants/support.ts (1 hunks)
  • src/context/authContext.tsx (2 hunks)
  • src/hooks/useCrispEmbedUrl.ts (1 hunks)
  • src/hooks/useCrispProxyUrl.ts (1 hunks)
  • src/hooks/useCrispUserData.ts (1 hunks)
  • src/utils/crisp.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • src/constants/crisp.ts
  • src/components/index.ts
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 942
File: src/components/AddMoney/consts/index.ts:2151-2162
Timestamp: 2025-06-30T10:44:08.048Z
Learning: Hugo0 often agrees with refactoring suggestions but defers implementation due to time constraints, preferring to track improvements as follow-up issues when they're part of larger architectural changes.
📚 Learning: 2025-08-07T12:53:50.946Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1072
File: src/app/(setup)/setup/page.tsx:173-175
Timestamp: 2025-08-07T12:53:50.946Z
Learning: In the peanut-ui setup flow at `src/app/(setup)/setup/page.tsx`, when handling unsupported scenarios, both device not supported and browser not supported cases should show the same "Unsupported browser" message using the `UnsupportedBrowserModal` component, rather than having distinct messaging for each scenario.

Applied to files:

  • src/app/(mobile-ui)/support/page.tsx
📚 Learning: 2025-07-24T13:26:10.290Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1014
File: src/components/Claim/Link/Initial.view.tsx:413-413
Timestamp: 2025-07-24T13:26:10.290Z
Learning: In the peanut-ui repository, the change from `${SQUID_API_URL}/route` to `${SQUID_API_URL}/v2/route` in src/components/Claim/Link/Initial.view.tsx was a typo fix, not an API migration, as the codebase was already using Squid API v2.

Applied to files:

  • src/app/(mobile-ui)/support/page.tsx
📚 Learning: 2025-07-05T16:58:25.340Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.

Applied to files:

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

Applied to files:

  • src/context/authContext.tsx
📚 Learning: 2024-10-29T16:06:38.812Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.

Applied to files:

  • src/context/authContext.tsx
📚 Learning: 2025-09-11T17:46:12.507Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.507Z
Learning: In Next.js applications, functions marked with "use server" are server actions that are safe to import in client components. Next.js generates proxy stubs for these functions, ensuring the actual implementation and any secrets (like process.env variables) remain on the server and are not bundled into the client JavaScript.

Applied to files:

  • src/context/authContext.tsx
📚 Learning: 2025-09-11T17:46:12.507Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1200
File: src/app/(mobile-ui)/recover-funds/page.tsx:9-9
Timestamp: 2025-09-11T17:46:12.507Z
Learning: Functions in Next.js that are not marked with "use server" and contain secrets are unsafe to import in client components, as they get bundled into the client JavaScript and can leak environment variables to the browser.

Applied to files:

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

Applied to files:

  • src/context/authContext.tsx
📚 Learning: 2025-05-13T10:05:24.057Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 845
File: src/components/Request/link/views/Create.request.link.view.tsx:81-81
Timestamp: 2025-05-13T10:05:24.057Z
Learning: In the peanut-ui project, pages that handle request flows (like Create.request.link.view.tsx) are only accessible to logged-in users who will always have a username, making null checks for user?.user.username unnecessary in these contexts.

Applied to files:

  • src/hooks/useCrispUserData.ts
🧬 Code graph analysis (8)
src/hooks/useCrispEmbedUrl.ts (2)
src/constants/crisp.ts (1)
  • CRISP_WEBSITE_ID (6-6)
src/hooks/useCrispUserData.ts (1)
  • CrispUserData (6-17)
src/app/crisp-proxy/page.tsx (1)
src/constants/crisp.ts (1)
  • CRISP_WEBSITE_ID (6-6)
src/hooks/useCrispProxyUrl.ts (1)
src/hooks/useCrispUserData.ts (1)
  • CrispUserData (6-17)
src/app/(mobile-ui)/support/page.tsx (3)
src/hooks/useCrispUserData.ts (1)
  • useCrispUserData (23-56)
src/hooks/useCrispProxyUrl.ts (1)
  • useCrispProxyUrl (15-69)
src/components/Global/PeanutLoading/index.tsx (1)
  • PeanutLoading (4-19)
src/components/Global/SupportDrawer/index.tsx (4)
src/context/SupportModalContext.tsx (1)
  • useSupportModalContext (39-45)
src/hooks/useCrispUserData.ts (1)
  • useCrispUserData (23-56)
src/hooks/useCrispProxyUrl.ts (1)
  • useCrispProxyUrl (15-69)
src/components/Global/PeanutLoading/index.tsx (1)
  • PeanutLoading (4-19)
src/utils/crisp.ts (1)
src/hooks/useCrispUserData.ts (1)
  • CrispUserData (6-17)
src/context/authContext.tsx (1)
src/utils/crisp.ts (1)
  • resetCrispProxySessions (76-107)
src/hooks/useCrispUserData.ts (2)
src/context/authContext.tsx (1)
  • useAuth (192-198)
src/constants/support.ts (2)
  • GRAFANA_DASHBOARD_BASE_URL (6-7)
  • ARBISCAN_ADDRESS_BASE_URL (10-10)
⏰ 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/CrispChat.tsx (1)

5-24: LGTM! Clean refactor to proxy-based approach.

The simplified implementation clearly delegates to the SupportDrawer proxy approach, and the JSDoc comment effectively explains the architectural decision.

src/context/authContext.tsx (1)

152-156: LGTM! Properly resets Crisp sessions on logout.

The call to resetCrispProxySessions() is correctly guarded and positioned in the logout flow to prevent session merging with the next user.

src/constants/support.ts (1)

1-10: LGTM! Well-documented support constants.

Clear constant definitions with appropriate JSDoc comments.

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

10-52: LGTM! Consistent proxy integration with proper loading states.

The implementation correctly handles the loading state, origin validation, and resets when the drawer closes. The pattern is consistent with the support page implementation.

src/app/(mobile-ui)/support/page.tsx (1)

8-37: LGTM! Consistent proxy integration.

The implementation mirrors the SupportDrawer pattern with proper loading state management and origin validation. The absence of loading state reset (present in SupportDrawer) is appropriate here since page unmounting handles cleanup.

src/utils/crisp.ts (1)

56-107: Appreciate the thorough session resets. Guarding against SSR access, catching iframe failures, and flagging deferred proxies should keep Crisp sessions neatly isolated across logouts.

src/hooks/useCrispUserData.ts (1)

31-54: Like the persistent wallet/KYC sourcing. Reading the Peanut wallet address and Manteca/bridge IDs straight from the auth payload sidesteps transient ZeroDev gaps and gives support richer, durable metadata.

;(window as any).CRISP_RUNTIME_CONFIG = {
lock_maximized: true,
lock_full_view: true,
cross_origin_cookies: true, // Essential for session persistence in iframes
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify cross_origin_cookies support and necessity.

Setting cross_origin_cookies: true is flagged as "Essential for session persistence in iframes" (Line 26). Since this proxy is same-origin (not cross-origin), verify whether this setting is necessary or if it's a remnant from earlier cross-origin approaches.


🌐 Web query:

Does Crisp CRISP_RUNTIME_CONFIG cross_origin_cookies setting apply to same-origin iframes?

💡 Result:

Short answer: No — cross_origin_cookies is meant to fix cross-site / cross-origin cookie issues (external embeds/iframed pages hosted on a different domain). It isn’t required for a same-origin iframe and has no special effect there. [1][2][3]

Sources:

  • Crisp help: CRISP_RUNTIME_CONFIG example and note about fixing cross-domain cookie issues for embeds/iframed pages. [1][2]
  • Explanation of browser cookie behavior for iframes (cross-site vs same-site contexts). [3]

Remove unnecessary cross_origin_cookies setting for same-origin proxy.

cross_origin_cookies is meant to fix cross-site/cross-origin cookie issues and has no special effect for same-origin iframes. Since this proxy is same-origin, remove the cross_origin_cookies: true setting (Line 26) and its misleading comment about being essential for session persistence.

🤖 Prompt for AI Agents
In src/app/crisp-proxy/page.tsx around line 26, remove the unnecessary
cross_origin_cookies: true property and its misleading comment since this proxy
is same-origin; delete that line (and any trailing comma if needed) so the
config reflects only required options and run format/lint to ensure syntax
remains valid.

@Hugo0 Hugo0 merged commit 3ea50a3 into peanut-wallet-dev Nov 3, 2025
5 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Feb 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Being worked on Being worked on enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants