Files
zeropost-tool/app/page.js
T
Ник (Claude) 69226cbbde fix: Link2 undefined crash + goal multi-select + custom goal
ChannelView.js:
- Добавлен Link2 в import lucide-react (ReferenceError при открытии канала)
- Отображение goal учитывает множественные значения через split(',')

app/page.js:
- Аналогичный фикс отображения goal (split → map → join)

channels/new/page.js:
- Цель канала: single-select → multi-select (можно выбрать несколько)
- Кастомная цель: поле + кнопка «+», Enter, чипы с удалением
- Сохраняется как CSV строка (goal: goals.join(','))

DB:
- channels.goal varchar(50) → varchar(255) для длинных кастомных значений
2026-06-09 08:39:32 +03:00

101 lines
3.7 KiB
JavaScript
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 { redirect } from 'next/navigation';
import Link from 'next/link';
import { requireUser } from '@/lib/session';
import { engine } from '@/lib/engine';
import Header from '@/components/Header';
import { Plus, MessageSquare, Users, Target } from 'lucide-react';
const GOAL_LABELS = {
educational: 'Обучение',
news: 'Новости',
entertainment: 'Развлечение',
expert: 'Экспертный',
sales: 'Продажи',
};
export default async function HomePage() {
const user = await requireUser();
if (!user) redirect('/login');
let channels = [];
try {
channels = await engine.listChannels(user.id);
} catch (err) {
console.error('listChannels failed:', err.message);
}
return (
<>
<Header user={user} />
<main className="max-w-6xl mx-auto p-4 sm:p-6">
<div className="flex items-center justify-between mb-6">
<div>
<h1 className="text-2xl font-bold">Мои каналы</h1>
<p className="text-sm text-gray-500 mt-1">
Управляй контентом и публикациями
</p>
</div>
<Link href="/channels/new" className="btn-primary">
<Plus className="w-4 h-4" />
Добавить канал
</Link>
</div>
{channels.length === 0 ? (
<div className="card p-12 text-center">
<div className="inline-flex items-center justify-center w-14 h-14 rounded-full bg-surface2 mb-4">
<MessageSquare className="w-7 h-7 text-gray-500" />
</div>
<h2 className="text-lg font-semibold mb-1">Пока пусто</h2>
<p className="text-sm text-gray-500 mb-6">
Создай первый канал, чтобы начать генерировать посты
</p>
<Link href="/channels/new" className="btn-primary">
<Plus className="w-4 h-4" />
Создать канал
</Link>
</div>
) : (
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
{channels.map(ch => (
<Link
key={ch.id}
href={`/channels/${ch.id}`}
className="card p-5 hover:border-accent/40 transition-colors group"
>
<div className="flex items-start justify-between mb-3">
<h3 className="font-semibold group-hover:text-accent transition-colors">
{ch.name}
</h3>
<span className="text-xs px-2 py-0.5 rounded-full bg-surface2 text-gray-400">
{(ch.goal || '').split(',').map(g => GOAL_LABELS[g.trim()] || g.trim()).join(' · ')}
</span>
</div>
{ch.niche && (
<p className="text-xs text-gray-500 line-clamp-2 mb-3">
{ch.niche}
</p>
)}
<div className="flex items-center gap-4 text-xs text-gray-500">
{ch.audience && (
<span className="flex items-center gap-1">
<Users className="w-3 h-3" />
Есть ЦА
</span>
)}
{ch.style?.example_posts?.length > 0 && (
<span className="flex items-center gap-1">
<Target className="w-3 h-3 text-accent" />
{ch.style.example_posts.length} пример{ch.style.example_posts.length === 1 ? '' : 'а'}
</span>
)}
</div>
</Link>
))}
</div>
)}
</main>
</>
);
}