UNPKG

create-ex-den-kit

Version:

Create exam projects with Ex-Den-Kit

227 lines (212 loc) 8.02 kB
import React, { useState } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { motion } from 'framer-motion'; import { useForm } from 'react-hook-form'; import { useAuth } from '../contexts/AuthContext'; import { useTheme } from '../contexts/ThemeContext'; import { UserPlus, Eye, EyeOff } from 'lucide-react'; const Register = () => { const { register: registerUser } = useAuth(); const { config } = useTheme(); const navigate = useNavigate(); const [showPassword, setShowPassword] = useState(false); const [isLoading, setIsLoading] = useState(false); const { register, handleSubmit, formState: { errors }, setError, } = useForm(); const onSubmit = async (data) => { setIsLoading(true); const result = await registerUser(data); setIsLoading(false); if (result.success) { navigate('/login'); } else { setError('login', { message: result.error }); } }; return ( <div className="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 flex items-center justify-center p-4"> <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5 }} className="max-w-md w-full" > <div className="bg-white rounded-2xl shadow-xl p-8"> <div className="text-center mb-8"> <motion.div initial={{ scale: 0 }} animate={{ scale: 1 }} transition={{ delay: 0.2, type: 'spring' }} className="text-6xl mb-4" > {config.icon} </motion.div> <h2 className="text-3xl font-bold text-gray-900">Регистрация</h2> <p className="text-gray-600 mt-2">Создайте новый аккаунт в {config.name}</p> </div> <form onSubmit={handleSubmit(onSubmit)} className="space-y-4"> <div> <label className="block text-sm font-medium text-gray-700 mb-1"> Логин </label> <input type="text" {...register('login', { required: 'Введите логин', minLength: { value: 6, message: 'Логин должен содержать минимум 6 символов' }, pattern: { value: /^[а-яА-Яa-zA-Z0-9]+$/, message: 'Логин может содержать только буквы и цифры' } })} className="input-field" placeholder="Минимум 6 символов" /> {errors.login && ( <p className="error-message">{errors.login.message}</p> )} </div> <div> <label className="block text-sm font-medium text-gray-700 mb-1"> Пароль </label> <div className="relative"> <input type={showPassword ? 'text' : 'password'} {...register('password', { required: 'Введите пароль', minLength: { value: 6, message: 'Пароль должен содержать минимум 6 символов' } })} className="input-field pr-10" placeholder="Минимум 6 символов" /> <button type="button" onClick={() => setShowPassword(!showPassword)} className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700" > {showPassword ? <EyeOff size={20} /> : <Eye size={20} />} </button> </div> {errors.password && ( <p className="error-message">{errors.password.message}</p> )} </div> <div> <label className="block text-sm font-medium text-gray-700 mb-1"> ФИО </label> <input type="text" {...register('fullName', { required: 'Введите ФИО', pattern: { value: /^[а-яА-Я\s]+$/, message: 'ФИО может содержать только кириллицу и пробелы' } })} className="input-field" placeholder="Иванов Иван Иванович" /> {errors.fullName && ( <p className="error-message">{errors.fullName.message}</p> )} </div> <div> <label className="block text-sm font-medium text-gray-700 mb-1"> Телефон </label> <input type="tel" {...register('phone', { required: 'Введите телефон', pattern: { value: /^\+7\(\d{3}\)-\d{3}-\d{2}-\d{2}$/, message: 'Формат: +7(XXX)-XXX-XX-XX' } })} className="input-field" placeholder="+7(999)-123-45-67" /> {errors.phone && ( <p className="error-message">{errors.phone.message}</p> )} </div> <div> <label className="block text-sm font-medium text-gray-700 mb-1"> Email </label> <input type="email" {...register('email', { required: 'Введите email', pattern: { value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, message: 'Неверный формат email' } })} className="input-field" placeholder="example@mail.ru" /> {errors.email && ( <p className="error-message">{errors.email.message}</p> )} </div> <motion.button whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} type="submit" disabled={isLoading} className="w-full btn-primary flex items-center justify-center space-x-2 mt-6" > {isLoading ? ( <motion.div animate={{ rotate: 360 }} transition={{ duration: 1, repeat: Infinity, ease: 'linear' }} className="w-5 h-5 border-2 border-white border-t-transparent rounded-full" /> ) : ( <> <UserPlus size={20} /> <span>Зарегистрироваться</span> </> )} </motion.button> </form> <div className="mt-6 text-center"> <p className="text-gray-600"> Уже есть аккаунт?{' '} <Link to="/login" className="text-primary hover:underline font-medium"> Войти </Link> </p> </div> </div> <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ delay: 0.5 }} className="text-center mt-4" > <Link to="/theme" className="text-gray-500 hover:text-primary transition-colors text-sm" > ← Сменить тему </Link> </motion.div> </motion.div> </div> ); }; export default Register;