feat(manteca): BRL PIX deposit QR screen (details.depositAddresses.PIX)#2335
Conversation
Companion to peanut-api-ts #1093. For BRL, Add Money now shows Manteca's dynamic PIX QR instead of the static bank-details screen: render the copia-e-cola via QRCodeWrapper, a copy button, a live m:ss expiry countdown, and poll the deposit intent status to auto-advance to a success state. ARS path untouched. - showQR step (nuqs) routed by the response discriminator (type === 'QR') - useMantecaDepositPolling: read-only mirror of GET /manteca/deposit/:id/status - QRCodeWrapper gains an optional className width-override (160 -> 280px here) - hook + component tests
…'s details Drops MantecaPixDepositData; the dynamic QR now reads from the existing MantecaDepositResponseData.details.qr (the ramp-on synthetic), routed to showQR by currency. Matches the BE pivot (api #1093) off deposit-request. details.qr is a stub until Manteca confirms the field name.
…g screen Two PIX-deposit polish items: - Add money → Brazil now defaults the input denomination to BRL (Argentina → ARS) instead of USD — you deposit in your local currency. - Show the branded CyclingLoading screen (spinning peanut + rotating messages, same as PIX-payment processing) while the BRL QR is being generated, and in place of the plain "Preparing your PIX QR…" fallback.
…lement screen - Add money → Brazil defaults the denomination to BRL (PIX is in BRL); every other country keeps USD (Argentina reverts to USD). - useMantecaDepositPolling now surfaces a 'processing' status for the payment-settling window (Manteca PROCESSING / AWAITING_SETTLEMENT); the QR screen shows the branded CyclingLoading during it, so the flow is QR → processing → "Deposit received!".
…ire the maintenance warn
Manteca shipped the dynamic BRL QR to prod today. Probe (mono
ops/scripts/manteca/probe-brl-rampon-qr.ts) pinned the real shape: the
EMVCo copia-e-cola rides in details.depositAddresses.PIX.{code,url,
expiresAt,bankId}; the old static depositAddress/depositAlias are gone
for BRL (now optional in the type — the ARS share-details screen keeps a
'' fallback but BRL never routes there).
With the QR flow live the warn-only maintenance surface comes off:
pixBrazilOnrampMaintenance flips false (machinery stays for future
outages), the unused banner copy is trimmed to the badge, and the
maintenance test now snapshots/restores the shipped flag instead of
hardcoding true — flipping the committed default no longer poisons the
config singleton for later tests.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughThis PR adds a BRL PIX QR deposit flow to Manteca deposits: a new ChangesBRL PIX QR Deposit Feature
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
Code-analysis diffPainscore total: 5856.19 → 5869.37 (+13.18) 🆕 New findings (19)
✅ Resolved (16)
📈 Painscore deltas (top movers)
|
🧪 UI test report — ✅ all greenSuites
📊 Coverage (unit)
⏱ 10 slowest test cases
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/components/AddMoney/hooks/useMantecaDepositPolling.ts (1)
29-32: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winNo upper bound on polling duration.
refetchIntervalonly stops on a terminalstatusstring; there's no time-based cutoff tied topriceExpireAt(available onMantecaDepositResponseData.details). If a user abandons the QR screen without completing or the backend never emits a terminal status, this will poll every 5s indefinitely for as long as the tab stays open.Consider stopping (or slowing) polling once the deposit's price/QR has expired, independent of the terminal-status check.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/AddMoney/hooks/useMantecaDepositPolling.ts` around lines 29 - 32, The polling in useMantecaDepositPolling currently only stops when refetchInterval sees a terminal status, so it can run forever if the deposit never completes. Update the refetchInterval logic to also inspect MantecaDepositResponseData.details.priceExpireAt and stop or slow polling once that expiration time has passed, even when status is still non-terminal. Keep the existing TERMINAL_STATUSES check, but add the time-based cutoff in the same polling decision path so the hook no longer refetches indefinitely.src/components/AddMoney/components/__tests__/MantecaPixQrDeposit.test.tsx (1)
63-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMissing coverage for
processingstatus and the qr-loading (noqr) branch.Only
pending,expired, andcompletedare exercised; theprocessingstatus branch (CyclingLoading) and the!qrloading branch are untested.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/AddMoney/components/__tests__/MantecaPixQrDeposit.test.tsx` around lines 63 - 98, Add test coverage in MantecaPixQrDeposit.test.tsx for the missing MantecaPixQrDeposit branches: the deposit polling status 'processing' should render the CyclingLoading state, and the branch where qr is absent should render the loading/no-QR fallback. Update or add focused tests around the existing mockUseMantecaDepositPolling setup to force these states and assert the expected UI, alongside the current pending, expired, and completed cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/AddMoney/hooks/useMantecaDepositPolling.ts`:
- Around line 35-41: The polling status in useMantecaDepositPolling is ignoring
transport/API errors because it only reads data?.data?.status, so persistent
failures never transition out of pending. Update the status derivation to also
inspect data?.error (and related fetch failure state) from getDepositStatus, and
map repeated failures to a terminal failed state instead of continuing to return
pending. Use the existing useMantecaDepositPolling hook, TERMINAL_STATUSES,
PROCESSING_STATUSES, and refetchInterval logic to stop polling and surface
failure after a reasonable number of consecutive errors.
---
Nitpick comments:
In `@src/components/AddMoney/components/__tests__/MantecaPixQrDeposit.test.tsx`:
- Around line 63-98: Add test coverage in MantecaPixQrDeposit.test.tsx for the
missing MantecaPixQrDeposit branches: the deposit polling status 'processing'
should render the CyclingLoading state, and the branch where qr is absent should
render the loading/no-QR fallback. Update or add focused tests around the
existing mockUseMantecaDepositPolling setup to force these states and assert the
expected UI, alongside the current pending, expired, and completed cases.
In `@src/components/AddMoney/hooks/useMantecaDepositPolling.ts`:
- Around line 29-32: The polling in useMantecaDepositPolling currently only
stops when refetchInterval sees a terminal status, so it can run forever if the
deposit never completes. Update the refetchInterval logic to also inspect
MantecaDepositResponseData.details.priceExpireAt and stop or slow polling once
that expiration time has passed, even when status is still non-terminal. Keep
the existing TERMINAL_STATUSES check, but add the time-based cutoff in the same
polling decision path so the hook no longer refetches indefinitely.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3cc91288-5b5d-440c-80f0-906e0fe84d4a
📒 Files selected for processing (11)
src/components/AddMoney/components/MantecaAddMoney.tsxsrc/components/AddMoney/components/MantecaDepositShareDetails.tsxsrc/components/AddMoney/components/MantecaPixQrDeposit.tsxsrc/components/AddMoney/components/__tests__/MantecaPixQrDeposit.test.tsxsrc/components/AddMoney/hooks/__tests__/useMantecaDepositPolling.test.tsxsrc/components/AddMoney/hooks/useMantecaDepositPolling.tssrc/components/AddWithdraw/__tests__/AddWithdrawCountriesList.test.tsxsrc/components/Global/QRCodeWrapper/index.tsxsrc/config/underMaintenance.config.tssrc/services/manteca.tssrc/types/manteca.types.ts
| {!qr ? ( | ||
| <CyclingLoading /> |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== File outline ==\n'
ast-grep outline src/components/AddMoney/components/MantecaPixQrDeposit.tsx --view expanded || true
printf '\n== Relevant search ==\n'
rg -n "depositAddresses\\.PIX|useMantecaDepositPolling|CyclingLoading|qrTimedOut|onBack" src/components/AddMoney -S || true
printf '\n== File excerpt ==\n'
sed -n '1,220p' src/components/AddMoney/components/MantecaPixQrDeposit.tsxRepository: peanutprotocol/peanut-ui
Length of output: 13305
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Test file ==\n'
sed -n '1,220p' src/components/AddMoney/components/__tests__/MantecaPixQrDeposit.test.tsx
printf '\n== Polling hook ==\n'
sed -n '1,220p' src/components/AddMoney/hooks/useMantecaDepositPolling.ts
printf '\n== Type definition search ==\n'
rg -n "type MantecaDepositResponseData|interface MantecaDepositResponseData|depositAddresses" src/types src/components/AddMoney -SRepository: peanutprotocol/peanut-ui
Length of output: 7738
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Type file excerpt ==\n'
sed -n '1,180p' src/types/manteca.types.ts
printf '\n== Component usage search ==\n'
rg -n "MantecaPixQrDeposit|depositDetails" src/components/AddMoney -S
printf '\n== MantecaAddMoney excerpt ==\n'
sed -n '1,380p' src/components/AddMoney/components/MantecaAddMoney.tsxRepository: peanutprotocol/peanut-ui
Length of output: 24260
Add a fallback when the PIX code is missing.
depositAddresses.PIX?.code is optional here, and when it’s absent this screen stays on CyclingLoading forever. The expiry state never renders because it’s gated behind qr, and useMantecaDepositPolling only tracks settlement status. Add a timeout/error + retry/back state, or make the API guarantee the PIX code at creation time.
| const status: MantecaDepositPollStatus = useMemo(() => { | ||
| const s = data?.data?.status | ||
| if (s === 'COMPLETED') return 'completed' | ||
| if (s && TERMINAL_STATUSES.includes(s)) return 'failed' | ||
| if (s && PROCESSING_STATUSES.includes(s)) return 'processing' | ||
| return 'pending' | ||
| }, [data]) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Persistent API failures never surface as failed.
mantecaApi.getDepositStatus returns { error: data.error || 'Failed to fetch deposit status.' } on non-OK responses and { error: ... } on exceptions instead of throwing. But status here only inspects data?.data?.status — it never checks data?.error. If the status endpoint keeps erroring (bad depositId, 5xx, network blip), s stays undefined, so status resolves to 'pending' indefinitely, refetchInterval keeps polling every 5s forever, and onComplete/the failed state never fires. The user is stuck on the QR/processing screen with no failure feedback.
🔧 Proposed fix
const status: MantecaDepositPollStatus = useMemo(() => {
- const s = data?.data?.status
+ const s = data?.data?.status
+ if (!data?.data && data?.error) return 'failed'
if (s === 'COMPLETED') return 'completed'
if (s && TERMINAL_STATUSES.includes(s)) return 'failed'
if (s && PROCESSING_STATUSES.includes(s)) return 'processing'
return 'pending'
}, [data])Consider also capping consecutive failures (e.g. via failureCount) before giving up, rather than treating every fetch error as instantly terminal.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const status: MantecaDepositPollStatus = useMemo(() => { | |
| const s = data?.data?.status | |
| if (s === 'COMPLETED') return 'completed' | |
| if (s && TERMINAL_STATUSES.includes(s)) return 'failed' | |
| if (s && PROCESSING_STATUSES.includes(s)) return 'processing' | |
| return 'pending' | |
| }, [data]) | |
| const status: MantecaDepositPollStatus = useMemo(() => { | |
| const s = data?.data?.status | |
| if (!data?.data && data?.error) return 'failed' | |
| if (s === 'COMPLETED') return 'completed' | |
| if (s && TERMINAL_STATUSES.includes(s)) return 'failed' | |
| if (s && PROCESSING_STATUSES.includes(s)) return 'processing' | |
| return 'pending' | |
| }, [data]) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/AddMoney/hooks/useMantecaDepositPolling.ts` around lines 35 -
41, The polling status in useMantecaDepositPolling is ignoring transport/API
errors because it only reads data?.data?.status, so persistent failures never
transition out of pending. Update the status derivation to also inspect
data?.error (and related fetch failure state) from getDepositStatus, and map
repeated failures to a terminal failed state instead of continuing to return
pending. Use the existing useMantecaDepositPolling hook, TERMINAL_STATUSES,
PROCESSING_STATUSES, and refetchInterval logic to stop polling and surface
failure after a reasonable number of consecutive errors.
BRL PIX deposit — frontend · ✅ unblocked, wired to the prod-confirmed contract
Supersedes #2315 (same commits rebased onto
main+ the un-stub commit — repo rules block force-push, hence the new branch; targetingmainsince this fixes the currently-broken BRL deposit UX: Manteca stopped returning the static PIX key, so the old share-details screen shows nothing to pay).Adds a
showQRstep to the Manteca Add-Money flow for BRL: renders the dynamic PIX QR from the ramp-on synthetic'sdetails.depositAddresses.PIX(prod-confirmed 2026-07-02 viamono/ops/scripts/manteca/probe-brl-rampon-qr.ts), with a livem:sscountdown offpriceExpireAt(the locked-rate guarantee — the QR string itself lives ~3 days) and a "copia e cola" copy button. Status polling advances QR → processing → "Deposit received!" viaGET /manteca/deposit/:id/status. ARS keeps its existing bank-details screen, untouched.Flow:
POST /manteca/deposit (BRL)→ ramp-on synthetic withdetails.depositAddresses.PIX.code→showQR(routed by currency) → poll status →processing(settling) → success onCOMPLETED.Also in this PR:
pixBrazilOnrampMaintenanceflipsfalse(machinery stays for future outages), the in-flow banner wiring is removed, unused banner copy trimmed to the badge. Makes chore(add-money): PIX-BR onramp recovery toggle + maintenance-flag cleanup #2269 obsolete.true(adopted from chore(add-money): PIX-BR onramp recovery toggle + maintenance-flag cleanup #2269) — flipping the committed default can't poison the config singleton.details.depositAddress/depositAliasare now optional in the type (absent for BRL); the ARS share-details screen keeps a''fallback and BRL never routes there.QRCodeWrappergains an optionalclassNamewidth-override (zero blast radius on other callers).Cross-repo: depends on peanutprotocol/peanut-api-ts#1110 (status endpoint) — land BE first.
Local gate: prettier ✓ ·
tsc✓ (0 errors) · jest 1650/1654 passed, 3 skipped, 1 failure pre-existing on main (add-money-states › loaded EVM deposit shows QR code and address— crypto-deposit limits copy, unrelated; reproduced on pristine main).🤖 Generated with Claude Code