444 lines
19 KiB
TypeScript
444 lines
19 KiB
TypeScript
"use client"
|
||
|
||
import React, { useState } from "react"
|
||
import { useHistory } from "react-router-dom"
|
||
import manImage from "../assets/man.svg" // Reverted to original import
|
||
|
||
import { connect } from '../confconnect';
|
||
import axios from 'axios';
|
||
|
||
|
||
|
||
export default function LoginPage() {
|
||
const history = useHistory()
|
||
// Стейты для формы входа
|
||
const [email, setEmail] = useState("")
|
||
const [password, setPassword] = useState("")
|
||
const [showPassword, setShowPassword] = useState(false)
|
||
const [rememberMe, setRememberMe] = useState(false)
|
||
const [activeTab, setActiveTab] = useState<"login" | "register">("login")
|
||
|
||
// Состояние и обработчики регистрационной формы / локальное состояние
|
||
const [registerFormData, setRegisterFormData] = useState({
|
||
email: "", // Removed firstName, lastName
|
||
password: "",
|
||
confirmPassword: "",
|
||
name: "",
|
||
})
|
||
const [showRegisterPassword, setShowRegisterPassword] = useState(false)
|
||
const [showConfirmRegisterPassword, setShowConfirmRegisterPassword] = useState(false)
|
||
|
||
// Обработчик входа
|
||
const handleLogin = async (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
|
||
console.log('Перед отправкой:', { email, password });
|
||
|
||
try {
|
||
const response = await connect.post('/auth/api/login', {
|
||
email,
|
||
password,
|
||
rememberMe,
|
||
});
|
||
if (response.status === 200 || response.status === 204 || response.status === 201) {
|
||
// Предположим, что сервер возвращает данные с токеном
|
||
const data = response.data;
|
||
|
||
// Сохраняем данные в localStorage
|
||
localStorage.setItem('authToken', data.token);
|
||
localStorage.setItem('userEmail', data.user_email);
|
||
localStorage.setItem('userId', String(data.user_id));
|
||
|
||
// Можно сохранить флаг входа
|
||
localStorage.setItem('isLoggedIn', 'true');
|
||
|
||
// Перенаправляем пользователя
|
||
history.push("/home");
|
||
} else {
|
||
console.log('Ответ:', response);
|
||
}
|
||
} catch (error) {
|
||
if (axios.isAxiosError(error)) {
|
||
console.error('Ошибка при входе:', error.message);
|
||
if (error.response) {
|
||
console.error('Статус:', error.response.status);
|
||
console.error('Данные ответа:', error.response.data);
|
||
if (error.response.status === 400) {
|
||
alert('Неверные данные для входа');
|
||
}
|
||
}
|
||
} else {
|
||
console.error('Неожиданная ошибка:', error);
|
||
}
|
||
alert('Ошибка при входе');
|
||
}
|
||
};
|
||
|
||
|
||
|
||
// Обработчик регистрации
|
||
const handleRegisterSubmit = async (e: React.FormEvent) => {
|
||
e.preventDefault()
|
||
if (registerFormData.password !== registerFormData.confirmPassword) {
|
||
alert("Пароли не совпадают")
|
||
return
|
||
}
|
||
try {
|
||
const response = await connect.post('/auth/api/register', {
|
||
email: registerFormData.email,
|
||
name: registerFormData.email,
|
||
password: registerFormData.password,
|
||
})
|
||
|
||
// Предположим, что ответ содержит объект с токеном и другой информацией
|
||
const data = response.data
|
||
|
||
// Сохраняем нужные данные в localStorage
|
||
localStorage.setItem('authToken', data.token)
|
||
localStorage.setItem('userEmail', data.user_email)
|
||
localStorage.setItem('userId', String(data.user_id))
|
||
localStorage.setItem('userName', data.user_name)
|
||
|
||
console.log('Данные сохранены в localStorage')
|
||
alert('Вы успешно зерегистрировались!')
|
||
console.log('Отправляемые данные:', { email, password });
|
||
|
||
// После этого можно перейти или показать сообщение
|
||
history.push("/home")
|
||
} catch (error) {
|
||
console.error('Ошибка при регистрации:', error)
|
||
alert('Ошибка при регистрации')
|
||
}
|
||
}
|
||
|
||
const handleRegisterInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||
setRegisterFormData({
|
||
...registerFormData,
|
||
[e.target.name]: e.target.value,
|
||
})
|
||
}
|
||
|
||
|
||
|
||
return (
|
||
<div className="min-h-screen bg-gradient-to-br from-[#3ABBC7] to-[#0D212C] flex items-center justify-center p-4">
|
||
<div className="bg-white h-[58%] w-full z-0 absolute bottom-0"></div>
|
||
<div className="relative z-10 w-full max-w-md">
|
||
{/* Header Section */}
|
||
<div className="flex items-center justify-center gap-4 mb-8">
|
||
<img className="h-20 w-auto flex-shrink-0" src={manImage || "/placeholder.svg"} alt="man" />
|
||
<div className="flex flex-col text-white">
|
||
<h1 className="text-4xl font-bold mb-1">Реабилитация</h1>
|
||
<div className="w-full bg-white h-0.5 mb-1"></div>
|
||
<p className="font-medium text-lg">Восстановление после травмы</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Login/Register Form Container */}
|
||
<div className="bg-white/5 backdrop-blur-lg glass-morphism rounded-3xl p-8 border border-white/20 shadow-2xl">
|
||
{/* Tab Buttons Container */}
|
||
<div className="flex justify-center gap-2 mb-8 bg-white/10 backdrop-blur-lg rounded-xl px-2 py-2 shadow-inner">
|
||
<button
|
||
type="button"
|
||
onClick={() => setActiveTab("login")}
|
||
className={`flex-1 px-3 py-3 rounded-xl text-lg font-semibold transition-all duration-300 ${
|
||
activeTab === "login"
|
||
? "bg-white text-gray-800 shadow-lg"
|
||
: "text-white/80 hover:text-white hover:bg-white/10"
|
||
}`}
|
||
>
|
||
Вход
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() => setActiveTab("register")}
|
||
className={`flex-1 px-3 py-3 rounded-xl text-lg font-semibold transition-all duration-300 ${
|
||
activeTab === "register"
|
||
? "bg-white text-gray-800 shadow-lg"
|
||
: "text-white/80 hover:text-white hover:bg-white/10"
|
||
}`}
|
||
>
|
||
Регистрация
|
||
</button>
|
||
</div>
|
||
|
||
{activeTab === "login" && (
|
||
<form onSubmit={handleLogin} className="space-y-6">
|
||
<p className="text-gray-700 text-center text-lg font-medium mb-4">Введите логин и пароль</p>
|
||
{/* Email Input */}
|
||
<div>
|
||
<label htmlFor="email" className="block text-gray-700 text-sm font-semibold mb-2 sr-only">
|
||
Электронная почта
|
||
</label>
|
||
<div className="relative">
|
||
<input
|
||
id="email"
|
||
type="email"
|
||
value={email}
|
||
onChange={(e) => setEmail(e.target.value)}
|
||
className="w-full bg-white rounded-xl px-4 py-3 text-gray-800 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#2BACBE] focus:border-transparent transition-all shadow-sm"
|
||
placeholder="Электронная почта"
|
||
required
|
||
/>
|
||
<svg
|
||
className="absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-500"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
fill="none"
|
||
viewBox="0 0 24 24"
|
||
stroke="currentColor"
|
||
strokeWidth="2"
|
||
>
|
||
<path
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
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>
|
||
</div>
|
||
</div>
|
||
{/* Password Input */}
|
||
<div>
|
||
<label htmlFor="password" className="block text-gray-700/90 text-sm font-semibold mb-2 sr-only">
|
||
Пароль
|
||
</label>
|
||
<div className="relative">
|
||
<input
|
||
id="password"
|
||
type={showPassword ? "text" : "password"}
|
||
value={password}
|
||
onChange={(e) => setPassword(e.target.value)}
|
||
className="w-full bg-white rounded-xl px-4 py-3 text-gray-800 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#2BACBE] focus:border-transparent transition-all shadow-sm"
|
||
placeholder="Пароль"
|
||
required
|
||
/>
|
||
<button
|
||
type="button"
|
||
onClick={() => setShowPassword(!showPassword)}
|
||
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 transition-colors"
|
||
aria-label={showPassword ? "Hide password" : "Show password"}
|
||
>
|
||
{showPassword ? (
|
||
<svg
|
||
className="w-5 h-5"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
fill="none"
|
||
viewBox="0 0 24 24"
|
||
stroke="currentColor"
|
||
strokeWidth="2"
|
||
>
|
||
<path
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21"
|
||
/>
|
||
</svg>
|
||
) : (
|
||
<svg
|
||
className="w-5 h-5"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
fill="none"
|
||
viewBox="0 0 24 24"
|
||
stroke="currentColor"
|
||
strokeWidth="2"
|
||
>
|
||
<path
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v3"
|
||
/>
|
||
</svg>
|
||
)}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
{/* Remember Me & Forgot Password */}
|
||
<div className="flex justify-between items-center text-sm mt-4">
|
||
<label htmlFor="remember-me" className="flex items-center text-gray-700/80 cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
id="remember-me"
|
||
checked={rememberMe}
|
||
onChange={(e) => setRememberMe(e.target.checked)}
|
||
className="mr-2 h-4 w-4 text-[#2BACBE] rounded border-gray-300 focus:ring-[#2BACBE] accent-[#2BACBE]"
|
||
/>
|
||
Запомнить
|
||
</label>
|
||
<button
|
||
type="button"
|
||
onClick={() => history.push("/forgot-password")}
|
||
className="text-[#2BACBE] font-medium hover:text-[#2099A8] transition-colors"
|
||
>
|
||
Забыли пароль?
|
||
</button>
|
||
</div>
|
||
{/* Login Button */}
|
||
<button
|
||
type="submit"
|
||
className="w-full bg-[#2BACBE] hover:bg-[#2099A8] text-white font-bold py-3 px-6 rounded-xl border border-[#2BACBE] transition-all duration-300 transform hover:scale-105 shadow-lg mt-6"
|
||
>
|
||
Войти
|
||
</button>
|
||
</form>
|
||
)}
|
||
|
||
|
||
{/* Регистрация */}
|
||
{activeTab === "register" && (
|
||
<form onSubmit={handleRegisterSubmit} className="space-y-4">
|
||
<p className="text-gray-700 text-center text-lg font-medium mb-4">Создайте новый аккаунт</p>
|
||
{/* Email */}
|
||
<div>
|
||
<label htmlFor="registerEmail" className="block text-gray-700 text-sm font-semibold mb-2 sr-only">
|
||
Электронная почта
|
||
</label>
|
||
<input
|
||
id="registerEmail"
|
||
type="email"
|
||
name="email"
|
||
value={registerFormData.email}
|
||
onChange={handleRegisterInputChange}
|
||
className="w-full bg-white rounded-xl px-4 py-3 text-gray-800 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#2BACBE] focus:border-transparent transition-all shadow-sm"
|
||
placeholder="Электронная почта"
|
||
required
|
||
/>
|
||
</div>
|
||
{/* Password */}
|
||
<div>
|
||
<label htmlFor="registerPassword" className="block text-gray-700/90 text-sm font-semibold mb-2 sr-only">
|
||
Пароль
|
||
</label>
|
||
<div className="relative">
|
||
<input
|
||
id="registerPassword"
|
||
type={showRegisterPassword ? "text" : "password"}
|
||
name="password"
|
||
value={registerFormData.password}
|
||
onChange={handleRegisterInputChange}
|
||
className="w-full bg-white rounded-xl px-4 py-3 text-gray-800 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#2BACBE] focus:border-transparent transition-all shadow-sm"
|
||
placeholder="Пароль"
|
||
required
|
||
/>
|
||
<button
|
||
type="button"
|
||
onClick={() => setShowRegisterPassword(!showRegisterPassword)}
|
||
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 transition-colors"
|
||
aria-label={showRegisterPassword ? "Hide password" : "Show password"}
|
||
>
|
||
{showRegisterPassword ? (
|
||
<svg
|
||
className="w-5 h-5"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
fill="none"
|
||
viewBox="0 0 24 24"
|
||
stroke="currentColor"
|
||
strokeWidth="2"
|
||
>
|
||
<path
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21"
|
||
/>
|
||
</svg>
|
||
) : (
|
||
<svg
|
||
className="w-5 h-5"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
fill="none"
|
||
viewBox="0 0 24 24"
|
||
stroke="currentColor"
|
||
strokeWidth="2"
|
||
>
|
||
<path
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v3"
|
||
/>
|
||
</svg>
|
||
)}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
{/* Confirm Password */}
|
||
<div>
|
||
<label htmlFor="confirmPassword" className="block text-gray-700/90 text-sm font-semibold mb-2 sr-only">
|
||
Подтвердите пароль
|
||
</label>
|
||
<div className="relative">
|
||
<input
|
||
id="confirmPassword"
|
||
type={showConfirmRegisterPassword ? "text" : "password"}
|
||
name="confirmPassword"
|
||
value={registerFormData.confirmPassword}
|
||
onChange={handleRegisterInputChange}
|
||
className="w-full bg-white rounded-xl px-4 py-3 text-gray-800 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#2BACBE] focus:border-transparent transition-all shadow-sm"
|
||
placeholder="Подтвердите пароль"
|
||
required
|
||
/>
|
||
<button
|
||
type="button"
|
||
onClick={() => setShowConfirmRegisterPassword(!showConfirmRegisterPassword)}
|
||
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700 transition-colors"
|
||
aria-label={showConfirmRegisterPassword ? "Hide password" : "Show password"}
|
||
>
|
||
{showConfirmRegisterPassword ? (
|
||
<svg
|
||
className="w-5 h-5"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
fill="none"
|
||
viewBox="0 0 24 24"
|
||
stroke="currentColor"
|
||
strokeWidth="2"
|
||
>
|
||
<path
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21"
|
||
/>
|
||
</svg>
|
||
) : (
|
||
<svg
|
||
className="w-5 h-5"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
fill="none"
|
||
viewBox="0 0 24 24"
|
||
stroke="currentColor"
|
||
strokeWidth="2"
|
||
>
|
||
<path
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v3"
|
||
/>
|
||
</svg>
|
||
)}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
{/* Register Button */}
|
||
<button
|
||
type="submit"
|
||
className="w-full bg-[#2BACBE] hover:bg-[#2099A8] text-white font-bold py-3 px-6 rounded-xl border border-[#2BACBE] transition-all duration-300 transform hover:scale-105 shadow-lg mt-6"
|
||
>
|
||
Зарегистрироваться
|
||
</button>
|
||
</form>
|
||
)}
|
||
|
||
{/* Login/Register Link (always visible) */}
|
||
<div className="text-center mt-6">
|
||
<p className="text-gray-700/80 text-sm">
|
||
{activeTab === "login" ? "Нет аккаунта?" : "Уже есть аккаунт?"}{" "}
|
||
<button
|
||
onClick={() => setActiveTab(activeTab === "login" ? "register" : "login")} // Toggle tab instead of pushing to new route
|
||
className="text-gray-700 font-semibold hover:underline"
|
||
>
|
||
{activeTab === "login" ? "Зарегистрироваться" : "Войти"}
|
||
</button>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|