feat: handle manteca qr-pay kyc gating#1225
feat: handle manteca qr-pay kyc gating#1225jjramirezn merged 2 commits intofeat/manteca-integrationfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded@kushagrasarathe has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 58 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughAdds a KYC gate to the QR pay flow using a new hook. Defers payment fetching until gate allows. Introduces a server action to resolve Bridge customer country, redirect URL utilities, KYC modal success callbacks, WebSocket-driven KYC updates, identity verification redirect handling, and minor form cleanup. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
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 Pre-merge checks❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
|
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (8)
src/components/Kyc/InitiateMantecaKYCModal.tsx (1)
77-84: Align prop optionality with usage (?.)
onKycSuccessis required in the prop type but invoked with optional chaining. Make it optional for consistency and backward compatibility.Apply:
- onKycSuccess: () => void + onKycSuccess?: () => voidsrc/components/AddMoney/UserDetailsForm.tsx (1)
20-21:isSubmittingprop is ignored — either remove it or wire it to inputsParent passes
isSubmitting, but the component no longer uses it. Either drop the prop across call sites or use it to disable inputs to prevent edits during submit.Apply:
-export const UserDetailsForm = forwardRef<{ handleSubmit: () => void }, UserDetailsFormProps>( - ({ onSubmit, onValidChange, initialData }, ref) => { +export const UserDetailsForm = forwardRef<{ handleSubmit: () => void }, UserDetailsFormProps>( + ({ onSubmit, onValidChange, initialData, isSubmitting }, ref) => { ... - <BaseInput + <BaseInput {...field} type={type} placeholder={placeholder} + disabled={!!isSubmitting} className="h-12 w-full rounded-sm border border-n-1 bg-white px-4 text-sm" />Also applies to: 63-69
src/hooks/useMantecaKycFlow.ts (1)
46-55: Avoid magic string for completion status
'WIDGET_FINISHED'is a raw string; prefer a single source of truth to prevent typos and ease future changes.Apply:
+ const MANTECA_COMPLETION_STATUSES = new Set<string>([MantecaKycStatus.ACTIVE, 'WIDGET_FINISHED']) ... - onMantecaKycStatusUpdate: async (status) => { - if (status === MantecaKycStatus.ACTIVE || status === 'WIDGET_FINISHED') { + onMantecaKycStatusUpdate: async (status) => { + if (MANTECA_COMPLETION_STATUSES.has(status)) { await fetchUser() handleIframeClose('completed') } },Also consider lifting the string into a typed union or enum in
@/interfaceswhen feasible.src/utils/general.utils.ts (1)
1220-1228: Tighten types and clear expiry key as well
- Return
string | nullfor clarity.- Remove the paired
-expirykey to avoid stale entries if expiry is ever used.Apply:
-export const getRedirectUrl = () => { - return getFromLocalStorage('redirect') -} +export const getRedirectUrl = (): string | null => { + return (getFromLocalStorage('redirect') as string | null) ?? null +} -export const clearRedirectUrl = () => { - if (typeof localStorage !== 'undefined') { - localStorage.removeItem('redirect') - } -} +export const clearRedirectUrl = () => { + if (typeof localStorage !== 'undefined') { + localStorage.removeItem('redirect') + localStorage.removeItem('redirect-expiry') + } +}src/components/Profile/views/IdentityVerification.view.tsx (1)
23-23: Sanitize stored redirect before navigationEven though you store a relative URL, sanitize the value at use to guard against unexpected contents.
Apply:
-import { getRedirectUrl, clearRedirectUrl } from '@/utils/general.utils' +import { getRedirectUrl, clearRedirectUrl, sanitizeRedirectURL } from '@/utils/general.utils' ... - const handleRedirect = useCallback(() => { + const handleRedirect = useCallback(() => { const redirectUrl = getRedirectUrl() if (redirectUrl) { clearRedirectUrl() - router.push(redirectUrl) + router.push(sanitizeRedirectURL(redirectUrl)) } else { router.replace('/profile') } }, [router])Also applies to: 38-46
src/app/actions/bridge/get-customer.ts (1)
58-58: Remove debug console.log.Leftover debug string in server logs; keep noise out.
- console.log('normalized kushagra', normalized)src/app/(mobile-ui)/qr-pay/page.tsx (1)
236-284: Show a loader during KYC gate LOADING.Currently renders header + empty body. Display a spinner for better UX.
- if (shouldBlockPay) { + if (shouldBlockPay) { + if (kycGateState === QrKycState.LOADING) { + return <PeanutLoading /> + } return ( <div className="flex min-h-[inherit] flex-col gap-8">src/hooks/useQrKycGate.ts (1)
18-22: Doc nit: The hook doesn’t inspect “country of the QR code.”It checks user KYC and Bridge country. Tweak wording to avoid confusion.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/app/(mobile-ui)/qr-pay/page.tsx(8 hunks)src/app/actions/bridge/get-customer.ts(1 hunks)src/components/AddMoney/UserDetailsForm.tsx(1 hunks)src/components/Kyc/InitiateMantecaKYCModal.tsx(2 hunks)src/components/Profile/views/IdentityVerification.view.tsx(4 hunks)src/hooks/useMantecaKycFlow.ts(2 hunks)src/hooks/useQrKycGate.ts(1 hunks)src/utils/general.utils.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-05-15T14:47:26.891Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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/hooks/useMantecaKycFlow.ts
📚 Learning: 2025-05-15T14:45:45.632Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#857
File: src/hooks/useWebSocket.ts:5-5
Timestamp: 2025-05-15T14:45:45.632Z
Learning: For the WebSocketStatus type in useWebSocket.ts, it was decided to keep it as a non-exported type until there's a specific need to export it. The team prefers to address potential issues when they become actual requirements rather than preemptively.
Applied to files:
src/hooks/useMantecaKycFlow.ts
📚 Learning: 2025-08-20T09:08:19.266Z
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#1112
File: src/components/Claim/Link/views/BankFlowManager.view.tsx:336-343
Timestamp: 2025-08-20T09:08:19.266Z
Learning: In the KYC flow implementation, `setJustCompletedKyc` must be called after `await fetchUser()` in the `handleKycSuccess` callback. Setting `justCompletedKyc` before fetching the user would cause a re-fetching loop because `handleKycSuccess` is set in a useEffect inside the KYC hook, which would cause the UI flow to get stuck in one view.
Applied to files:
src/hooks/useMantecaKycFlow.tssrc/app/(mobile-ui)/qr-pay/page.tsxsrc/components/Profile/views/IdentityVerification.view.tsx
📚 Learning: 2025-09-08T03:13:09.111Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#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-12-02T17:19:18.532Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#551
File: src/components/Request/Create/Views/Initial.view.tsx:151-156
Timestamp: 2024-12-02T17:19:18.532Z
Learning: In the `InitialView` component at `src/components/Request/Create/Views/Initial.view.tsx`, when setting the default chain and token in the `useEffect` triggered by `isPeanutWallet`, it's acceptable to omit the setters from the dependency array and not include additional error handling for invalid defaults.
Applied to files:
src/app/(mobile-ui)/qr-pay/page.tsx
📚 Learning: 2024-10-25T11:33:46.776Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#484
File: src/components/Cashout/Components/Initial.view.tsx:273-274
Timestamp: 2024-10-25T11:33:46.776Z
Learning: In the `InitialCashoutView` component (`src/components/Cashout/Components/Initial.view.tsx`), linked bank accounts should not generate error states, and the `ValidatedInput` component will clear any error messages if needed. Therefore, it's unnecessary to manually clear the error state when selecting or clearing linked bank accounts.
Applied to files:
src/components/AddMoney/UserDetailsForm.tsx
📚 Learning: 2025-08-14T14:42:54.411Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1094
File: src/utils/withdraw.utils.ts:181-191
Timestamp: 2025-08-14T14:42:54.411Z
Learning: The countryCodeMap in src/components/AddMoney/consts/index.ts uses uppercase 3-letter country codes as keys (like 'AUT', 'BEL', 'CZE') that map to 2-letter country codes, requiring input normalization to uppercase for proper lookups.
Applied to files:
src/app/actions/bridge/get-customer.ts
🧬 Code graph analysis (5)
src/hooks/useMantecaKycFlow.ts (2)
src/context/authContext.tsx (1)
useAuth(182-188)src/hooks/useWebSocket.ts (1)
useWebSocket(19-186)
src/app/(mobile-ui)/qr-pay/page.tsx (5)
src/hooks/useQrKycGate.ts (1)
useQrKycGate(23-71)src/components/Global/DirectSendQR/utils.ts (1)
isPaymentProcessorQR(100-107)src/services/manteca.ts (1)
mantecaApi(89-166)src/components/Kyc/InitiateMantecaKYCModal.tsx (1)
MantecaGeoSpecificKycModal(72-126)src/utils/general.utils.ts (3)
saveRedirectUrl(1214-1218)getRedirectUrl(1220-1222)clearRedirectUrl(1224-1228)
src/hooks/useQrKycGate.ts (2)
src/context/authContext.tsx (1)
useAuth(182-188)src/app/actions/bridge/get-customer.ts (1)
getBridgeCustomerCountry(38-66)
src/app/actions/bridge/get-customer.ts (3)
src/components/AddMoney/consts/index.ts (1)
countryData(271-2439)src/utils/__mocks__/next-cache.ts (1)
unstable_cache(1-1)src/constants/general.consts.ts (2)
PEANUT_API_URL(43-47)PEANUT_API_KEY(49-49)
src/components/Profile/views/IdentityVerification.view.tsx (2)
src/utils/general.utils.ts (2)
getRedirectUrl(1220-1222)clearRedirectUrl(1224-1228)src/hooks/useBridgeKycFlow.ts (1)
useBridgeKycFlow(30-180)
🔇 Additional comments (12)
src/components/Kyc/InitiateMantecaKYCModal.tsx (1)
118-121: Close-then-callback sequencing looks goodClosing the modal before invoking
onKycSuccessavoids UI flicker and duplicate actions. LGTM.src/components/AddMoney/UserDetailsForm.tsx (1)
26-27: Form-state narrowing is fineUsing only
{ errors, isValid }is sufficient here and reduces unnecessary re-renders.src/hooks/useMantecaKycFlow.ts (2)
30-45: Centralized iframe close handler is correctClear branching: completed →
onSuccess, manual →onManualClose, fallback →onClose. This removes duplication and clarifies intent. LGTM.
25-26: Fetch-before-success matches prior KYC loop fixCalling
await fetchUser()before firing success prevents the known re-fetch loop. Good alignment with prior learnings.src/components/Profile/views/IdentityVerification.view.tsx (3)
48-52: Bridge KYC: fetch-then-redirect is correctEnsures fresh user state before post-KYC routing. Matches documented sequencing.
53-56: Confirm Manteca KYC fetch timing
useMantecaKycFlowfetches user on completion before invokingonKycSuccess. Please confirm no additional fetch is required here and that this doesn’t re-trigger any effects downstream.
255-256: WiringonKycSuccessto Manteca modalHooking the redirect callback into the geo-specific modal is correct and completes the flow. LGTM.
src/app/actions/bridge/get-customer.ts (2)
18-29: Good: ISO3→ISO2 map built once with uppercase normalization.This aligns with our prior learning about 3-letter keys mapping to 2-letter codes and avoids lookup misses.
31-36: Good: Country normalization handles ISO2 and ISO3 cleanly.Straightforward and returns null on unknowns.
src/app/(mobile-ui)/qr-pay/page.tsx (2)
136-149: LGTM: Deferring payment-lock fetch until KYC gate passes.Prevents premature requests and aligns UI flow with gating.
420-430: LGTM: Pay button disabled while gated or invalid.Good guardrail to prevent premature actions.
src/hooks/useQrKycGate.ts (1)
34-41: LGTM: Short‑circuit when Manteca KYC is active.Correctly unblocks flow early for verified users.
jjramirezn
left a comment
There was a problem hiding this comment.
Approved! Nice hook the useQrKycGate
| * It checks the user's KYC status and the country of the QR code to determine the appropriate action. | ||
| * @returns {QrKycGateResult} An object with the KYC gate state and a boolean indicating if the user should be blocked from paying. | ||
| */ | ||
| export function useQrKycGate(): QrKycGateResult { |
There was a problem hiding this comment.
praise: I like this hook!!!
Uh oh!
There was an error while loading. Please reload this page.