Files
gooseek/apps/auth-mcs/src/app/sign-in/page.tsx
home 783569b8e7 feat: монорепо миграция, Discover/SearxNG улучшения
- Миграция на монорепозиторий (apps/frontend, apps/chat-service, etc.)
- Discover: проверка SearxNG, понятное empty state при ненастроенном поиске
- searxng.ts: валидация URL, проверка JSON-ответа, авто-добавление http://
- docker/searxng-config: настройки для JSON API SearxNG

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-20 17:03:45 +03:00

245 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { authClient } from '@/lib/auth-client';
import Link from 'next/link';
type Tab = 'password' | 'ldap';
export default function SignInPage() {
const router = useRouter();
const [tab, setTab] = useState<Tab>('password');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [credential, setCredential] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const ldapEnabled = process.env.NEXT_PUBLIC_LDAP_ENABLED === 'true';
const handleEmailSignIn = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
setLoading(true);
try {
const { error } = await authClient.signIn.email({ email, password });
if (error) throw new Error(error.message);
router.push('/dashboard');
router.refresh();
} catch (err: unknown) {
setError(err instanceof Error ? err.message : 'Ошибка входа');
} finally {
setLoading(false);
}
};
const handleLdapSignIn = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
setLoading(true);
try {
const res = await fetch('/api/auth/sign-in/ldap', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ credential, password, callbackURL: '/dashboard' }),
credentials: 'include',
});
const data = await res.json();
if (!res.ok || data?.error) throw new Error(data?.message || data?.error?.message || 'Ошибка входа');
router.push('/dashboard');
router.refresh();
} catch (err: unknown) {
setError(err instanceof Error ? err.message : 'Ошибка LDAP входа');
} finally {
setLoading(false);
}
};
return (
<div
style={{
minHeight: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: 'linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)',
}}
>
<div
style={{
width: '100%',
maxWidth: 400,
padding: 32,
background: '#fff',
borderRadius: 12,
boxShadow: '0 8px 32px rgba(0,0,0,0.2)',
}}
>
<h1 style={{ margin: '0 0 24px', fontSize: 24, fontWeight: 600 }}>
Вход в систему
</h1>
{ldapEnabled && (
<div style={{ marginBottom: 16, display: 'flex', gap: 8 }}>
<button
type="button"
onClick={() => setTab('password')}
style={{
flex: 1,
padding: '10px 16px',
border: tab === 'password' ? '2px solid #6366f1' : '1px solid #ddd',
borderRadius: 8,
background: tab === 'password' ? '#eef2ff' : '#fff',
cursor: 'pointer',
fontWeight: 500,
}}
>
Email
</button>
<button
type="button"
onClick={() => setTab('ldap')}
style={{
flex: 1,
padding: '10px 16px',
border: tab === 'ldap' ? '2px solid #6366f1' : '1px solid #ddd',
borderRadius: 8,
background: tab === 'ldap' ? '#eef2ff' : '#fff',
cursor: 'pointer',
fontWeight: 500,
}}
>
LDAP / AD
</button>
</div>
)}
{error && (
<div
style={{
padding: 12,
marginBottom: 16,
background: '#fef2f2',
color: '#dc2626',
borderRadius: 8,
fontSize: 14,
}}
>
{error}
</div>
)}
{tab === 'password' ? (
<form onSubmit={handleEmailSignIn}>
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
style={{
width: '100%',
padding: 12,
marginBottom: 12,
border: '1px solid #ddd',
borderRadius: 8,
boxSizing: 'border-box',
}}
/>
<input
type="password"
placeholder="Пароль"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
style={{
width: '100%',
padding: 12,
marginBottom: 16,
border: '1px solid #ddd',
borderRadius: 8,
boxSizing: 'border-box',
}}
/>
<button
type="submit"
disabled={loading}
style={{
width: '100%',
padding: 12,
background: '#6366f1',
color: '#fff',
border: 'none',
borderRadius: 8,
fontSize: 16,
fontWeight: 600,
cursor: loading ? 'not-allowed' : 'pointer',
}}
>
{loading ? 'Вход...' : 'Войти'}
</button>
</form>
) : (
<form onSubmit={handleLdapSignIn}>
<input
type="text"
placeholder="Логин или DN"
value={credential}
onChange={(e) => setCredential(e.target.value)}
required
style={{
width: '100%',
padding: 12,
marginBottom: 12,
border: '1px solid #ddd',
borderRadius: 8,
boxSizing: 'border-box',
}}
/>
<input
type="password"
placeholder="Пароль"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
style={{
width: '100%',
padding: 12,
marginBottom: 16,
border: '1px solid #ddd',
borderRadius: 8,
boxSizing: 'border-box',
}}
/>
<button
type="submit"
disabled={loading}
style={{
width: '100%',
padding: 12,
background: '#6366f1',
color: '#fff',
border: 'none',
borderRadius: 8,
fontSize: 16,
fontWeight: 600,
cursor: loading ? 'not-allowed' : 'pointer',
}}
>
{loading ? 'Вход...' : 'Войти через LDAP'}
</button>
</form>
)}
<p style={{ marginTop: 24, textAlign: 'center', fontSize: 14, color: '#666' }}>
Нет аккаунта?{' '}
<Link href="/sign-up" style={{ color: '#6366f1', textDecoration: 'none' }}>
Регистрация
</Link>
</p>
</div>
</div>
);
}