import React, { useState, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import { fetchPosts, generatePost, createPost, publishPostDirect, deletePost, updatePostContent, clearError } from '../store/reducers/postsSlice'; import { fetchAccounts } from '../store/reducers/accountsSlice'; import { fetchSources } from '../store/reducers/sourcesSlice'; const Posts = () => { const dispatch = useDispatch(); const navigate = useNavigate(); const { items: posts, loading, error } = useSelector(state => state.posts); const { items: accounts } = useSelector(state => state.accounts); const { items: sources } = useSelector(state => state.sources); const [selectedAccount, setSelectedAccount] = useState(''); const [postContent, setPostContent] = useState(''); const [postImage, setPostImage] = useState(null); // State for image URL const [isGenerating, setIsGenerating] = useState(false); const [isCreating, setIsCreating] = useState(false); useEffect(() => { dispatch(fetchPosts()); dispatch(fetchAccounts()); dispatch(fetchSources()); dispatch(clearError()); }, [dispatch]); const handleGeneratePost = async () => { setIsGenerating(true); setPostImage(null); // Reset image when generating new post try { const result = await dispatch(generatePost()).unwrap(); // Handle case where content might be a list let content = result.content || 'Generated content will appear here...'; let image = null; // If content is an array, handle both content and image if (Array.isArray(content)) { content = content[0] || 'Generated content will appear here...'; image = content[1] || null; // Second element might be image URL } // If result has image_url property (from backend) else if (result.image_url) { image = result.image_url; } // If result has has_image_data property, it means image data exists but is in bytes else if (result.has_image_data) { // For now, we'll just show a placeholder or message // In a future update, we might fetch the image data separately image = 'HAS_IMAGE_DATA_BUT_NOT_URL'; // Special marker } setPostContent(content); setPostImage(image); } catch (err) { console.error('Failed to generate post:', err); // Show a user-friendly error message dispatch(clearError()); // You can dispatch a new action to set a specific error message // or use a local state variable to display the error } finally { setIsGenerating(false); } }; const handleCreatePost = async (e) => { e.preventDefault(); if (!selectedAccount || !postContent.trim()) { console.log('📝 [Posts] Missing required fields:', { selectedAccount, postContentLength: postContent.trim().length }); return; } console.log('📝 [Posts] Publishing post directly to LinkedIn:', { selectedAccount, postContentLength: postContent.length }); setIsCreating(true); try { // Publish directly to LinkedIn console.log('📝 [Posts] Publishing to LinkedIn'); const publishData = { social_account_id: selectedAccount, text_content: postContent }; // Add image URL if available if (postImage) { publishData.image_content_url = postImage; } const publishResult = await dispatch(publishPostDirect(publishData)).unwrap(); console.log('📝 [Posts] Published to LinkedIn successfully:', publishResult); // Only save to database if LinkedIn publish was successful console.log('📝 [Posts] Saving post to database as published'); const createData = { social_account_id: selectedAccount, text_content: postContent, is_published: true // Mark as published since we've already published it }; // Add image URL if available if (postImage) { createData.image_content_url = postImage; } await dispatch(createPost(createData)).unwrap(); console.log('📝 [Posts] Post saved to database'); // Reset form setSelectedAccount(''); setPostContent(''); setPostImage(null); setPostImage(null); } catch (err) { console.error('📝 [Posts] Failed to publish post:', err); // Don't save to database if LinkedIn publish failed } finally { setIsCreating(false); } }; const handleDeletePost = async (postId) => { try { await dispatch(deletePost(postId)).unwrap(); } catch (err) { console.error('Failed to delete post:', err); } }; const handleContentChange = (content) => { setPostContent(content); // If user manually edits content, we should clear the AI-generated image // as it might no longer be relevant if (postImage) { setPostImage(null); } }; // Filter published posts const publishedPosts = posts.filter(post => post.is_published); return (
{/* Header Section */}

Post Management

Create and publish your social media posts with intelligent content generation

{/* Stats Cards */}

Total Posts

{posts.length}

Published

{publishedPosts.length}

Accounts

{accounts.length}

{/* Error Display */} {error && (

{error}

)} {/* Info Message when no sources */} {sources.length === 0 && !loading && (

No RSS Sources Found

You need to add at least one RSS source to enable AI content generation. You can still manually create and publish posts without RSS sources.

)}
{/* Post Creation Section */}

Create New Post

{/* AI Generator */}

AI Content Generator

Powered by AI
{sources.length === 0 && !isGenerating && (

You need to add RSS sources before generating content.

)} {isGenerating && (

Please wait while we generate your post. This may take 2-5 minutes.

)}
{/* Content Editor */}