ALwrity + Wix + Wordpress + GSC + Bug Fixes

This commit is contained in:
ajaysi
2025-10-10 13:08:09 +05:30
parent af4c8afb5b
commit 11f164ae21
80 changed files with 125 additions and 678 deletions

View File

@@ -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
}

View File

@@ -52,14 +52,14 @@ export const ResearchPollingHandler: React.FC<ResearchPollingHandlerProps> = ({
} else {
polling.stopPolling();
}
}, [taskId]);
}, [taskId, polling]);
// Cleanup on unmount
useEffect(() => {
return () => {
polling.stopPolling();
};
}, []);
}, [polling]);
console.log('ResearchPollingHandler render:', {
taskId,

View File

@@ -213,7 +213,7 @@ export const RewriteFeedbackForm: React.FC<RewriteFeedbackFormProps> = ({
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<RewriteFeedbackFormProps> = ({
if (result.success && result.taskId) {
onRewriteStarted?.(result.taskId);
setIsCollectingFeedback(false);
return {
success: true,

View File

@@ -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<PreviewCardProps> = ({
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<PreviewCardProps> = ({
});
};
const getCurrentTime = () => {
return new Date().toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit'
});
};
return (
<Box>
<Typography variant="h6" sx={{ mb: 3, display: 'flex', alignItems: 'center', gap: 1 }}>

View File

@@ -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<SEOAnalysisModalProps> = ({
// 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<SEOAnalysisModalProps> = ({
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<SEOAnalysisModalProps> = ({
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 <Cancel sx={{ fontSize: 16 }} />;
case 'Medium': return <Warning sx={{ fontSize: 16 }} />;
case 'Low': return <CheckCircle sx={{ fontSize: 16 }} />;
default: return <Warning sx={{ fontSize: 16 }} />;
}
};
// Tooltip content for each metric
const getMetricTooltip = (category: string) => {
@@ -352,7 +330,7 @@ export const SEOAnalysisModal: React.FC<SEOAnalysisModalProps> = ({
if (isOpen && !analysisResult) {
runSEOAnalysis();
}
}, [isOpen]);
}, [isOpen, analysisResult, runSEOAnalysis]);
return (
<Dialog

View File

@@ -20,22 +20,13 @@ import {
Typography,
Tabs,
Tab,
Paper,
CircularProgress,
Alert,
IconButton,
Tooltip,
Chip,
Grid,
Card,
CardContent,
Divider,
TextField,
InputAdornment
Chip
} from '@mui/material';
import {
Close as CloseIcon,
ContentCopy as CopyIcon,
Check as CheckIcon,
Preview as PreviewIcon,
Search as SearchIcon,

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback } from 'react';
import React, { useState, useEffect } from 'react';
import {
Dialog,
DialogTitle,
@@ -12,15 +12,10 @@ import {
LinearProgress,
Chip,
IconButton,
Alert,
CircularProgress,
Card
CircularProgress
} from '@mui/material';
import {
Close as CloseIcon,
CheckCircle as CheckCircleIcon,
Error as ErrorIcon,
Refresh as RefreshIcon,
Schedule as ScheduleIcon,
TrendingUp as TrendingUpIcon,
School as SchoolIcon,
@@ -31,8 +26,7 @@ import {
import { motion, AnimatePresence } from 'framer-motion';
// Import existing components for reuse
import DataSourceTransparency from '../DataSourceTransparency';
import ProgressIndicator from '../ProgressIndicator';
// Note: DataSourceTransparency and ProgressIndicator are imported but may be used by child components
// Import panel components
import {
@@ -42,57 +36,28 @@ import {
StepResultsPanel,
EducationalPanel,
useCalendarGenerationPolling,
type CalendarGenerationProgress,
type QualityScores
} from './calendarGenerationModalPanels';
// Import new StepProgressTracker component
import StepProgressTracker from './calendarGenerationModalPanels/StepProgressTracker';
// Import styles
// Import styles (only used ones)
import {
dialogStyles,
contentContainerStyles,
progressBarContainerStyles,
progressBarStyles,
stepProgressBarStyles,
getStepIndicatorStyles,
getStepCardStyles,
stepCircleBaseStyles,
getStepCircleColor,
tabButtonStyles,
activityIndicatorStyles,
qualityScoreContainerStyles,
getQualityScoreBackground,
qualityScoreInnerStyles,
dataSourceCardStyles,
dataSourceIconStyles,
getDataSourceIconColor,
qualityMetricsContainerStyles,
getMetricColor,
stepResultsCardStyles,
stepResultsHeaderStyles,
stepResultsContentStyles,
loadingContainerStyles,
loadingContentStyles,
animationDurations,
animationEasing,
springConfig,
staggerDelay,
cardStaggerDelay,
fadeInUp,
fadeInLeft,
scaleIn,
slideInStaggered,
hoverLift,
hoverScale,
tapScale,
pulseAnimation,
smallPulseAnimation,
colorPulseAnimation,
progressFillAnimation,
progressOverlayStyles,
stepProgressOverlayStyles
progressOverlayStyles
} from './CalendarGenerationModal.styles';
// Types
@@ -262,19 +227,11 @@ const CalendarGenerationModal: React.FC<CalendarGenerationModalProps> = ({
}) => {
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<CalendarGenerationModalProps> = ({
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';

View File

@@ -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';

View File

@@ -181,8 +181,6 @@ const CalendarConfigurationStep: React.FC<CalendarConfigurationStepProps> = ({
const [userGuidance, setUserGuidance] = useState<UserGuidance | null>(null);
const [transparencyIndicators, setTransparencyIndicators] = useState<TransparencyIndicators | null>(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<CalendarConfigurationStepProps> = ({
// 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

View File

@@ -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<any>(null);
const [localGenerationProgress, setLocalGenerationProgress] = useState<number>(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 {

View File

@@ -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

View File

@@ -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<EnhancedPerformanceVisualizatio
const [error, setError] = useState<string | null>(null);
// Use real-time data hook
const { data: realTimeData, isConnected, error: realTimeError } = useMockRealTimeData(strategyId);
const { data: realTimeData, isConnected } = useMockRealTimeData(strategyId);
useEffect(() => {
loadQualityAnalysis();

View File

@@ -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<SystemStatusIndicatorProps> = ({ className
const [statusData, setStatusData] = useState<SystemStatusData | null>(null);
const [detailedStats, setDetailedStats] = useState<DetailedStatsData | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [, setError] = useState<string | null>(null);
const [dashboardOpen, setDashboardOpen] = useState(false);
const [chartData, setChartData] = useState<any[]>([]);
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<SystemStatusIndicatorProps> = ({ className
);
}
const total = statusData?.recent_requests ?? 0;
const failed = statusData?.recent_errors ?? 0;
const passed = Math.max(0, total - failed);
return (
<>
<Tooltip title={tooltipContent} arrow placement="bottom">

View File

@@ -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<any>({
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';

View File

@@ -7,8 +7,7 @@ import {
List,
ListItem,
ListItemText,
ListItemIcon,
Chip
ListItemIcon
} from '@mui/material';
import {
Analytics as AnalyticsIcon,

View File

@@ -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 () => {

View File

@@ -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<any>(null);
const [strategyData, setStrategyData] = useState<StrategyData | null>(null);
const [strategyDataLoading, setStrategyDataLoading] = useState(false);
const [strategyDataError, setStrategyDataError] = useState<string | null>(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');

View File

@@ -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<CalendarConfig | null>(null);
const [sessionId, setSessionId] = useState<string>('');
const [isStartingGeneration, setIsStartingGeneration] = useState(false);
const location = useLocation();
const { state: { strategyContext }, isFromStrategyActivation } = useStrategyCalendarContext();
const [userData, setUserData] = useState<any>({});
const [userData] = useState<any>({});
// 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]);

View File

@@ -3,8 +3,7 @@ import {
Box,
Tabs,
Tab,
Typography,
Alert
Typography
} from '@mui/material';
import {
Analytics as AnalyticsIcon,

View File

@@ -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 = () => {

View File

@@ -49,6 +49,7 @@ const RefineAnalysisTab: React.FC = () => {
useEffect(() => {
loadGapAnalysisData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const loadGapAnalysisData = async () => {

View File

@@ -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 += `<s class=\"fbw-del\">${escapeHtml(a[i])}</s>`;
out += `<s class="fbw-del">${escapeHtml(a[i])}</s>`;
i++;
} else {
out += `<em class=\"fbw-add\">${escapeHtml(b[j])}</em>`;
out += `<em class="fbw-add">${escapeHtml(b[j])}</em>`;
j++;
}
}
while (i < n) { out += `<s class=\"fbw-del\">${escapeHtml(a[i++])}</s>`; }
while (j < m) { out += `<em class=\"fbw-add\">${escapeHtml(b[j++])}</em>`; }
if (oldText.length > MAX || newText.length > MAX) out += '<span class=\"fbw-more\"> …</span>';
while (i < n) { out += `<s class="fbw-del">${escapeHtml(a[i++])}</s>`; }
while (j < m) { out += `<em class="fbw-add">${escapeHtml(b[j++])}</em>`; }
if (oldText.length > MAX || newText.length > MAX) out += '<span class="fbw-more"> …</span>';
return out;
}
@@ -148,7 +148,7 @@ const FacebookWriterContent: React.FC<FacebookWriterProps> = ({ className = '' }
const [livePreviewHtml, setLivePreviewHtml] = React.useState<string>('');
const [isPreviewing, setIsPreviewing] = React.useState<boolean>(false);
const [pendingEdit, setPendingEdit] = React.useState<{ src: string; target: string } | null>(null);
const [historyVersion, setHistoryVersion] = React.useState<number>(0);
const [, setHistoryVersion] = React.useState<number>(0);
const [adVariations, setAdVariations] = React.useState<{
headline_variations: string[];
primary_text_variations: string[];

View File

@@ -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 = '';

View File

@@ -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';

View File

@@ -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';

View File

@@ -29,8 +29,6 @@ interface ContentEditorProps {
topic?: string;
}
export { ContentEditor };
const ContentEditor: React.FC<ContentEditorProps> = ({
isPreviewing,
pendingEdit,
@@ -62,6 +60,7 @@ const ContentEditor: React.FC<ContentEditorProps> = ({
const ctaCooldownRef = useRef<number | null>(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<NodeJS.Timeout | null>(null);
const hasTriggeredOnceRef = useRef<boolean>(false);
@@ -228,8 +227,6 @@ const ContentEditor: React.FC<ContentEditorProps> = ({
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<ContentEditorProps> = ({
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<ContentEditorProps> = ({
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<ContentEditorProps> = ({
<CitationHoverHandler researchSources={researchSources || []} />
</div>
);
};
};
export { ContentEditor };

View File

@@ -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();

View File

@@ -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';

View File

@@ -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 {

View File

@@ -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<CompactSidebarProps> = ({
// 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);

View File

@@ -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 {

View File

@@ -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<EnhancedTodayModalProps> = ({
navigationState,
completeTask,
skipTask,
moveToNextTask,
isLoading,
isWorkflowComplete
} = useWorkflowStore();
const [selectedTask, setSelectedTask] = useState<TodayTask | null>(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<EnhancedTodayModalProps> = ({
}
};
const handleStartWorkflow = async () => {
if (currentWorkflow) {
await moveToNextTask();
}
};
const handleNextPillar = async () => {
// Close current modal
onClose();
@@ -158,9 +148,6 @@ const EnhancedTodayModal: React.FC<EnhancedTodayModalProps> = ({
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);

View File

@@ -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<ApiKeyCarouselProps> = ({
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<ApiKeyCarouselProps> = ({
}
};
const getStepIcon = (index: number) => {
const stepProvider = providers[index];
if (stepProvider.status === 'valid') {
return <CheckCircle sx={{ color: 'success.main' }} />;
}
return <Key sx={{ color: stepProvider === provider ? 'primary.main' : 'text.disabled' }} />;
};
return (
<Box sx={{ width: '100%', maxWidth: 600, mx: 'auto' }}>
{/* Progress Stepper - Hidden as requested */}

View File

@@ -10,13 +10,10 @@ import {
ListItemText,
Chip,
Divider,
Alert,
} from '@mui/material';
import {
CheckCircle,
Star,
Security,
Speed,
TrendingUp,
Insights,
Search,

View File

@@ -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('');

View File

@@ -52,7 +52,7 @@ const CompetitorAnalysisStep: React.FC<CompetitorAnalysisStepProps> = ({
const [analysisStep, setAnalysisStep] = useState('');
const [competitors, setCompetitors] = useState<Competitor[]>([]);
const [socialMediaAccounts, setSocialMediaAccounts] = useState<any>({});
const [socialMediaCitations, setSocialMediaCitations] = useState<any[]>([]);
const [, setSocialMediaCitations] = useState<any[]>([]);
const [researchSummary, setResearchSummary] = useState<ResearchSummary | null>(null);
const [error, setError] = useState<string | null>(null);
const [showProgressModal, setShowProgressModal] = useState(false);
@@ -260,6 +260,7 @@ const CompetitorAnalysisStep: React.FC<CompetitorAnalysisStepProps> = ({
} 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<CompetitorAnalysisStepProps> = ({
};
}, [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(() => {

View File

@@ -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 = () => {

View File

@@ -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<IntegrationsStepProps> = ({ onContinue, updateHeaderContent }) => {
const { getToken } = useAuth();
const [email, setEmail] = useState<string>('');
// 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<IntegrationPlatform[]>([
@@ -211,6 +197,7 @@ const IntegrationsStep: React.FC<IntegrationsStepProps> = ({ 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<IntegrationsStepProps> = ({ onContinue, updateH
const userEmail = getUserEmail();
setEmail(userEmail);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handlePlatformConnect = async (platformId: string) => {

View File

@@ -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';

View File

@@ -5,10 +5,8 @@
import React from 'react';
import {
Box,
Typography,
Card,
CardContent,
LinearProgress,
Stepper,
Step,

View File

@@ -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';
/**

View File

@@ -110,7 +110,6 @@ const Wizard: React.FC<WizardProps> = ({ 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(() => {

View File

@@ -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: {

View File

@@ -17,7 +17,6 @@ import {
} from '@mui/material';
import {
Web as WixIcon,
Add as AddIcon,
CheckCircle as CheckCircleIcon,
Error as ErrorIcon,
Refresh as RefreshIcon

View File

@@ -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';

View File

@@ -14,8 +14,7 @@ const SEOCopilotContext: React.FC<{ children: React.ReactNode }> = ({ children }
isLoading,
isAnalyzing,
isGenerating,
error,
loadPersonalizationData
error
} = useSEOCopilotStore();
const hasLoadedPersonalization = useRef(false);

View File

@@ -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';

View File

@@ -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();

View File

@@ -60,6 +60,7 @@ const GSCLoginButton: React.FC<GSCLoginButtonProps> = ({ onStatusChange }) => {
// Check GSC connection status on component mount
useEffect(() => {
checkGSCStatus();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const checkGSCStatus = async () => {

View File

@@ -31,7 +31,6 @@ import {
} from './seoUtils';
// Components
import CategoryCard from './CategoryCard';
import CriticalIssueCard from './CriticalIssueCard';
import AnalysisTabs from './AnalysisTabs';
import IssueDetailsDialog from './IssueDetailsDialog';

View File

@@ -80,8 +80,6 @@ const CitationHoverHandler: React.FC<CitationHoverHandlerProps> = ({ researchSou
modal.style.padding = '18px 20px';
const title = (src.title || 'Untitled').replace(/</g, '&lt;');
const url = (src.url || '').replace(/</g, '&lt;');
const sourceType = src.source_type ? String(src.source_type).replace('_', ' ') : '';
modal.innerHTML =
'<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">' +
@@ -163,8 +161,6 @@ const CitationHoverHandler: React.FC<CitationHoverHandlerProps> = ({ researchSou
tip.style.backdropFilter = 'blur(5px)';
const title = (src.title || 'Untitled').replace(/</g, '&lt;');
const url = (src.url || '').replace(/</g, '&lt;');
const sourceType = src.source_type ? String(src.source_type).replace('_', ' ') : '';
tip.innerHTML =
'<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">' +

View File

@@ -85,7 +85,7 @@ const ContentDisplayArea: React.FC<ContentDisplayAreaProps> = ({
if (draft !== localDraft) {
setLocalDraft(draft);
}
}, [draft]);
}, [draft, localDraft]);
// Cleanup debounced saver
useEffect(() => {

View File

@@ -356,6 +356,7 @@ const ContentPreviewHeaderWithModals: React.FC<ContentPreviewHeaderProps> = (pro
window.removeEventListener('showCitationsModal', handleShowCitationsModal as EventListener);
window.removeEventListener('showSearchQueriesModal', handleShowSearchQueriesModal as EventListener);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (

View File

@@ -36,7 +36,6 @@ const MainContentPreviewHeader: React.FC<MainContentPreviewHeaderProps> = ({
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';

View File

@@ -97,6 +97,7 @@ const PersonaChip: React.FC<PersonaChipProps> = ({
useEffect(() => {
fetchPersonaData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [platform, userId]);
const handleSavePersona = async (data: PersonaData, saveToDatabase: boolean) => {

View File

@@ -24,7 +24,7 @@ const QuickEditToolbar: React.FC<QuickEditToolbarProps> = ({ 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<QuickEditToolbarProps> = ({ draft, isPreviewing
</button>
<button
onClick={() => {
const target = `[Professionalized]` + '\n\n' + draft;
const target = '[Professionalized]\n\n' + draft;
window.dispatchEvent(new CustomEvent('linkedinwriter:applyEdit', { detail: { target } }));
}}
style={{ padding: '6px 10px', border: '1px solid #ddd', borderRadius: 6, background: '#fff', cursor: 'pointer' }}

View File

@@ -2,10 +2,6 @@ import React, { useState, useRef, useEffect } from 'react';
import { hallucinationDetectorService, HallucinationDetectionResponse } from '../../services/hallucinationDetectorService';
import FactCheckResults from '../LinkedInWriter/components/FactCheckResults';
interface TextSelectionHandlerProps {
contentRef: React.RefObject<HTMLDivElement>;
}
const useTextSelectionHandler = (contentRef: React.RefObject<HTMLDivElement>) => {
const [selectionMenu, setSelectionMenu] = useState<{ x: number; y: number; text: string } | null>(null);
const [factCheckResults, setFactCheckResults] = useState<HallucinationDetectionResponse | null>(null);
@@ -112,7 +108,7 @@ const useTextSelectionHandler = (contentRef: React.RefObject<HTMLDivElement>) =>
switch (editType) {
case 'tighten':
// Add hook emoji to the beginning
editedText = selectedText.replace(/^(.*?)([\.!?])?$/, '👉 $1$2');
editedText = selectedText.replace(/^(.*?)([.!?])?$/, '👉 $1$2');
break;
case 'add-cta':
// Add call-to-action

View File

@@ -13,12 +13,11 @@ import {
Select,
MenuItem,
Chip,
Divider,
Link
Divider
} from '@mui/material';
import { apiClient } from '../../api/client';
import { createClient, OAuthStrategy } from '@wix/sdk';
import { categories as blogCategoriesModule, tags as blogTagsModule, posts as blogPostsModule, draftPosts as blogDraftPostsModule } from '@wix/blog';
import { categories as blogCategoriesModule, tags as blogTagsModule } from '@wix/blog';
interface WixConnectionStatus {
connected: boolean;
@@ -49,7 +48,6 @@ const WixTestPage: React.FC = () => {
const [publishing, setPublishing] = useState(false);
const [categories, setCategories] = useState<BlogCategories | null>(null);
const [tags, setTags] = useState<BlogTags | null>(null);
const [authUrl, setAuthUrl] = useState<string>('');
// Blog post form state
const [blogTitle, setBlogTitle] = useState('Test Blog Post from ALwrity');
@@ -120,7 +118,6 @@ This integration opens up new possibilities for content creators who want to lev
// Use sessionStorage to ensure data is scoped to this tab/session
sessionStorage.setItem('wix_oauth_data', JSON.stringify(oauthData));
const { authUrl } = await wixClient.auth.getAuthUrl(oauthData);
setAuthUrl(authUrl);
window.location.href = authUrl;
} catch (error) {
console.error('Failed to start Wix OAuth flow:', error);

View File

@@ -12,11 +12,7 @@ import {
import { motion } from 'framer-motion';
import {
DollarSign,
TrendingUp,
RefreshCw,
AlertTriangle,
CheckCircle,
XCircle,
Info
} from 'lucide-react';
@@ -28,7 +24,6 @@ import {
formatCurrency,
formatNumber,
formatPercentage,
getUsageStatusColor,
getUsageStatusIcon,
calculateUsagePercentage
} from '../../services/billingService';
@@ -53,7 +48,6 @@ const BillingOverview: React.FC<BillingOverviewProps> = ({
const getStatusChip = () => {
const status = usageStats.usage_status;
const color = getUsageStatusColor(status);
const icon = getUsageStatusIcon(status);
let chipColor: 'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' = 'default';

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect } from 'react';
import {
Card,
CardContent,
@@ -26,9 +26,6 @@ import { billingService } from '../../services/billingService';
import { monitoringService } from '../../services/monitoringService';
import { onApiEvent } from '../../utils/apiEvents';
// Components
import ComprehensiveAPIBreakdown from './ComprehensiveAPIBreakdown';
interface CompactBillingDashboardProps {
userId?: string;
}
@@ -38,7 +35,6 @@ const CompactBillingDashboard: React.FC<CompactBillingDashboardProps> = ({ userI
const [systemHealth, setSystemHealth] = useState<SystemHealth | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [lastUpdated, setLastUpdated] = useState<Date | null>(null);
const fetchData = async () => {
try {
@@ -52,7 +48,6 @@ const CompactBillingDashboard: React.FC<CompactBillingDashboardProps> = ({ userI
setDashboardData(billingData);
setSystemHealth(healthData);
setLastUpdated(new Date());
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to fetch data');
} finally {
@@ -62,6 +57,7 @@ const CompactBillingDashboard: React.FC<CompactBillingDashboardProps> = ({ userI
useEffect(() => {
fetchData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [userId]);
// Event-driven refresh
@@ -77,11 +73,11 @@ const CompactBillingDashboard: React.FC<CompactBillingDashboardProps> = ({ userI
fetchData();
});
return unsubscribe;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const formatCurrency = (amount: number) => `$${amount.toFixed(4)}`;
const formatNumber = (num: number) => num.toLocaleString();
const formatPercentage = (num: number) => `${num.toFixed(1)}%`;
if (loading && !dashboardData) {
return (
@@ -118,9 +114,7 @@ const CompactBillingDashboard: React.FC<CompactBillingDashboardProps> = ({ userI
if (!dashboardData) return null;
const { current_usage, trends, limits, alerts } = dashboardData;
const activeProviders = Object.entries(current_usage.provider_breakdown)
.filter(([_, data]) => data.cost > 0);
const { current_usage, limits, alerts } = dashboardData;
return (
<motion.div

View File

@@ -10,26 +10,15 @@ import {
Accordion,
AccordionSummary,
AccordionDetails,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
} from '@mui/material';
import { ExpandMore } from '@mui/icons-material';
import { motion } from 'framer-motion';
import {
Info,
DollarSign,
Activity,
Zap,
Search,
Image,
Code,
Database,
Globe,
FileText,
BarChart3
} from 'lucide-react';

View File

@@ -8,11 +8,8 @@ import {
Chip,
} from '@mui/material';
import { motion } from 'framer-motion';
import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend } from 'recharts';
import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts';
import {
DollarSign,
TrendingUp,
BarChart3,
PieChart as PieChartIcon
} from 'lucide-react';

View File

@@ -3,13 +3,9 @@ import {
Box,
Container,
Grid,
Card,
CardContent,
Typography,
Alert,
CircularProgress,
useTheme,
useMediaQuery,
ToggleButton,
ToggleButtonGroup,
Tooltip,
@@ -18,14 +14,6 @@ import {
} from '@mui/material';
import { motion, AnimatePresence } from 'framer-motion';
import {
DollarSign,
TrendingUp,
AlertTriangle,
Activity,
Zap,
BarChart3,
PieChart,
Clock,
Grid3X3,
List,
Info,
@@ -61,11 +49,7 @@ const EnhancedBillingDashboard: React.FC<EnhancedBillingDashboardProps> = ({ use
const [systemHealth, setSystemHealth] = useState<SystemHealth | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [lastUpdated, setLastUpdated] = useState<Date | null>(null);
const [viewMode, setViewMode] = useState<ViewMode>('compact');
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const fetchDashboardData = async () => {
try {
@@ -75,7 +59,6 @@ const EnhancedBillingDashboard: React.FC<EnhancedBillingDashboardProps> = ({ use
]);
setDashboardData(billingData);
setSystemHealth(healthData);
setLastUpdated(new Date());
} catch (error) {
setError(error instanceof Error ? error.message : 'Failed to fetch dashboard data');
} finally {
@@ -95,7 +78,6 @@ const EnhancedBillingDashboard: React.FC<EnhancedBillingDashboardProps> = ({ use
.then(([billingData, health]) => {
setDashboardData(billingData);
setSystemHealth(health);
setLastUpdated(new Date());
})
.catch(() => {/* ignore */});
});

View File

@@ -12,7 +12,6 @@ import {
IconButton,
Tooltip,
Collapse,
Alert,
} from '@mui/material';
import { motion, AnimatePresence } from 'framer-motion';
import {

View File

@@ -22,7 +22,6 @@ import {
import {
TrendingUp,
TrendingDown,
BarChart3,
Calendar
} from 'lucide-react';

View File

@@ -13,9 +13,6 @@ import { motion } from 'framer-motion';
import {
Activity,
RefreshCw,
AlertTriangle,
CheckCircle,
XCircle,
Clock,
Zap
} from 'lucide-react';
@@ -27,7 +24,6 @@ import { SystemHealth } from '../../types/monitoring';
import {
getHealthStatusColor,
getHealthStatusIcon,
formatResponseTime,
formatErrorRate,
getPerformanceStatus
} from '../../services/monitoringService';

View File

@@ -1,5 +1,5 @@
import React, { Component, ErrorInfo, ReactNode } from 'react';
import { Box, Typography, Button, Alert, Stack } from '@mui/material';
import { Typography, Button, Alert, Stack } from '@mui/material';
import { Refresh as RefreshIcon } from '@mui/icons-material';
interface ComponentErrorBoundaryProps {

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { Box, Typography, Chip, Button, CircularProgress, Tooltip } from '@mui/material';
import { PlayArrow, Pause, Stop } from '@mui/icons-material';
import { Box, Typography, Chip, Button, Tooltip } from '@mui/material';
import { PlayArrow } from '@mui/icons-material';
import { ShimmerHeader } from './styled';
import UserBadge from './UserBadge';
import { DashboardHeaderProps } from './types';

View File

@@ -8,7 +8,6 @@ import {
Stack,
Alert,
Collapse,
IconButton,
Divider
} from '@mui/material';
import {

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { Box, Container, Alert, Button } from '@mui/material';
import { Container, Alert, Button } from '@mui/material';
import { DashboardContainer } from './styled';
import { ErrorDisplayProps } from './types';

View File

@@ -9,8 +9,7 @@ import { useCopilotReadable } from '@copilotkit/react-core';
import {
WritingPersona,
PlatformAdaptation,
PlatformType,
UserPersonasResponse
PlatformType
} from '../../../types/PlatformPersonaTypes';
import {
getUserPersonas,
@@ -37,6 +36,9 @@ interface PlatformPersonaProviderProps {
userId?: number; // Default to 1 for now, can be enhanced with auth context later
}
// Cache duration: 5 minutes (constant outside component to avoid dependency issues)
const CACHE_DURATION = 5 * 60 * 1000;
// Provider component
export const PlatformPersonaProvider: React.FC<PlatformPersonaProviderProps> = ({
children,
@@ -53,9 +55,6 @@ export const PlatformPersonaProvider: React.FC<PlatformPersonaProviderProps> = (
const lastRequestTime = useRef<number>(0);
const requestInProgress = useRef<boolean>(false);
const dataCacheTime = useRef<number>(0);
// Cache duration: 5 minutes
const CACHE_DURATION = 5 * 60 * 1000;
// Fetch persona data function
const fetchPersonas = useCallback(async () => {
@@ -253,7 +252,7 @@ export const PlatformPersonaProvider: React.FC<PlatformPersonaProviderProps> = (
dataCacheTime.current = Date.now();
requestInProgress.current = false;
}
}, [userId, platform, corePersona]);
}, [userId, platform, corePersona, platformPersona]);
// Initial data fetch
useEffect(() => {

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { Avatar, Box, Button, Menu, MenuItem, Typography, Tooltip } from '@mui/material';
import { Avatar, Box, Menu, MenuItem, Typography, Tooltip } from '@mui/material';
import { useUser, useClerk } from '@clerk/clerk-react';
interface UserBadgeProps {

View File

@@ -1,13 +1,11 @@
import React from 'react';
import {
LineChart,
Line,
BarChart,
Bar,
PieChart,
Pie,
Cell,
AreaChart,
Area,
XAxis,
YAxis,

View File

@@ -121,7 +121,7 @@ function validateContextIntegrity(state: StrategyCalendarState): boolean {
// Check if calendar context is valid when it exists
if (state.calendarContext) {
const { strategyContext, autoPopulatedData } = state.calendarContext;
const { strategyContext } = state.calendarContext;
if (strategyContext && !validateContextIntegrity({ ...state, strategyContext })) {
return false;
}

View File

@@ -2,14 +2,12 @@ import React from 'react';
import {
Article as ArticleIcon,
Search as SearchIcon,
Campaign as CampaignIcon,
Analytics as AnalyticsIcon,
Psychology as PsychologyIcon,
AutoAwesome as AutoAwesomeIcon,
Speed as SpeedIcon,
Business as BusinessIcon,
SocialDistance as SocialIcon,
Create as CreateIcon,
Dashboard as DashboardIcon,
Facebook as FacebookIcon,
LinkedIn as LinkedInIcon,

View File

@@ -40,7 +40,6 @@ export interface UsePersonaPollingReturn {
export function usePersonaPolling(options: UsePersonaPollingOptions = {}): UsePersonaPollingReturn {
const {
interval = 2000, // 2 seconds default
maxAttempts = 0, // No timeout - poll until backend says done
onProgress,
onComplete,
onError

View File

@@ -25,7 +25,6 @@ export function usePolling(
): UsePollingReturn {
const {
interval = 2000, // 2 seconds default
maxAttempts = 0, // No timeout - poll until backend says done
onProgress,
onComplete,
onError

View File

@@ -40,8 +40,6 @@ export const useWixConnection = () => {
const tokensRaw = sessionStorage.getItem('wix_tokens');
if (connectedFlag && tokensRaw) {
const tokens = JSON.parse(tokensRaw);
// Set connected status with site information from tokens
setStatus({
connected: true,

View File

@@ -319,7 +319,7 @@ export const useEnhancedStrategyStore = create<EnhancedStrategyStore>((set, get)
loadOnboardingIntegration: async (strategyId) => {
try {
const integration = await contentPlanningApi.getOnboardingIntegration(strategyId);
await contentPlanningApi.getOnboardingIntegration(strategyId);
// Handle onboarding integration data
} catch (error: any) {
console.error('Failed to load onboarding integration:', error);

View File

@@ -1,14 +1,7 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/static-build",
"config": {
"distDir": "build"
}
}
],
"buildCommand": "npm run build",
"outputDirectory": "build",
"routes": [
{
"src": "/(.*)",