From 11f164ae21cd6253d96682f8bb00abf36092d6f1 Mon Sep 17 00:00:00 2001 From: ajaysi Date: Fri, 10 Oct 2025 13:08:09 +0530 Subject: [PATCH] ALwrity + Wix + Wordpress + GSC + Bug Fixes --- ...ress_user_33Gz1FPI86VDXhRY8QN4ragRFGN.json | 4 +- .../BlogWriter/ResearchPollingHandler.tsx | 4 +- .../BlogWriter/RewriteFeedbackForm.tsx | 3 +- .../SEO/MetadataDisplay/PreviewCard.tsx | 26 +------ .../BlogWriter/SEOAnalysisModal.tsx | 30 +------- .../BlogWriter/SEOMetadataModal.tsx | 11 +-- .../CalendarGenerationModal.tsx | 59 ++------------- .../AdvancedOptionsStep.tsx | 4 - .../CalendarConfigurationStep.tsx | 4 +- .../components/ContentStrategyBuilder.tsx | 74 ++----------------- .../ContentStrategyBuilder/CopilotActions.tsx | 14 +--- .../EnhancedPerformanceVisualization.tsx | 18 +---- .../components/SystemStatusIndicator.tsx | 21 +----- .../tabs/CalendarTab.tsx | 74 +------------------ .../tabs/ContentOptimizerTab.tsx | 3 +- .../tabs/ContentPillarsTab.tsx | 4 +- .../tabs/ContentStrategyTab.tsx | 21 +----- .../tabs/CreateTab.tsx | 26 +++---- .../tabs/GapAnalysisTab.tsx | 3 +- .../tabs/KeywordResearchTab.tsx | 5 -- .../tabs/RefineAnalysisTab.tsx | 1 + .../FacebookWriter/FacebookWriter.tsx | 12 +-- .../RegisterLinkedInActions.tsx | 16 +--- .../RegisterLinkedInEditActions.tsx | 1 - .../components/BrainstormFlow.tsx | 2 +- .../components/ContentEditor.tsx | 13 ++-- .../MainDashboard/ContentLifecyclePillars.tsx | 22 +----- .../MainDashboard/MainDashboard.tsx | 2 +- .../components/AnalyzePillarChips.tsx | 2 +- .../components/CompactSidebar.tsx | 17 +---- .../components/EngagePillarChips.tsx | 2 +- .../components/EnhancedTodayModal.tsx | 15 +--- .../ApiKeyStep/utils/ApiKeyCarousel.tsx | 40 +--------- .../ApiKeyStep/utils/ApiKeySidebar.tsx | 3 - .../ApiKeyStep/utils/useApiKeyStep.ts | 2 - .../CompetitorAnalysisStep.tsx | 33 +-------- .../ComingSoonSection.tsx | 13 +--- .../OnboardingWizard/IntegrationsStep.tsx | 22 ++---- .../PersonaStep/ComingSoonSection.tsx | 12 +-- .../components/AnalysisProgressDisplay.tsx | 2 - .../WebsiteStep/utils/renderUtils.tsx | 12 +-- .../components/OnboardingWizard/Wizard.tsx | 1 - .../common/GSCPlatformCard.tsx | 3 +- .../common/WixPlatformCard.tsx | 1 - .../common/WordPressOAuthPlatformCard.tsx | 5 +- .../SEODashboard/SEOCopilotContext.tsx | 3 +- .../SEODashboard/SEOCopilotTest.tsx | 2 +- .../components/SEODashboard/SEODashboard.tsx | 3 - .../components/GSCLoginButton.tsx | 1 + .../components/SEOAnalyzerPanel.tsx | 1 - .../TextEditor/CitationHoverHandler.tsx | 4 - .../TextEditor/ContentDisplayArea.tsx | 2 +- .../ContentPreviewHeaderWithModals.tsx | 1 + .../MainContentPreviewHeader.tsx | 1 - .../PersonaChip.tsx | 1 + .../TextEditor/QuickEditToolbar.tsx | 4 +- .../TextEditor/TextSelectionHandler.tsx | 6 +- .../components/WixTestPage/WixTestPage.tsx | 7 +- .../components/billing/BillingOverview.tsx | 6 -- .../billing/CompactBillingDashboard.tsx | 14 +--- .../billing/ComprehensiveAPIBreakdown.tsx | 11 --- .../src/components/billing/CostBreakdown.tsx | 5 +- .../billing/EnhancedBillingDashboard.tsx | 18 ----- .../src/components/billing/UsageAlerts.tsx | 1 - .../src/components/billing/UsageTrends.tsx | 1 - .../monitoring/SystemHealthIndicator.tsx | 4 - .../shared/ComponentErrorBoundary.tsx | 2 +- .../src/components/shared/DashboardHeader.tsx | 4 +- .../src/components/shared/ErrorBoundary.tsx | 1 - .../src/components/shared/ErrorDisplay.tsx | 2 +- .../PlatformPersonaProvider.tsx | 11 ++- frontend/src/components/shared/UserBadge.tsx | 2 +- .../shared/charts/AdvancedChartComponents.tsx | 2 - .../src/contexts/StrategyCalendarContext.tsx | 2 +- frontend/src/data/toolCategories.ts | 2 - frontend/src/hooks/usePersonaPolling.ts | 1 - frontend/src/hooks/usePolling.ts | 1 - frontend/src/hooks/useWixConnection.ts | 2 - frontend/src/stores/enhancedStrategyStore.ts | 2 +- frontend/vercel.json | 11 +-- 80 files changed, 125 insertions(+), 678 deletions(-) diff --git a/backend/.onboarding_progress_user_33Gz1FPI86VDXhRY8QN4ragRFGN.json b/backend/.onboarding_progress_user_33Gz1FPI86VDXhRY8QN4ragRFGN.json index 16ad3df1..1f81d61b 100644 --- a/backend/.onboarding_progress_user_33Gz1FPI86VDXhRY8QN4ragRFGN.json +++ b/backend/.onboarding_progress_user_33Gz1FPI86VDXhRY8QN4ragRFGN.json @@ -1428,7 +1428,7 @@ "title": "Personalization", "description": "Set up personalization features", "status": "completed", - "completed_at": "2025-10-09T13:05:12.886271", + "completed_at": "2025-10-10T08:44:52.292617", "data": { "corePersona": { "analysis_notes": "This persona is generated based on general best practices for professional and engaging content, as no specific website, content, audience, or brand data was provided. The details are inferred to create a functional, albeit generic, persona. For a truly precise and actionable persona, comprehensive input data across all specified categories (website analysis, content insights, audience intelligence, brand voice, technical metrics, competitive analysis, content strategy, research preferences) is essential. The current persona serves as a foundational template that would be significantly refined and customized with actual data.", @@ -2677,7 +2677,7 @@ ], "current_step": 5, "started_at": "2025-09-29T17:22:14.375002", - "last_updated": "2025-10-09T13:05:12.888068", + "last_updated": "2025-10-10T08:44:52.293336", "is_completed": false, "completed_at": null } \ No newline at end of file diff --git a/frontend/src/components/BlogWriter/ResearchPollingHandler.tsx b/frontend/src/components/BlogWriter/ResearchPollingHandler.tsx index 611856f7..b07f7521 100644 --- a/frontend/src/components/BlogWriter/ResearchPollingHandler.tsx +++ b/frontend/src/components/BlogWriter/ResearchPollingHandler.tsx @@ -52,14 +52,14 @@ export const ResearchPollingHandler: React.FC = ({ } else { polling.stopPolling(); } - }, [taskId]); + }, [taskId, polling]); // Cleanup on unmount useEffect(() => { return () => { polling.stopPolling(); }; - }, []); + }, [polling]); console.log('ResearchPollingHandler render:', { taskId, diff --git a/frontend/src/components/BlogWriter/RewriteFeedbackForm.tsx b/frontend/src/components/BlogWriter/RewriteFeedbackForm.tsx index 0fea868f..23e610ab 100644 --- a/frontend/src/components/BlogWriter/RewriteFeedbackForm.tsx +++ b/frontend/src/components/BlogWriter/RewriteFeedbackForm.tsx @@ -213,7 +213,7 @@ export const RewriteFeedbackForm: React.FC = ({ onRewriteStarted, onRewriteTriggered }) => { - const [isCollectingFeedback, setIsCollectingFeedback] = useState(false); + // Note: isCollectingFeedback state removed as it was unused // Rewrite Blog Action with HITL useCopilotActionTyped({ @@ -303,7 +303,6 @@ export const RewriteFeedbackForm: React.FC = ({ if (result.success && result.taskId) { onRewriteStarted?.(result.taskId); - setIsCollectingFeedback(false); return { success: true, diff --git a/frontend/src/components/BlogWriter/SEO/MetadataDisplay/PreviewCard.tsx b/frontend/src/components/BlogWriter/SEO/MetadataDisplay/PreviewCard.tsx index 551f60d9..6ac707d1 100644 --- a/frontend/src/components/BlogWriter/SEO/MetadataDisplay/PreviewCard.tsx +++ b/frontend/src/components/BlogWriter/SEO/MetadataDisplay/PreviewCard.tsx @@ -16,21 +16,13 @@ import { Card, CardContent, Chip, - Divider, - Alert, - IconButton, - Tooltip, - Button + Alert } from '@mui/material'; import { - ContentCopy as CopyIcon, - Check as CheckIcon, Search as SearchIcon, - Share as ShareIcon, Code as CodeIcon, Facebook as FacebookIcon, Twitter as TwitterIcon, - LinkedIn as LinkedInIcon, Google as GoogleIcon } from '@mui/icons-material'; @@ -43,15 +35,6 @@ export const PreviewCard: React.FC = ({ metadata, blogTitle }) => { - const copyToClipboard = async (text: string, itemId: string) => { - try { - await navigator.clipboard.writeText(text); - // You could add a state to show "Copied!" feedback here - } catch (err) { - console.error('Failed to copy to clipboard:', err); - } - }; - const getCurrentDate = () => { return new Date().toLocaleDateString('en-US', { year: 'numeric', @@ -60,13 +43,6 @@ export const PreviewCard: React.FC = ({ }); }; - const getCurrentTime = () => { - return new Date().toLocaleTimeString('en-US', { - hour: '2-digit', - minute: '2-digit' - }); - }; - return ( diff --git a/frontend/src/components/BlogWriter/SEOAnalysisModal.tsx b/frontend/src/components/BlogWriter/SEOAnalysisModal.tsx index b83d099d..3534febe 100644 --- a/frontend/src/components/BlogWriter/SEOAnalysisModal.tsx +++ b/frontend/src/components/BlogWriter/SEOAnalysisModal.tsx @@ -5,11 +5,10 @@ * Integrates with CopilotKit for real-time progress updates and user interactions. */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { Dialog, DialogContent, - DialogTitle, Button, Chip, LinearProgress, @@ -23,7 +22,6 @@ import { Alert, Grid, Paper, - Divider, IconButton, Tooltip } from '@mui/material'; @@ -33,11 +31,8 @@ import { Cancel, Warning, TrendingUp, - GpsFixed, - MenuBook, Search, BarChart, - Lightbulb, Refresh, Close } from '@mui/icons-material'; @@ -165,7 +160,7 @@ export const SEOAnalysisModal: React.FC = ({ // Debug logging console.log('SEOAnalysisModal render:', { isOpen, blogContent: blogContent?.length, researchData: !!researchData }); - const runSEOAnalysis = async () => { + const runSEOAnalysis = useCallback(async () => { try { setIsAnalyzing(true); setError(null); @@ -267,7 +262,7 @@ export const SEOAnalysisModal: React.FC = ({ setError(err instanceof Error ? err.message : 'Analysis failed'); setIsAnalyzing(false); } - }; + }, [blogContent, blogTitle, researchData]); const getScoreColor = (score: number) => { if (score >= 80) return 'success.main'; @@ -281,23 +276,6 @@ export const SEOAnalysisModal: React.FC = ({ return 'error'; }; - const getPriorityColor = (priority: string) => { - switch (priority) { - case 'High': return 'error.main'; - case 'Medium': return 'warning.main'; - case 'Low': return 'success.main'; - default: return 'text.secondary'; - } - }; - - const getPriorityIcon = (priority: string) => { - switch (priority) { - case 'High': return ; - case 'Medium': return ; - case 'Low': return ; - default: return ; - } - }; // Tooltip content for each metric const getMetricTooltip = (category: string) => { @@ -352,7 +330,7 @@ export const SEOAnalysisModal: React.FC = ({ if (isOpen && !analysisResult) { runSEOAnalysis(); } - }, [isOpen]); + }, [isOpen, analysisResult, runSEOAnalysis]); return ( = ({ }) => { const [activeTab, setActiveTab] = useState(0); const [educationalPanelExpanded, setEducationalPanelExpanded] = useState(false); - const [expandedSections, setExpandedSections] = useState({ - dataSources: true, - progress: true, - educational: false, - messages: true, - stepResults: true - }); // Use polling hook for real backend data only const { progress, isPolling, - error, startPolling, stopPolling, getStepStatus, @@ -309,11 +266,7 @@ const CalendarGenerationModal: React.FC = ({ console.log('โŒ Calendar generation error:', currentProgress.errors); onError(currentProgress.errors[0]?.message || 'Unknown error'); } - }, [currentProgress?.status, currentProgress?.errors, onError]); - - const handleTabChange = (event: React.SyntheticEvent, newValue: number) => { - setActiveTab(newValue); - }; + }, [currentProgress, onError]); const getQualityColor = (score: number) => { if (score >= 0.9) return 'success'; diff --git a/frontend/src/components/ContentPlanningDashboard/components/CalendarWizardSteps/AdvancedOptionsStep.tsx b/frontend/src/components/ContentPlanningDashboard/components/CalendarWizardSteps/AdvancedOptionsStep.tsx index d6416e61..368909d3 100644 --- a/frontend/src/components/ContentPlanningDashboard/components/CalendarWizardSteps/AdvancedOptionsStep.tsx +++ b/frontend/src/components/ContentPlanningDashboard/components/CalendarWizardSteps/AdvancedOptionsStep.tsx @@ -10,10 +10,8 @@ import { InputLabel, Select, MenuItem, - TextField, Slider, FormControlLabel, - Checkbox, Alert, IconButton, Tooltip, @@ -23,12 +21,10 @@ import { } from '@mui/material'; import { AutoAwesome as AIIcon, - Speed as SpeedIcon, Analytics as AnalyticsIcon, TrendingUp as TrendingIcon, Psychology as PsychologyIcon, Info as InfoIcon, - Settings as SettingsIcon, Assessment as AssessmentIcon } from '@mui/icons-material'; diff --git a/frontend/src/components/ContentPlanningDashboard/components/CalendarWizardSteps/CalendarConfigurationStep.tsx b/frontend/src/components/ContentPlanningDashboard/components/CalendarWizardSteps/CalendarConfigurationStep.tsx index f4fa80a6..3a02152b 100644 --- a/frontend/src/components/ContentPlanningDashboard/components/CalendarWizardSteps/CalendarConfigurationStep.tsx +++ b/frontend/src/components/ContentPlanningDashboard/components/CalendarWizardSteps/CalendarConfigurationStep.tsx @@ -181,8 +181,6 @@ const CalendarConfigurationStep: React.FC = ({ const [userGuidance, setUserGuidance] = useState(null); const [transparencyIndicators, setTransparencyIndicators] = useState(null); const [showSmartDefaults, setShowSmartDefaults] = useState(true); - const [showUserGuidance, setShowUserGuidance] = useState(true); - const [showTransparency, setShowTransparency] = useState(true); // Generate smart defaults and guidance when strategy context changes useEffect(() => { @@ -245,6 +243,8 @@ const CalendarConfigurationStep: React.FC = ({ // Fix invalid timezone onConfigUpdate({ timeZone: 'America/New_York' }); } + // timeZones is a const defined later in this component, safe to exclude + // eslint-disable-next-line react-hooks/exhaustive-deps }, [calendarConfig.timeZone, onConfigUpdate]); // Apply smart defaults to configuration diff --git a/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx b/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx index 826e7883..7d308de6 100644 --- a/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx +++ b/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx @@ -1,4 +1,4 @@ - import React, { useState, useEffect, useRef, useMemo } from 'react'; +import React, { useState, useEffect, useRef, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { Box, @@ -6,60 +6,19 @@ import { Typography, Button, LinearProgress, - Alert, - Chip, - IconButton, - Tooltip as MuiTooltip, - Card, - CardContent, Grid, - Divider, - CircularProgress, - Badge, - Collapse, - Accordion, - AccordionSummary, - AccordionDetails, - List, - ListItem, - ListItemIcon, - ListItemText, Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; import { - Business as BusinessIcon, - People as PeopleIcon, - TrendingUp as TrendingUpIcon, - ContentPaste as ContentIcon, - Analytics as AnalyticsIcon, - Help as HelpIcon, - CheckCircle as CheckCircleIcon, - Warning as WarningIcon, AutoAwesome as AutoAwesomeIcon, - Refresh as RefreshIcon, - Save as SaveIcon, - ArrowForward as ArrowForwardIcon, - ArrowBack as ArrowBackIcon, - Assessment as AssessmentIcon, - ExpandMore as ExpandMoreIcon, - Info as InfoIcon, - Visibility as VisibilityIcon, - School as SchoolIcon, - Lightbulb as LightbulbIcon, - Psychology as PsychologyIcon, - Timeline as TimelineIcon, - FiberManualRecord as FiberManualRecordIcon, - Schedule as ScheduleIcon + Info as InfoIcon } from '@mui/icons-material'; -import { motion, AnimatePresence } from 'framer-motion'; import { useStrategyBuilderStore, STRATEGIC_INPUT_FIELDS } from '../../../stores/strategyBuilderStore'; import { useEnhancedStrategyStore } from '../../../stores/enhancedStrategyStore'; -import StrategicInputField from './ContentStrategyBuilder/StrategicInputField'; import EnhancedTooltip from './ContentStrategyBuilder/EnhancedTooltip'; -import AIRecommendationsPanel from './AIRecommendationsPanel'; import DataSourceTransparency from './DataSourceTransparency'; import StrategyAutofillTransparencyModal from './StrategyAutofillTransparencyModal'; import EnterpriseDatapointsModal from './EnterpriseDatapointsModal'; @@ -79,7 +38,7 @@ import { useStrategyCreation } from './ContentStrategyBuilder/hooks/useStrategyC import { useCopilotReadable, useCopilotAdditionalInstructions } from "@copilotkit/react-core"; // Import extracted utilities -import { getCategoryIcon, getCategoryColor, getCategoryName, getCategoryStatus } from './ContentStrategyBuilder/utils/categoryHelpers'; +import { getCategoryIcon, getCategoryColor } from './ContentStrategyBuilder/utils/categoryHelpers'; import { getEducationalContent } from './ContentStrategyBuilder/utils/educationalContent'; import { setupCSSAnimations, cleanupCSSAnimations } from './ContentStrategyBuilder/utils/cssAnimations'; @@ -115,7 +74,6 @@ const ContentStrategyBuilder: React.FC = () => { updateFormField, validateFormField, validateAllFields, - resetForm, autoPopulateFromOnboarding, createStrategy: createEnhancedStrategy, calculateCompletionPercentage, @@ -128,9 +86,6 @@ const ContentStrategyBuilder: React.FC = () => { // Enhanced Strategy Store (for AI analysis, progressive disclosure, transparency) const { aiGenerating, - currentStep, - completedSteps, - disclosureSteps, transparencyModalOpen, transparencyGenerationProgress: storeGenerationProgress, currentPhase, @@ -144,11 +99,6 @@ const ContentStrategyBuilder: React.FC = () => { addTransparencyMessage, clearTransparencyMessages, setTransparencyGenerating: setIsGenerating, - completeStep, - getNextStep, - getPreviousStep, - setCurrentStep, - canProceedToDisclosureStep: canProceedToStep, generateAIRecommendations, setAIGenerating } = useEnhancedStrategyStore(); @@ -157,7 +107,7 @@ const ContentStrategyBuilder: React.FC = () => { useCopilotActions(); // Check if this component is currently visible (active tab) - const [isVisible, setIsVisible] = useState(false); + const [, setIsVisible] = useState(false); useEffect(() => { // Use a small delay to ensure the component is actually rendered @@ -171,10 +121,8 @@ const ContentStrategyBuilder: React.FC = () => { }; }, []); - const [showAIRecommendations, setShowAIRecommendations] = useState(false); + const [, setShowAIRecommendations] = useState(false); const [showDataSourceTransparency, setShowDataSourceTransparency] = useState(false); - const [localEducationalContent, setLocalEducationalContent] = useState(null); - const [localGenerationProgress, setLocalGenerationProgress] = useState(0); const [showAIRecModal, setShowAIRecModal] = useState(false); // Ref to track if we've already set the default category @@ -355,13 +303,9 @@ const ContentStrategyBuilder: React.FC = () => { const { refreshMessage, - setRefreshMessage, refreshProgress, - setRefreshProgress, isRefreshing, - setIsRefreshing, refreshError, - setRefreshError, handleAIRefresh } = useAIRefresh({ setTransparencyModalOpen, @@ -374,18 +318,16 @@ const ContentStrategyBuilder: React.FC = () => { setError }); + // getCompletionStats depends on formData, so we include it to recalculate when data changes + // eslint-disable-next-line react-hooks/exhaustive-deps const completionStats = useMemo(() => getCompletionStats(), [formData]); - const completionPercentage = useMemo(() => calculateCompletionPercentage(), [formData]); // Use extracted hooks const { reviewedCategories, isMarkingReviewed, categoryCompletionMessage, - handleConfirmCategoryReview, - isCategoryReviewed, - getNextUnreviewedCategory, - setReviewedCategories + handleConfirmCategoryReview } = useCategoryReview({ completionStats, setError, setActiveCategory }); const { diff --git a/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder/CopilotActions.tsx b/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder/CopilotActions.tsx index 9bfff736..0cc762c0 100644 --- a/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder/CopilotActions.tsx +++ b/frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder/CopilotActions.tsx @@ -13,8 +13,6 @@ export const useCopilotActions = () => { updateFormField, validateFormField, setError, - autoPopulatedFields, - dataSources, calculateCompletionPercentage, getCompletionStats } = useStrategyBuilderStore(); @@ -93,7 +91,7 @@ export const useCopilotActions = () => { console.log(`๐Ÿ“ Populating field ${fieldId} with value: ${value}`); // Call backend API for intelligent field population - const response = await contentPlanningApi.generateCategoryData( + await contentPlanningApi.generateCategoryData( 'individual_field', `Populate ${fieldId} with: ${value}. Reasoning: ${reasoning || 'User request'}`, formData @@ -188,7 +186,7 @@ export const useCopilotActions = () => { setTransparencyGenerating(false); return { success: false, message: error.message || 'Unknown error' }; } - }, [formData, updateFormField, setError, calculateCompletionPercentage, setTransparencyModalOpen, setTransparencyGenerating, setTransparencyGenerationProgress, setCurrentPhase, clearTransparencyMessages, addTransparencyMessage, setAIGenerating]); + }, [formData, updateFormField, setError, calculateCompletionPercentage, setTransparencyModalOpen, setTransparencyGenerating, setTransparencyGenerationProgress, setCurrentPhase, clearTransparencyMessages, addTransparencyMessage, setAIGenerating, triggerTransparencyFlow]); // Action 4: Validate field const validateStrategyField = useCallback(async ({ fieldId }: any) => { @@ -301,11 +299,7 @@ export const useCopilotActions = () => { // Start transparency flow (same as Refresh & Autofill button) const { transparencyInterval } = await triggerTransparencyFlow('autofill', 'Auto-population from onboarding data'); - // Get current form data to see what's already filled - const currentFilledFields = Object.keys(formData).filter(key => { - const value = formData[key]; - return value && typeof value === 'string' && value.trim() !== ''; - }); + // Get empty fields that need to be filled const emptyFields = Object.keys(formData).filter(key => { const value = formData[key]; return !value || typeof value !== 'string' || value.trim() === ''; @@ -429,7 +423,7 @@ export const useCopilotActions = () => { setTransparencyGenerating(false); return { success: false, message: error.message || 'Unknown error' }; } - }, [formData, updateFormField, calculateCompletionPercentage, setError, setTransparencyModalOpen, setTransparencyGenerating, setTransparencyGenerationProgress, setCurrentPhase, clearTransparencyMessages, addTransparencyMessage, setAIGenerating]); + }, [formData, updateFormField, calculateCompletionPercentage, setError, setTransparencyModalOpen, setTransparencyGenerating, setTransparencyGenerationProgress, setCurrentPhase, clearTransparencyMessages, addTransparencyMessage, setAIGenerating, triggerTransparencyFlow]); // Call useCopilotAction hooks unconditionally - they will handle context availability internally // This is the only way to comply with React hooks rules diff --git a/frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/components/EnhancedPerformanceVisualization.tsx b/frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/components/EnhancedPerformanceVisualization.tsx index 61c74963..e680c1b1 100644 --- a/frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/components/EnhancedPerformanceVisualization.tsx +++ b/frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/components/EnhancedPerformanceVisualization.tsx @@ -10,8 +10,6 @@ import { Tooltip, Alert, AlertTitle, - CircularProgress, - LinearProgress, Divider, Button, Dialog, @@ -24,13 +22,7 @@ import { ListItemIcon } from '@mui/material'; import { - TrendingUp as TrendingUpIcon, - TrendingDown as TrendingDownIcon, Assessment as AssessmentIcon, - Speed as SpeedIcon, - Visibility as VisibilityIcon, - People as EngagementIcon, - MonetizationOn as MonetizationOnIcon, Refresh as RefreshIcon, AutoAwesome as AutoAwesomeIcon, CheckCircle as CheckCircleIcon, @@ -38,11 +30,10 @@ import { Error as ErrorIcon, Analytics as AnalyticsIcon, Lightbulb as LightbulbIcon, - Timeline as TimelineIcon, Close as CloseIcon } from '@mui/icons-material'; -import { motion, AnimatePresence } from 'framer-motion'; -import { safeRenderText, safeRenderArray, hasValidData, getFallbackValue } from '../utils/defensiveRendering'; +import { motion } from 'framer-motion'; +import { safeRenderText } from '../utils/defensiveRendering'; // Import our advanced chart components import { @@ -56,9 +47,6 @@ import { // Import real-time data hook import { useMockRealTimeData } from '../../../../../hooks/useRealTimeData'; -// Import API services -import { strategyMonitoringApi } from '../../../../../services/strategyMonitoringApi'; - interface EnhancedPerformanceVisualizationProps { strategyId: number; strategyData: any; @@ -88,7 +76,7 @@ const EnhancedPerformanceVisualization: React.FC(null); // Use real-time data hook - const { data: realTimeData, isConnected, error: realTimeError } = useMockRealTimeData(strategyId); + const { data: realTimeData, isConnected } = useMockRealTimeData(strategyId); useEffect(() => { loadQualityAnalysis(); diff --git a/frontend/src/components/ContentPlanningDashboard/components/SystemStatusIndicator.tsx b/frontend/src/components/ContentPlanningDashboard/components/SystemStatusIndicator.tsx index 390ab12a..d886c5a9 100644 --- a/frontend/src/components/ContentPlanningDashboard/components/SystemStatusIndicator.tsx +++ b/frontend/src/components/ContentPlanningDashboard/components/SystemStatusIndicator.tsx @@ -5,21 +5,16 @@ import { Typography, Chip, CircularProgress, - Alert, IconButton, Dialog, DialogTitle, DialogContent, DialogActions, Button, - Grid, - Paper, - LinearProgress, List, ListItem, ListItemText, ListItemIcon, - Divider, Card, CardContent, CardHeader, @@ -33,14 +28,8 @@ import { Help as UnknownIcon, Refresh as RefreshIcon, Close as CloseIcon, - TrendingUp as TrendingUpIcon, - TrendingDown as TrendingDownIcon, - Speed as SpeedIcon, BugReport as BugReportIcon, - Storage as StorageIcon, - Timeline as TimelineIcon, - Analytics as AnalyticsIcon, - NetworkCheck as NetworkCheckIcon + Analytics as AnalyticsIcon } from '@mui/icons-material'; import { motion, AnimatePresence } from 'framer-motion'; import MonitoringCharts from './MonitoringCharts'; @@ -95,10 +84,10 @@ const SystemStatusIndicator: React.FC = ({ className const [statusData, setStatusData] = useState(null); const [detailedStats, setDetailedStats] = useState(null); const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); + const [, setError] = useState(null); const [dashboardOpen, setDashboardOpen] = useState(false); const [chartData, setChartData] = useState([]); - const [cachePerf, setCachePerf] = useState<{ hits: number; misses: number; hit_rate: number } | null>(null); + const [, setCachePerf] = useState<{ hits: number; misses: number; hit_rate: number } | null>(null); const fetchStatus = async () => { setLoading(true); @@ -243,10 +232,6 @@ const SystemStatusIndicator: React.FC = ({ className ); } - const total = statusData?.recent_requests ?? 0; - const failed = statusData?.recent_errors ?? 0; - const passed = Math.max(0, total - failed); - return ( <> diff --git a/frontend/src/components/ContentPlanningDashboard/tabs/CalendarTab.tsx b/frontend/src/components/ContentPlanningDashboard/tabs/CalendarTab.tsx index d3880c35..61ae7740 100644 --- a/frontend/src/components/ContentPlanningDashboard/tabs/CalendarTab.tsx +++ b/frontend/src/components/ContentPlanningDashboard/tabs/CalendarTab.tsx @@ -29,10 +29,7 @@ import { ListItem, ListItemText, ListItemIcon, - Divider, - LinearProgress, - Tooltip, - Badge + LinearProgress } from '@mui/material'; import { Add as AddIcon, @@ -42,27 +39,17 @@ import { Event as EventIcon, Refresh as RefreshIcon, TrendingUp as TrendingIcon, - ContentCopy as RepurposeIcon, Analytics as AnalyticsIcon, ExpandMore as ExpandMoreIcon, Schedule as ScheduleIcon, Psychology as PsychologyIcon, Business as BusinessIcon, - Group as GroupIcon, Timeline as TimelineIcon, Lightbulb as LightbulbIcon, CheckCircle as CheckCircleIcon, - Warning as WarningIcon, - Info as InfoIcon, - DataUsage as DataUsageIcon, - Insights as InsightsIcon, - Assessment as AssessmentIcon, - Campaign as CampaignIcon, - Speed as SpeedIcon, AutoAwesome as AutoAwesomeIcon } from '@mui/icons-material'; import { useContentPlanningStore } from '../../../stores/contentPlanningStore'; -import { contentPlanningApi } from '../../../services/contentPlanningApi'; interface TabPanelProps { children?: React.ReactNode; @@ -92,15 +79,10 @@ const CalendarTab: React.FC = () => { createEvent, updateEvent, deleteEvent, - loading, error, loadCalendarEvents, - updateCalendarEvents, // New calendar generation state generatedCalendar, - performancePrediction, - contentRepurposing, - aiInsights, calendarGenerationError, dataLoading, calendarGenerationLoading @@ -118,28 +100,15 @@ const CalendarTab: React.FC = () => { status: 'draft' as 'draft' | 'scheduled' | 'published' }); - // Enhanced state for data transparency - const [userData, setUserData] = useState({ - onboardingData: {}, - gapAnalysis: {}, - strategyData: {}, - recommendationsData: [], - performanceData: {}, - aiAnalysisResults: [] - }); - const safeCalendarEvents = Array.isArray(calendarEvents) ? calendarEvents : []; useEffect(() => { loadCalendarData(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const loadCalendarData = async () => { try { - // Load comprehensive user data for calendar generation - const comprehensiveData = await contentPlanningApi.getComprehensiveUserData(1); // Pass user ID - setUserData(comprehensiveData.data); // Extract the data from the response - // Load existing calendar events await loadCalendarEvents(); } catch (error) { @@ -211,45 +180,6 @@ const CalendarTab: React.FC = () => { await loadCalendarData(); }; - const handleDataUpdate = (updatedData: any) => { - setUserData((prev: any) => ({ ...prev, ...updatedData })); - }; - - const handleGenerateCalendar = async (calendarConfig: any) => { - try { - await contentPlanningApi.generateComprehensiveCalendar({ - ...calendarConfig, - userData - }); - } catch (error) { - console.error('Error generating calendar:', error); - } - }; - - const handleOptimizeContent = async (contentData: any) => { - try { - await contentPlanningApi.optimizeContent(contentData); - } catch (error) { - console.error('Error optimizing content:', error); - } - }; - - const handlePredictPerformance = async (contentData: any) => { - try { - await contentPlanningApi.predictPerformance(contentData); - } catch (error) { - console.error('Error predicting performance:', error); - } - }; - - const handleGetTrendingTopics = async () => { - try { - await contentPlanningApi.getTrendingTopics({ user_id: 1, industry: 'technology' }); - } catch (error) { - console.error('Error getting trending topics:', error); - } - }; - const getStatusColor = (status: string) => { switch (status) { case 'draft': return 'default'; diff --git a/frontend/src/components/ContentPlanningDashboard/tabs/ContentOptimizerTab.tsx b/frontend/src/components/ContentPlanningDashboard/tabs/ContentOptimizerTab.tsx index 9d454eb8..192f330d 100644 --- a/frontend/src/components/ContentPlanningDashboard/tabs/ContentOptimizerTab.tsx +++ b/frontend/src/components/ContentPlanningDashboard/tabs/ContentOptimizerTab.tsx @@ -7,8 +7,7 @@ import { List, ListItem, ListItemText, - ListItemIcon, - Chip + ListItemIcon } from '@mui/material'; import { Analytics as AnalyticsIcon, diff --git a/frontend/src/components/ContentPlanningDashboard/tabs/ContentPillarsTab.tsx b/frontend/src/components/ContentPlanningDashboard/tabs/ContentPillarsTab.tsx index 87b5f6b2..4b3fedb8 100644 --- a/frontend/src/components/ContentPlanningDashboard/tabs/ContentPillarsTab.tsx +++ b/frontend/src/components/ContentPlanningDashboard/tabs/ContentPillarsTab.tsx @@ -9,9 +9,6 @@ import { Button, CircularProgress } from '@mui/material'; -import { - PieChart as PieChartIcon -} from '@mui/icons-material'; import { useContentPlanningStore } from '../../../stores/contentPlanningStore'; const ContentPillarsTab: React.FC = () => { @@ -21,6 +18,7 @@ const ContentPillarsTab: React.FC = () => { useEffect(() => { loadContentPillars(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentStrategy]); const loadContentPillars = async () => { diff --git a/frontend/src/components/ContentPlanningDashboard/tabs/ContentStrategyTab.tsx b/frontend/src/components/ContentPlanningDashboard/tabs/ContentStrategyTab.tsx index 8a84f27a..ab22fd27 100644 --- a/frontend/src/components/ContentPlanningDashboard/tabs/ContentStrategyTab.tsx +++ b/frontend/src/components/ContentPlanningDashboard/tabs/ContentStrategyTab.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useMemo } from 'react'; +import React, { useState, useEffect } from 'react'; import { Box, Paper, @@ -25,25 +25,13 @@ const ContentStrategyTab: React.FC = () => { const strategies = useContentPlanningStore(state => state.strategies); const currentStrategy = useContentPlanningStore(state => state.currentStrategy); const latestGeneratedStrategy = useContentPlanningStore(state => state.latestGeneratedStrategy); - const aiInsights = useContentPlanningStore(state => state.aiInsights); - const aiRecommendations = useContentPlanningStore(state => state.aiRecommendations); - const loading = useContentPlanningStore(state => state.loading); const error = useContentPlanningStore(state => state.error); const loadStrategies = useContentPlanningStore(state => state.loadStrategies); const loadAIInsights = useContentPlanningStore(state => state.loadAIInsights); const loadAIRecommendations = useContentPlanningStore(state => state.loadAIRecommendations); const setLatestGeneratedStrategy = useContentPlanningStore(state => state.setLatestGeneratedStrategy); - - const [strategyForm, setStrategyForm] = useState({ - name: '', - description: '', - industry: '', - target_audience: '', - content_pillars: [] - }); // Real data states - const [strategicIntelligence, setStrategicIntelligence] = useState(null); const [strategyData, setStrategyData] = useState(null); const [strategyDataLoading, setStrategyDataLoading] = useState(false); const [strategyDataError, setStrategyDataError] = useState(null); @@ -65,6 +53,7 @@ const ContentStrategyTab: React.FC = () => { // Load data on component mount useEffect(() => { loadInitialData(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Check if coming from strategy builder @@ -92,7 +81,7 @@ const ContentStrategyTab: React.FC = () => { console.log('๐Ÿงน Clearing latest generated strategy cache (navigating away from strategy builder)'); // Note: We don't clear the cache here as it might be needed for the current session } - }, [location.state]); + }, [location.state, latestGeneratedStrategy]); // Track strategy status changes for debugging (with debounce) useEffect(() => { @@ -136,6 +125,7 @@ const ContentStrategyTab: React.FC = () => { setShowOnboarding(true); } // If strategiesArray.length === 0 and !hasCheckedStrategy, do nothing (wait for data to load) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [strategies, loadStrategies, isFromStrategyBuilder]); const loadStrategyData = async () => { @@ -390,9 +380,6 @@ const ContentStrategyTab: React.FC = () => { } if (strategiesArray.length > 0) { - // Find the most recent strategy - const latestStrategy = strategiesArray[0]; // Assuming strategies are sorted by date - // For now, we'll assume strategies are active if they exist // In a real implementation, you would check a status field from the database setStrategyStatus('active'); diff --git a/frontend/src/components/ContentPlanningDashboard/tabs/CreateTab.tsx b/frontend/src/components/ContentPlanningDashboard/tabs/CreateTab.tsx index 5976f393..02f4b5a4 100644 --- a/frontend/src/components/ContentPlanningDashboard/tabs/CreateTab.tsx +++ b/frontend/src/components/ContentPlanningDashboard/tabs/CreateTab.tsx @@ -1,10 +1,9 @@ -import React, { useState, useEffect, useCallback, useMemo } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { Box, Typography, Tabs, - Tab, - Button + Tab } from '@mui/material'; import { AutoAwesome as AutoAwesomeIcon, @@ -20,7 +19,6 @@ import { apiClient } from '../../../api/client'; // Import hooks and services import { useStrategyCalendarContext } from '../../../contexts/StrategyCalendarContext'; -import { contentPlanningApi } from '../../../services/contentPlanningApi'; // Import types import { type CalendarConfig } from '../components/CalendarWizardSteps/types'; @@ -51,11 +49,10 @@ const CreateTab: React.FC = () => { const [isModalOpen, setIsModalOpen] = useState(false); const [currentCalendarConfig, setCurrentCalendarConfig] = useState(null); const [sessionId, setSessionId] = useState(''); - const [isStartingGeneration, setIsStartingGeneration] = useState(false); const location = useLocation(); const { state: { strategyContext }, isFromStrategyActivation } = useStrategyCalendarContext(); - const [userData, setUserData] = useState({}); + const [userData] = useState({}); // Handle navigation from strategy activation useEffect(() => { @@ -74,7 +71,7 @@ const CreateTab: React.FC = () => { console.log('๐ŸŽฏ CreateTab: Switching to Calendar Wizard tab (index 1)'); setTabValue(1); // Switch to Calendar Wizard tab } - }, [isFromStrategyActivation, strategyContext?.activationStatus]); + }, [isFromStrategyActivation, strategyContext?.activationStatus, location.state]); // Also check on mount for immediate navigation state useEffect(() => { @@ -109,9 +106,6 @@ const CreateTab: React.FC = () => { setCurrentCalendarConfig(calendarConfig); setIsModalOpen(true); - // Set loading state to prevent multiple clicks - setIsStartingGeneration(true); - // Transform calendarConfig to match backend CalendarGenerationRequest format const requestData = { user_id: 1, // Default user ID @@ -126,20 +120,19 @@ const CreateTab: React.FC = () => { // Call the new start endpoint to get session ID with retry logic let startResponse; - let retryCount = 0; const maxRetries = 3; - while (retryCount < maxRetries) { + for (let retryCount = 0; retryCount < maxRetries; retryCount++) { try { const response = await apiClient.post('/api/content-planning/calendar-generation/start', requestData); startResponse = { ok: true, data: response.data }; break; // Success, exit retry loop } catch (error: any) { console.warn(`โš ๏ธ Attempt ${retryCount + 1} failed with error:`, error); - retryCount++; - if (retryCount < maxRetries) { + if (retryCount < maxRetries - 1) { // Wait before retry (exponential backoff) - await new Promise(resolve => setTimeout(resolve, 1000 * retryCount)); + const delay = 1000 * (retryCount + 1); + await new Promise(resolve => setTimeout(resolve, delay)); } else { startResponse = { ok: false, data: null }; } @@ -175,8 +168,7 @@ const CreateTab: React.FC = () => { setCurrentCalendarConfig(null); setSessionId(''); } finally { - // Clear loading state - setIsStartingGeneration(false); + // Cleanup complete } }, [userData, strategyContext]); diff --git a/frontend/src/components/ContentPlanningDashboard/tabs/GapAnalysisTab.tsx b/frontend/src/components/ContentPlanningDashboard/tabs/GapAnalysisTab.tsx index d0abec68..5b33fe0c 100644 --- a/frontend/src/components/ContentPlanningDashboard/tabs/GapAnalysisTab.tsx +++ b/frontend/src/components/ContentPlanningDashboard/tabs/GapAnalysisTab.tsx @@ -3,8 +3,7 @@ import { Box, Tabs, Tab, - Typography, - Alert + Typography } from '@mui/material'; import { Analytics as AnalyticsIcon, diff --git a/frontend/src/components/ContentPlanningDashboard/tabs/KeywordResearchTab.tsx b/frontend/src/components/ContentPlanningDashboard/tabs/KeywordResearchTab.tsx index 6a4b1265..967b0f41 100644 --- a/frontend/src/components/ContentPlanningDashboard/tabs/KeywordResearchTab.tsx +++ b/frontend/src/components/ContentPlanningDashboard/tabs/KeywordResearchTab.tsx @@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react'; import { Box, Grid, - Paper, Typography, Card, CardContent, @@ -16,10 +15,6 @@ import { TableRow, Button } from '@mui/material'; -import { - Search as SearchIcon -} from '@mui/icons-material'; -import { useContentPlanningStore } from '../../../stores/contentPlanningStore'; import { contentPlanningApi } from '../../../services/contentPlanningApi'; const KeywordResearchTab: React.FC = () => { diff --git a/frontend/src/components/ContentPlanningDashboard/tabs/RefineAnalysisTab.tsx b/frontend/src/components/ContentPlanningDashboard/tabs/RefineAnalysisTab.tsx index a796a987..ae29d4b0 100644 --- a/frontend/src/components/ContentPlanningDashboard/tabs/RefineAnalysisTab.tsx +++ b/frontend/src/components/ContentPlanningDashboard/tabs/RefineAnalysisTab.tsx @@ -49,6 +49,7 @@ const RefineAnalysisTab: React.FC = () => { useEffect(() => { loadGapAnalysisData(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const loadGapAnalysisData = async () => { diff --git a/frontend/src/components/FacebookWriter/FacebookWriter.tsx b/frontend/src/components/FacebookWriter/FacebookWriter.tsx index 1a0b34ba..cb78d7be 100644 --- a/frontend/src/components/FacebookWriter/FacebookWriter.tsx +++ b/frontend/src/components/FacebookWriter/FacebookWriter.tsx @@ -87,16 +87,16 @@ function diffMarkup(oldText: string, newText: string): string { out += a[i]; i++; j++; } else if (dp[i + 1][j] >= dp[i][j + 1]) { - out += `${escapeHtml(a[i])}`; + out += `${escapeHtml(a[i])}`; i++; } else { - out += `${escapeHtml(b[j])}`; + out += `${escapeHtml(b[j])}`; j++; } } - while (i < n) { out += `${escapeHtml(a[i++])}`; } - while (j < m) { out += `${escapeHtml(b[j++])}`; } - if (oldText.length > MAX || newText.length > MAX) out += ' โ€ฆ'; + while (i < n) { out += `${escapeHtml(a[i++])}`; } + while (j < m) { out += `${escapeHtml(b[j++])}`; } + if (oldText.length > MAX || newText.length > MAX) out += ' โ€ฆ'; return out; } @@ -148,7 +148,7 @@ const FacebookWriterContent: React.FC = ({ className = '' } const [livePreviewHtml, setLivePreviewHtml] = React.useState(''); const [isPreviewing, setIsPreviewing] = React.useState(false); const [pendingEdit, setPendingEdit] = React.useState<{ src: string; target: string } | null>(null); - const [historyVersion, setHistoryVersion] = React.useState(0); + const [, setHistoryVersion] = React.useState(0); const [adVariations, setAdVariations] = React.useState<{ headline_variations: string[]; primary_text_variations: string[]; diff --git a/frontend/src/components/LinkedInWriter/RegisterLinkedInActions.tsx b/frontend/src/components/LinkedInWriter/RegisterLinkedInActions.tsx index 6121348b..2cdf3cd7 100644 --- a/frontend/src/components/LinkedInWriter/RegisterLinkedInActions.tsx +++ b/frontend/src/components/LinkedInWriter/RegisterLinkedInActions.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { useCopilotAction } from '@copilotkit/react-core'; -import { linkedInWriterApi, LinkedInPostRequest, GroundingLevel } from '../../services/linkedInWriterApi'; +import { linkedInWriterApi, GroundingLevel } from '../../services/linkedInWriterApi'; import { mapPostType, mapTone, @@ -8,7 +8,6 @@ import { mapSearchEngine, readPrefs } from './utils/linkedInWriterUtils'; -import { PostHITL, ArticleHITL, CarouselHITL, VideoScriptHITL, CommentResponseHITL } from './components'; import { apiClient } from '../../api/client'; const useCopilotActionTyped = useCopilotAction as any; @@ -125,17 +124,6 @@ const RegisterLinkedInActions: React.FC = () => { ] }})); - // If refining existing content, use the current draft as context - let existingContent = ''; - if (args?.refine_existing) { - // Get current draft from the page context - const textarea = document.querySelector('textarea') as HTMLTextAreaElement; - const currentDraft = textarea?.value || ''; - if (currentDraft) { - existingContent = `\n\nREFINE THIS EXISTING CONTENT:\n${currentDraft}`; - } - } - // Start detailed progress tracking window.dispatchEvent(new CustomEvent('linkedinwriter:progressStep', { detail: { @@ -750,7 +738,7 @@ const RegisterLinkedInActions: React.FC = () => { { name: 'improvement_type', type: 'string', required: false } ], handler: async (args: any) => { - const { recommendation, current_content, improvement_type } = args; + const { recommendation } = args; // Analyze the recommendation and provide specific improvement guidance let improvementGuidance = ''; diff --git a/frontend/src/components/LinkedInWriter/RegisterLinkedInEditActions.tsx b/frontend/src/components/LinkedInWriter/RegisterLinkedInEditActions.tsx index 38489fef..8902d239 100644 --- a/frontend/src/components/LinkedInWriter/RegisterLinkedInEditActions.tsx +++ b/frontend/src/components/LinkedInWriter/RegisterLinkedInEditActions.tsx @@ -57,7 +57,6 @@ const RegisterLinkedInEditActions: React.FC = () => { ], handler: async (args: any) => { const content = args?.content || ''; - const industry = args?.industry || 'Technology'; // Placeholder for hashtag addition const hashtags = '#ProfessionalDevelopment #Networking #IndustryInsights #CareerGrowth'; diff --git a/frontend/src/components/LinkedInWriter/components/BrainstormFlow.tsx b/frontend/src/components/LinkedInWriter/components/BrainstormFlow.tsx index 7177ab93..09e1ff2d 100644 --- a/frontend/src/components/LinkedInWriter/components/BrainstormFlow.tsx +++ b/frontend/src/components/LinkedInWriter/components/BrainstormFlow.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { usePlatformPersonaContext } from '../../shared/PersonaContext/PlatformPersonaProvider'; import { apiClient } from '../../../api/client'; diff --git a/frontend/src/components/LinkedInWriter/components/ContentEditor.tsx b/frontend/src/components/LinkedInWriter/components/ContentEditor.tsx index 5ebaebbd..84b68b64 100644 --- a/frontend/src/components/LinkedInWriter/components/ContentEditor.tsx +++ b/frontend/src/components/LinkedInWriter/components/ContentEditor.tsx @@ -29,8 +29,6 @@ interface ContentEditorProps { topic?: string; } -export { ContentEditor }; - const ContentEditor: React.FC = ({ isPreviewing, pendingEdit, @@ -62,6 +60,7 @@ const ContentEditor: React.FC = ({ const ctaCooldownRef = useRef(null); // 15s cooldown after dismissing CTA useEffect(() => { if (DEBUG_WA) console.log('๐ŸŽฏ [ContentEditor] waSuggestion changed:', waSuggestion); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [waSuggestion]); const waTimerRef = useRef(null); const hasTriggeredOnceRef = useRef(false); @@ -228,8 +227,6 @@ const ContentEditor: React.FC = ({ lastWords: words.slice(-5).join(' ') }); - const now = Date.now(); - const last = lastSuggestMetaRef.current; const textHash = getStableContextHash(uptoCaret); // After first auto-trigger, stop auto-calling API. Show CTA instead. @@ -271,7 +268,7 @@ const ContentEditor: React.FC = ({ let userError = "Failed to get writing suggestion"; if (msg.includes('429') || msg.includes('RESOURCE_EXHAUSTED')) { userError = "API quota exceeded. Please try again later or upgrade your plan."; - const match = msg.match(/\"retryDelay\"\s*:\s*\"(\d+)s\"/); + const match = msg.match(/"retryDelay"\s*:\s*"(\d+)s"/); const retryMs = match ? parseInt(match[1], 10) * 1000 : 40000; coolDownUntilRef.current = Date.now() + retryMs; console.warn('โœ๏ธ [ContentEditor] Entering suggestion cooldown for ms:', retryMs); @@ -316,7 +313,7 @@ const ContentEditor: React.FC = ({ let userError = "Failed to get writing suggestion"; if (msg.includes('429') || msg.includes('RESOURCE_EXHAUSTED')) { userError = "API quota exceeded. Please try again later or upgrade your plan."; - const match = msg.match(/\"retryDelay\"\s*:\s*\"(\d+)s\"/); + const match = msg.match(/"retryDelay"\s*:\s*"(\d+)s"/); const retryMs = match ? parseInt(match[1], 10) * 1000 : 40000; coolDownUntilRef.current = Date.now() + retryMs; console.warn('โœ๏ธ [ContentEditor] Entering suggestion cooldown for ms:', retryMs); @@ -421,4 +418,6 @@ const ContentEditor: React.FC = ({ ); -}; \ No newline at end of file +}; + +export { ContentEditor }; \ No newline at end of file diff --git a/frontend/src/components/MainDashboard/ContentLifecyclePillars.tsx b/frontend/src/components/MainDashboard/ContentLifecyclePillars.tsx index cdc46327..37d60f7b 100644 --- a/frontend/src/components/MainDashboard/ContentLifecyclePillars.tsx +++ b/frontend/src/components/MainDashboard/ContentLifecyclePillars.tsx @@ -3,29 +3,12 @@ import { Box, Container, Typography, - Card, CardContent, - useTheme, - useMediaQuery, Chip, Tooltip, - Paper, - Modal, - Button, - IconButton, - Divider, - LinearProgress, - Avatar, - Stack + Paper } from '@mui/material'; import { motion, AnimatePresence } from 'framer-motion'; -import { - Close as CloseIcon, - Settings as SettingsIcon, - CheckCircle as CheckIcon, - RadioButtonUnchecked as UncheckedIcon, - TrendingUp as TrendingUpIcon -} from '@mui/icons-material'; import GeneratePillarChips from './components/GeneratePillarChips'; import PublishPillarChips from './components/PublishPillarChips'; import AnalyzePillarChips from './components/AnalyzePillarChips'; @@ -484,14 +467,11 @@ const PillarCard: React.FC<{ // Main Content Lifecycle Pillars Component const ContentLifecyclePillars: React.FC = () => { - const theme = useTheme(); - const isMobile = useMediaQuery(theme.breakpoints.down('md')); const [onboardingModalOpen, setOnboardingModalOpen] = useState(false); // Workflow store hooks const { currentWorkflow, - workflowProgress, isLoading: workflowLoading, startWorkflow, } = useWorkflowStore(); diff --git a/frontend/src/components/MainDashboard/MainDashboard.tsx b/frontend/src/components/MainDashboard/MainDashboard.tsx index 6575fea2..5002d2fa 100644 --- a/frontend/src/components/MainDashboard/MainDashboard.tsx +++ b/frontend/src/components/MainDashboard/MainDashboard.tsx @@ -23,7 +23,7 @@ import CompactSidebar from './components/CompactSidebar'; // Shared types and utilities import { Tool } from '../shared/types'; -import { getFilteredCategories, getToolsForCategory } from '../shared/utils'; +import { getToolsForCategory } from '../shared/utils'; // Zustand stores import { useDashboardStore } from '../../stores/dashboardStore'; diff --git a/frontend/src/components/MainDashboard/components/AnalyzePillarChips.tsx b/frontend/src/components/MainDashboard/components/AnalyzePillarChips.tsx index f88895a5..1561d3e8 100644 --- a/frontend/src/components/MainDashboard/components/AnalyzePillarChips.tsx +++ b/frontend/src/components/MainDashboard/components/AnalyzePillarChips.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Box, Chip, useTheme } from '@mui/material'; +import { Box, Chip } from '@mui/material'; import { motion, AnimatePresence } from 'framer-motion'; import { useNavigate } from 'react-router-dom'; import { diff --git a/frontend/src/components/MainDashboard/components/CompactSidebar.tsx b/frontend/src/components/MainDashboard/components/CompactSidebar.tsx index e66d44e2..6131fc2a 100644 --- a/frontend/src/components/MainDashboard/components/CompactSidebar.tsx +++ b/frontend/src/components/MainDashboard/components/CompactSidebar.tsx @@ -3,7 +3,6 @@ import { Box, Paper, Typography, - Chip, IconButton, Tooltip, Divider, @@ -14,8 +13,6 @@ import { Filter, ChevronLeft, ChevronRight, - Activity, - Zap, Star } from 'lucide-react'; @@ -78,26 +75,16 @@ const CompactSidebar: React.FC = ({ // State for search expansion on hover const [isSearchExpanded, setIsSearchExpanded] = useState(false); // State for sidebar hover expansion - const [isSidebarHovered, setIsSidebarHovered] = useState(false); + const [, setIsSidebarHovered] = useState(false); // State for favorites expansion on hover const [isFavoritesExpanded, setIsFavoritesExpanded] = useState(false); // Track original collapsed state for hover behavior const [wasOriginallyCollapsed, setWasOriginallyCollapsed] = useState(false); const [isAnimating, setIsAnimating] = useState(false); - const [rippleIndex, setRippleIndex] = useState(-1); + const [, setRippleIndex] = useState(-1); const [shouldAutoExpand, setShouldAutoExpand] = useState(false); const [userHasInteracted, setUserHasInteracted] = useState(false); - // Calculate total tools count - const totalTools = Object.values(toolCategories).reduce((sum, category) => { - if ('tools' in category) { - return sum + category.tools.length; - } else if ('subCategories' in category) { - return sum + Object.values(category.subCategories).reduce((subSum, subCat) => subSum + subCat.tools.length, 0); - } - return sum; - }, 0); - // Ripple effect for chips const startRippleEffect = useCallback(() => { const categoryEntries = Object.entries(toolCategories).slice(0, 5); diff --git a/frontend/src/components/MainDashboard/components/EngagePillarChips.tsx b/frontend/src/components/MainDashboard/components/EngagePillarChips.tsx index 0b8c8ca5..ca06ff9d 100644 --- a/frontend/src/components/MainDashboard/components/EngagePillarChips.tsx +++ b/frontend/src/components/MainDashboard/components/EngagePillarChips.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Box, Chip, useTheme } from '@mui/material'; +import { Box, Chip } from '@mui/material'; import { motion, AnimatePresence } from 'framer-motion'; import { useNavigate } from 'react-router-dom'; import { diff --git a/frontend/src/components/MainDashboard/components/EnhancedTodayModal.tsx b/frontend/src/components/MainDashboard/components/EnhancedTodayModal.tsx index 46bf5c77..dabce5d3 100644 --- a/frontend/src/components/MainDashboard/components/EnhancedTodayModal.tsx +++ b/frontend/src/components/MainDashboard/components/EnhancedTodayModal.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React from 'react'; import { Box, Typography, @@ -10,7 +10,6 @@ import { IconButton, Avatar, Stack, - LinearProgress, CircularProgress, Card, CardContent @@ -57,13 +56,10 @@ const EnhancedTodayModal: React.FC = ({ navigationState, completeTask, skipTask, - moveToNextTask, isLoading, isWorkflowComplete } = useWorkflowStore(); - const [selectedTask, setSelectedTask] = useState(null); - // Prefer live workflow tasks (to reflect updated statuses), fallback to props const liveTasks = currentWorkflow?.tasks && Array.isArray(currentWorkflow.tasks) && currentWorkflow.tasks.length > 0 ? currentWorkflow.tasks @@ -100,12 +96,6 @@ const EnhancedTodayModal: React.FC = ({ } }; - const handleStartWorkflow = async () => { - if (currentWorkflow) { - await moveToNextTask(); - } - }; - const handleNextPillar = async () => { // Close current modal onClose(); @@ -158,9 +148,6 @@ const EnhancedTodayModal: React.FC = ({ task.status === 'completed' || task.status === 'skipped' ); - // Check if this is the Plan pillar - const isPlanPillar = pillarId === 'plan'; - // Define pillar order for navigation const pillarOrder = ['plan', 'generate', 'publish', 'analyze', 'engage', 'remarket']; const currentPillarIndex = pillarOrder.indexOf(pillarId); diff --git a/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/ApiKeyCarousel.tsx b/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/ApiKeyCarousel.tsx index a9071246..71cc9885 100644 --- a/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/ApiKeyCarousel.tsx +++ b/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/ApiKeyCarousel.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useEffect } from 'react'; import { Box, Card, @@ -7,10 +7,6 @@ import { IconButton, Button, Typography, - Stepper, - Step, - StepLabel, - StepConnector, Fade, LinearProgress, } from '@mui/material'; @@ -25,7 +21,6 @@ import { Key, ContentPasteRounded, } from '@mui/icons-material'; -import { styled } from '@mui/material/styles'; interface ApiKeyCarouselProps { providers: Array<{ @@ -40,40 +35,19 @@ interface ApiKeyCarouselProps { link: string; free: boolean; recommended: boolean; - benefits: string[]; - }>; + benefits: string[]; +}>; currentProvider: number; setCurrentProvider: (index: number) => void; onProviderFocus: (provider: any) => void; } -const CustomStepConnector = styled(StepConnector)(({ theme }) => ({ - '&.MuiStepConnector-alternativeLabel': { - top: 10, - left: 'calc(-50% + 16px)', - right: 'calc(50% + 16px)', - }, - '& .MuiStepConnector-line': { - height: 3, - border: 0, - background: 'linear-gradient(90deg, #E2E8F0 0%, #CBD5E1 100%)', - borderRadius: 2, - }, - '&.MuiStepConnector-active .MuiStepConnector-line': { - background: 'linear-gradient(90deg, #3B82F6 0%, #1D4ED8 100%)', - }, - '&.MuiStepConnector-completed .MuiStepConnector-line': { - background: 'linear-gradient(90deg, #10B981 0%, #059669 100%)', - }, -})); - const ApiKeyCarousel: React.FC = ({ providers, currentProvider, setCurrentProvider, onProviderFocus, }) => { - const [autoProgress, setAutoProgress] = useState(false); const provider = providers[currentProvider]; const getAccentColor = (name: string) => { @@ -117,14 +91,6 @@ const ApiKeyCarousel: React.FC = ({ } }; - const getStepIcon = (index: number) => { - const stepProvider = providers[index]; - if (stepProvider.status === 'valid') { - return ; - } - return ; - }; - return ( {/* Progress Stepper - Hidden as requested */} diff --git a/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/ApiKeySidebar.tsx b/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/ApiKeySidebar.tsx index 0e71b1b1..dc14b3fc 100644 --- a/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/ApiKeySidebar.tsx +++ b/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/ApiKeySidebar.tsx @@ -10,13 +10,10 @@ import { ListItemText, Chip, Divider, - Alert, } from '@mui/material'; import { CheckCircle, Star, - Security, - Speed, TrendingUp, Insights, Search, diff --git a/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/useApiKeyStep.ts b/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/useApiKeyStep.ts index 8acfbf8e..9341fa59 100644 --- a/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/useApiKeyStep.ts +++ b/frontend/src/components/OnboardingWizard/ApiKeyStep/utils/useApiKeyStep.ts @@ -1,12 +1,10 @@ import { useState, useEffect, useCallback } from 'react'; -import { useAuth } from '@clerk/clerk-react'; import { getApiKeysForOnboarding, getStep1ApiKeysFromProgress, saveApiKey } from '../../../../api/onboarding'; import { getKeyStatus, formatErrorMessage } from '../../common/onboardingUtils'; import { Provider } from './ProviderCard'; import { apiClient } from '../../../../api/client'; export const useApiKeyStep = (onContinue: (stepData?: any) => void) => { - const { getToken } = useAuth(); const [geminiKey, setGeminiKey] = useState(''); const [exaKey, setExaKey] = useState(''); const [copilotkitKey, setCopilotkitKey] = useState(''); diff --git a/frontend/src/components/OnboardingWizard/CompetitorAnalysisStep.tsx b/frontend/src/components/OnboardingWizard/CompetitorAnalysisStep.tsx index 59a912c5..7bc392ec 100644 --- a/frontend/src/components/OnboardingWizard/CompetitorAnalysisStep.tsx +++ b/frontend/src/components/OnboardingWizard/CompetitorAnalysisStep.tsx @@ -52,7 +52,7 @@ const CompetitorAnalysisStep: React.FC = ({ const [analysisStep, setAnalysisStep] = useState(''); const [competitors, setCompetitors] = useState([]); const [socialMediaAccounts, setSocialMediaAccounts] = useState({}); - const [socialMediaCitations, setSocialMediaCitations] = useState([]); + const [, setSocialMediaCitations] = useState([]); const [researchSummary, setResearchSummary] = useState(null); const [error, setError] = useState(null); const [showProgressModal, setShowProgressModal] = useState(false); @@ -260,6 +260,7 @@ const CompetitorAnalysisStep: React.FC = ({ } finally { setIsAnalyzingSitemap(false); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [userUrl, competitors, industryContext, isAnalyzingSitemap]); // Initialize: Check cache first, then run analysis if needed @@ -313,36 +314,6 @@ const CompetitorAnalysisStep: React.FC = ({ }; }, [competitors, researchSummary, sitemapAnalysis, userUrl, industryContext]); - const handleContinue = async () => { - // Save research preferences to backend before continuing - try { - const researchData = getResearchData(); - - // Extract research preferences for saving (use defaults if not available) - const researchPreferences = { - research_depth: 'Comprehensive', - content_types: ['blog_posts', 'social_media'], - auto_research: true, - factual_content: true - }; - - // Save research preferences to backend - await aiApiClient.post('/api/ai-research/configure-preferences', { - research_depth: researchPreferences.research_depth, - content_types: researchPreferences.content_types, - auto_research: researchPreferences.auto_research, - factual_content: researchPreferences.factual_content - }); - - console.log('Research preferences saved to backend'); - } catch (error) { - console.error('Error saving research preferences:', error); - // Continue anyway - don't block user progress for save errors - } - - // Continue with wizard navigation - onContinue(getResearchData()); - }; // Expose data collection function to parent (only when onDataReady changes) useEffect(() => { diff --git a/frontend/src/components/OnboardingWizard/CompetitorAnalysisStep/ComingSoonSection.tsx b/frontend/src/components/OnboardingWizard/CompetitorAnalysisStep/ComingSoonSection.tsx index 26b7e888..cedb1c39 100644 --- a/frontend/src/components/OnboardingWizard/CompetitorAnalysisStep/ComingSoonSection.tsx +++ b/frontend/src/components/OnboardingWizard/CompetitorAnalysisStep/ComingSoonSection.tsx @@ -15,22 +15,13 @@ import { ListItem, ListItemIcon, ListItemText, - Alert, - LinearProgress + Alert } from '@mui/material'; import { Search as SearchIcon, Analytics as AnalyticsIcon, - TrendingUp as TrendingIcon, - Speed as SpeedIcon, - Security as SecurityIcon, CheckCircle as CheckIcon, - Schedule as ScheduleIcon, - Rocket as RocketIcon, - DataUsage as DataIcon, - Compare as CompareIcon, - Insights as InsightsIcon, - Assessment as AssessmentIcon + Insights as InsightsIcon } from '@mui/icons-material'; export const ComingSoonSection: React.FC = () => { diff --git a/frontend/src/components/OnboardingWizard/IntegrationsStep.tsx b/frontend/src/components/OnboardingWizard/IntegrationsStep.tsx index 4ba08108..46fee958 100644 --- a/frontend/src/components/OnboardingWizard/IntegrationsStep.tsx +++ b/frontend/src/components/OnboardingWizard/IntegrationsStep.tsx @@ -1,5 +1,4 @@ import React, { useState, useEffect } from 'react'; -import { useAuth } from '@clerk/clerk-react'; import { Box, Fade, @@ -17,19 +16,7 @@ import { // Platform Icons Web as WordPressIcon, Web as WixIcon, - Google as GoogleIcon, - // Status Icons - CheckCircle as CheckIcon, - Error as ErrorIcon, - Info as InfoIcon, - Launch as LaunchIcon, - Security as SecurityIcon, - Verified as VerifiedIcon, - Schedule as ScheduleIcon, - TrendingUp as TrendingUpIcon, - Email as EmailIcon, - Business as BusinessIcon, - Notifications as NotificationsIcon + Google as GoogleIcon } from '@mui/icons-material'; // Import refactored components @@ -59,12 +46,11 @@ interface IntegrationPlatform { } const IntegrationsStep: React.FC = ({ onContinue, updateHeaderContent }) => { - const { getToken } = useAuth(); const [email, setEmail] = useState(''); // Use custom hooks - const { gscSites, connectedPlatforms, setConnectedPlatforms, setGscSites, handleGSCConnect } = useGSCConnection(); - const { isLoading, showToast, setShowToast, toastMessage, setToastMessage, handleConnect } = usePlatformConnections(); + const { gscSites, connectedPlatforms, setConnectedPlatforms, handleGSCConnect } = useGSCConnection(); + const { isLoading, showToast, setShowToast, toastMessage, handleConnect } = usePlatformConnections(); // Initialize integrations data const [integrations] = useState([ @@ -211,6 +197,7 @@ const IntegrationsStep: React.FC = ({ onContinue, updateH // Remove query parameters from URL window.history.replaceState({}, document.title, window.location.pathname); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Get user email from Clerk @@ -255,6 +242,7 @@ const IntegrationsStep: React.FC = ({ onContinue, updateH const userEmail = getUserEmail(); setEmail(userEmail); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const handlePlatformConnect = async (platformId: string) => { diff --git a/frontend/src/components/OnboardingWizard/PersonaStep/ComingSoonSection.tsx b/frontend/src/components/OnboardingWizard/PersonaStep/ComingSoonSection.tsx index 1e94ca17..32983068 100644 --- a/frontend/src/components/OnboardingWizard/PersonaStep/ComingSoonSection.tsx +++ b/frontend/src/components/OnboardingWizard/PersonaStep/ComingSoonSection.tsx @@ -15,22 +15,12 @@ import { ListItem, ListItemIcon, ListItemText, - Divider, - Alert, - LinearProgress + Alert } from '@mui/material'; import { - AutoAwesome as AutoAwesomeIcon, - ContentPaste as ContentIcon, Psychology as PsychologyIcon, - TrendingUp as TrendingIcon, - Security as SecurityIcon, - Speed as SpeedIcon, CheckCircle as CheckIcon, - Schedule as ScheduleIcon, - Rocket as RocketIcon, DataUsage as DataIcon, - Tune as TuneIcon, SmartToy as SmartToyIcon } from '@mui/icons-material'; diff --git a/frontend/src/components/OnboardingWizard/WebsiteStep/components/AnalysisProgressDisplay.tsx b/frontend/src/components/OnboardingWizard/WebsiteStep/components/AnalysisProgressDisplay.tsx index a1d3d2dc..77f68524 100644 --- a/frontend/src/components/OnboardingWizard/WebsiteStep/components/AnalysisProgressDisplay.tsx +++ b/frontend/src/components/OnboardingWizard/WebsiteStep/components/AnalysisProgressDisplay.tsx @@ -5,10 +5,8 @@ import React from 'react'; import { - Box, Typography, Card, - CardContent, LinearProgress, Stepper, Step, diff --git a/frontend/src/components/OnboardingWizard/WebsiteStep/utils/renderUtils.tsx b/frontend/src/components/OnboardingWizard/WebsiteStep/utils/renderUtils.tsx index 4f5bbea4..e1a717f1 100644 --- a/frontend/src/components/OnboardingWizard/WebsiteStep/utils/renderUtils.tsx +++ b/frontend/src/components/OnboardingWizard/WebsiteStep/utils/renderUtils.tsx @@ -17,26 +17,18 @@ import { Alert, Button, Slide, - Zoom, - Divider + Zoom } from '@mui/material'; import { useTheme, alpha } from '@mui/material/styles'; import { ExpandMore as ExpandMoreIcon, CheckCircle as CheckIcon, - Info as InfoIcon, Psychology as PsychologyIcon, - TrendingUp as TrendingUpIcon, Analytics as AnalyticsIcon, Business as BusinessIcon, AutoAwesome as AutoAwesomeIcon, Star as StarIcon, - Warning as WarningIcon, - Language as LanguageIcon, - Web as WebIcon, - Palette as PaletteIcon, - Speed as SpeedIcon, - Group as GroupIcon + Warning as WarningIcon } from '@mui/icons-material'; /** diff --git a/frontend/src/components/OnboardingWizard/Wizard.tsx b/frontend/src/components/OnboardingWizard/Wizard.tsx index 4c4ac051..62d659b0 100644 --- a/frontend/src/components/OnboardingWizard/Wizard.tsx +++ b/frontend/src/components/OnboardingWizard/Wizard.tsx @@ -110,7 +110,6 @@ const Wizard: React.FC = ({ onComplete }) => { // Use refs to avoid dependency cycles const stepDataRef = useRef(stepData); const competitorDataCollectorRef = useRef(competitorDataCollector); - const personaStepRef = useRef<{ handleContinue: () => void } | null>(null); // Keep refs in sync with state useEffect(() => { diff --git a/frontend/src/components/OnboardingWizard/common/GSCPlatformCard.tsx b/frontend/src/components/OnboardingWizard/common/GSCPlatformCard.tsx index e201584c..da7b573f 100644 --- a/frontend/src/components/OnboardingWizard/common/GSCPlatformCard.tsx +++ b/frontend/src/components/OnboardingWizard/common/GSCPlatformCard.tsx @@ -10,10 +10,9 @@ import { Tooltip } from '@mui/material'; import { - Google as GoogleIcon, Refresh as RefreshIcon } from '@mui/icons-material'; -import { gscAPI, type GSCSite } from '../../../api/gsc'; +import { type GSCSite } from '../../../api/gsc'; interface GSCPlatformCardProps { platform: { diff --git a/frontend/src/components/OnboardingWizard/common/WixPlatformCard.tsx b/frontend/src/components/OnboardingWizard/common/WixPlatformCard.tsx index 23fdc4c2..89c32df6 100644 --- a/frontend/src/components/OnboardingWizard/common/WixPlatformCard.tsx +++ b/frontend/src/components/OnboardingWizard/common/WixPlatformCard.tsx @@ -17,7 +17,6 @@ import { } from '@mui/material'; import { Web as WixIcon, - Add as AddIcon, CheckCircle as CheckCircleIcon, Error as ErrorIcon, Refresh as RefreshIcon diff --git a/frontend/src/components/OnboardingWizard/common/WordPressOAuthPlatformCard.tsx b/frontend/src/components/OnboardingWizard/common/WordPressOAuthPlatformCard.tsx index eaabbd0c..4f7d50bd 100644 --- a/frontend/src/components/OnboardingWizard/common/WordPressOAuthPlatformCard.tsx +++ b/frontend/src/components/OnboardingWizard/common/WordPressOAuthPlatformCard.tsx @@ -15,7 +15,6 @@ import { DialogTitle, DialogContent, DialogActions, - Alert, CircularProgress, IconButton, Tooltip, @@ -27,12 +26,10 @@ import { } from '@mui/material'; import { Web as WordPressIcon, - Add as AddIcon, Delete as DeleteIcon, CheckCircle as CheckCircleIcon, Error as ErrorIcon, - Refresh as RefreshIcon, - Launch as LaunchIcon + Refresh as RefreshIcon } from '@mui/icons-material'; import { useWordPressOAuth } from '../../../hooks/useWordPressOAuth'; diff --git a/frontend/src/components/SEODashboard/SEOCopilotContext.tsx b/frontend/src/components/SEODashboard/SEOCopilotContext.tsx index 2dea2e1a..0e53513f 100644 --- a/frontend/src/components/SEODashboard/SEOCopilotContext.tsx +++ b/frontend/src/components/SEODashboard/SEOCopilotContext.tsx @@ -14,8 +14,7 @@ const SEOCopilotContext: React.FC<{ children: React.ReactNode }> = ({ children } isLoading, isAnalyzing, isGenerating, - error, - loadPersonalizationData + error } = useSEOCopilotStore(); const hasLoadedPersonalization = useRef(false); diff --git a/frontend/src/components/SEODashboard/SEOCopilotTest.tsx b/frontend/src/components/SEODashboard/SEOCopilotTest.tsx index bdaecba0..6ecf47df 100644 --- a/frontend/src/components/SEODashboard/SEOCopilotTest.tsx +++ b/frontend/src/components/SEODashboard/SEOCopilotTest.tsx @@ -1,7 +1,7 @@ // SEO CopilotKit Test Component // Simple test to verify CopilotKit sidebar functionality -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import { Box, Button, Typography, Paper, Alert } from '@mui/material'; import { useCopilotAction } from '@copilotkit/react-core'; diff --git a/frontend/src/components/SEODashboard/SEODashboard.tsx b/frontend/src/components/SEODashboard/SEODashboard.tsx index 63c07d96..96eb407c 100644 --- a/frontend/src/components/SEODashboard/SEODashboard.tsx +++ b/frontend/src/components/SEODashboard/SEODashboard.tsx @@ -6,7 +6,6 @@ import { Typography, Alert, Skeleton, - useTheme, Chip, Button } from '@mui/material'; @@ -31,8 +30,6 @@ import { userDataAPI } from '../../api/userData'; // SEO Dashboard component const SEODashboard: React.FC = () => { - const theme = useTheme(); - // Clerk authentication hooks const { isSignedIn, isLoaded } = useAuth(); const { user } = useUser(); diff --git a/frontend/src/components/SEODashboard/components/GSCLoginButton.tsx b/frontend/src/components/SEODashboard/components/GSCLoginButton.tsx index 4801f039..afd7ad7c 100644 --- a/frontend/src/components/SEODashboard/components/GSCLoginButton.tsx +++ b/frontend/src/components/SEODashboard/components/GSCLoginButton.tsx @@ -60,6 +60,7 @@ const GSCLoginButton: React.FC = ({ onStatusChange }) => { // Check GSC connection status on component mount useEffect(() => { checkGSCStatus(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const checkGSCStatus = async () => { diff --git a/frontend/src/components/SEODashboard/components/SEOAnalyzerPanel.tsx b/frontend/src/components/SEODashboard/components/SEOAnalyzerPanel.tsx index 003d9a70..87123b83 100644 --- a/frontend/src/components/SEODashboard/components/SEOAnalyzerPanel.tsx +++ b/frontend/src/components/SEODashboard/components/SEOAnalyzerPanel.tsx @@ -31,7 +31,6 @@ import { } from './seoUtils'; // Components -import CategoryCard from './CategoryCard'; import CriticalIssueCard from './CriticalIssueCard'; import AnalysisTabs from './AnalysisTabs'; import IssueDetailsDialog from './IssueDetailsDialog'; diff --git a/frontend/src/components/TextEditor/CitationHoverHandler.tsx b/frontend/src/components/TextEditor/CitationHoverHandler.tsx index ac990ef6..d67fff2a 100644 --- a/frontend/src/components/TextEditor/CitationHoverHandler.tsx +++ b/frontend/src/components/TextEditor/CitationHoverHandler.tsx @@ -80,8 +80,6 @@ const CitationHoverHandler: React.FC = ({ researchSou modal.style.padding = '18px 20px'; const title = (src.title || 'Untitled').replace(/ = ({ researchSou tip.style.backdropFilter = 'blur(5px)'; const title = (src.title || 'Untitled').replace(/ = ({ if (draft !== localDraft) { setLocalDraft(draft); } - }, [draft]); + }, [draft, localDraft]); // Cleanup debounced saver useEffect(() => { diff --git a/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/ContentPreviewHeaderWithModals.tsx b/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/ContentPreviewHeaderWithModals.tsx index 247b056f..232b9a0f 100644 --- a/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/ContentPreviewHeaderWithModals.tsx +++ b/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/ContentPreviewHeaderWithModals.tsx @@ -356,6 +356,7 @@ const ContentPreviewHeaderWithModals: React.FC = (pro window.removeEventListener('showCitationsModal', handleShowCitationsModal as EventListener); window.removeEventListener('showSearchQueriesModal', handleShowSearchQueriesModal as EventListener); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( diff --git a/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/MainContentPreviewHeader.tsx b/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/MainContentPreviewHeader.tsx index f1f1c69c..166d91cb 100644 --- a/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/MainContentPreviewHeader.tsx +++ b/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/MainContentPreviewHeader.tsx @@ -36,7 +36,6 @@ const MainContentPreviewHeader: React.FC = ({ onAssistantToggle, topic }) => { - const formatPercent = (v?: number) => typeof v === 'number' ? `${Math.round(v * 100)}%` : 'โ€”'; const getChipColor = (v?: number) => { if (typeof v !== 'number') return '#6b7280'; if (v >= 0.8) return '#10b981'; diff --git a/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/PersonaChip.tsx b/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/PersonaChip.tsx index 54f99446..9d18cea9 100644 --- a/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/PersonaChip.tsx +++ b/frontend/src/components/TextEditor/ContentPreviewHeaderComponents/PersonaChip.tsx @@ -97,6 +97,7 @@ const PersonaChip: React.FC = ({ useEffect(() => { fetchPersonaData(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [platform, userId]); const handleSavePersona = async (data: PersonaData, saveToDatabase: boolean) => { diff --git a/frontend/src/components/TextEditor/QuickEditToolbar.tsx b/frontend/src/components/TextEditor/QuickEditToolbar.tsx index 8911eb56..50032965 100644 --- a/frontend/src/components/TextEditor/QuickEditToolbar.tsx +++ b/frontend/src/components/TextEditor/QuickEditToolbar.tsx @@ -24,7 +24,7 @@ const QuickEditToolbar: React.FC = ({ draft, isPreviewing const lines = draft.split('\n'); if (lines.length > 0) { const first = lines[0].trim(); - lines[0] = first.replace(/^(.*?)([\.!?])?$/, '๐Ÿ‘‰ $1$2'); + lines[0] = first.replace(/^(.*?)([.!?])?$/, '๐Ÿ‘‰ $1$2'); } const target = lines.join('\n'); window.dispatchEvent(new CustomEvent('linkedinwriter:applyEdit', { detail: { target } })); @@ -62,7 +62,7 @@ const QuickEditToolbar: React.FC = ({ draft, isPreviewing