create-ex-den-kit
Version:
Create exam projects with Ex-Den-Kit
227 lines (212 loc) • 8.02 kB
JSX
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;