Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | 22x 22x 22x 22x 22x 22x 22x 22x 22x 3x 3x 3x 3x 3x 1x 2x 3x 22x 3x 3x 3x 1x | import { useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { motion } from 'framer-motion'
import { Eye, EyeOff, Sparkles } from 'lucide-react'
import { useAuthStore } from '../store/auth'
export default function Register() {
const [email, setEmail] = useState('')
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [showPassword, setShowPassword] = useState(false)
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
const register = useAuthStore(s => s.register)
const navigate = useNavigate()
const handleSubmit = async (e) => {
e.preventDefault()
setError('')
setLoading(true)
try {
await register(email, username, password)
navigate('/')
} catch (err) {
setError(err.response?.data?.error || 'Ошибка регистрации')
} finally {
setLoading(false)
}
}
return (
<div className="min-h-screen flex items-center justify-center p-4 bg-gradient-to-br from-primary-50 via-white to-accent-50 dark:from-gray-950 dark:via-gray-900 dark:to-gray-950 transition-colors duration-300">
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="w-full max-w-md">
<div className="text-center mb-8">
<motion.div initial={{ scale: 0 }} animate={{ scale: 1 }} transition={{ type: 'spring', delay: 0.1 }} className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-gradient-to-br from-primary-500 to-accent-500 mb-4">
<Sparkles className="w-8 h-8 text-white" />
</motion.div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">Создай аккаунт</h1>
<p className="text-gray-500 dark:text-gray-400 mt-1">Начни отслеживать свои привычки</p>
</div>
<div className="card p-6">
<form onSubmit={handleSubmit} className="space-y-4">
{error && (
<motion.div initial={{ opacity: 0, height: 0 }} animate={{ opacity: 1, height: 'auto' }} className="p-3 rounded-xl bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 text-sm">
{error}
</motion.div>
)}
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5">Как тебя зовут?</label>
<input type="text" value={username} onChange={(e) => setUsername(e.target.value)} className="input" placeholder="Имя" required />
</div>
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5">Email</label>
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} className="input" placeholder="your@email.com" required />
</div>
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5">Пароль</label>
<div className="relative">
<input type={showPassword ? 'text' : 'password'} value={password} onChange={(e) => setPassword(e.target.value)} className="input pr-12" placeholder="Минимум 8 символов" minLength={8} required />
<button type="button" onClick={() => setShowPassword(!showPassword)} className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
{showPassword ? <EyeOff size={20} /> : <Eye size={20} />}
</button>
</div>
</div>
<button type="submit" disabled={loading} className="btn btn-primary w-full">
{loading ? 'Создаём...' : 'Создать аккаунт'}
</button>
</form>
<p className="text-center text-sm text-gray-500 dark:text-gray-400 mt-6">
Уже есть аккаунт?{' '}<Link to="/login" className="text-primary-600 dark:text-primary-400 hover:text-primary-700 font-medium">Войти</Link>
</p>
</div>
</motion.div>
</div>
)
}
|