Skip to content

fix(card): reopen WebSDK on Sumsub level transition instead of timing out#2171

Open
Hugo0 wants to merge 2 commits into
devfrom
fix/card-apply-level-transition
Open

fix(card): reopen WebSDK on Sumsub level transition instead of timing out#2171
Hugo0 wants to merge 2 commits into
devfrom
fix/card-apply-level-transition

Conversation

@Hugo0

@Hugo0 Hugo0 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Card-apply can chain two Sumsub levels back-to-back: MAIN (e.g. Rain-required SELFIE after liveness was added to the level config) followed by rain-card-application (occupation / salary / purpose / monthly-volume questionnaire). When the user finishes MAIN, the BE's next /rain/cards call returns status: 'incomplete' with a new token at rain-card-application — that's a level transition, not "Sumsub auto-review still pending".

The old handleSumsubComplete polled "until status != incomplete" for 15s, read the level-transition response as still pending, timed out, and surfaced "Verification is taking longer than expected. Please try again." Users on a single-level path were fine; users in the MAIN→action chain (anyone whose existing Sumsub applicant was missing a doc Rain's level config now requires) hit a wall.

This PR:

  • Tracks the level the WebSDK was opened at (lastSumsubLevelRef).
  • New helper resolvePostSumsubAction branches on that level:
    • just-completed MAIN → single fetch, expect incomplete + new token, reopen the WebSDK at rain-card-application. Falls through to advance in the edge case where BE skips straight to terms-required (returning user whose questionnaire was already filled).
    • just-completed rain-card-application → keep the existing poll-for-settle behavior (Sumsub auto-review for the questionnaire really can be eventually consistent).
  • Returns a discriminated union (reopen-websdk / advance / timeout / aborted); the page just switches on kind.

The existing pollUntilApplyAdvances helper is untouched — semantics preserved for callers that aren't on the level-transition path.

Risks

  • FE-only. No BE / API contract change. No DB. No cross-repo deploy order.
  • Behavioral diff for users in the MAIN→action chain: previously hit "taking longer than expected" error; now hit a second WebSDK that prompts the questionnaire. Both flows match what the BE is telling the FE to do.
  • The fast-path skips polling for ~14s in the MAIN→action case. If a future BE change moved Sumsub auto-review work to the level-transition response, we'd surface incomplete data sooner — but the BE today does no Sumsub work on a fresh action; it just returns the token. Worth re-checking if BE auto-review semantics change.

Test plan

  • npx jest src/components/Card/__tests__/cardApply.utils.test.ts — 14/14 pass (6 existing + 8 new for resolvePostSumsubAction covering: MAIN→reopen, MAIN→skip-to-terms edge, normal action-level advance, poll timeout, signal-aborted-on-entry, signal-aborted-mid-poll, null-level fallback, fetch-error propagation).
  • npm run typecheck clean on changed files (one pre-existing SEOFooter.tsx worktree-submodule artifact, unrelated).
  • pnpm prettier --check clean.
  • pnpm eslint clean on changed files.
  • CI green.
  • CodeRabbit review.
  • /code-review pass.
  • Sandbox QA — set up a user whose main applicant is approved but missing a Rain-required doc; tap "Get your card"; verify FE opens MAIN WebSDK for the missing doc, then reopens at rain-card-application instead of error-screen; complete questionnaire; proceeds to terms-required → card issued. Regression: confirm single-level path (all main docs present) still polls-and-advances as before.

Out of scope (follow-ups)

  • Sumsub byExternalActionId API quirk: returns 404 for an action that byActionId/one returns 200 for. Existing list-fallback in src/sumsub/service.ts:319-333 already masks it functionally; worth filing with Sumsub support, not blocking this PR.
  • WAITLIST_SKIP badge not in BE's SKIP_BADGE_CODES allowlist — separate small PR on peanut-api-ts, best gated on Konrad's [TASK-12497] Feat/context instead of storage #953 foundation landing.

… out

The card-apply flow can chain TWO Sumsub levels: MAIN (e.g. Rain-required
SELFIE) followed by `rain-card-application` (occupation/salary/purpose
questionnaire). When the user finished MAIN, the next /rain/cards call
returned `status:'incomplete'` with a new token at the next level —
`handleSumsubComplete`'s "poll until non-incomplete" loop read that as
"Sumsub auto-review still pending" and timed out at 15s, leaving the user
on a generic "Verification is taking longer than expected" error instead
of progressing to the questionnaire.

Track the level the WebSDK was opened at; on close, branch:
- just-completed MAIN → single fetch, reopen WebSDK at the new level
- just-completed `rain-card-application` → keep the existing poll-for-settle

`resolvePostSumsubAction` encapsulates the dispatch so the rule is
unit-testable; covers the level transition, the skip-to-terms edge case
(returning user with questionnaire pre-filled), poll-timeout, abort, and
error-propagation paths.
@vercel

vercel Bot commented Jun 2, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
peanut-wallet Ready Ready Preview, Comment Jun 2, 2026 9:53pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@Hugo0, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 27 minutes and 37 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0bca092b-f6da-4d3f-813c-76fe81c9c153

📥 Commits

Reviewing files that changed from the base of the PR and between 3d12bf0 and e026d51.

📒 Files selected for processing (3)
  • src/app/(mobile-ui)/card/page.tsx
  • src/components/Card/__tests__/cardApply.utils.test.ts
  • src/components/Card/cardApply.utils.ts

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

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 5835.46 → 5837.54 (+2.08)
Findings: +1 net (+5 new, -4 resolved)

🆕 New findings (5)

  • critical complexity — src/app/(mobile-ui)/card/page.tsx — CC 101, MI 56.62, SLOC 410
  • high hotspot — src/app/(mobile-ui)/card/page.tsx — 31 commits, +975/-377 lines since 6 months ago
  • medium high-mdd — src/app/(mobile-ui)/card/page.tsx:52 — CardPage: MDD 93.4 (uses across many lines from declarations)
  • medium complexity — src/components/Card/cardApply.utils.ts — CC 15, MI 53.45, SLOC 50
  • low high-mdd — src/app/(mobile-ui)/card/page.tsx:358 — : MDD 15.6 (uses across many lines from declarations)

✅ Resolved (4)

  • src/app/(mobile-ui)/card/page.tsx — CC 98, MI 57.24, SLOC 389
  • src/app/(mobile-ui)/card/page.tsx:52 — CardPage: MDD 87.3 (uses across many lines from declarations)
  • src/app/(mobile-ui)/card/page.tsx — 29 commits, +927/-370 lines since 6 months ago
  • src/components/Card/cardApply.utils.ts — CC 7, MI 63.59, SLOC 17

📈 Painscore deltas (top movers)

File Before After Δ
src/components/Card/cardApply.utils.ts 5.1 6.7 +1.6
src/app/(mobile-ui)/card/page.tsx 13.8 14.3 +0.5

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • unit: 1270 ran, 0 failed, 0 skipped, 20.3s

📊 Coverage (unit)

metric %
statements 50.2%
branches 31.1%
functions 34.4%
lines 50.0%
⏱ 10 slowest test cases
time test
0.4s src/app/actions/__tests__/api-headers.test.ts › should include Content-Type in updateUserById
0.3s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › every stamp stays within canvas at any count
0.3s src/app/actions/__tests__/api-headers-extended.test.ts › should not include apiKey in updateUserById body
0.2s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › Manteca PIX form ready shows merchant card + amount input + pay button
0.1s src/components/Request/__tests__/request-states.test.tsx › API failure shows error message and toast
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid UK IBAN with spaces
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid 9-digit US account
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle too long for US account
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid Italian IBAN
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle invalid ETH address (missing 0x prefix)
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

@Hugo0

Hugo0 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

…iveness guard

Two /code-review follow-ups on the prior commit:

1. Analytics drift on the reopened (action-level) WebSDK: `handleSumsubComplete`
   sets `sumsubCompletedRef.current = true` at entry so a subsequent close of
   the just-completed WebSDK doesn't fire `CARD_SUMSUB_CLOSED`. But the new
   `reopen-websdk` branch immediately opens the SDK AGAIN at the next level,
   and if the user abandons the questionnaire there, the flag is still `true`
   from the MAIN completion → `handleSumsubClose` skips the abandonment
   metric. Reset to `false` inside the `reopen-websdk` case before the new
   `setSumsubToken` so questionnaire abandonment is counted.

2. Switch on `action.kind` had no `default`. Adding a future variant to
   `PostSumsubAction` would silently fall through. Add the
   `_exhaustive: never = action` pattern so TS catches it at compile time.
@Hugo0 Hugo0 marked this pull request as ready for review June 2, 2026 21:55
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