From c8d94251e9a0da1139c92f4673c232f93b4f5b58 Mon Sep 17 00:00:00 2001 From: Egor Date: Fri, 23 Jan 2026 11:33:26 +0300 Subject: [PATCH] Add files via upload --- src/pages/Login.tsx | 221 +++++++++++++++++++++++++++++++----------- src/pages/Profile.tsx | 6 +- 2 files changed, 168 insertions(+), 59 deletions(-) diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index a3683a3..90e7cdc 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -12,10 +12,13 @@ export default function Login() { const { t } = useTranslation() const navigate = useNavigate() const location = useLocation() - const { isAuthenticated, loginWithTelegram, loginWithEmail } = useAuthStore() + const { isAuthenticated, loginWithTelegram, loginWithEmail, registerWithEmail } = useAuthStore() const [activeTab, setActiveTab] = useState<'telegram' | 'email'>('telegram') + const [authMode, setAuthMode] = useState<'login' | 'register'>('login') const [email, setEmail] = useState('') const [password, setPassword] = useState('') + const [confirmPassword, setConfirmPassword] = useState('') + const [firstName, setFirstName] = useState('') const [error, setError] = useState('') const [isLoading, setIsLoading] = useState(false) const [isTelegramWebApp, setIsTelegramWebApp] = useState(false) @@ -94,22 +97,49 @@ export default function Login() { tryTelegramAuth() }, [loginWithTelegram, navigate, t, getReturnUrl]) - const handleEmailLogin = async (e: React.FormEvent) => { + const handleEmailSubmit = async (e: React.FormEvent) => { e.preventDefault() setError('') + + // Валидация email + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + if (!email.trim() || !emailRegex.test(email.trim())) { + setError(t('auth.invalidEmail', 'Please enter a valid email address')) + return + } + + if (authMode === 'register') { + // Валидация для регистрации + if (password !== confirmPassword) { + setError(t('auth.passwordMismatch', 'Passwords do not match')) + return + } + if (password.length < 8) { + setError(t('auth.passwordTooShort', 'Password must be at least 8 characters')) + return + } + } + setIsLoading(true) try { - await loginWithEmail(email, password) + if (authMode === 'login') { + await loginWithEmail(email, password) + } else { + await registerWithEmail(email, password, firstName || undefined) + } navigate(getReturnUrl(), { replace: true }) } catch (err: unknown) { const error = err as { response?: { status?: number; data?: { detail?: string } } } - // Show user-friendly error messages without exposing sensitive server details const status = error.response?.status - if (status === 401 || status === 403) { - setError(t('auth.invalidCredentials', 'Неверный email или пароль')) + const detail = error.response?.data?.detail + + if (status === 400 && detail?.includes('already registered')) { + setError(t('auth.emailAlreadyRegistered', 'This email is already registered')) + } else if (status === 401 || status === 403) { + setError(t('auth.invalidCredentials', 'Invalid email or password')) } else if (status === 429) { - setError(t('auth.tooManyAttempts', 'Слишком много попыток. Попробуйте позже')) + setError(t('auth.tooManyAttempts', 'Too many attempts. Please try again later')) } else { setError(t('common.error')) } @@ -205,60 +235,137 @@ export default function Login() { )} ) : ( -
-
- - setEmail(e.target.value)} - /> +
+ {/* Login / Register toggle */} +
+ +
-
- - setPassword(e.target.value)} - /> -
- - -

- {t('auth.registerHint')} -

- +
+ + setEmail(e.target.value)} + /> +
+ +
+ + setPassword(e.target.value)} + /> +
+ + {/* Confirm password - only for registration */} + {authMode === 'register' && ( +
+ + setConfirmPassword(e.target.value)} + /> +
+ )} + + + + + {/* Verification notice for registration */} + {authMode === 'register' && ( +

+ {t('auth.verificationEmailNotice', 'After registration, a verification email will be sent to your address')} +

+ )} + + {/* Forgot password link - only for login */} + {authMode === 'login' && ( +

+ {t('auth.registerHint')} +

+ )} +
)}
diff --git a/src/pages/Profile.tsx b/src/pages/Profile.tsx index a2d4b83..ddc9079 100644 --- a/src/pages/Profile.tsx +++ b/src/pages/Profile.tsx @@ -74,8 +74,10 @@ export default function Profile() { setError(null) setSuccess(null) - if (!email.trim()) { - setError(t('profile.emailRequired')) + // Валидация email + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + if (!email.trim() || !emailRegex.test(email.trim())) { + setError(t('profile.invalidEmail', 'Please enter a valid email address')) return }