feat: P4 ChannelAnalytics tab; P5 FromUrlModal + URL→draft in ChannelView
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user