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:
@@ -1,5 +1,6 @@
|
||||
import { useState, useRef, useEffect, useCallback } from 'react';
|
||||
import { debug } from '../../../utils/debug';
|
||||
import { hashContent, getSeoCacheKey } from '../../../utils/contentHash';
|
||||
import { blogWriterApi, BlogSEOActionableRecommendation } from '../../../services/blogWriterApi';
|
||||
import { blogWriterCache } from '../../../services/blogWriterCache';
|
||||
|
||||
@@ -218,6 +219,44 @@ export const useSEOManager = ({
|
||||
const [seoRecommendationsApplied, setSeoRecommendationsApplied] = useState(false);
|
||||
const lastSEOModalOpenRef = useRef<number>(0);
|
||||
|
||||
// Restore cached SEO analysis on mount when sections are available
|
||||
useEffect(() => {
|
||||
const restoreCachedSEO = async () => {
|
||||
if (seoAnalysis) return;
|
||||
|
||||
const title = selectedTitle || '';
|
||||
if (!title && (!outline || outline.length === 0)) return;
|
||||
|
||||
const fullMarkdown = (outline || []).map(s => `## ${s.heading}\n\n${(sections || {})[s.id] || ''}`).join('\n\n');
|
||||
if (!fullMarkdown && !title) return;
|
||||
|
||||
try {
|
||||
const hash = await hashContent(`${title}\n${fullMarkdown}`);
|
||||
const cacheKey = getSeoCacheKey(hash, title);
|
||||
const cached = window.localStorage.getItem(cacheKey);
|
||||
if (cached) {
|
||||
const parsed = JSON.parse(cached);
|
||||
if (parsed && typeof parsed.overall_score === 'number' && parsed.category_scores) {
|
||||
debug.log('[SEOManager] Restored cached SEO analysis', { cacheKey, score: parsed.overall_score });
|
||||
setSeoAnalysis(parsed);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debug.log('[SEOManager] Failed to restore cached SEO analysis', e);
|
||||
}
|
||||
};
|
||||
|
||||
restoreCachedSEO();
|
||||
|
||||
try {
|
||||
const wasApplied = localStorage.getItem('blog_seo_recommendations_applied') === 'true';
|
||||
if (wasApplied) {
|
||||
setSeoRecommendationsApplied(true);
|
||||
debug.log('[SEOManager] Restored seoRecommendationsApplied flag');
|
||||
}
|
||||
} catch {}
|
||||
}, [selectedTitle, sections, outline, seoAnalysis, setSeoAnalysis, setSeoRecommendationsApplied]);
|
||||
|
||||
// Helper: run same checks as analyzeSEO and open modal
|
||||
const runSEOAnalysisDirect = useCallback((): string => {
|
||||
const hasSections = !!sections && Object.keys(sections).length > 0;
|
||||
@@ -387,6 +426,9 @@ export const useSEOManager = ({
|
||||
// Mark recommendations as applied (this will trigger phase navigation check)
|
||||
// But we'll stay in SEO phase to show updated content
|
||||
setSeoRecommendationsApplied(true);
|
||||
try {
|
||||
localStorage.setItem('blog_seo_recommendations_applied', 'true');
|
||||
} catch {}
|
||||
debug.log('[BlogWriter] seoRecommendationsApplied set to true');
|
||||
|
||||
// Ensure we stay in SEO phase to show updated content
|
||||
|
||||
Reference in New Issue
Block a user