feat: add authentication support and user model

- Updated `env.example` to include NextAuth configuration for authentication.
- Added `next-auth` dependency to manage user sessions.
- Introduced `User` model in Prisma schema with fields for user details and password hashing.
- Integrated `AuthProvider` in layout for session management across the app.
- Enhanced `Header` component with `AuthButton` for user authentication controls.
This commit is contained in:
Julien Froidefond
2025-09-30 21:49:52 +02:00
parent 43c141d3cd
commit 17b86b6087
20 changed files with 1418 additions and 13 deletions

103
src/actions/profile.ts Normal file
View File

@@ -0,0 +1,103 @@
'use server'
import { getServerSession } from 'next-auth/next'
import { authOptions } from '@/lib/auth'
import { usersService } from '@/services/users'
import { revalidatePath } from 'next/cache'
export async function updateProfile(formData: {
name?: string
firstName?: string
lastName?: string
avatar?: string
}) {
try {
const session = await getServerSession(authOptions)
if (!session?.user?.id) {
return { success: false, error: 'Non authentifié' }
}
// Validation
if (formData.firstName && formData.firstName.length > 50) {
return { success: false, error: 'Le prénom ne peut pas dépasser 50 caractères' }
}
if (formData.lastName && formData.lastName.length > 50) {
return { success: false, error: 'Le nom ne peut pas dépasser 50 caractères' }
}
if (formData.name && formData.name.length > 100) {
return { success: false, error: 'Le nom d\'affichage ne peut pas dépasser 100 caractères' }
}
if (formData.avatar && formData.avatar.length > 500) {
return { success: false, error: 'L\'URL de l\'avatar ne peut pas dépasser 500 caractères' }
}
// Mettre à jour l'utilisateur
const updatedUser = await usersService.updateUser(session.user.id, {
name: formData.name || null,
firstName: formData.firstName || null,
lastName: formData.lastName || null,
avatar: formData.avatar || null,
})
// Revalider la page de profil
revalidatePath('/profile')
return {
success: true,
user: {
id: updatedUser.id,
email: updatedUser.email,
name: updatedUser.name,
firstName: updatedUser.firstName,
lastName: updatedUser.lastName,
avatar: updatedUser.avatar,
role: updatedUser.role,
createdAt: updatedUser.createdAt.toISOString(),
lastLoginAt: updatedUser.lastLoginAt?.toISOString() || null,
}
}
} catch (error) {
console.error('Profile update error:', error)
return { success: false, error: 'Erreur lors de la mise à jour du profil' }
}
}
export async function getProfile() {
try {
const session = await getServerSession(authOptions)
if (!session?.user?.id) {
return { success: false, error: 'Non authentifié' }
}
const user = await usersService.getUserById(session.user.id)
if (!user) {
return { success: false, error: 'Utilisateur non trouvé' }
}
return {
success: true,
user: {
id: user.id,
email: user.email,
name: user.name,
firstName: user.firstName,
lastName: user.lastName,
avatar: user.avatar,
role: user.role,
createdAt: user.createdAt.toISOString(),
lastLoginAt: user.lastLoginAt?.toISOString() || null,
}
}
} catch (error) {
console.error('Profile get error:', error)
return { success: false, error: 'Erreur lors de la récupération du profil' }
}
}