Skip to content

feat(onboarding): add email verification code UI#3052

Open
baktun14 wants to merge 2 commits intomainfrom
feat/auth0-verification-frontend
Open

feat(onboarding): add email verification code UI#3052
baktun14 wants to merge 2 commits intomainfrom
feat/auth0-verification-frontend

Conversation

@baktun14
Copy link
Copy Markdown
Contributor

@baktun14 baktun14 commented Apr 9, 2026

Why

Part of CON-197 — Replace Auth0's default email verification link with a 6-digit code flow.

This is PR 2 of 2 — frontend only. Split from #2824 to make review manageable.
Depends on PR 1 (backend): #3051

What

  • VerificationCodeInput: 6-digit OTP input with autofill support (extracted per review feedback)
  • EmailVerificationStep: code entry UI with cooldown timer and resend
  • EmailVerificationContainer: lean container orchestrating send/verify/resend (UI concerns moved to view per review feedback)
  • VerifyEmailPage: updated to use new code-based verification
  • SessionService: simplified to remove legacy verification logic
  • useEmailVerificationRequiredEventHandler: updated for code-based flow
  • Snackbar: fix DOM nesting warning
  • Unit tests for all new and modified components

13 files changed (~670 additions, ~465 deletions)

Summary by CodeRabbit

  • New Features

    • Email verification now uses 6-digit code entry with autofill support and paste functionality.
    • Added resend code button with 60-second cooldown timer.
    • Improved in-app notifications for verification code delivery and verification status.
  • Bug Fixes

    • Streamlined email verification page with automatic redirection to signup flow.

@baktun14 baktun14 requested a review from a team as a code owner April 9, 2026 23:08
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

This pull request refactors the email verification flow across the onboarding experience. The main changes replace a prop-driven verification interface with async code-send and code-verify functions, introduce a new 6-digit code input component, redirect the verification page to the onboarding flow, and migrate signup from Auth0's endpoint to the console API endpoint with simplified error handling.

Changes

Cohort / File(s) Summary
Email Verification Container Refactoring
apps/deploy-web/src/components/onboarding/steps/EmailVerificationContainer/EmailVerificationContainer.tsx, EmailVerificationContainer.spec.tsx
Replaced prop-driven UI state (isEmailVerified, isResending, isChecking, handlers) with async function props (sendCode(), verifyCode(code)). Removed snackbar/notificator dependencies and added auto-advance on user.emailVerified with analytics tracking. Updated tests to verify new callback signatures and auto-complete behavior.
Email Verification Step Implementation
apps/deploy-web/src/components/onboarding/steps/EmailVerificationStep/EmailVerificationStep.tsx, EmailVerificationStep.spec.tsx, VerificationCodeInput.tsx, VerificationCodeInput.spec.tsx
Introduced new VerificationCodeInput component with 6-digit entry, paste handling, and ref-based reset API. Refactored EmailVerificationStep to use async props, manage local resend cooldown state (60s countdown), and emit notifications via injected useNotificator. Added comprehensive tests for code input behavior, resend flow, and error handling.
Verify Email Page Simplification
apps/deploy-web/src/components/onboarding/VerifyEmailPage/VerifyEmailPage.tsx, VerifyEmailPage.spec.tsx
Removed verification mutation and state handling; now immediately redirects to onboarding signup page. Deleted VerificationResult component and conditional verification UI. Tests now focus on redirect behavior rather than verification state.
Onboarding View Integration
apps/deploy-web/src/components/onboarding/OnboardingView/OnboardingView.tsx
Updated render prop to explicitly extract and pass sendCode and verifyCode from container props instead of spreading all props.
Email Verification Event Handler Update
apps/deploy-web/src/hooks/useEmailVerificationRequiredEventHandler.tsx
Changed action from auth.sendVerificationEmail() to auth.sendVerificationCode() with updated messaging and dependencies.
Signup Service Migration
apps/deploy-web/src/services/session/session.service.ts, session.service.spec.ts
Migrated signup from Auth0 endpoint to console API POST /v1/auth/signup. Simplified error handling by removing invalid_password variant and narrowing to user_exists (409) and signup_failed cases.
Snackbar Component
packages/ui/components/custom/snackbar.tsx
Removed children prop from type; changed subtitle container from <p> to <div>.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/auth0-verification-frontend

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

Comment on lines +25 to +27
useEffect(() => {
d.redirect(d.UrlService.onboarding({ returnTo: "/" }));
}, [d]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

question: could you please clarify the purpose of this redirect?

Base automatically changed from feat/auth0-verification-backend to main April 20, 2026 18:08
…to-advance

Implement 6-digit code input with OTP autofill, cooldown timer for
resend, auto-advance on verification success, and toast notifications
for errors. Extracts VerificationCodeInput component and simplifies
EmailVerificationContainer/Step separation.
Remove redundant refs (cooldownRef, isSendingRef) that duplicated state,
fix resend button showing "Verifying..." label, remove dead user.id
guard, and inject redirect as dependency to simplify VerifyEmailPage tests.
@baktun14 baktun14 force-pushed the feat/auth0-verification-frontend branch from 126318b to 19eaf9e Compare April 20, 2026 21:09
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 20, 2026

Codecov Report

❌ Patch coverage is 83.06452% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.24%. Comparing base (50bf139) to head (19eaf9e).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...ps/EmailVerificationStep/VerificationCodeInput.tsx 78.12% 10 Missing and 4 partials ⚠️
...nts/onboarding/VerifyEmailPage/VerifyEmailPage.tsx 40.00% 3 Missing ⚠️
...ps/EmailVerificationStep/EmailVerificationStep.tsx 94.28% 2 Missing ⚠️
...nents/onboarding/OnboardingView/OnboardingView.tsx 0.00% 1 Missing ⚠️
...hooks/useEmailVerificationRequiredEventHandler.tsx 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3052      +/-   ##
==========================================
- Coverage   61.05%   60.24%   -0.81%     
==========================================
  Files        1027      988      -39     
  Lines       24593    23652     -941     
  Branches     6063     5903     -160     
==========================================
- Hits        15016    14250     -766     
+ Misses       8363     8198     -165     
+ Partials     1214     1204      -10     
Flag Coverage Δ *Carryforward flag
api 82.69% <ø> (ø) Carriedforward from 50bf139
deploy-web 45.05% <83.06%> (+0.19%) ⬆️
log-collector ?
notifications 86.06% <ø> (ø) Carriedforward from 50bf139
provider-console 81.48% <ø> (ø)
provider-proxy 85.21% <ø> (ø) Carriedforward from 50bf139
tx-signer ?

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
...rificationContainer/EmailVerificationContainer.tsx 100.00% <100.00%> (ø)
...deploy-web/src/services/session/session.service.ts 78.12% <100.00%> (-1.29%) ⬇️
...nents/onboarding/OnboardingView/OnboardingView.tsx 0.00% <0.00%> (ø)
...hooks/useEmailVerificationRequiredEventHandler.tsx 5.26% <0.00%> (+0.50%) ⬆️
...ps/EmailVerificationStep/EmailVerificationStep.tsx 94.44% <94.28%> (+94.44%) ⬆️
...nts/onboarding/VerifyEmailPage/VerifyEmailPage.tsx 62.50% <40.00%> (-26.39%) ⬇️
...ps/EmailVerificationStep/VerificationCodeInput.tsx 78.12% <78.12%> (ø)

... and 42 files with indirect coverage changes

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

Copy link
Copy Markdown
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: 5

🧹 Nitpick comments (2)
apps/deploy-web/src/services/session/session.service.spec.ts (1)

144-170: Make duplicate-user test resilient to backend status mapping.

Line [145] hardcodes 409, but this flow is contract-sensitive. Consider covering both 409 and 422 to prevent brittle behavior across backend versions.

Suggested test hardening
-    it("returns user_exists when user already exists and sign-in fails", async () => {
-      const { service, consoleApiHttpClient, externalHttpClient } = setup();
-
-      consoleApiHttpClient.post.mockResolvedValueOnce({
-        status: 409,
+    it.each([409, 422])("returns user_exists when user already exists (status %s) and sign-in fails", async duplicateStatus => {
+      const { service, consoleApiHttpClient, externalHttpClient } = setup();
+
+      consoleApiHttpClient.post.mockResolvedValueOnce({
+        status: duplicateStatus,
         data: {
           message: "The user already exists."
         },
         headers: {}
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/deploy-web/src/services/session/session.service.spec.ts` around lines
144 - 170, The duplicate-user test is brittle because it hardcodes
consoleApiHttpClient.post to return status 409; update the test around
service.signUp to accept the backend mapping change by mocking
consoleApiHttpClient.post to return either 409 or 422 (e.g., parametrize or set
up two sub-cases) while keeping externalHttpClient.post mocked as shown; ensure
the assertion on the resulting error (message "Such user already exists but
credentials are invalid" and code "user_exists") and the call count assertions
for consoleApiHttpClient.post and externalHttpClient.post remain unchanged so
the behavior is validated for both backend status variants.
apps/deploy-web/src/components/onboarding/VerifyEmailPage/VerifyEmailPage.spec.tsx (1)

10-13: Prefer getByText for this presence check.

queryByText(...).toBeInTheDocument() makes failures harder to debug because you lose the thrown query error and DOM snapshot.

Based on learnings: In apps/{deploy-web,provider-console}/**/*.spec.tsx files: Use getBy methods instead of queryBy methods when testing element presence with toBeInTheDocument() because getBy throws an error and shows DOM state when element is not found, providing better debugging information than queryBy which returns null.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/deploy-web/src/components/onboarding/VerifyEmailPage/VerifyEmailPage.spec.tsx`
around lines 10 - 13, Change the presence assertion in the "shows redirect
loading text" test to use screen.getByText instead of screen.queryByText so
failures throw with DOM snapshot; locate the test that calls setup() in
VerifyEmailPage.spec.tsx and update the expectation referencing the "Redirecting
to email verification..." string to use getByText(...).toBeInTheDocument() (test
helper: setup).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/deploy-web/src/components/onboarding/steps/EmailVerificationStep/EmailVerificationStep.tsx`:
- Around line 63-70: The reset of the verification input is being called while
isVerifying is still true so the VerificationCodeInput.reset() cannot focus
(disabled inputs ignore focus); change the finally/error handling in the async
flow around verifyCode so that setIsVerifying(false) runs before calling
codeInputRef.current?.reset(), and ensure the reset/refocus is deferred until
after the disabled state clears (e.g., call reset inside a next-tick/setTimeout
0 or after awaiting state flush) so the input can receive focus; update the code
paths around verifyCode, setIsVerifying, and codeInputRef.reset to reflect this
ordering.

In
`@apps/deploy-web/src/components/onboarding/steps/EmailVerificationStep/VerificationCodeInput.tsx`:
- Around line 49-77: The multi-character branch in handleDigitChange currently
treats any value.length > 1 as a paste/autofill and scatters characters into
subsequent cells, which causes a typed replacement like "oldChar+newChar" to
spill instead of replacing the current box; update handleDigitChange so that
when value.length > 1 you first check the current stored digit at that index
(use digits or setDigits(prev => ...) to read prev[index]) and if that slot was
already populated and value.length === 2 treat it as a replacement: write the
last character of value into newDigits[index] (not shifting the old one forward)
and only spread any remaining characters after that; otherwise (empty slot or
true paste/autofill of multiple chars) keep the existing
fill-into-following-cells behavior. Apply the same fix to the duplicate logic in
the other identical handler (the block noted around the other occurrence).

In
`@apps/deploy-web/src/components/onboarding/VerifyEmailPage/VerifyEmailPage.tsx`:
- Around line 14-16: The redirect implementation in the redirect function
currently sets window.location.href which adds a history entry and causes a
back-button loop for the transient VerifyEmailPage; change it to use
location.replace(url) so the /verify-email step is not kept in history. Update
the redirect function that writes ONBOARDING_STEP_KEY and currently calls
window.location.href to call window.location.replace(url) (preserving the
existing localStorage write to OnboardingStepIndex.EMAIL_VERIFICATION).

In `@apps/deploy-web/src/hooks/useEmailVerificationRequiredEventHandler.tsx`:
- Around line 24-31: The analytics event name
"resend_verification_email_btn_clk" is now incorrect for the button that calls
auth.sendVerificationCode(); update the event emitted by analyticsService.track
in the onClick handler to a new, distinct name (e.g.,
"send_verification_code_btn_clk" or similar) so this flow is not merged with the
old resend metric; locate the analyticsService.track call in
useEmailVerificationRequiredEventHandler (the onClick handler that calls
auth.sendVerificationCode) and replace the string, and update any related tests
or analytics mapping entries that expect the old event name.

In `@apps/deploy-web/src/services/session/session.service.ts`:
- Around line 96-99: The duplicate-user detection in session.service.ts is using
status 409 but the backend maps Auth0's duplicate-user to 422, so update the
check (the isUserExists assignment that currently compares signupResponse.status
=== 409) to treat 422 as the duplicate case (e.g., compare against 422 or
include both 409 and 422), so that the existing branch (return Err when status
>=400 and !isUserExists) and the idempotent fallback in password-signup.ts are
triggered correctly; locate the signupResponse handling in the signup function
in session.service.ts and adjust the status check accordingly.

---

Nitpick comments:
In
`@apps/deploy-web/src/components/onboarding/VerifyEmailPage/VerifyEmailPage.spec.tsx`:
- Around line 10-13: Change the presence assertion in the "shows redirect
loading text" test to use screen.getByText instead of screen.queryByText so
failures throw with DOM snapshot; locate the test that calls setup() in
VerifyEmailPage.spec.tsx and update the expectation referencing the "Redirecting
to email verification..." string to use getByText(...).toBeInTheDocument() (test
helper: setup).

In `@apps/deploy-web/src/services/session/session.service.spec.ts`:
- Around line 144-170: The duplicate-user test is brittle because it hardcodes
consoleApiHttpClient.post to return status 409; update the test around
service.signUp to accept the backend mapping change by mocking
consoleApiHttpClient.post to return either 409 or 422 (e.g., parametrize or set
up two sub-cases) while keeping externalHttpClient.post mocked as shown; ensure
the assertion on the resulting error (message "Such user already exists but
credentials are invalid" and code "user_exists") and the call count assertions
for consoleApiHttpClient.post and externalHttpClient.post remain unchanged so
the behavior is validated for both backend status variants.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b6b50647-33f9-4d31-8564-eab3c0f9772f

📥 Commits

Reviewing files that changed from the base of the PR and between 50bf139 and 19eaf9e.

📒 Files selected for processing (13)
  • apps/deploy-web/src/components/onboarding/OnboardingView/OnboardingView.tsx
  • apps/deploy-web/src/components/onboarding/VerifyEmailPage/VerifyEmailPage.spec.tsx
  • apps/deploy-web/src/components/onboarding/VerifyEmailPage/VerifyEmailPage.tsx
  • apps/deploy-web/src/components/onboarding/steps/EmailVerificationContainer/EmailVerificationContainer.spec.tsx
  • apps/deploy-web/src/components/onboarding/steps/EmailVerificationContainer/EmailVerificationContainer.tsx
  • apps/deploy-web/src/components/onboarding/steps/EmailVerificationStep/EmailVerificationStep.spec.tsx
  • apps/deploy-web/src/components/onboarding/steps/EmailVerificationStep/EmailVerificationStep.tsx
  • apps/deploy-web/src/components/onboarding/steps/EmailVerificationStep/VerificationCodeInput.spec.tsx
  • apps/deploy-web/src/components/onboarding/steps/EmailVerificationStep/VerificationCodeInput.tsx
  • apps/deploy-web/src/hooks/useEmailVerificationRequiredEventHandler.tsx
  • apps/deploy-web/src/services/session/session.service.spec.ts
  • apps/deploy-web/src/services/session/session.service.ts
  • packages/ui/components/custom/snackbar.tsx

Comment on lines +63 to +70
try {
await verifyCode(code);
notificator.success("Your email has been successfully verified");
} catch (error) {
notificator.error(d.extractErrorMessage(error as AppError));
codeInputRef.current?.reset();
} finally {
setIsVerifying(false);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Failed verification clears the code but drops focus.

VerificationCodeInput.reset() focuses the first box immediately, but Line 68 calls it while disabled={isVerifying} is still true. Browsers ignore focus on disabled inputs, so after an invalid code the field is cleared but keyboard users have to click back into it. Defer the reset/refocus until after isVerifying is cleared.

Possible fix
       } catch (error) {
         notificator.error(d.extractErrorMessage(error as AppError));
-        codeInputRef.current?.reset();
+        setTimeout(() => codeInputRef.current?.reset(), 0);
       } finally {
         setIsVerifying(false);
       }
📝 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.

Suggested change
try {
await verifyCode(code);
notificator.success("Your email has been successfully verified");
} catch (error) {
notificator.error(d.extractErrorMessage(error as AppError));
codeInputRef.current?.reset();
} finally {
setIsVerifying(false);
try {
await verifyCode(code);
notificator.success("Your email has been successfully verified");
} catch (error) {
notificator.error(d.extractErrorMessage(error as AppError));
setTimeout(() => codeInputRef.current?.reset(), 0);
} finally {
setIsVerifying(false);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/deploy-web/src/components/onboarding/steps/EmailVerificationStep/EmailVerificationStep.tsx`
around lines 63 - 70, The reset of the verification input is being called while
isVerifying is still true so the VerificationCodeInput.reset() cannot focus
(disabled inputs ignore focus); change the finally/error handling in the async
flow around verifyCode so that setIsVerifying(false) runs before calling
codeInputRef.current?.reset(), and ensure the reset/refocus is deferred until
after the disabled state clears (e.g., call reset inside a next-tick/setTimeout
0 or after awaiting state flush) so the input can receive focus; update the code
paths around verifyCode, setIsVerifying, and codeInputRef.reset to reflect this
ordering.

Comment on lines +49 to +77
const handleDigitChange = useCallback(
(index: number, value: string) => {
if (!/^\d*$/.test(value) || disabled) return;

if (value.length > 1) {
const filled = value.slice(0, CODE_LENGTH - index);
setDigits(prev => {
const newDigits = [...prev];
for (let i = 0; i < filled.length; i++) {
newDigits[index + i] = filled[i];
}
return newDigits;
});
const nextIndex = index + filled.length;
if (nextIndex < CODE_LENGTH) {
inputRefs.current[nextIndex]?.focus();
}
return;
}

setDigits(prev => {
const newDigits = [...prev];
newDigits[index] = value;
return newDigits;
});
if (value && index < CODE_LENGTH - 1) {
inputRefs.current[index + 1]?.focus();
}
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Editing a filled digit can overwrite later boxes.

If a user clicks back into a populated box and types a new digit, the browser can hand onChange a 2-character value like "19". Lines 53-66 currently treat every multi-character value as paste/autofill, so the new character spills into the next cells instead of replacing the current one.

Possible fix
         <Input
           key={index}
           ref={el => {
             inputRefs.current[index] = el;
           }}
           type="text"
           aria-label={`Verification code digit ${index + 1}`}
           autoComplete={index === 0 ? "one-time-code" : "off"}
           inputMode="numeric"
           value={digit}
+          onFocus={e => e.currentTarget.select()}
           onChange={e => handleDigitChange(index, e.target.value)}
           onKeyDown={e => handleKeyDown(index, e)}
           className="h-12 w-12"

Also applies to: 112-123

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/deploy-web/src/components/onboarding/steps/EmailVerificationStep/VerificationCodeInput.tsx`
around lines 49 - 77, The multi-character branch in handleDigitChange currently
treats any value.length > 1 as a paste/autofill and scatters characters into
subsequent cells, which causes a typed replacement like "oldChar+newChar" to
spill instead of replacing the current box; update handleDigitChange so that
when value.length > 1 you first check the current stored digit at that index
(use digits or setDigits(prev => ...) to read prev[index]) and if that slot was
already populated and value.length === 2 treat it as a replacement: write the
last character of value into newDigits[index] (not shifting the old one forward)
and only spread any remaining characters after that; otherwise (empty slot or
true paste/autofill of multiple chars) keep the existing
fill-into-following-cells behavior. Apply the same fix to the duplicate logic in
the other identical handler (the block noted around the other occurrence).

Comment on lines +14 to +16
redirect: (url: string) => {
window.localStorage.setItem(ONBOARDING_STEP_KEY, OnboardingStepIndex.EMAIL_VERIFICATION.toString());
window.location.href = url;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use location.replace for this redirect page.

window.location.href adds /verify-email to history, so Back lands here and immediately redirects again. For a transient page like this, that creates a back-button loop.

Suggested change
   redirect: (url: string) => {
     window.localStorage.setItem(ONBOARDING_STEP_KEY, OnboardingStepIndex.EMAIL_VERIFICATION.toString());
-    window.location.href = url;
+    window.location.replace(url);
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/deploy-web/src/components/onboarding/VerifyEmailPage/VerifyEmailPage.tsx`
around lines 14 - 16, The redirect implementation in the redirect function
currently sets window.location.href which adds a history entry and causes a
back-button loop for the transient VerifyEmailPage; change it to use
location.replace(url) so the /verify-email step is not kept in history. Update
the redirect function that writes ONBOARDING_STEP_KEY and currently calls
window.location.href to call window.location.replace(url) (preserving the
existing localStorage write to OnboardingStepIndex.EMAIL_VERIFICATION).

Comment on lines +24 to +31
label: "Send verification code",
side: "left",
size: "lg",
onClick: () => {
analyticsService.track("resend_verification_email_btn_clk", "Amplitude");
if (!user?.id) {
return;
}

auth
.sendVerificationEmail(user.id)
.sendVerificationCode()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Rename the analytics event to match the new action.

Line 28 still emits resend_verification_email_btn_clk, but this button now sends a code. Keeping the old event name will merge two different flows into the same metric and skew the onboarding data.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/deploy-web/src/hooks/useEmailVerificationRequiredEventHandler.tsx`
around lines 24 - 31, The analytics event name
"resend_verification_email_btn_clk" is now incorrect for the button that calls
auth.sendVerificationCode(); update the event emitted by analyticsService.track
in the onClick handler to a new, distinct name (e.g.,
"send_verification_code_btn_clk" or similar) so this flow is not merged with the
old resend metric; locate the analyticsService.track call in
useEmailVerificationRequiredEventHandler (the onClick handler that calls
auth.sendVerificationCode) and replace the string, and update any related tests
or analytics mapping entries that expect the old event name.

Comment on lines +96 to +99
const isUserExists = signupResponse.status === 409;
if (signupResponse.status >= 400 && !isUserExists) {
return Err({
message: signupResponse.data.friendly_message || signupResponse.data.message || signupResponse.data.description || "Signup failed",
message: signupResponse.data?.message || "Signup failed",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify duplicate-signup status contract and affected callers.
rg -n -C4 --type ts '"/v1/auth/signup"|statusCode === 409|createError\(422|createError\(409' apps/api/src/auth
rg -n -C4 --type ts 'code === "user_exists"|signup_failed|status === 409|status === 422' \
  apps/deploy-web/src/services/session/session.service.ts \
  apps/deploy-web/src/pages/api/auth/password-signup.ts

Repository: akash-network/console

Length of output: 5092


Check for 422 status code, not 409, for duplicate-user handling.

The backend converts Auth0's 409 (user exists) to a 422 status code before sending the response (see auth.controller.ts lines 32–33). Line 96 checks only for 409, so duplicate signup attempts incorrectly return signup_failed instead of user_exists, bypassing the idempotent fallback logic in password-signup.ts.

Proposed fix
-    const isUserExists = signupResponse.status === 409;
+    const isUserExists = signupResponse.status === 422;
📝 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.

Suggested change
const isUserExists = signupResponse.status === 409;
if (signupResponse.status >= 400 && !isUserExists) {
return Err({
message: signupResponse.data.friendly_message || signupResponse.data.message || signupResponse.data.description || "Signup failed",
message: signupResponse.data?.message || "Signup failed",
const isUserExists = signupResponse.status === 422;
if (signupResponse.status >= 400 && !isUserExists) {
return Err({
message: signupResponse.data?.message || "Signup failed",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/deploy-web/src/services/session/session.service.ts` around lines 96 -
99, The duplicate-user detection in session.service.ts is using status 409 but
the backend maps Auth0's duplicate-user to 422, so update the check (the
isUserExists assignment that currently compares signupResponse.status === 409)
to treat 422 as the duplicate case (e.g., compare against 422 or include both
409 and 422), so that the existing branch (return Err when status >=400 and
!isUserExists) and the idempotent fallback in password-signup.ts are triggered
correctly; locate the signupResponse handling in the signup function in
session.service.ts and adjust the status check accordingly.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants