From 55cf4923b818d570d64e6d1d8fbfd3a060ee759c Mon Sep 17 00:00:00 2001 From: Eric Gullickson <16152721+ericgullickson@users.noreply.github.com> Date: Mon, 22 Dec 2025 21:34:05 -0600 Subject: [PATCH] feat: onboarding pre-work --- Makefile | 10 +- ONBOARDING-FIX.md | 193 +++++++++++ backend/src/_system/cli/create-admin.ts | 315 ++++++++++++++++++ .../src/core/auth/auth0-management.client.ts | 5 +- .../migrations/001_create_admin_users.sql | 6 +- .../api/user-profile.controller.ts | 12 +- .../api/user-profile.validation.ts | 1 - .../domain/user-profile.service.ts | 10 +- docs/PROMPTS.md | 11 +- .../components/DeleteAccountDialog.tsx | 19 +- .../settings/mobile/DeleteAccountModal.tsx | 25 +- .../features/settings/types/profile.types.ts | 1 - 12 files changed, 537 insertions(+), 71 deletions(-) create mode 100644 ONBOARDING-FIX.md create mode 100644 backend/src/_system/cli/create-admin.ts diff --git a/Makefile b/Makefile index c3e9265..6ee2bc6 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help setup start stop clean logs shell-backend shell-frontend migrate rebuild traefik-dashboard traefik-logs service-discovery network-inspect health-check-all mobile-setup db-shell-app install type-check lint build-local +.PHONY: help setup start stop clean logs shell-backend shell-frontend migrate create-admin rebuild traefik-dashboard traefik-logs service-discovery network-inspect health-check-all mobile-setup db-shell-app install type-check lint build-local help: @echo "MotoVaultPro - Simplified 5-Container Architecture" @@ -14,6 +14,7 @@ help: @echo " make shell-backend - Open shell in backend container" @echo " make shell-frontend - Open shell in frontend container" @echo " make migrate - Run database migrations" + @echo " make create-admin - Create initial admin user (fresh deployments only)" @echo "" @echo "K8s-Ready Architecture Commands:" @echo " make traefik-dashboard - Access Traefik service discovery dashboard" @@ -94,6 +95,13 @@ migrate: @docker compose exec mvp-backend node dist/_system/migrations/run-all.js @echo "Migrations completed." +create-admin: + @echo "" + @echo "Creating initial admin user..." + @echo "This command is only for fresh deployments with no existing admins." + @echo "" + @docker compose exec -it mvp-backend node dist/_system/cli/create-admin.js + rebuild: @echo "Rebuilding containers with latest code changes..." @docker compose up -d --build --remove-orphans diff --git a/ONBOARDING-FIX.md b/ONBOARDING-FIX.md new file mode 100644 index 0000000..8db4066 --- /dev/null +++ b/ONBOARDING-FIX.md @@ -0,0 +1,193 @@ +# Fix New User Signup Wizard Flow + +## Problem Summary +The new user signup wizard is broken: +1. After Auth0 callback, users go to `/garage` instead of `/verify-email` +2. Users can access `/garage/*` without verified email +3. Onboarding flow is bypassed entirely +4. **New Requirement**: Block login completely at Auth0 for unverified users + +## Root Causes +1. **Auth0Provider.tsx:29** - `onRedirectCallback` defaults to `/garage` without checking verification +2. **App.tsx:472-481** - Callback route just shows "Processing login..." with no routing logic +3. **App.tsx:549+** - Protected routes have no email verification check +4. **Auth0** - No rule/action blocking unverified users from logging in + +--- + +## Implementation Plan + +### Phase 1: Auth0 Configuration (Manual Step) + +**Auth0 Dashboard -> Actions -> Flows -> Login** + +Create a Post Login Action to block unverified users: + +```javascript +exports.onExecutePostLogin = async (event, api) => { + if (!event.user.email_verified) { + api.access.deny('Please verify your email address before logging in. Check your inbox for a verification link.'); + } +}; +``` + +This ensures: +- Unverified users cannot get a JWT +- They see a clear error on the Auth0 login screen +- They must click the verification link before logging in + +### Phase 2: Update Signup Flow + +**After signup, redirect to a "Check Your Email" page (not /verify-email)** + +The new flow: +1. User submits signup form +2. Backend creates Auth0 user (unverified) +3. Auth0 automatically sends verification email +4. Frontend shows "Check Your Email" page with: + - Message: "We've sent a verification link to your email" + - Resend button (calls public resend endpoint) + - "Back to Login" button +5. User clicks email link -> Auth0 marks as verified +6. User can now login -> goes to /onboarding + +### Phase 3: Backend Changes + +**File: `backend/src/features/auth/api/auth.routes.ts`** +- Add `POST /api/auth/resend-verification-public` (no JWT required) +- Takes email address, looks up user, resends verification + +**File: `backend/src/features/auth/api/auth.controller.ts`** +- Add `resendVerificationPublic` handler + +**File: `backend/src/features/auth/domain/auth.service.ts`** +- Add `resendVerificationByEmail` method + +**File: `backend/src/features/auth/api/auth.routes.ts`** +- Add `GET /api/auth/user-status` (JWT required) +- Returns: `{ emailVerified, onboardingCompleted, email }` + +**File: `backend/src/core/plugins/auth.plugin.ts`** +- Add `/api/auth/user-status` to `VERIFICATION_EXEMPT_ROUTES` + +### Phase 4: Create Callback Handler + +**File: `frontend/src/features/auth/pages/CallbackPage.tsx`** (NEW) +- Fetches user status after Auth0 callback +- Routes based on status: + - Not onboarded -> `/onboarding` + - Onboarded -> `/garage` (or returnTo) +- Note: Unverified users never reach this (blocked by Auth0) + +**File: `frontend/src/features/auth/mobile/CallbackMobileScreen.tsx`** (NEW) +- Mobile version + +### Phase 5: Update Auth0Provider + +**File: `frontend/src/core/auth/Auth0Provider.tsx`** + +Update `onRedirectCallback` (line 27-31): + +```typescript +const onRedirectCallback = (appState?: { returnTo?: string }) => { + navigate('/callback', { + replace: true, + state: { returnTo: appState?.returnTo || '/garage' } + }); +}; +``` + +### Phase 6: Rename/Update Verify Email Page + +**File: `frontend/src/features/auth/pages/VerifyEmailPage.tsx`** +- Rename concept to "Check Your Email" page +- Remove polling (user can't be authenticated) +- Show static message + resend button (calls public endpoint) +- Add "Back to Login" button + +**File: `frontend/src/features/auth/mobile/VerifyEmailMobileScreen.tsx`** +- Same changes for mobile + +### Phase 7: Update App.tsx Routing + +**File: `frontend/src/App.tsx`** + +1. Replace callback handling (lines 472-481) with CallbackPage +2. Add onboarding guard after authentication check +3. Remove email verification check from frontend (Auth0 handles it) + +```typescript +// After isAuthenticated check: +// Fetch onboarding status +// If not onboarded -> /onboarding +// Otherwise -> proceed to /garage +``` + +### Phase 8: Create Supporting Files + +**File: `frontend/src/core/auth/useUserStatus.ts`** (NEW) +- Hook for fetching user status + +**File: `frontend/src/features/auth/api/auth.api.ts`** +- Add `getUserStatus()` +- Add `resendVerificationPublic(email)` (no auth) + +--- + +## Files to Modify + +### Auth0 (Manual Configuration) +- Create Post Login Action to block unverified users + +### Backend +- `backend/src/features/auth/api/auth.routes.ts` - Add endpoints +- `backend/src/features/auth/api/auth.controller.ts` - Add handlers +- `backend/src/features/auth/domain/auth.service.ts` - Add methods +- `backend/src/core/plugins/auth.plugin.ts` - Update exempt routes + +### Frontend +- `frontend/src/core/auth/Auth0Provider.tsx` - Fix onRedirectCallback +- `frontend/src/App.tsx` - Add route guards and callback handler +- `frontend/src/features/auth/pages/CallbackPage.tsx` - NEW +- `frontend/src/features/auth/mobile/CallbackMobileScreen.tsx` - NEW +- `frontend/src/features/auth/pages/VerifyEmailPage.tsx` - Update to static page +- `frontend/src/features/auth/mobile/VerifyEmailMobileScreen.tsx` - Update +- `frontend/src/core/auth/useUserStatus.ts` - NEW +- `frontend/src/features/auth/api/auth.api.ts` - Add functions + +--- + +## New User Flow (After Fix) + +``` +1. Signup form submission +2. -> POST /api/auth/signup (creates unverified Auth0 user) +3. -> Navigate to /verify-email (static "Check Your Email" page) +4. User clicks verification link in email +5. -> Auth0 marks user as verified +6. User clicks "Login" on /verify-email page +7. -> Auth0 login succeeds (user is now verified) +8. -> /callback page fetches status +9. -> Not onboarded? -> /onboarding +10. -> Complete onboarding -> /garage +``` + +## Returning User Flow + +``` +1. Login attempt (unverified) -> Auth0 blocks with error message +2. Login attempt (verified, not onboarded) -> /callback -> /onboarding +3. Login attempt (verified, onboarded) -> /callback -> /garage +``` + +--- + +## Testing Checklist +- [ ] Auth0 Action blocks unverified login with clear error +- [ ] Signup -> check-email page -> verify via email -> login works +- [ ] Resend verification from check-email page works +- [ ] Verified user (no onboarding) -> onboarding wizard +- [ ] Verified + onboarded user -> direct to garage +- [ ] Direct URL access to /garage -> requires login +- [ ] All flows work on mobile +- [ ] All flows work on desktop diff --git a/backend/src/_system/cli/create-admin.ts b/backend/src/_system/cli/create-admin.ts new file mode 100644 index 0000000..8de3605 --- /dev/null +++ b/backend/src/_system/cli/create-admin.ts @@ -0,0 +1,315 @@ +/** + * @ai-summary CLI script for creating initial admin user on fresh deployments + * @ai-context Runs inside backend container with access to Auth0 and PostgreSQL + * + * Usage: node dist/_system/cli/create-admin.js + * + * Interactive prompts for email and password, then: + * 1. Checks if any admin exists (errors if yes) + * 2. Creates user in Auth0 via Management API + * 3. Creates user_profile record + * 4. Creates admin_users record with audit log + */ + +import * as readline from 'readline'; +import { Pool } from 'pg'; +import { appConfig } from '../../core/config/config-loader'; +import { auth0ManagementClient } from '../../core/auth/auth0-management.client'; +import { UserProfileRepository } from '../../features/user-profile/data/user-profile.repository'; +import { AdminRepository } from '../../features/admin/data/admin.repository'; +import { AdminService } from '../../features/admin/domain/admin.service'; + +// Terminal color codes +const colors = { + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + cyan: '\x1b[36m', + reset: '\x1b[0m', + bold: '\x1b[1m', +}; + +function printInfo(msg: string): void { + console.log(`${colors.green}[INFO]${colors.reset} ${msg}`); +} + +function printError(msg: string): void { + console.log(`${colors.red}[ERROR]${colors.reset} ${msg}`); +} + +function printWarn(msg: string): void { + console.log(`${colors.yellow}[WARN]${colors.reset} ${msg}`); +} + +/** + * Prompt for text input + */ +function prompt(rl: readline.Interface, question: string): Promise { + return new Promise((resolve) => { + rl.question(question, (answer) => { + resolve(answer.trim()); + }); + }); +} + +/** + * Prompt for password input (masked - characters not echoed) + */ +function promptPassword(question: string): Promise { + return new Promise((resolve) => { + process.stdout.write(question); + + const stdin = process.stdin; + const wasRaw = stdin.isRaw; + + stdin.setRawMode?.(true); + stdin.resume(); + + let password = ''; + + const onData = (char: Buffer): void => { + const c = char.toString(); + + if (c === '\n' || c === '\r') { + stdin.removeListener('data', onData); + stdin.setRawMode?.(wasRaw); + stdin.pause(); + console.log(); // newline after password + resolve(password); + } else if (c === '\u0003') { + // Ctrl+C - exit gracefully + console.log('\n\nAborted by user.'); + process.exit(1); + } else if (c === '\u007f' || c === '\b') { + // Backspace + password = password.slice(0, -1); + // Optionally show backspace effect + if (password.length >= 0) { + process.stdout.write('\b \b'); + } + } else if (c.charCodeAt(0) >= 32) { + // Printable character + password += c; + process.stdout.write('*'); // Show asterisk for each character + } + }; + + stdin.on('data', onData); + }); +} + +/** + * Validate email format + */ +function validateEmail(email: string): boolean { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); +} + +/** + * Validate password strength + * Returns error message or null if valid + */ +function validatePassword(password: string): string | null { + if (password.length < 8) { + return 'Password must be at least 8 characters long'; + } + if (!/[A-Z]/.test(password)) { + return 'Password must contain at least one uppercase letter'; + } + if (!/[a-z]/.test(password)) { + return 'Password must contain at least one lowercase letter'; + } + if (!/[0-9]/.test(password)) { + return 'Password must contain at least one number'; + } + return null; +} + +/** + * Wait for database to be available + */ +async function waitForDatabase(pool: Pool, timeoutMs = 30000): Promise { + const start = Date.now(); + while (true) { + try { + await pool.query('SELECT 1'); + return; + } catch (error) { + if (Date.now() - start > timeoutMs) { + throw new Error('Database connection timeout'); + } + await new Promise((res) => setTimeout(res, 1000)); + } + } +} + +async function main(): Promise { + console.log(''); + console.log(`${colors.bold}${colors.cyan}========================================${colors.reset}`); + console.log(`${colors.bold}${colors.cyan} MotoVaultPro - Create Admin User${colors.reset}`); + console.log(`${colors.bold}${colors.cyan}========================================${colors.reset}`); + console.log(''); + + // Initialize database pool + const pool = new Pool({ + connectionString: appConfig.getDatabaseUrl(), + }); + + try { + // Wait for database + printInfo('Connecting to database...'); + await waitForDatabase(pool); + printInfo('Database connected.'); + + // Initialize repositories and services + const userProfileRepo = new UserProfileRepository(pool); + const adminRepo = new AdminRepository(pool); + const adminService = new AdminService(adminRepo); + + // Step 1: Check if any admin already exists + printInfo('Checking for existing admin users...'); + const existingAdmins = await adminService.getActiveAdmins(); + + if (existingAdmins.length > 0) { + console.log(''); + printError('An admin user already exists!'); + console.log(''); + console.log(` Found ${existingAdmins.length} existing admin(s):`); + for (const admin of existingAdmins) { + console.log(` - ${admin.email} (${admin.role})`); + } + console.log(''); + console.log(' This command is only for initial admin setup on fresh deployments.'); + console.log(' To create additional admins, use the admin panel.'); + console.log(''); + process.exit(1); + } + + printInfo('No existing admins found. Proceeding with setup.'); + console.log(''); + + // Step 2: Create readline interface for interactive prompts + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + // Prompt for email + let email: string; + while (true) { + email = await prompt(rl, 'Enter admin email: '); + if (!email) { + printError('Email is required'); + continue; + } + if (!validateEmail(email)) { + printError('Please enter a valid email address'); + continue; + } + break; + } + + // Close readline before password prompts (we handle raw input directly) + rl.close(); + + // Prompt for password + let password: string; + while (true) { + password = await promptPassword('Enter password: '); + const passwordError = validatePassword(password); + if (passwordError) { + printError(passwordError); + continue; + } + + const confirmPassword = await promptPassword('Confirm password: '); + if (password !== confirmPassword) { + printError('Passwords do not match'); + continue; + } + break; + } + + console.log(''); + printInfo('Creating admin user...'); + + // Step 3: Create user in Auth0 (with email pre-verified for trusted CLI-created admins) + printInfo('Creating user in Auth0...'); + let auth0Sub: string; + try { + auth0Sub = await auth0ManagementClient.createUser({ email, password, emailVerified: true }); + printInfo(`Auth0 user created: ${auth0Sub}`); + } catch (error) { + printError( + `Failed to create Auth0 user: ${error instanceof Error ? error.message : 'Unknown error'}` + ); + process.exit(1); + } + + // Step 4: Create user_profile record (with email verified for trusted CLI-created admins) + printInfo('Creating user profile...'); + try { + const displayName = email.split('@')[0]; // Use email prefix as display name + await userProfileRepo.create(auth0Sub, email, displayName); + // Mark email as verified in database (trusted admin created via CLI) + await userProfileRepo.updateEmailVerified(auth0Sub, true); + printInfo('User profile created (email verified).'); + } catch (error) { + printError( + `Failed to create user profile: ${error instanceof Error ? error.message : 'Unknown error'}` + ); + // Attempt to clean up Auth0 user + printWarn('Attempting to clean up Auth0 user...'); + try { + await auth0ManagementClient.deleteUser(auth0Sub); + printInfo('Auth0 user cleaned up.'); + } catch (cleanupError) { + printError('Failed to clean up Auth0 user - manual cleanup may be required'); + } + process.exit(1); + } + + // Step 5: Create admin_users record + printInfo('Creating admin record...'); + try { + const admin = await adminService.createAdmin( + email, + 'admin', + auth0Sub, + 'system-cli' // createdBy indicator for CLI-created admins + ); + printInfo(`Admin record created: ${admin.email} (${admin.role})`); + } catch (error) { + printError( + `Failed to create admin record: ${error instanceof Error ? error.message : 'Unknown error'}` + ); + printWarn('User was created but admin privileges were not assigned.'); + printWarn('You may need to manually grant admin access via the database.'); + process.exit(1); + } + + // Success + console.log(''); + console.log(`${colors.bold}${colors.green}========================================${colors.reset}`); + console.log(`${colors.bold}${colors.green} Admin User Created Successfully!${colors.reset}`); + console.log(`${colors.bold}${colors.green}========================================${colors.reset}`); + console.log(''); + console.log(` Email: ${email}`); + console.log(` Role: admin`); + console.log(` Auth0 ID: ${auth0Sub}`); + console.log(''); + console.log(' You can now log in at https://motovaultpro.com'); + console.log(''); + } catch (error) { + printError(`Unexpected error: ${error instanceof Error ? error.message : 'Unknown error'}`); + process.exit(1); + } finally { + await pool.end(); + } +} + +// Only run if executed directly +if (require.main === module) { + main(); +} diff --git a/backend/src/core/auth/auth0-management.client.ts b/backend/src/core/auth/auth0-management.client.ts index 734d36a..ce8cda1 100644 --- a/backend/src/core/auth/auth0-management.client.ts +++ b/backend/src/core/auth/auth0-management.client.ts @@ -9,6 +9,7 @@ import { logger } from '../logging/logger'; interface CreateUserParams { email: string; password: string; + emailVerified?: boolean; // Optional: set true for trusted users (e.g., CLI-created admins) } interface UserDetails { @@ -46,7 +47,7 @@ class Auth0ManagementClientSingleton { * @param password User's password * @returns Auth0 user ID */ - async createUser({ email, password }: CreateUserParams): Promise { + async createUser({ email, password, emailVerified = false }: CreateUserParams): Promise { try { const client = this.getClient(); @@ -54,7 +55,7 @@ class Auth0ManagementClientSingleton { connection: this.CONNECTION_NAME, email, password, - email_verified: false, + email_verified: emailVerified, }); const user = response.data; diff --git a/backend/src/features/admin/migrations/001_create_admin_users.sql b/backend/src/features/admin/migrations/001_create_admin_users.sql index 3ca517b..c6b665d 100644 --- a/backend/src/features/admin/migrations/001_create_admin_users.sql +++ b/backend/src/features/admin/migrations/001_create_admin_users.sql @@ -18,10 +18,8 @@ CREATE INDEX IF NOT EXISTS idx_admin_users_created_at ON admin_users(created_at) -- Create index on revoked_at for active admin queries CREATE INDEX IF NOT EXISTS idx_admin_users_revoked_at ON admin_users(revoked_at); --- Seed initial admin user (idempotent) -INSERT INTO admin_users (auth0_sub, email, role, created_by) -VALUES ('system|bootstrap', 'admin@motovaultpro.com', 'admin', 'system') -ON CONFLICT (auth0_sub) DO NOTHING; +-- Note: Initial admin user is created via `make create-admin` command +-- This allows for dynamic email/password configuration on fresh deployments -- Create update trigger function (if not exists) DO $$ diff --git a/backend/src/features/user-profile/api/user-profile.controller.ts b/backend/src/features/user-profile/api/user-profile.controller.ts index 4bb89b3..68c8732 100644 --- a/backend/src/features/user-profile/api/user-profile.controller.ts +++ b/backend/src/features/user-profile/api/user-profile.controller.ts @@ -157,12 +157,11 @@ export class UserProfileController { }); } - const { password, confirmationText } = validation.data; + const { confirmationText } = validation.data; - // Request deletion + // Request deletion (user is already authenticated via JWT) const profile = await this.userProfileService.requestDeletion( auth0Sub, - password, confirmationText ); @@ -178,13 +177,6 @@ export class UserProfileController { userId: request.userContext?.userId, }); - if (error.message.includes('Invalid password')) { - return reply.code(401).send({ - error: 'Unauthorized', - message: 'Invalid password', - }); - } - if (error.message.includes('Invalid confirmation')) { return reply.code(400).send({ error: 'Bad Request', diff --git a/backend/src/features/user-profile/api/user-profile.validation.ts b/backend/src/features/user-profile/api/user-profile.validation.ts index bcf78e2..dfb95f6 100644 --- a/backend/src/features/user-profile/api/user-profile.validation.ts +++ b/backend/src/features/user-profile/api/user-profile.validation.ts @@ -18,7 +18,6 @@ export const updateProfileSchema = z.object({ export type UpdateProfileInput = z.infer; export const requestDeletionSchema = z.object({ - password: z.string().min(1, 'Password is required'), confirmationText: z.string().refine((val) => val === 'DELETE', { message: 'Confirmation text must be exactly "DELETE"', }), diff --git a/backend/src/features/user-profile/domain/user-profile.service.ts b/backend/src/features/user-profile/domain/user-profile.service.ts index 9681e5a..285a264 100644 --- a/backend/src/features/user-profile/domain/user-profile.service.ts +++ b/backend/src/features/user-profile/domain/user-profile.service.ts @@ -328,12 +328,12 @@ export class UserProfileService { // ============================================ /** - * Request account deletion with password verification + * Request account deletion * Sets 30-day grace period before permanent deletion + * Note: User is already authenticated via JWT, confirmation text is sufficient */ async requestDeletion( auth0Sub: string, - password: string, confirmationText: string ): Promise { try { @@ -353,12 +353,6 @@ export class UserProfileService { throw new Error('Deletion already requested'); } - // Verify password with Auth0 - const passwordValid = await auth0ManagementClient.verifyPassword(profile.email, password); - if (!passwordValid) { - throw new Error('Invalid password'); - } - // Request deletion const updatedProfile = await this.repository.requestDeletion(auth0Sub); diff --git a/docs/PROMPTS.md b/docs/PROMPTS.md index cefc704..2025dfb 100644 --- a/docs/PROMPTS.md +++ b/docs/PROMPTS.md @@ -19,7 +19,7 @@ comprehensive spec.md - containing requirements, architecture decisions, data mo You are a senior software engineer specializsing in NodeJS, Typescript, front end and back end development. You will be delegating tasks to the platform-agent, feature-agent, first-frontend-agent and quality-agent when appropriate. *** ACTION *** -- You will be implementing improvements to the User Management. +- You will be fixing a workflow logic in the new user sign up wizard. - Make no assumptions. - Ask clarifying questions. - Ultrathink @@ -27,11 +27,10 @@ You are a senior software engineer specializsing in NodeJS, Typescript, front en *** CONTEXT *** - This is a modern web app for managing a vehicle fleet. It has both a desktop and mobile versions of the site that both need to maintain feature parity. It's currently deployed via docker compose but in the future will be deployed via k8s. - Read README.md CLAUDE.md and AI-INDEX.md and follow relevant instructions to understand this code repository in the context of this change. -- There is no delete option for users -- GPDR requires that users are able to fully delete their information -- There is a Delete button in the user settings. This needs to be implemented -- The same functionality should be enabled admin settings for user management. - +- When a new user signs up, they are immediately redirected to https://motovaultpro.com/verify-email which is supposed to send them through a new user wizard. +- The user is also allowed to login before the email is confirmed. There are API errors but the login is allowed. +- It should not even let people login without a verified email. +- The new user wizard exists. It worked in the past. Recent user changes must have broken the workflow. *** CHANGES TO IMPLEMENT *** - Research this code base and ask iterative questions to compile a complete plan. diff --git a/frontend/src/features/settings/components/DeleteAccountDialog.tsx b/frontend/src/features/settings/components/DeleteAccountDialog.tsx index 14adb79..2a7e0b3 100644 --- a/frontend/src/features/settings/components/DeleteAccountDialog.tsx +++ b/frontend/src/features/settings/components/DeleteAccountDialog.tsx @@ -23,28 +23,26 @@ interface DeleteAccountDialogProps { } export const DeleteAccountDialog: React.FC = ({ open, onClose }) => { - const [password, setPassword] = useState(''); const [confirmationText, setConfirmationText] = useState(''); const requestDeletionMutation = useRequestDeletion(); // Clear form when dialog closes useEffect(() => { if (!open) { - setPassword(''); setConfirmationText(''); } }, [open]); const handleSubmit = async () => { - if (!password || confirmationText !== 'DELETE') { + if (confirmationText !== 'DELETE') { return; } - await requestDeletionMutation.mutateAsync({ password, confirmationText }); + await requestDeletionMutation.mutateAsync({ confirmationText }); onClose(); }; - const isValid = password.length > 0 && confirmationText === 'DELETE'; + const isValid = confirmationText === 'DELETE'; return ( @@ -61,17 +59,6 @@ export const DeleteAccountDialog: React.FC = ({ open, - setPassword(e.target.value)} - fullWidth - required - autoComplete="current-password" - helperText="Enter your password to confirm" - /> - = ({ isOpen, onClose }) => { - const [password, setPassword] = useState(''); const [confirmationText, setConfirmationText] = useState(''); const requestDeletionMutation = useRequestDeletion(); // Clear form when modal closes useEffect(() => { if (!isOpen) { - setPassword(''); setConfirmationText(''); } }, [isOpen]); @@ -26,15 +24,15 @@ export const DeleteAccountModal: React.FC = ({ isOpen, if (!isOpen) return null; const handleSubmit = async () => { - if (!password || confirmationText !== 'DELETE') { + if (confirmationText !== 'DELETE') { return; } - await requestDeletionMutation.mutateAsync({ password, confirmationText }); + await requestDeletionMutation.mutateAsync({ confirmationText }); onClose(); }; - const isValid = password.length > 0 && confirmationText === 'DELETE'; + const isValid = confirmationText === 'DELETE'; return (
@@ -50,23 +48,6 @@ export const DeleteAccountModal: React.FC = ({ isOpen,

- {/* Password Input */} -
- - setPassword(e.target.value)} - placeholder="Enter your password" - className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-red-500 focus:border-red-500" - style={{ fontSize: '16px', minHeight: '44px' }} - autoComplete="current-password" - /> -

Enter your password to confirm

-
- {/* Confirmation Input */}