import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react'; import { Paper, IconButton, Chip, TextField, Tooltip, CircularProgress, Divider, Box } from '@mui/material'; import { Edit as EditIcon, DeleteOutline as DeleteOutlineIcon, FileCopyOutlined as FileCopyOutlinedIcon, ExpandMore as ExpandMoreIcon, ExpandLess as ExpandLessIcon, MoreHoriz as MoreHorizIcon, Visibility as VisibilityIcon, } from '@mui/icons-material'; import useBlogTextSelectionHandler from './BlogTextSelectionHandler'; import HoverMenu from './HoverMenu'; import { blogWriterApi } from '../../../services/blogWriterApi'; import { TextToSpeechButton } from '../../shared/TextToSpeechButton'; interface BlogSectionProps { id: any; title: string; content: string; wordCount: number; sources: number; outlineData?: { subheadings: string[]; keyPoints: string[]; keywords: string[]; references: any[]; targetWords: number; }; onContentUpdate?: (sections: any[]) => void; onDeleteSection?: (sectionId: any) => void; expandedSections: Set; toggleSectionExpansion: (sectionId: any) => void; refreshToken?: number; flowAnalysisResults?: any; sectionImage?: string; convertMarkdownToHTML?: (md: string) => string; } const BlogSection: React.FC = ({ id, title, content: initialContent, sources, outlineData, onContentUpdate, onDeleteSection, expandedSections, toggleSectionExpansion, refreshToken, flowAnalysisResults, sectionImage, convertMarkdownToHTML }) => { const [isEditing, setIsEditing] = useState(false); const [isPreviewing, setIsPreviewing] = useState(false); const [sectionTitle, setSectionTitle] = useState(title); const [content, setContent] = useState(initialContent); const [isGenerating, setIsGenerating] = useState(false); const [isHovered, setIsHovered] = useState(false); const [isFocused, setIsFocused] = useState(false); const contentRef = useRef(null); const [toolsAnchorEl, setToolsAnchorEl] = useState(null); const [activeTool, setActiveTool] = useState(null); const [toolLoading, setToolLoading] = useState(false); const [toolResult, setToolResult] = useState(null); const [toolDialogOpen, setToolDialogOpen] = useState(false); const wordCount_ = useMemo(() => content.split(/\s+/).filter(Boolean).length, [content]); const handleFormatText = useCallback((formatType: string, startPos?: number, endPos?: number) => { const textarea = contentRef.current; if (!textarea) return; const start = startPos ?? textarea.selectionStart; const end = endPos ?? textarea.selectionEnd; const selected = content.substring(start, end); const trimmed = selected.trim(); let replacement: string; let cursorPos: number; switch (formatType) { case 'bold': { const outerMatch = trimmed.match(/^\*\*(.+)\*\*$/s); if (outerMatch) { replacement = outerMatch[1]; } else { replacement = `**${trimmed.replace(/\*\*/g, '')}**`; } cursorPos = start + replacement.length; break; } case 'italic': { const outerMatch = trimmed.match(/^\*(?!\*)(.+)(? ${trimmed}` : `> Quote`; cursorPos = start + replacement.length; break; } case 'code': { const outerMatch = trimmed.match(/^`(.+)`$/s); if (outerMatch) { replacement = outerMatch[1]; } else { replacement = `\`${trimmed.replace(/`/g, '')}\``; } cursorPos = start + replacement.length; break; } case 'hr': { replacement = `\n\n---\n\n`; cursorPos = start + replacement.length; break; } default: return; } const newContent = content.substring(0, start) + replacement + content.substring(end); setContent(newContent); if (onContentUpdate) onContentUpdate([{ id, content: newContent }]); window.dispatchEvent(new CustomEvent('blogwriter:replaceSelectedText', { detail: { originalText: selected, editedText: replacement, editType: 'format' } })); requestAnimationFrame(() => { textarea.focus(); textarea.setSelectionRange(cursorPos, cursorPos); }); }, [content, id, onContentUpdate]); const assistiveWriting = useBlogTextSelectionHandler( contentRef, (originalText: string, newText: string, editType: string) => { if (contentRef.current) { const textarea = contentRef.current; let updatedContent: string; if (editType === 'smart-suggestion') { updatedContent = newText; } else { updatedContent = textarea.value.replace(originalText, newText); } setContent(updatedContent); if (onContentUpdate) onContentUpdate([{ id, content: updatedContent }]); } }, handleFormatText ); const formatContent = (rawContent: string) => { if (!rawContent) return rawContent; return rawContent.replace(/\n{3,}/g, '\n\n').replace(/\n(?!\n)/g, '\n\n').trim(); }; useEffect(() => { if (initialContent !== content) { setContent(formatContent(initialContent)); } }, [initialContent]); const handleContentChange = (e: any) => { const newContent = e.target.value; const cursorPos = e.target.selectionStart; setContent(newContent); assistiveWriting.handleTypingChange(newContent, cursorPos); }; const handleFocus = () => setIsFocused(true); const handleBlur = () => setIsFocused(false); const closeToolDialog = () => { setToolDialogOpen(false); setToolLoading(false); }; const runSectionTool = useCallback(async (tool: 'originality' | 'optimize' | 'fact' | 'links' | 'flow') => { setActiveTool(tool); setToolResult(null); setToolLoading(true); setToolDialogOpen(true); try { let res; if (tool === 'originality') { res = await blogWriterApi.sectionOriginalityTools({ section_id: String(id), title: sectionTitle, content }); } else if (tool === 'links') { res = await blogWriterApi.sectionInternalLinkTools({ section_id: String(id), title: sectionTitle, content }); } else if (tool === 'fact') { res = await blogWriterApi.sectionFactCheckTools({ section_id: String(id), title: sectionTitle, content }); } else if (tool === 'optimize') { res = await blogWriterApi.sectionOptimizeTools({ section_id: String(id), title: sectionTitle, content, keywords: outlineData?.keywords || [], goal: 'readability' }); } else if (tool === 'flow') { res = await blogWriterApi.analyzeFlowAdvanced({ title: sectionTitle, sections: [{ id: String(id), heading: sectionTitle, content }] }); } setToolResult(res); } catch (error: any) { setToolResult({ success: false, error: error?.message || 'Request failed' }); } finally { setToolLoading(false); } }, [id, sectionTitle, content, outlineData]); const applyOptimizedContent = () => { const next = toolResult?.optimized_content; if (!next) return; setContent(next); if (onContentUpdate) onContentUpdate([{ id, content: next }]); closeToolDialog(); }; const insertLinkSuggestion = (url: string) => { if (!url) return; const next = `${content || ''}\n\n[Related](${url})`; setContent(next); if (onContentUpdate) onContentUpdate([{ id, content: next }]); }; const handleGenerateContent = async () => { setIsGenerating(true); await new Promise(resolve => setTimeout(resolve, 2000)); setIsGenerating(false); }; // HoverMenu action handler const handleSectionAction = useCallback((action: string) => { switch (action) { case 'generate-content': handleGenerateContent(); break; case 'enhance-section': runSectionTool('optimize'); break; case 'fact-check': runSectionTool('fact'); break; case 'source-mapping': runSectionTool('originality'); break; case 'seo-analysis': runSectionTool('flow'); break; case 'add-subsection': break; case 'copy-section': break; case 'delete-section': break; default: break; } }, []); return (
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} >
{id}. {isEditing ? ( setSectionTitle(e.target.value)} onBlur={() => setIsEditing(false)} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === 'Escape') setIsEditing(false); }} autoFocus InputProps={{ disableUnderline: true, className: 'text-xl md:text-2xl font-bold font-serif text-gray-800' }} /> ) : (

setIsEditing(true)} > {sectionTitle}

)} {/* Section Toolbar - Shows on hover, positioned next to title */}
{/* Preview/Edit Toggle */} {convertMarkdownToHTML && ( setIsPreviewing(!isPreviewing)} sx={{ width: 32, height: 32, bgcolor: isPreviewing ? '#4f46e5' : 'white', color: isPreviewing ? 'white' : '#475569', border: '1px solid #e2e8f0', boxShadow: '0 1px 3px rgba(0,0,0,0.1)', '&:hover': { bgcolor: isPreviewing ? '#4338ca' : '#f8fafc', borderColor: isPreviewing ? '#4338ca' : '#cbd5e1', transform: 'translateY(-1px)', boxShadow: '0 2px 6px rgba(0,0,0,0.15)', }, transition: 'all 0.2s ease', }} > {isPreviewing ? : } )} {/* Copy Button */} {/* More Actions */} setToolsAnchorEl(e.currentTarget)} sx={{ width: 32, height: 32, bgcolor: 'white', color: '#64748b', border: '1px solid #e2e8f0', boxShadow: '0 1px 3px rgba(0,0,0,0.1)', '&:hover': { bgcolor: '#f8fafc', borderColor: '#cbd5e1', transform: 'translateY(-1px)', boxShadow: '0 2px 6px rgba(0,0,0,0.15)', }, transition: 'all 0.2s ease', }}> {/* Delete Button */} { if (window.confirm(`Are you sure you want to delete "${sectionTitle}"? This cannot be undone.`)) { onDeleteSection?.(id); } }} sx={{ width: 32, height: 32, bgcolor: 'white', color: '#ef4444', border: '1px solid #fecaca', boxShadow: '0 1px 3px rgba(0,0,0,0.1)', '&:hover': { bgcolor: '#fef2f2', borderColor: '#fca5a5', transform: 'translateY(-1px)', boxShadow: '0 2px 6px rgba(0,0,0,0.15)', }, transition: 'all 0.2s ease', }}> {/* Text-to-Speech Button */} {content && content.trim().length > 0 && ( )}
{sectionImage && (
{`Image
)} {isGenerating ? (
Generating content...
) : isPreviewing && convertMarkdownToHTML ? ( // Preview Mode
) : ( // Edit Mode
)} {/* Outline info */} {outlineData && expandedSections.has(id) && (
{outlineData.keyPoints?.length > 0 && (
Key Points
{outlineData.keyPoints.map((point: any, i: any) => ( ))}
)} {outlineData.subheadings?.length > 0 && (
Subheadings
{outlineData.subheadings.map((sub: any, i: any) => ( ))}
)} {outlineData.targetWords > 0 && (
Target words
{outlineData.targetWords}
)} {outlineData.keywords?.length > 0 && (
Keywords
{outlineData.keywords.map((kw: any, i: any) => ( ))}
)} {outlineData.references?.length > 0 && (
References ({outlineData.references.length})
{outlineData.references.slice(0, 3).map((ref: any, i: any) => ( ))} {outlineData.references.length > 3 && ( )}
)}
)} {/* Bottom word count - compact */}
📝 {wordCount_} words {outlineData?.targetWords && outlineData.targetWords > 0 && ( <> / = outlineData.targetWords * 0.9 ? '#10b981' : '#94a3b8', }}> {outlineData.targetWords} target )}
{outlineData && ( toggleSectionExpansion(id)} sx={{ width: 28, height: 28, bgcolor: 'transparent', color: '#64748b', '&:hover': { bgcolor: '#f1f5f9', }, }}> {expandedSections.has(id) ? : } )}
{/* HoverMenu for section-level actions */} setToolsAnchorEl(null)} type="section" onAction={handleSectionAction} context={{ sectionId: String(id), hasContent: content.trim().length > 0, sources, wordCount: wordCount_, }} /> {/* Tool result dialog */} {toolDialogOpen && (
e.stopPropagation()}>

{activeTool === 'originality' && 'Originality Check'} {activeTool === 'optimize' && 'Optimize Section'} {activeTool === 'fact' && 'SIF Fact Check'} {activeTool === 'links' && 'Internal Link Suggestions'} {activeTool === 'flow' && 'Flow Analysis'}

{toolLoading && (
Working...
)} {!toolLoading && toolResult?.error && (
{toolResult.error}
)} {!toolLoading && activeTool === 'optimize' && toolResult?.optimized_content && (
{toolResult?.diff_summary &&

{toolResult.diff_summary}

} {Array.isArray(toolResult?.changes_made) && toolResult.changes_made.length > 0 && (
    {toolResult.changes_made.map((c: string, idx: number) => (
  • {c}
  • ))}
)}
)} {!toolLoading && activeTool === 'links' && (
{Array.isArray(toolResult?.suggestions) && toolResult.suggestions.length > 0 ? ( toolResult.suggestions.map((s: any, idx: number) => (

{s.url}

confidence: {(s.confidence ?? 0).toFixed?.(2) ?? s.confidence}

)) ) : (

No suggestions yet. Make sure SIF index has your website content.

)}
)} {!toolLoading && activeTool === 'originality' && (
{toolResult?.cannibalization &&
{JSON.stringify(toolResult.cannibalization, null, 2)}
} {Array.isArray(toolResult?.matches) && toolResult.matches.length > 0 ? (
{toolResult.matches.map((m: any, idx: number) => (

{m.id ?? 'unknown'} ({(m.score ?? 0).toFixed?.(3) ?? m.score})

{m.excerpt &&

{m.excerpt}

}
))}
) : (

No close matches found.

)}
)} {!toolLoading && activeTool === 'fact' && (
{toolResult?.verification &&
{JSON.stringify(toolResult.verification, null, 2)}
} {Array.isArray(toolResult?.citations) && toolResult.citations.length > 0 && (
{toolResult.citations.map((c: any, idx: number) => (

{c.citation_text || c.title || c.source}

{c.source}

))}
)}
)} {!toolLoading && activeTool === 'flow' && (
{JSON.stringify(toolResult, null, 2)}
)}
{activeTool === 'optimize' && toolResult?.optimized_content && ( )}
)} {assistiveWriting.renderSelectionMenu()}
); }; export default BlogSection;