support-bot-saas/frontend/src/pages/Login.tsx
ed0ss 0063df0a87
Some checks are pending
CI / lint-backend (push) Waiting to run
CI / lint-frontend (push) Waiting to run
CI / build-backend (push) Blocked by required conditions
CI / build-frontend (push) Blocked by required conditions
Реструктуризация проекта в SaaS: FastAPI бэкенд, React SPA фронтенд, Helm-чарт, CI/CD
- Бэкенд: FastAPI + SQLAlchemy async + PostgreSQL, JWT-аутентификация,
  Qdrant multi-tenant векторное хранилище, Celery воркер
- Фронтенд: React + Vite + TypeScript SPA (логин, регистрация,
  дашборд, поиск по коллекциям, настройки)
- Инфраструктура: docker-compose, Helm-чарт, GitHub Actions CI,
  Prometheus/Grafana мониторинг
- Embedding через OpenRouter (nvidia/llama-nemotron-embed-vl-1b-v2:free)
- LLM: google/gemma-4-31b-it:free через OpenRouter
2026-06-20 17:40:27 +03:00

56 lines
1.6 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.

import { useState } from 'react'
import { useNavigate, Link } from 'react-router-dom'
import { api, setToken } from '../api/client'
export default function Login() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const navigate = useNavigate()
async function handleSubmit(e: React.FormEvent) {
e.preventDefault()
try {
const res = await api.login(email, password)
setToken(res.access_token)
navigate('/dashboard')
} catch (err: any) {
setError(err.message)
}
}
return (
<div style={{ maxWidth: 400, margin: '100px auto', padding: 20 }}>
<h1>Вход</h1>
<form onSubmit={handleSubmit}>
<div>
<input
type="email"
placeholder="Email"
value={email}
onChange={e => setEmail(e.target.value)}
required
style={{ width: '100%', padding: 8, marginBottom: 8 }}
/>
</div>
<div>
<input
type="password"
placeholder="Пароль"
value={password}
onChange={e => setPassword(e.target.value)}
required
style={{ width: '100%', padding: 8, marginBottom: 8 }}
/>
</div>
{error && <p style={{ color: 'red' }}>{error}</p>}
<button type="submit" style={{ width: '100%', padding: 10 }}>
Войти
</button>
</form>
<p style={{ marginTop: 12 }}>
Нет аккаунта? <Link to="/register">Регистрация</Link>
</p>
</div>
)
}