base
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
import { useState } from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import { Gamepad2, Loader2 } from 'lucide-react'
|
||||
import { supa } from '../lib/supabase'
|
||||
import { Select } from '../components/ui'
|
||||
import { MemberRole, ROLE_LABELS } from '../lib/types'
|
||||
|
||||
export default function Login(): JSX.Element {
|
||||
const [mode, setMode] = useState<'signin' | 'signup'>('signin')
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [fullName, setFullName] = useState('')
|
||||
const [role, setRole] = useState<MemberRole>('programmer')
|
||||
const [busy, setBusy] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const [info, setInfo] = useState('')
|
||||
|
||||
const submit = async (): Promise<void> => {
|
||||
setError('')
|
||||
setInfo('')
|
||||
setBusy(true)
|
||||
try {
|
||||
if (mode === 'signup') {
|
||||
const { error } = await supa().auth.signUp({
|
||||
email,
|
||||
password,
|
||||
options: { data: { full_name: fullName || email.split('@')[0], role } }
|
||||
})
|
||||
if (error) throw error
|
||||
setInfo('Compte créé ! Tu peux maintenant te connecter.')
|
||||
setMode('signin')
|
||||
} else {
|
||||
const { error } = await supa().auth.signInWithPassword({ email, password })
|
||||
if (error) throw error
|
||||
}
|
||||
} catch (e) {
|
||||
setError(translate((e as Error).message))
|
||||
} finally {
|
||||
setBusy(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 16, scale: 0.97 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
transition={{ type: 'spring', stiffness: 260, damping: 24 }}
|
||||
className="card w-full max-w-sm"
|
||||
>
|
||||
<div className="mb-6 flex flex-col items-center gap-2 text-center">
|
||||
<div className="rounded-xl bg-accent/20 p-3 text-accent">
|
||||
<Gamepad2 size={28} />
|
||||
</div>
|
||||
<h1 className="text-xl font-semibold text-white">GameDev Tracker</h1>
|
||||
<p className="text-sm text-gray-400">
|
||||
{mode === 'signin' ? 'Connecte-toi à ton équipe' : 'Crée ton compte membre'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{mode === 'signup' && (
|
||||
<>
|
||||
<label className="label">Nom complet</label>
|
||||
<input
|
||||
className="input mb-3"
|
||||
placeholder="Alex Martin"
|
||||
value={fullName}
|
||||
onChange={(e) => setFullName(e.target.value)}
|
||||
/>
|
||||
<label className="label">Rôle dans l'équipe</label>
|
||||
<Select
|
||||
className="mb-3"
|
||||
value={role}
|
||||
onChange={(e) => setRole(e.target.value as MemberRole)}
|
||||
>
|
||||
{Object.entries(ROLE_LABELS).map(([v, l]) => (
|
||||
<option key={v} value={v}>
|
||||
{l}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</>
|
||||
)}
|
||||
|
||||
<label className="label">Email</label>
|
||||
<input
|
||||
className="input mb-3"
|
||||
type="email"
|
||||
placeholder="toi@email.com"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
/>
|
||||
<label className="label">Mot de passe</label>
|
||||
<input
|
||||
className="input mb-4"
|
||||
type="password"
|
||||
placeholder="••••••••"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && submit()}
|
||||
/>
|
||||
|
||||
{error && <p className="mb-3 text-sm text-rose-400">{error}</p>}
|
||||
{info && <p className="mb-3 text-sm text-accent2">{info}</p>}
|
||||
|
||||
<button className="btn-primary w-full" onClick={submit} disabled={busy}>
|
||||
{busy && <Loader2 className="animate-spin" size={16} />}
|
||||
{mode === 'signin' ? 'Se connecter' : "Créer le compte"}
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="mt-4 w-full text-center text-sm text-gray-400 hover:text-white"
|
||||
onClick={() => {
|
||||
setMode(mode === 'signin' ? 'signup' : 'signin')
|
||||
setError('')
|
||||
setInfo('')
|
||||
}}
|
||||
>
|
||||
{mode === 'signin' ? "Pas encore de compte ? S'inscrire" : 'Déjà un compte ? Se connecter'}
|
||||
</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function translate(msg: string): string {
|
||||
if (msg.includes('Invalid login')) return 'Email ou mot de passe incorrect.'
|
||||
if (msg.includes('already registered')) return 'Cet email est déjà utilisé.'
|
||||
if (msg.includes('at least 6')) return 'Le mot de passe doit faire au moins 6 caractères.'
|
||||
return msg
|
||||
}
|
||||
Reference in New Issue
Block a user