Skip to content

🚸 app: handle invalid id flow#769

Open
franm91 wants to merge 1 commit intomainfrom
manteca
Open

🚸 app: handle invalid id flow#769
franm91 wants to merge 1 commit intomainfrom
manteca

Conversation

@franm91
Copy link
Member

@franm91 franm91 commented Feb 12, 2026


Open with Devin

Summary by CodeRabbit

  • New Features

    • New flow to resume/update KYC for invalid tax IDs, preserving session so users can continue verification; updated KYC UI text and action labels.
  • Bug Fixes

    • Any non-"complete" verification now routes to an error flow and clears related cached data; improved onboarding status handling and back-navigation behavior.
  • Localization

    • Added Spanish translations for new KYC and verification messages.

@changeset-bot
Copy link

changeset-bot bot commented Feb 12, 2026

🦋 Changeset detected

Latest commit: cf2b0b2

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link

coderabbitai bot commented Feb 12, 2026

Walkthrough

Adds an "invalid legal id" recovery flow: server can return inquiry/session tokens on that error; client caches tokens, routes users to a resumed KYC flow that reuses tokens via startMantecaKYC, clears the cache on completion/error, and introduces pending-state handling, UI text/translation updates, and a small navigation tweak.

Changes

Cohort / File(s) Summary
Server: ramp onboarding error shape
src/utils/server.ts
Detects invalid legal id error responses and returns { code, inquiryId, sessionToken } for that case instead of throwing; expands valibot imports.
Onboarding orchestration
src/utils/completeOnboarding.ts
Captures startRampOnboarding result; when inquiryId present caches tokens at ["ramp","invalid-legal-id"] and routes to /add-funds/kyc; otherwise routes to status with pending=true; still invalidates providers and reports errors.
Persona/KYC token plumbing
src/utils/persona.ts
Extends manteca state with optional tokens; startMantecaKYC(tokens?) accepts/reuses provided tokens to avoid re-requesting tokens and stores tokens on the current manteca state.
KYC UI & behavior
src/components/add-funds/KYC.tsx
Reads cached invalidLegalId tokens and passes them to startMantecaKYC; treats any non-complete status as error and clears the cached tokens on both error and success; updates title/detail text and primary button labels based on presence of invalidLegalId.
Status & pending handling
src/components/add-funds/Status.tsx
Parses pending URL param with a 5s timeout, conditionally fetches providers and countryCode, auto-navigates to ramp when Manteca provider is ACTIVE, and shows a disabled "Verifying..." + Spinner until ready; Close button shown only when ready.
Navigation tweak
src/components/add-funds/Onboard.tsx
Uses replace instead of push when KYC status is not started, changing history/back behavior.
Translations
src/i18n/es.json
Adds four Spanish strings for invalid-ID messaging, "Update information", and "Verifying...".
Release notes
.changeset/sparkly-pugs-accept.md
Adds a changeset entry noting the patch release and invalid-id flow handling.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Client as Client App
    participant Server
    participant Cache as QueryCache
    participant KYC as Manteca KYC

    User->>Client: Start ramp onboarding
    Client->>Server: startRampOnboarding()
    alt Server returns success
        Server-->>Client: success response
        Client->>Client: navigate to /add-funds/status?pending=true
    else Server returns invalid legal id
        Server-->>Client: { code: "invalid legal id", inquiryId, sessionToken }
        Client->>Cache: set ["ramp","invalid-legal-id"] = {inquiryId, sessionToken}
        Client->>Client: navigate to /add-funds/kyc
        Client->>Cache: get ["ramp","invalid-legal-id"]
        Client->>KYC: startMantecaKYC(tokens={inquiryId, sessionToken})
        KYC->>User: present resumed KYC flow
        User-->>KYC: completes verification
        KYC-->>Client: result = "complete"
        Client->>Cache: delete ["ramp","invalid-legal-id"]
        Client->>Client: navigate to /add-funds/status
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • cruzdanilo
  • dieguezguille
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ⚠️ Unable to check for merge conflicts: Stream setup permanently failed: 14 UNAVAILABLE: read ECONNRESET
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'handle invalid id flow' accurately reflects the main change: adding support for managing invalid legal ID scenarios across multiple components and utilities.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 manteca
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch manteca
  • Create stacked PR with resolved conflicts
  • Post resolved changes as copyable diffs in a comment

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.

❤️ Share

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

@sentry
Copy link

sentry bot commented Feb 12, 2026

Codecov Report

❌ Patch coverage is 0% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.32%. Comparing base (48a97e6) to head (cf2b0b2).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/utils/persona.ts 0.00% 6 Missing ⚠️
src/utils/server.ts 0.00% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #769      +/-   ##
==========================================
- Coverage   68.46%   68.32%   -0.15%     
==========================================
  Files         207      207              
  Lines        7059     7030      -29     
  Branches     2214     2200      -14     
==========================================
- Hits         4833     4803      -30     
- Misses       2029     2034       +5     
+ Partials      197      193       -4     
Flag Coverage Δ
e2e 68.03% <0.00%> (-0.31%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 4 potential issues.

View 3 additional findings in Devin Review.

Open in Devin Review

const { code } = await response.json();
throw new APIError(response.status, code);
const body = await response.json();
if (body.code === "invalid legal id") {

Choose a reason for hiding this comment

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

🚩 Hardcoded error code string bypasses shared constant

The comparison body.code === "invalid legal id" uses a hardcoded string literal rather than referencing the MantecaErrorCodes.INVALID_LEGAL_ID constant that the server uses (server/api/ramp.ts:211). If the server-side constant value ever changes, this client-side check would silently stop matching, causing the "invalid legal id" flow to be treated as a generic API error instead.

The @exactly/common package is already used for shared constants (e.g., AUTH_EXPIRY, domain, Credential). The error code string could be moved there to ensure consistency between client and server.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Member Author

Choose a reason for hiding this comment

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

The error code string is part of the HTTP API contract, not shared business logic — if the server value changes, the frontend safely falls back to the generic APIError path, and the server's own integration tests (which hardcode the same string) would break first.

Comment on lines 38 to 50
const { data: providers, isFetching } = useQuery({
queryKey: ["ramp", "providers", countryCode],
queryFn: () => getRampProviders(countryCode),
enabled: isPending && timedOut && !!countryCode,
});

useEffect(() => {
if (providers?.manteca.status === "ACTIVE" && currency) {
router.replace({ pathname: "/add-funds/ramp", params: { currency } });
}
}, [providers, currency, router]);

const ready = !isPending || (timedOut && !isFetching);

Choose a reason for hiding this comment

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

🚩 Providers query only polls once — no retry if status isn't ACTIVE yet

The pending flow in Status.tsx waits 5 seconds (setTimeout at line 33), then fetches providers exactly once (no refetchInterval). If the manteca status isn't ACTIVE after that single fetch, the ready variable becomes true (line 50: timedOut && !isFetching), and the user sees the "Close" button with the message "We're verifying your information. You'll be able to add funds soon."

This appears to be a deliberate design choice — the page acts as a notification that verification is in progress, not as a real-time polling screen. The user closes and returns later. However, if the server typically processes onboarding within 10-30 seconds, adding a refetchInterval (e.g., poll every 5 seconds for up to 60 seconds) could improve the user experience by auto-redirecting to the ramp page once the status becomes ACTIVE.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is deliberate. getRampProviders is an expensive backend query, and polling would risk leaving the user waiting indefinitely if a non-timing error occurs. if the status is already ACTIVE, we auto-redirect; otherwise, the user closes and returns later.

@gemini-code-assist
Copy link

Summary of Changes

Hello @franm91, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refines the user experience for the Know Your Customer (KYC) onboarding process, particularly when issues arise with a user's identification. It introduces a dedicated flow for invalid legal IDs, allowing users to re-engage with the verification process with specific guidance. Additionally, it enhances the feedback provided during the initial onboarding by introducing a pending state, ensuring users are informed about the ongoing verification without being stuck on an unresponsive screen.

Highlights

  • Enhanced KYC Flow for Invalid IDs: Implemented a new flow to gracefully handle cases where a user's legal ID is deemed invalid during the KYC process, allowing them to update their information rather than encountering a generic error.
  • Improved Onboarding Status Handling: Introduced a 'pending' status for the onboarding process, providing a better user experience by displaying a 'Verifying...' state with a timeout before allowing the user to close the screen or proceed.
  • Dynamic UI Updates: Modified the KYC screen to dynamically adjust text and button labels based on whether an invalid legal ID has been detected, guiding the user more clearly on the next steps.
  • KYC Session Resumption: Updated the startMantecaKYC function to accept existing inquiry and session tokens, enabling the resumption of a KYC flow if a previous attempt resulted in an invalid ID.
  • Internationalization Updates: Added new Spanish translations for the updated UI texts related to invalid ID status and verification.
Changelog
  • .changeset/sparkly-pugs-accept.md
    • Added a new changeset file to document the patch for @exactly/mobile related to handling invalid ID flow.
  • src/components/add-funds/KYC.tsx
    • Imported queryClient for state management.
    • Retrieved invalidLegalId data from queryClient to determine the state of the KYC process.
    • Passed invalidLegalId to startMantecaKYC to allow for resuming an existing inquiry.
    • Removed invalid-legal-id query data upon successful KYC completion.
    • Conditionally rendered UI text and button labels based on the presence of an invalidLegalId.
  • src/components/add-funds/Status.tsx
    • Imported useEffect, useState, Spinner, useQuery, and getRampProviders for enhanced status handling.
    • Extracted a pending parameter from local search params to manage the verification state.
    • Implemented a 5-second timeout for the pending state and logic to re-fetch ramp providers.
    • Conditionally rendered a 'Verifying...' spinner or a 'Close' button based on the ready state of the verification process.
  • src/i18n/es.json
    • Added new translation keys for 'Your ID needs to be updated', 'There was an issue with your tax ID. Please update your information to continue.', 'Update information', and 'Verifying...'.
  • src/utils/completeOnboarding.ts
    • Modified startRampOnboarding call to check for an inquiryId in the result.
    • Set invalid-legal-id query data and redirected to the KYC screen if an inquiryId is returned.
    • Added a pending: 'true' parameter to the status page redirection to indicate ongoing verification.
  • src/utils/persona.ts
    • Updated startMantecaKYC to accept an optional tokens object (containing inquiryId and sessionToken).
    • Used provided tokens if available, otherwise fetched new tokens for KYC initiation.
  • src/utils/server.ts
    • Imported object and string from valibot for schema validation.
    • Modified startRampOnboarding to specifically check for an 'invalid legal id' error code.
    • Returned inquiryId and sessionToken when an 'invalid legal id' error occurs, instead of throwing a generic API error.
Activity
  • The pull request description includes a Devin review badge, indicating it may have undergone automated review.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@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: 3

🤖 Fix all issues with AI agents
In `@src/components/add-funds/KYC.tsx`:
- Line 38: The call to startMantecaKYC uses a redundant nullish-coalescing to
undefined; remove the "?? undefined" and pass invalidLegalId directly
(invalidLegalId is already typed as { inquiryId: string; sessionToken: string }
| undefined from queryClient.getQueryData). Update the invocation of
startMantecaKYC(invalidLegalId) accordingly to simplify the code.

In `@src/utils/completeOnboarding.ts`:
- Around line 10-17: The cached Persona tokens stored via
queryClient.setQueryData(["ramp","invalid-legal-id"]) can become stale if the
user abandons the KYC screen; update the flow so this cache is not left
indefinitely: either attach an expiry/gc marker when setting the data (e.g.,
store a timestamp or gcTime alongside inquiryId/sessionToken) and have KYC.tsx
check and reject expired entries before calling startMantecaKYC, or ensure the
KYC cancel/error and route-change handlers call
queryClient.removeQueries(["ramp","invalid-legal-id"]) to clear the entry;
modify the code that sets the cache in completeOnboarding (the
queryClient.setQueryData call) and the KYC cancel/error handlers (the place that
currently removes the entry on success) so stale tokens are evicted
automatically or explicitly removed on abandon.

In `@src/utils/persona.ts`:
- Around line 135-139: The current promise reuse in startMantecaKYC can return
an in-flight promise that was created with a different tokens value; update the
logic that checks the shared current promise so it also compares the incoming
tokens argument to the tokens used to create the existing promise (or store a
small object {promise, tokens} instead of just promise) and only reuse
current.promise when the tokens match; otherwise create a new promise that
awaits import("persona") and tokens ?? getKYCTokens(...), then set current to
the new {promise, tokens} before returning. Ensure references to current,
startMantecaKYC, and getKYCTokens are updated accordingly.

Comment on lines +10 to +17
if ("inquiryId" in result) {
queryClient.setQueryData(["ramp", "invalid-legal-id"], {
inquiryId: result.inquiryId,
sessionToken: result.sessionToken,
});
router.replace({ pathname: "/add-funds/kyc", params: { currency } });
return;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Stale cached tokens if user abandons the KYC screen.

The ["ramp", "invalid-legal-id"] cache entry is only removed on successful KYC completion (KYC.tsx Line 44). If the user navigates away (e.g., presses back or the app backgrounds), the tokens remain cached indefinitely. On a later visit to KYC.tsx, expired Persona tokens would be passed to startMantecaKYC, likely producing an opaque error.

Consider also clearing the cache on cancel/error, or setting a gcTime on this query data so stale tokens are automatically evicted.

Proposed fix in KYC.tsx mutationFn
     async mutationFn() {
       if (!currency) return;
       const result = await startMantecaKYC(invalidLegalId ?? undefined);
-      if (result.status === "cancel") return;
+      if (result.status === "cancel") {
+        queryClient.removeQueries({ queryKey: ["ramp", "invalid-legal-id"] });
+        return;
+      }
       if (result.status !== "complete") {
+        queryClient.removeQueries({ queryKey: ["ramp", "invalid-legal-id"] });
         router.replace({ pathname: "/add-funds/status", params: { status: "error", currency } });
         return;
       }
🤖 Prompt for AI Agents
In `@src/utils/completeOnboarding.ts` around lines 10 - 17, The cached Persona
tokens stored via queryClient.setQueryData(["ramp","invalid-legal-id"]) can
become stale if the user abandons the KYC screen; update the flow so this cache
is not left indefinitely: either attach an expiry/gc marker when setting the
data (e.g., store a timestamp or gcTime alongside inquiryId/sessionToken) and
have KYC.tsx check and reject expired entries before calling startMantecaKYC, or
ensure the KYC cancel/error and route-change handlers call
queryClient.removeQueries(["ramp","invalid-legal-id"]) to clear the entry;
modify the code that sets the cache in completeOnboarding (the
queryClient.setQueryData call) and the KYC cancel/error handlers (the place that
currently removes the entry on success) so stale tokens are evicted
automatically or explicitly removed on abandon.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new user flow to handle cases where a user's legal ID is invalid during the KYC process. The changes are well-structured, modifying the API client to handle the specific error case, updating the onboarding logic to redirect the user, and adjusting the KYC screen to present the user with context-specific information for re-verification. A significant improvement opportunity has been identified in the Status.tsx component, where the current implementation for checking the verification status could lead to a confusing user experience. My review includes a suggestion to implement polling for a more robust and user-friendly status update mechanism, which remains valid as it does not contradict any provided rules.

Comment on lines +38 to +42
const { data: providers, isFetching } = useQuery({
queryKey: ["ramp", "providers", countryCode],
queryFn: () => getRampProviders(countryCode),
enabled: isPending && timedOut && !!countryCode,
});

Choose a reason for hiding this comment

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

high

The current implementation to fetch provider status will only run once after the initial 5-second timeout. If the backend verification is not complete by then, the user will be shown a "Close" button and will not receive further updates, potentially leading to a confusing experience where they are not aware the process is still running. To provide a better user experience and automatically update the status, you should implement polling.

Suggested change
const { data: providers, isFetching } = useQuery({
queryKey: ["ramp", "providers", countryCode],
queryFn: () => getRampProviders(countryCode),
enabled: isPending && timedOut && !!countryCode,
});
const { data: providers, isFetching } = useQuery({
queryKey: ["ramp", "providers", countryCode],
queryFn: () => getRampProviders(countryCode),
enabled: isPending && timedOut && !!countryCode,
refetchInterval: (query) => (query.state.data?.manteca.status === "ACTIVE" ? false : 5000),
});

Copy link
Member Author

Choose a reason for hiding this comment

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

good catch but in this case is deliberate. getRampProviders is an expensive backend query, and polling would risk leaving the user waiting indefinitely if a non-timing error occurs. if the status is already ACTIVE, we auto-redirect; otherwise, the user closes and returns later.

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 6 additional findings in Devin Review.

Open in Devin Review

Comment on lines 44 to 46
}
queryClient.removeQueries({ queryKey: ["ramp", "invalid-legal-id"] });
await completeOnboarding(router, currency);

Choose a reason for hiding this comment

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

🚩 Potential loop between KYC and completeOnboarding if server keeps returning invalid-legal-id

After a successful Persona inquiry in the invalid-legal-id flow (result.status === "complete"), completeOnboarding is called again (line 46), which calls startRampOnboarding. If the server still returns "invalid legal id" (e.g., the user submitted the same invalid document), completeOnboarding sets new query data and navigates back to KYC, creating a cycle: KYC → Persona complete → completeOnboarding → invalid legal id → KYC → ...

This isn't an infinite loop in the strict sense (it requires user interaction at each step — the user must click the button and complete the Persona inquiry each time), but it could be a confusing UX if the server-side validation keeps rejecting the document. There's no maximum retry counter or different error handling after repeated failures.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is intentional, the only way to validate the updated document is by calling startRampOnboarding again, since manteca performs the legal ID validation server-side during onboarding. Each iteration requires explicit user action
There is no client-side way to pre-validate whether the new document will be accepted.

Copy link

@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: 2

🤖 Fix all issues with AI agents
In `@src/components/add-funds/Status.tsx`:
- Around line 37-42: The useQuery call for the ["user","country"] key (data
assigned to countryCode) lacks a queryFn and is enabled by default, which can
cause runtime fetch errors or unexpected fetches in React Query v5; change this
to read cached value instead of attempting a fetch by either using
queryClient.getQueryData(["user","country"]) where countryCode is needed or make
the useQuery explicitly non-fetching (add enabled: false) and read its data from
the cache, and ensure the providers query (queryKey
["ramp","providers",countryCode], queryFn getRampProviders, enabled: isPending
&& timedOut && !!countryCode) still uses the cache-backed countryCode so
auto-navigation behavior remains correct if getKYCStatus(..., true) has
previously populated the ["user","country"] cache.

In `@src/utils/persona.ts`:
- Around line 141-145: The Promise.all currently awaits getRedirectURI() inline
which forces evaluate it before import("persona") can start; hoist the redirect
URI resolution into its own promise/variable before the Promise.all so
import("persona") and the getKYCTokens(...) invocation run in parallel — e.g.,
call getRedirectURI() (or create a redirectUriPromise) first, then use
Promise.all([{ import("persona") }, tokens ?? getKYCTokens("manteca", await
redirectUriPromise)]) to ensure import("persona") and token retrieval execute
concurrently; update the code around the Platform.OS === "web" block and the
references to import("persona") and getKYCTokens to use the hoisted
promise/variable.

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 7 additional findings in Devin Review.

Open in Devin Review

@franm91 franm91 force-pushed the manteca branch 2 times, most recently from 9afdb94 to 5a9335f Compare February 13, 2026 12:34
Copy link

@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

🤖 Fix all issues with AI agents
In `@src/utils/server.ts`:
- Around line 306-314: The startRampOnboarding response currently returns two
shapes causing brittle discrimination by `"inquiryId" in result`; update
startRampOnboarding to return a tagged union (e.g., success object with a
distinct tag like { status: "ok", data: ... } or include a unique discriminator
field on the error path like { code, inquiryId, sessionToken }) so consumers can
reliably discriminate by the tag/`code` field; then update completeOnboarding.ts
to check the explicit discriminator (e.g., `result.status === "ok"` or `'code'
in result`) instead of testing for `inquiryId`. Reference startRampOnboarding
and completeOnboarding.ts when applying the change and ensure types/signatures
are updated accordingly.

Copy link

@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: 2

Comment on lines +29 to +32
const invalidLegalId = queryClient.getQueryData<{ inquiryId: string; sessionToken: string }>([
"ramp",
"invalid-legal-id",
]);
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Reading query cache outside a hook won't trigger re-renders.

queryClient.getQueryData is a snapshot read — if ["ramp", "invalid-legal-id"] changes while this component is mounted, the UI won't update. This is currently safe because the value is only set before navigating here and cleared inside the mutation, but it's worth noting for future maintainability. If re-render reactivity is ever needed, switch to useQueryClient().getQueryData inside the mutation or useQuery with enabled: false.

Comment on lines +44 to +48
useEffect(() => {
if (isPending && providers?.manteca.status === "ACTIVE" && currency) {
router.replace({ pathname: "/add-funds/ramp", params: { currency } });
}
}, [isPending, providers, currency, router]);
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Auto-navigation effect: if manteca status is not ACTIVE, user sees Close after timeout with no retry.

When providers?.manteca.status is not "ACTIVE" (e.g., still "ONBOARDING" or "PENDING"), the effect doesn't navigate, and once timedOut && !isFetching the user only sees the "Close" button. There's no polling or retry mechanism — the user must manually close and re-enter the flow.

This may be intentional (the screen says "We're verifying your information"), but if the expectation is that manteca status transitions to ACTIVE within seconds, consider adding refetchInterval to the providers query so it polls until active or a max attempt is reached.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant