fix: WYSIWYG editor, content generation, and writing assistant bug fixes

- Fix text selection menu not showing: wire contentRef via inputRef on multiline TextField
- Fix blog title not truncating: add min-w-0 for flex item overflow
- Fix outline generation 500: escape curly braces in f-string prompt template
- Fix content generation 'NoneType not callable': replace SessionLocal() with get_session_for_user(), add db param to MediumBlogGenerator, fix signature mismatch in database_task_manager
- Fix writing assistant suggest 500: add auth + user_id to API endpoint and service, replace sync requests with httpx.AsyncClient
- Fix hallucination detector 404: explicitly include router in main.py and app.py
- Fix missing error_data in task failure responses
- Hide CopilotKit web inspector button
- Remove hardcoded fallback suggestions from SmartTypingAssist
- Fix stale closure refs in SmartTypingAssist handleTypingChange
- Add two-column editor layout, stats bar, section hover menu
- Various subscription, billing, and research module improvements
This commit is contained in:
ajaysi
2026-05-14 09:11:30 +05:30
parent 7385100017
commit 928c2f20aa
113 changed files with 4344 additions and 10064 deletions

View File

@@ -1,6 +1,7 @@
import { useState, useEffect, useCallback } from 'react';
import { BlogOutlineSection, BlogResearchResponse, BlogSEOMetadataResponse, BlogSEOAnalyzeResponse, SourceMappingStats, GroundingInsights, OptimizationResults, ResearchCoverage } from '../services/blogWriterApi';
import { researchCache } from '../services/researchCache';
import { blogWriterCache } from '../services/blogWriterCache';
const MINOR_TITLE_WORDS = new Set([
'a', 'an', 'and', 'or', 'but', 'the', 'for', 'nor', 'on', 'at', 'to', 'from', 'by',
@@ -94,36 +95,70 @@ export const useBlogWriterState = () => {
// Cache recovery - restore most recent research on page load
useEffect(() => {
const cachedEntries = researchCache.getAllCachedEntries();
if (cachedEntries.length > 0) {
// Get the most recent cached research
const mostRecent = cachedEntries[0];
console.log('Restoring cached research from page load:', mostRecent.keywords);
setResearch(mostRecent.result);
// Also try to restore outline if it exists in localStorage
try {
const savedOutline = localStorage.getItem('blog_outline');
const savedTitleOptions = localStorage.getItem('blog_title_options');
const savedSelectedTitle = localStorage.getItem('blog_selected_title');
const restoreState = async () => {
const cachedEntries = researchCache.getAllCachedEntries();
if (cachedEntries.length > 0) {
// Get the most recent cached research
const mostRecent = cachedEntries[0];
console.log('Restoring cached research from page load:', mostRecent.keywords);
setResearch(mostRecent.result);
if (savedOutline) {
setOutline(JSON.parse(savedOutline));
// Also try to restore outline if it exists in localStorage
try {
const savedOutline = localStorage.getItem('blog_outline');
const savedTitleOptions = localStorage.getItem('blog_title_options');
const savedSelectedTitle = localStorage.getItem('blog_selected_title');
if (savedOutline) {
const parsedOutline = JSON.parse(savedOutline);
setOutline(parsedOutline);
// Restore content sections from cache when outline is available
const outlineIds = parsedOutline.map((s: any) => String(s.id));
const cachedContent = blogWriterCache.getCachedContent(outlineIds);
if (cachedContent && Object.keys(cachedContent).length > 0) {
setSections(cachedContent);
console.log('Restored content sections from cache', { sections: Object.keys(cachedContent).length });
}
}
if (savedTitleOptions) {
setTitleOptions(JSON.parse(savedTitleOptions));
}
if (savedSelectedTitle) {
setSelectedTitle(savedSelectedTitle);
}
// Restore contentConfirmed from localStorage
const savedContentConfirmed = localStorage.getItem('blog_content_confirmed');
if (savedContentConfirmed === 'true') {
setContentConfirmed(true);
}
console.log('Restored outline, content, and title data from localStorage');
} catch (error) {
console.error('Error restoring outline data:', error);
}
if (savedTitleOptions) {
setTitleOptions(JSON.parse(savedTitleOptions));
}
if (savedSelectedTitle) {
setSelectedTitle(savedSelectedTitle);
}
console.log('Restored outline and title data from localStorage');
} catch (error) {
console.error('Error restoring outline data:', error);
}
}
};
restoreState();
}, []);
// Persist contentConfirmed to localStorage whenever it changes
useEffect(() => {
try {
localStorage.setItem('blog_content_confirmed', String(contentConfirmed));
} catch {}
}, [contentConfirmed]);
// Persist sections to blogWriterCache whenever they change
useEffect(() => {
const outlineIds = outline.map(s => String(s.id));
if (outlineIds.length > 0 && Object.keys(sections).length > 0) {
blogWriterCache.cacheContent(sections, outlineIds);
}
}, [sections, outline]);
// Handle research completion
const handleResearchComplete = useCallback((researchData: BlogResearchResponse) => {
setResearch(researchData);