feat: P4 ChannelAnalytics tab; P5 FromUrlModal + URL→draft in ChannelView

This commit is contained in:
Nik (Claude)
2026-06-08 11:09:03 +03:00
parent b8a570f04a
commit eac6e2ed13
7 changed files with 555 additions and 0 deletions
+43
View File
@@ -9,6 +9,8 @@ import {
import PhotoSearchModal from './PhotoSearchModal';
import PostPreview from './PostPreview';
import PostTemplates from './PostTemplates';
import ChannelAnalytics from './ChannelAnalytics';
import FromUrlModal from './FromUrlModal';
const GOAL_LABELS = {
educational: 'Обучение', news: 'Новости',
@@ -53,6 +55,7 @@ export default function ChannelView({ channel }) {
// Photo search modal
const [showPhotoSearch, setShowPhotoSearch] = useState(false);
const [showFromUrl, setShowFromUrl] = useState(false);
// Трансформации
const [transforming, setTransforming] = useState(false);
@@ -85,6 +88,7 @@ export default function ChannelView({ channel }) {
// Сохранение и публикация
const [savedPostId, setSavedPostId] = useState(null);
const [publishing, setPublishing] = useState(false);
const [activeTab, setActiveTab] = useState('generate'); // generate | analytics
const [showScheduler, setShowScheduler] = useState(false);
const [scheduleAt, setScheduleAt] = useState('');
const [history, setHistory] = useState([]);
@@ -118,6 +122,13 @@ export default function ChannelView({ channel }) {
setShowPhotoSearch(false);
}
function applyFromUrl({ content, imageUrl, title }) {
setPost(content);
if (imageUrl) setImage(imageUrl);
if (title && !topic.trim()) setTopic(title.slice(0, 120));
setSavedPostId(null);
}
async function savePost(status = 'draft', scheduledAt = null) {
if (!post) return;
setPublishing(true);
@@ -330,6 +341,22 @@ export default function ChannelView({ channel }) {
</Link>
</div>
{/* Вкладки */}
<div className="flex items-center gap-0.5 rounded-lg p-0.5 bg-surface2 border border-border self-start mb-2">
{[['generate','Создать пост'],['analytics','Аналитика']].map(([id,label]) => (
<button key={id} onClick={() => setActiveTab(id)}
className={`px-4 py-1.5 rounded-md text-sm font-medium transition-colors
${activeTab===id ? 'bg-surface text-text shadow-sm' : 'text-text-soft hover:text-text'}`}>
{label}
</button>
))}
</div>
{activeTab === 'analytics' && (
<ChannelAnalytics channelId={channel.id} channelName={channel.tg_username} />
)}
{activeTab === 'generate' && <>
{/* Generator */}
<div className="card p-5 mb-6">
<div className="flex items-center justify-between mb-3 flex-wrap gap-2">
@@ -339,6 +366,13 @@ export default function ChannelView({ channel }) {
</h2>
<div className="flex items-center gap-3">
<PostTemplates onSelect={applyTemplate} disabled={generating} />
<button
onClick={() => setShowFromUrl(true)}
className="text-xs inline-flex items-center gap-1 text-accent hover:underline"
>
<Link2 className="w-3.5 h-3.5" />
По ссылке
</button>
<button
onClick={fetchIdeas}
disabled={loadingIdeas}
@@ -613,6 +647,14 @@ export default function ChannelView({ channel }) {
</div>
)}
{/* From URL modal */}
<FromUrlModal
open={showFromUrl}
channelId={channel.id}
onClose={() => setShowFromUrl(false)}
onApply={applyFromUrl}
/>
{/* Photo search modal */}
<PhotoSearchModal
open={showPhotoSearch}
@@ -709,6 +751,7 @@ export default function ChannelView({ channel }) {
</div>
</div>
)}
</> }
</main>
);
}