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 (
Create and publish your social media posts with intelligent content generation
Total Posts
{posts.length}
Published
{publishedPosts.length}
Accounts
{accounts.length}
{error}
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.
You need to add RSS sources before generating content.
)} {isGenerating && (Please wait while we generate your post. This may take 2-5 minutes.
)}Image data exists but cannot be displayed directly
The image will be included when you publish the post
Your published posts will appear here once you publish them.
{post.Text_content}