My-Weekly-ToDo-List/src/app/api/auth/signup/route.ts
mARTin 4ac73d3e03 feat: onboarding wizard for first-time users + UI fixes
- 6-step onboarding wizard (welcome, language, connect providers,
  view style, work hours, styling) for new signups
- Added hasCompletedOnboarding field to User schema
- Fixed subtask progress bar in GridTaskBlock (simple/calendar views)
- Fixed kanban drag-and-drop to someday area
- Fixed weather/provider icon overlap in time grid tasks
- Provider icon positioning: inline when weather on, top-right when off

v1.56.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 13:52:29 +01:00

113 lines
3.2 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
export const dynamic = 'force-dynamic';
import { PrismaClient } from '@prisma/client';
import { hash } from 'bcryptjs';
import { sendVerificationEmail, generateVerificationCode, generateVerificationToken } from '@/lib/email';
const prisma = new PrismaClient();
export async function POST(request: NextRequest) {
try {
const { name, email, password } = await request.json();
if (!email || !password) {
return NextResponse.json(
{ error: 'Email and password are required' },
{ status: 400 }
);
}
if (password.length < 8) {
return NextResponse.json(
{ error: 'Password must be at least 8 characters' },
{ status: 400 }
);
}
// Check if user already exists
const existingUser = await prisma.user.findUnique({
where: { email }
});
if (existingUser) {
// If user exists but isn't verified, resend verification
if (!existingUser.emailVerified) {
const code = generateVerificationCode();
const token = generateVerificationToken();
const expires = new Date(Date.now() + 15 * 60 * 1000); // 15 minutes
await prisma.user.update({
where: { id: existingUser.id },
data: {
emailVerificationCode: code,
emailVerificationToken: token,
emailVerificationExpires: expires,
},
});
try {
await sendVerificationEmail(email, code, token);
} catch (emailError) {
console.error('Failed to send verification email:', emailError);
}
return NextResponse.json({
message: 'Verification email resent',
requiresVerification: true,
});
}
return NextResponse.json(
{ error: 'User already exists' },
{ status: 400 }
);
}
// Hash password
const passwordHash = await hash(password, 12);
// Generate verification code and token
const code = generateVerificationCode();
const token = generateVerificationToken();
const expires = new Date(Date.now() + 15 * 60 * 1000); // 15 minutes
// Create user (NOT verified)
const user = await prisma.user.create({
data: {
name: name || undefined,
email,
passwordHash,
emailVerificationCode: code,
emailVerificationToken: token,
emailVerificationExpires: expires,
hasCompletedOnboarding: false,
// emailVerified is NOT set — user must verify
},
select: {
id: true,
email: true,
name: true,
}
});
// Send verification email
try {
await sendVerificationEmail(email, code, token);
} catch (emailError) {
console.error('Failed to send verification email:', emailError);
// User is created but email failed — they can use "resend" later
}
return NextResponse.json({
message: 'Account created. Please check your email for a verification code.',
requiresVerification: true,
user,
});
} catch (error) {
console.error('Signup error:', error);
return NextResponse.json(
{ error: 'Failed to create user' },
{ status: 500 }
);
}
}