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:
56
src/components/AuthButton.tsx
Normal file
56
src/components/AuthButton.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
'use client'
|
||||
|
||||
import { useSession, signOut } from 'next-auth/react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
|
||||
export function AuthButton() {
|
||||
const { data: session, status } = useSession()
|
||||
const router = useRouter()
|
||||
|
||||
if (status === 'loading') {
|
||||
return (
|
||||
<div className="text-[var(--muted-foreground)] text-sm">
|
||||
Chargement...
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
return (
|
||||
<Button
|
||||
onClick={() => router.push('/login')}
|
||||
size="sm"
|
||||
>
|
||||
Se connecter
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<Button
|
||||
onClick={() => router.push('/profile')}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="p-1 h-auto"
|
||||
title={`Profil - ${session.user?.email}`}
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||
</svg>
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => signOut({ callbackUrl: '/login' })}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="p-1 h-auto"
|
||||
title="Déconnexion"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
|
||||
</svg>
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
7
src/components/AuthProvider.tsx
Normal file
7
src/components/AuthProvider.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { SessionProvider } from "next-auth/react"
|
||||
|
||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
return <SessionProvider>{children}</SessionProvider>
|
||||
}
|
||||
11
src/components/TowerBackground.tsx
Normal file
11
src/components/TowerBackground.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
export function TowerBackground() {
|
||||
return (
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-[var(--primary)]/20 via-[var(--background)] to-[var(--accent)]/20">
|
||||
{/* Effet de profondeur */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent"></div>
|
||||
|
||||
{/* Effet de lumière */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-transparent via-[var(--primary)]/5 to-transparent"></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
37
src/components/TowerLogo.tsx
Normal file
37
src/components/TowerLogo.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
interface TowerLogoProps {
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
showText?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function TowerLogo({ size = 'md', showText = true, className = '' }: TowerLogoProps) {
|
||||
const sizeClasses = {
|
||||
sm: 'w-12 h-12',
|
||||
md: 'w-20 h-20',
|
||||
lg: 'w-32 h-32'
|
||||
}
|
||||
|
||||
const textSizes = {
|
||||
sm: 'text-2xl',
|
||||
md: 'text-4xl',
|
||||
lg: 'text-6xl'
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`text-center ${className}`}>
|
||||
<div className={`inline-flex items-center justify-center ${sizeClasses[size]} rounded-2xl mb-4 text-6xl`}>
|
||||
🗼
|
||||
</div>
|
||||
{showText && (
|
||||
<>
|
||||
<h1 className={`${textSizes[size]} font-mono font-bold text-[var(--foreground)] mb-2`}>
|
||||
TowerControl
|
||||
</h1>
|
||||
<p className="text-[var(--muted-foreground)] text-lg">
|
||||
Tour de contrôle de vos projets
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { useState } from 'react';
|
||||
import { Theme } from '@/lib/theme-config';
|
||||
import { THEME_CONFIG, getThemeMetadata } from '@/lib/theme-config';
|
||||
import { useKeyboardShortcutsModal } from '@/contexts/KeyboardShortcutsContext';
|
||||
import { AuthButton } from '@/components/AuthButton';
|
||||
|
||||
interface HeaderProps {
|
||||
title?: string;
|
||||
@@ -173,6 +174,12 @@ export function Header({ title = "TowerControl", subtitle = "Task Management", s
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Auth controls à droite mobile */}
|
||||
<div className="flex items-center gap-1">
|
||||
<AuthButton />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -264,9 +271,15 @@ export function Header({ title = "TowerControl", subtitle = "Task Management", s
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
{/* Contrôles à droite */}
|
||||
<div className="flex items-center gap-2">
|
||||
<AuthButton />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user