Files
ghaddaditw 56380ec301 Guide users to the dashboard after they provide required business details
Add 'onboardingComplete' and business info fields to allowed updates in authController.ts.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 556aa286-edd2-4cea-8583-f4fc3cfd119b
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/81470e0d-8ae8-4335-9301-cd9a69e670fa/9cb7723a-8921-4263-af37-6daa7845de3e.jpg
2025-05-30 17:42:53 +00:00

209 lines
6.4 KiB
TypeScript

import { Request, Response } from 'express';
import bcrypt from 'bcryptjs';
import { storage } from '../storage';
import { loginSchema, registerSchema } from '@shared/schema';
import { AuthenticatedRequest } from '../middleware/auth';
export const authController = {
async register(req: Request, res: Response) {
try {
const validatedData = registerSchema.parse(req.body);
// Check if user already exists
const existingUser = await storage.getUserByEmail(validatedData.email);
if (existingUser) {
return res.status(400).json({ error: 'User already exists with this email' });
}
const existingUsername = await storage.getUserByUsername(validatedData.username);
if (existingUsername) {
return res.status(400).json({ error: 'Username already taken' });
}
// Hash password
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(validatedData.password as string, saltRounds);
// Determine role - special handling for admin user
let userRole = "standard";
if (validatedData.email === "dev@adminlocal.com") {
userRole = "admin";
} else if (validatedData.role === "pro") {
userRole = "pro";
}
// Create user
const user = await storage.createUser({
username: validatedData.username,
email: validatedData.email,
password: hashedPassword,
role: userRole,
firstName: validatedData.firstName,
lastName: validatedData.lastName,
onboardingComplete: false,
voiceEnabled: true,
ttsEnabled: true
});
// Remove password from response
const { password, ...userWithoutPassword } = user;
res.status(201).json({
message: 'User created successfully',
user: userWithoutPassword
});
} catch (error) {
console.error('Registration error:', error);
if (error instanceof Error && error.name === 'ZodError') {
return res.status(400).json({ error: 'Invalid input data', details: error.message });
}
res.status(500).json({ error: 'Failed to create user' });
}
},
async login(req: Request, res: Response) {
try {
const validatedData = loginSchema.parse(req.body);
const user = await storage.getUserByEmail(validatedData.email);
if (!user) {
return res.status(401).json({ error: 'Invalid email or password' });
}
const isValidPassword = await bcrypt.compare(validatedData.password, user.password);
if (!isValidPassword) {
return res.status(401).json({ error: 'Invalid email or password' });
}
// Use passport login
req.login(user, (err) => {
if (err) {
console.error('Login error:', err);
return res.status(500).json({ error: 'Login failed' });
}
const { password, ...userWithoutPassword } = user;
res.json({
message: 'Login successful',
user: userWithoutPassword
});
});
} catch (error) {
console.error('Login error:', error);
if (error instanceof Error && error.name === 'ZodError') {
return res.status(400).json({ error: 'Invalid input data' });
}
res.status(500).json({ error: 'Login failed' });
}
},
async logout(req: Request, res: Response) {
req.logout((err) => {
if (err) {
console.error('Logout error:', err);
return res.status(500).json({ error: 'Logout failed' });
}
res.json({ message: 'Logout successful' });
});
},
async me(req: AuthenticatedRequest, res: Response) {
try {
if (!req.user) {
return res.status(401).json({ error: 'Not authenticated' });
}
const { password, ...userWithoutPassword } = req.user;
res.json({ user: userWithoutPassword });
} catch (error) {
console.error('Get user error:', error);
res.status(500).json({ error: 'Failed to get user information' });
}
},
async updateProfile(req: AuthenticatedRequest, res: Response) {
try {
if (!req.user) {
return res.status(401).json({ error: 'Not authenticated' });
}
const allowedUpdates = [
'firstName',
'lastName',
'voiceEnabled',
'ttsEnabled',
'onboardingComplete',
'businessName',
'bio',
'specializations',
'phoneNumber',
'address',
'allowAppointmentBooking',
'isProfessional',
'isPublicProfile',
'professionalType'
];
const updates: any = {};
for (const field of allowedUpdates) {
if (req.body[field] !== undefined) {
updates[field] = req.body[field];
}
}
if (Object.keys(updates).length === 0) {
return res.status(400).json({ error: 'No valid fields to update' });
}
const updatedUser = await storage.updateUser(req.user.id, updates);
if (!updatedUser) {
return res.status(404).json({ error: 'User not found' });
}
const { password, ...userWithoutPassword } = updatedUser;
res.json({
message: 'Profile updated successfully',
user: userWithoutPassword
});
} catch (error) {
console.error('Update profile error:', error);
res.status(500).json({ error: 'Failed to update profile' });
}
},
async completeOnboarding(req: AuthenticatedRequest, res: Response) {
try {
if (!req.user) {
return res.status(401).json({ error: 'Not authenticated' });
}
const { role, preferences } = req.body;
// Update user onboarding status and role if provided
const updates: any = { onboardingComplete: true };
if (role && ['standard', 'pro', 'admin'].includes(role)) {
updates.role = role;
}
const updatedUser = await storage.updateUser(req.user.id, updates);
if (!updatedUser) {
return res.status(404).json({ error: 'User not found' });
}
// Save user preferences if provided
if (preferences) {
await storage.updateUserPreferences(req.user.id, preferences);
}
const { password, ...userWithoutPassword } = updatedUser;
res.json({
message: 'Onboarding completed successfully',
user: userWithoutPassword
});
} catch (error) {
console.error('Complete onboarding error:', error);
res.status(500).json({ error: 'Failed to complete onboarding' });
}
}
};