Files
postcast-tool/app/login/page.js
T
Ник (Claude) ab4e340db9 feat: onboarding + topic bank UI + channel limit handling
/onboarding: 3-шаговый вайзард (платформа → название/ниша → готово)
login/page.js: новый пользователь → /onboarding, существующий → /
TopicBank.js: просмотр/пополнение/добавление/удаление тем
ChannelEdit AI-стиль: TopicBank компонент внизу вкладки
channels/new: при 402 CHANNEL_LIMIT_REACHED → ошибка + redirect /plans
lib/engine.js: ENGINE_URL дефолт 3040 → 3030
API routes: /api/topics-bank/[channelId]/{refill,add}, /item/[id]
2026-06-12 11:50:22 +03:00

100 lines
3.4 KiB
JavaScript

'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { Sparkles } from 'lucide-react';
import ThemeToggle from '@/components/ThemeToggle';
export default function LoginPage() {
const router = useRouter();
const [mode, setMode] = useState('login');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [busy, setBusy] = useState(false);
async function submit(e) {
e.preventDefault();
setBusy(true);
setError('');
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password, mode }),
});
const data = await res.json();
setBusy(false);
if (!res.ok) {
setError(data.error || 'Ошибка');
return;
}
// Новый пользователь → онбординг, существующий → главная
router.push(data.isNew ? '/onboarding' : '/');
}
return (
<main className="min-h-screen flex items-center justify-center p-4 relative">
<div className="absolute top-4 right-4">
<ThemeToggle />
</div>
<div className="w-full max-w-md">
<div className="flex items-center gap-2 mb-8 justify-center">
<Sparkles className="w-7 h-7 text-accent" />
<span className="text-2xl font-bold">ZeroPost</span>
</div>
<div className="card p-8">
<h1 className="text-xl font-semibold mb-1">
{mode === 'login' ? 'Вход' : 'Регистрация'}
</h1>
<p className="text-sm text-gray-500 mb-6">
ИИ-ассистент для Telegram-каналов
</p>
<form onSubmit={submit} className="space-y-4">
<div>
<label className="label">Email</label>
<input
type="email"
required
value={email}
onChange={e => setEmail(e.target.value)}
className="input"
placeholder="you@example.com"
/>
</div>
<div>
<label className="label">Пароль</label>
<input
type="password"
required
minLength={6}
value={password}
onChange={e => setPassword(e.target.value)}
className="input"
placeholder="••••••••"
/>
</div>
{error && (
<div className="text-sm text-red-400 bg-red-500/10 border border-red-500/20 rounded-lg px-3 py-2">
{error}
</div>
)}
<button disabled={busy} className="btn-primary w-full">
{busy ? 'Подождите...' : (mode === 'login' ? 'Войти' : 'Зарегистрироваться')}
</button>
</form>
<button
onClick={() => { setMode(mode === 'login' ? 'register' : 'login'); setError(''); }}
className="w-full text-center text-sm text-gray-500 hover:text-gray-300 mt-6"
>
{mode === 'login' ? 'Нет аккаунта? Зарегистрироваться' : 'Уже есть аккаунт? Войти'}
</button>
</div>
</div>
</main>
);
}