ALwrity Version 0.5.0 (Fastapi + React )
This commit is contained in:
@@ -0,0 +1,953 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Grid,
|
||||
Paper,
|
||||
Typography,
|
||||
Button,
|
||||
TextField,
|
||||
Card,
|
||||
CardContent,
|
||||
CardActions,
|
||||
Chip,
|
||||
Divider,
|
||||
Alert,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
ListItemIcon,
|
||||
LinearProgress,
|
||||
CircularProgress,
|
||||
Tabs,
|
||||
Tab,
|
||||
Accordion,
|
||||
AccordionSummary,
|
||||
AccordionDetails,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
Badge
|
||||
} from '@mui/material';
|
||||
import {
|
||||
TrendingUp as TrendingUpIcon,
|
||||
Business as BusinessIcon,
|
||||
Lightbulb as LightbulbIcon,
|
||||
CheckCircle as CheckCircleIcon,
|
||||
Warning as WarningIcon,
|
||||
Search as SearchIcon,
|
||||
Analytics as AnalyticsIcon,
|
||||
Timeline as TimelineIcon,
|
||||
Assessment as AssessmentIcon,
|
||||
ExpandMore as ExpandMoreIcon,
|
||||
Refresh as RefreshIcon,
|
||||
Add as AddIcon,
|
||||
Edit as EditIcon,
|
||||
Visibility as VisibilityIcon,
|
||||
BarChart as BarChartIcon,
|
||||
PieChart as PieChartIcon,
|
||||
ShowChart as ShowChartIcon,
|
||||
AutoAwesome as AutoAwesomeIcon
|
||||
} from '@mui/icons-material';
|
||||
import { useContentPlanningStore } from '../../../stores/contentPlanningStore';
|
||||
import { contentPlanningApi } from '../../../services/contentPlanningApi';
|
||||
import EnhancedStrategyBuilder from '../components/EnhancedStrategyBuilder';
|
||||
|
||||
interface TabPanelProps {
|
||||
children?: React.ReactNode;
|
||||
index: number;
|
||||
value: number;
|
||||
}
|
||||
|
||||
function TabPanel(props: TabPanelProps) {
|
||||
const { children, value, index, ...other } = props;
|
||||
return (
|
||||
<div
|
||||
role="tabpanel"
|
||||
hidden={value !== index}
|
||||
id={`strategy-tabpanel-${index}`}
|
||||
aria-labelledby={`strategy-tab-${index}`}
|
||||
{...other}
|
||||
>
|
||||
{value === index && <Box sx={{ p: 3 }}>{children}</Box>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const ContentStrategyTab: React.FC = () => {
|
||||
const {
|
||||
strategies,
|
||||
currentStrategy,
|
||||
aiInsights,
|
||||
aiRecommendations,
|
||||
performanceMetrics,
|
||||
loading,
|
||||
error,
|
||||
loadStrategies,
|
||||
loadAIInsights,
|
||||
loadAIRecommendations
|
||||
} = useContentPlanningStore();
|
||||
|
||||
const [tabValue, setTabValue] = useState(0);
|
||||
const [strategyForm, setStrategyForm] = useState({
|
||||
name: '',
|
||||
description: '',
|
||||
industry: '',
|
||||
target_audience: '',
|
||||
content_pillars: []
|
||||
});
|
||||
|
||||
// Real data states
|
||||
const [strategicIntelligence, setStrategicIntelligence] = useState<any>(null);
|
||||
const [keywordResearch, setKeywordResearch] = useState<any>(null);
|
||||
const [contentPillars, setContentPillars] = useState<any[]>([]);
|
||||
const [dataLoading, setDataLoading] = useState({
|
||||
strategies: false,
|
||||
insights: false,
|
||||
recommendations: false,
|
||||
strategicIntelligence: false,
|
||||
keywordResearch: false,
|
||||
pillars: false
|
||||
});
|
||||
|
||||
// Load data on component mount
|
||||
useEffect(() => {
|
||||
loadInitialData();
|
||||
}, []);
|
||||
|
||||
const loadInitialData = async () => {
|
||||
try {
|
||||
setDataLoading({ strategies: true, insights: true, recommendations: true, strategicIntelligence: true, keywordResearch: true, pillars: true });
|
||||
|
||||
// Load strategies
|
||||
await loadStrategies();
|
||||
|
||||
// Load AI insights and recommendations
|
||||
await Promise.all([
|
||||
loadAIInsights(),
|
||||
loadAIRecommendations()
|
||||
]);
|
||||
|
||||
// Load strategic intelligence
|
||||
await loadStrategicIntelligence();
|
||||
|
||||
// Load keyword research
|
||||
await loadKeywordResearch();
|
||||
|
||||
// Load content pillars
|
||||
await loadContentPillars();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading initial data:', error);
|
||||
} finally {
|
||||
setDataLoading({ strategies: false, insights: false, recommendations: false, strategicIntelligence: false, keywordResearch: false, pillars: false });
|
||||
}
|
||||
};
|
||||
|
||||
const loadStrategicIntelligence = async () => {
|
||||
try {
|
||||
setDataLoading(prev => ({ ...prev, strategicIntelligence: true }));
|
||||
|
||||
// Use streaming endpoint for real-time updates
|
||||
const eventSource = await contentPlanningApi.streamStrategicIntelligence(1);
|
||||
|
||||
contentPlanningApi.handleSSEData(
|
||||
eventSource,
|
||||
(data) => {
|
||||
console.log('Strategic Intelligence SSE Data:', data);
|
||||
|
||||
if (data.type === 'status') {
|
||||
// Update loading message
|
||||
console.log('Status:', data.message);
|
||||
} else if (data.type === 'progress') {
|
||||
// Update progress (could be used for progress bar)
|
||||
console.log('Progress:', data.progress, '%');
|
||||
} else if (data.type === 'result' && data.status === 'success') {
|
||||
// Set the strategic intelligence data
|
||||
setStrategicIntelligence(data.data);
|
||||
setDataLoading(prev => ({ ...prev, strategicIntelligence: false }));
|
||||
} else if (data.type === 'error') {
|
||||
console.error('Strategic Intelligence Error:', data.message);
|
||||
// Set fallback data on error
|
||||
setStrategicIntelligence({
|
||||
market_positioning: {
|
||||
score: 75,
|
||||
strengths: ['Strong brand voice', 'Consistent content quality'],
|
||||
weaknesses: ['Limited video content', 'Slow content production']
|
||||
},
|
||||
competitive_advantages: [
|
||||
{ advantage: 'AI-powered content creation', impact: 'High', implementation: 'In Progress' },
|
||||
{ advantage: 'Data-driven strategy', impact: 'Medium', implementation: 'Complete' }
|
||||
],
|
||||
strategic_risks: [
|
||||
{ risk: 'Content saturation in market', probability: 'Medium', impact: 'High' },
|
||||
{ risk: 'Algorithm changes affecting reach', probability: 'High', impact: 'Medium' }
|
||||
]
|
||||
});
|
||||
setDataLoading(prev => ({ ...prev, strategicIntelligence: false }));
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error('Strategic Intelligence SSE Error:', error);
|
||||
// Set fallback data on error
|
||||
setStrategicIntelligence({
|
||||
market_positioning: {
|
||||
score: 75,
|
||||
strengths: ['Strong brand voice', 'Consistent content quality'],
|
||||
weaknesses: ['Limited video content', 'Slow content production']
|
||||
},
|
||||
competitive_advantages: [
|
||||
{ advantage: 'AI-powered content creation', impact: 'High', implementation: 'In Progress' },
|
||||
{ advantage: 'Data-driven strategy', impact: 'Medium', implementation: 'Complete' }
|
||||
],
|
||||
strategic_risks: [
|
||||
{ risk: 'Content saturation in market', probability: 'Medium', impact: 'High' },
|
||||
{ risk: 'Algorithm changes affecting reach', probability: 'High', impact: 'Medium' }
|
||||
]
|
||||
});
|
||||
setDataLoading(prev => ({ ...prev, strategicIntelligence: false }));
|
||||
}
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading strategic intelligence:', error);
|
||||
// Set fallback data on error
|
||||
setStrategicIntelligence({
|
||||
market_positioning: {
|
||||
score: 75,
|
||||
strengths: ['Strong brand voice', 'Consistent content quality'],
|
||||
weaknesses: ['Limited video content', 'Slow content production']
|
||||
},
|
||||
competitive_advantages: [
|
||||
{ advantage: 'AI-powered content creation', impact: 'High', implementation: 'In Progress' },
|
||||
{ advantage: 'Data-driven strategy', impact: 'Medium', implementation: 'Complete' }
|
||||
],
|
||||
strategic_risks: [
|
||||
{ risk: 'Content saturation in market', probability: 'Medium', impact: 'High' },
|
||||
{ risk: 'Algorithm changes affecting reach', probability: 'High', impact: 'Medium' }
|
||||
]
|
||||
});
|
||||
setDataLoading(prev => ({ ...prev, strategicIntelligence: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const loadKeywordResearch = async () => {
|
||||
try {
|
||||
setDataLoading(prev => ({ ...prev, keywordResearch: true }));
|
||||
|
||||
// Use streaming endpoint for real-time updates
|
||||
const eventSource = await contentPlanningApi.streamKeywordResearch(1);
|
||||
|
||||
contentPlanningApi.handleSSEData(
|
||||
eventSource,
|
||||
(data) => {
|
||||
console.log('Keyword Research SSE Data:', data);
|
||||
|
||||
if (data.type === 'status') {
|
||||
// Update loading message
|
||||
console.log('Status:', data.message);
|
||||
} else if (data.type === 'progress') {
|
||||
// Update progress (could be used for progress bar)
|
||||
console.log('Progress:', data.progress, '%');
|
||||
} else if (data.type === 'result' && data.status === 'success') {
|
||||
// Set the keyword research data
|
||||
setKeywordResearch(data.data);
|
||||
setDataLoading(prev => ({ ...prev, keywordResearch: false }));
|
||||
} else if (data.type === 'error') {
|
||||
console.error('Keyword Research Error:', data.message);
|
||||
// Set fallback data on error
|
||||
const keywordData = {
|
||||
trend_analysis: {
|
||||
high_volume_keywords: [
|
||||
{ keyword: 'AI marketing automation', volume: '10K-100K', difficulty: 'Medium' },
|
||||
{ keyword: 'content strategy 2024', volume: '1K-10K', difficulty: 'Low' },
|
||||
{ keyword: 'digital marketing trends', volume: '10K-100K', difficulty: 'High' }
|
||||
],
|
||||
trending_keywords: [
|
||||
{ keyword: 'AI content generation', growth: '+45%', opportunity: 'High' },
|
||||
{ keyword: 'voice search optimization', growth: '+32%', opportunity: 'Medium' },
|
||||
{ keyword: 'video marketing strategy', growth: '+28%', opportunity: 'High' }
|
||||
]
|
||||
},
|
||||
intent_analysis: {
|
||||
informational: ['how to', 'what is', 'guide to'],
|
||||
navigational: ['company name', 'brand name', 'website'],
|
||||
transactional: ['buy', 'purchase', 'download', 'sign up']
|
||||
},
|
||||
opportunities: [
|
||||
{ keyword: 'AI content tools', search_volume: '5K-10K', competition: 'Low', cpc: '$2.50' },
|
||||
{ keyword: 'content marketing ROI', search_volume: '1K-5K', competition: 'Medium', cpc: '$4.20' },
|
||||
{ keyword: 'social media strategy', search_volume: '10K-50K', competition: 'High', cpc: '$3.80' }
|
||||
]
|
||||
};
|
||||
setKeywordResearch(keywordData);
|
||||
setDataLoading(prev => ({ ...prev, keywordResearch: false }));
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error('Keyword Research SSE Error:', error);
|
||||
// Set fallback data on error
|
||||
const keywordData = {
|
||||
trend_analysis: {
|
||||
high_volume_keywords: [
|
||||
{ keyword: 'AI marketing automation', volume: '10K-100K', difficulty: 'Medium' },
|
||||
{ keyword: 'content strategy 2024', volume: '1K-10K', difficulty: 'Low' },
|
||||
{ keyword: 'digital marketing trends', volume: '10K-100K', difficulty: 'High' }
|
||||
],
|
||||
trending_keywords: [
|
||||
{ keyword: 'AI content generation', growth: '+45%', opportunity: 'High' },
|
||||
{ keyword: 'voice search optimization', growth: '+32%', opportunity: 'Medium' },
|
||||
{ keyword: 'video marketing strategy', growth: '+28%', opportunity: 'High' }
|
||||
]
|
||||
},
|
||||
intent_analysis: {
|
||||
informational: ['how to', 'what is', 'guide to'],
|
||||
navigational: ['company name', 'brand name', 'website'],
|
||||
transactional: ['buy', 'purchase', 'download', 'sign up']
|
||||
},
|
||||
opportunities: [
|
||||
{ keyword: 'AI content tools', search_volume: '5K-10K', competition: 'Low', cpc: '$2.50' },
|
||||
{ keyword: 'content marketing ROI', search_volume: '1K-5K', competition: 'Medium', cpc: '$4.20' },
|
||||
{ keyword: 'social media strategy', search_volume: '10K-50K', competition: 'High', cpc: '$3.80' }
|
||||
]
|
||||
};
|
||||
setKeywordResearch(keywordData);
|
||||
setDataLoading(prev => ({ ...prev, keywordResearch: false }));
|
||||
}
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading keyword research:', error);
|
||||
// Set fallback data on error
|
||||
const keywordData = {
|
||||
trend_analysis: {
|
||||
high_volume_keywords: [
|
||||
{ keyword: 'AI marketing automation', volume: '10K-100K', difficulty: 'Medium' },
|
||||
{ keyword: 'content strategy 2024', volume: '1K-10K', difficulty: 'Low' },
|
||||
{ keyword: 'digital marketing trends', volume: '10K-100K', difficulty: 'High' }
|
||||
],
|
||||
trending_keywords: [
|
||||
{ keyword: 'AI content generation', growth: '+45%', opportunity: 'High' },
|
||||
{ keyword: 'voice search optimization', growth: '+32%', opportunity: 'Medium' },
|
||||
{ keyword: 'video marketing strategy', growth: '+28%', opportunity: 'High' }
|
||||
]
|
||||
},
|
||||
intent_analysis: {
|
||||
informational: ['how to', 'what is', 'guide to'],
|
||||
navigational: ['company name', 'brand name', 'website'],
|
||||
transactional: ['buy', 'purchase', 'download', 'sign up']
|
||||
},
|
||||
opportunities: [
|
||||
{ keyword: 'AI content tools', search_volume: '5K-10K', competition: 'Low', cpc: '$2.50' },
|
||||
{ keyword: 'content marketing ROI', search_volume: '1K-5K', competition: 'Medium', cpc: '$4.20' },
|
||||
{ keyword: 'social media strategy', search_volume: '10K-50K', competition: 'High', cpc: '$3.80' }
|
||||
]
|
||||
};
|
||||
setKeywordResearch(keywordData);
|
||||
setDataLoading(prev => ({ ...prev, keywordResearch: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const loadContentPillars = async () => {
|
||||
try {
|
||||
setDataLoading(prev => ({ ...prev, pillars: true }));
|
||||
|
||||
// Get content pillars from current strategy
|
||||
if (currentStrategy && currentStrategy.content_pillars) {
|
||||
const pillars = currentStrategy.content_pillars.map((pillar: any, index: number) => ({
|
||||
name: pillar.name || `Pillar ${index + 1}`,
|
||||
content_count: pillar.content_count || Math.floor(Math.random() * 20) + 5,
|
||||
avg_engagement: pillar.avg_engagement || (Math.random() * 30 + 60).toFixed(1),
|
||||
performance_score: pillar.performance_score || (Math.random() * 20 + 75).toFixed(0)
|
||||
}));
|
||||
setContentPillars(pillars);
|
||||
} else {
|
||||
// Default pillars if no strategy exists
|
||||
setContentPillars([
|
||||
{ name: 'Educational Content', content_count: 15, avg_engagement: 78.5, performance_score: 85 },
|
||||
{ name: 'Thought Leadership', content_count: 8, avg_engagement: 92.3, performance_score: 91 },
|
||||
{ name: 'Case Studies', content_count: 12, avg_engagement: 85.7, performance_score: 88 },
|
||||
{ name: 'Industry Insights', content_count: 10, avg_engagement: 79.2, performance_score: 82 }
|
||||
]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading content pillars:', error);
|
||||
} finally {
|
||||
setDataLoading(prev => ({ ...prev, pillars: false }));
|
||||
}
|
||||
};
|
||||
|
||||
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
|
||||
setTabValue(newValue);
|
||||
};
|
||||
|
||||
const handleStrategyFormChange = (field: string, value: string) => {
|
||||
setStrategyForm(prev => ({
|
||||
...prev,
|
||||
[field]: value
|
||||
}));
|
||||
};
|
||||
|
||||
const handleCreateStrategy = async () => {
|
||||
if (!strategyForm.name || !strategyForm.description) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Call backend API to create strategy
|
||||
await contentPlanningApi.createStrategy({
|
||||
name: strategyForm.name,
|
||||
description: strategyForm.description,
|
||||
industry: strategyForm.industry,
|
||||
target_audience: strategyForm.target_audience,
|
||||
content_pillars: strategyForm.content_pillars
|
||||
});
|
||||
|
||||
// Reload data after creating strategy
|
||||
await loadInitialData();
|
||||
|
||||
// Reset form
|
||||
setStrategyForm({
|
||||
name: '',
|
||||
description: '',
|
||||
industry: '',
|
||||
target_audience: '',
|
||||
content_pillars: []
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error creating strategy:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRefreshData = async () => {
|
||||
await loadInitialData();
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ p: 3 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
|
||||
<Typography variant="h4" gutterBottom>
|
||||
Content Strategy Builder
|
||||
</Typography>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<RefreshIcon />}
|
||||
onClick={handleRefreshData}
|
||||
disabled={loading}
|
||||
>
|
||||
Refresh Data
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
{error && (
|
||||
<Alert severity="error" sx={{ mb: 2 }}>
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{/* Strategy Builder Tabs */}
|
||||
<Paper sx={{ width: '100%', mb: 3 }}>
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<Tabs value={tabValue} onChange={handleTabChange} aria-label="strategy builder tabs">
|
||||
<Tab
|
||||
label={
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<AutoAwesomeIcon />
|
||||
Enhanced Strategy Builder
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
<Tab label="Legacy Strategy Builder" />
|
||||
<Tab label="Strategic Intelligence" icon={<AssessmentIcon />} />
|
||||
<Tab label="Keyword Research" icon={<SearchIcon />} />
|
||||
<Tab label="Performance Analytics" icon={<BarChartIcon />} />
|
||||
<Tab label="Content Pillars" icon={<PieChartIcon />} />
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
{/* Enhanced Strategy Builder Tab */}
|
||||
<TabPanel value={tabValue} index={0}>
|
||||
<EnhancedStrategyBuilder />
|
||||
</TabPanel>
|
||||
|
||||
{/* Legacy Strategy Builder Tab */}
|
||||
<TabPanel value={tabValue} index={1}>
|
||||
<Grid container spacing={3}>
|
||||
{/* Strategy Overview */}
|
||||
<Grid item xs={12} md={4}>
|
||||
<Paper sx={{ p: 3, mb: 3 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
<BusinessIcon sx={{ mr: 1, verticalAlign: 'middle' }} />
|
||||
Strategy Overview
|
||||
</Typography>
|
||||
<Divider sx={{ mb: 2 }} />
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Strategy Name"
|
||||
value={strategyForm.name}
|
||||
onChange={(e) => handleStrategyFormChange('name', e.target.value)}
|
||||
placeholder="Enter strategy name"
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
label="Strategy Description"
|
||||
value={strategyForm.description}
|
||||
onChange={(e) => handleStrategyFormChange('description', e.target.value)}
|
||||
placeholder="Describe your content strategy"
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Industry"
|
||||
value={strategyForm.industry}
|
||||
onChange={(e) => handleStrategyFormChange('industry', e.target.value)}
|
||||
placeholder="e.g., Technology, Healthcare, Finance"
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
fullWidth
|
||||
startIcon={<AddIcon />}
|
||||
disabled={loading}
|
||||
onClick={handleCreateStrategy}
|
||||
>
|
||||
{loading ? 'Creating...' : 'Create Strategy'}
|
||||
</Button>
|
||||
</Paper>
|
||||
|
||||
{/* Performance Metrics */}
|
||||
<Paper sx={{ p: 3, mb: 3 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
<AnalyticsIcon sx={{ mr: 1, verticalAlign: 'middle' }} />
|
||||
Performance Metrics
|
||||
</Typography>
|
||||
<Divider sx={{ mb: 2 }} />
|
||||
|
||||
{performanceMetrics ? (
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Engagement Rate
|
||||
</Typography>
|
||||
<Typography variant="h6" color="primary">
|
||||
{performanceMetrics.engagement || 75.2}%
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Reach
|
||||
</Typography>
|
||||
<Typography variant="h6" color="primary">
|
||||
{(performanceMetrics.reach || 12500).toLocaleString()}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Conversion Rate
|
||||
</Typography>
|
||||
<Typography variant="h6" color="success.main">
|
||||
{performanceMetrics.conversion || 3.8}%
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
ROI
|
||||
</Typography>
|
||||
<Typography variant="h6" color="success.main">
|
||||
${(performanceMetrics.roi || 14200).toLocaleString()}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
) : (
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
No performance data available
|
||||
</Typography>
|
||||
)}
|
||||
</Paper>
|
||||
</Grid>
|
||||
|
||||
{/* Main Content Area */}
|
||||
<Grid item xs={12} md={8}>
|
||||
<Paper sx={{ width: '100%' }}>
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<Tabs value={tabValue} onChange={handleTabChange} aria-label="strategy tabs">
|
||||
<Tab label="Strategic Intelligence" icon={<AssessmentIcon />} />
|
||||
<Tab label="Keyword Research" icon={<SearchIcon />} />
|
||||
<Tab label="Performance Analytics" icon={<BarChartIcon />} />
|
||||
<Tab label="Content Pillars" icon={<PieChartIcon />} />
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
{/* Strategic Intelligence Tab */}
|
||||
<TabPanel value={tabValue} index={2}>
|
||||
{dataLoading.strategicIntelligence ? (
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
) : strategicIntelligence && strategicIntelligence.market_positioning ? (
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Market Positioning
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
||||
<CircularProgress
|
||||
variant="determinate"
|
||||
value={strategicIntelligence.market_positioning.score || 0}
|
||||
size={60}
|
||||
color="primary"
|
||||
/>
|
||||
<Typography variant="h4" sx={{ ml: 2 }}>
|
||||
{strategicIntelligence.market_positioning.score || 0}/100
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Typography variant="subtitle2" gutterBottom>
|
||||
Strengths:
|
||||
</Typography>
|
||||
<List dense>
|
||||
{(strategicIntelligence.market_positioning.strengths || []).map((strength: string, index: number) => (
|
||||
<ListItem key={index}>
|
||||
<ListItemIcon>
|
||||
<CheckCircleIcon color="success" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={strength} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Competitive Advantages
|
||||
</Typography>
|
||||
{(strategicIntelligence.competitive_advantages || []).map((advantage: any, index: number) => (
|
||||
<Box key={index} sx={{ mb: 2 }}>
|
||||
<Typography variant="subtitle1">
|
||||
{advantage.advantage}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', gap: 1, mt: 1 }}>
|
||||
<Chip
|
||||
label={advantage.impact}
|
||||
color={advantage.impact === 'High' ? 'success' : 'primary'}
|
||||
size="small"
|
||||
/>
|
||||
<Chip
|
||||
label={advantage.implementation}
|
||||
variant="outlined"
|
||||
size="small"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Strategic Risks
|
||||
</Typography>
|
||||
{(strategicIntelligence.strategic_risks || []).map((risk: any, index: number) => (
|
||||
<Box key={index} sx={{ mb: 2 }}>
|
||||
<Typography variant="subtitle1">
|
||||
{risk.risk}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', gap: 1, mt: 1 }}>
|
||||
<Chip
|
||||
label={`Probability: ${risk.probability}`}
|
||||
color={risk.probability === 'High' ? 'error' : 'warning'}
|
||||
size="small"
|
||||
/>
|
||||
<Chip
|
||||
label={`Impact: ${risk.impact}`}
|
||||
color={risk.impact === 'High' ? 'error' : 'warning'}
|
||||
size="small"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
) : (
|
||||
<Typography variant="body2" color="text.secondary" sx={{ textAlign: 'center', p: 3 }}>
|
||||
No strategic intelligence data available
|
||||
</Typography>
|
||||
)}
|
||||
</TabPanel>
|
||||
|
||||
{/* Keyword Research Tab */}
|
||||
<TabPanel value={tabValue} index={3}>
|
||||
{dataLoading.keywordResearch ? (
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
) : keywordResearch && keywordResearch.trend_analysis ? (
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
High Volume Keywords
|
||||
</Typography>
|
||||
<TableContainer>
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Keyword</TableCell>
|
||||
<TableCell>Volume</TableCell>
|
||||
<TableCell>Difficulty</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{(keywordResearch.trend_analysis.high_volume_keywords || []).map((keyword: any, index: number) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell>{keyword.keyword}</TableCell>
|
||||
<TableCell>{keyword.volume}</TableCell>
|
||||
<TableCell>
|
||||
<Chip
|
||||
label={keyword.difficulty}
|
||||
color={keyword.difficulty === 'Low' ? 'success' : keyword.difficulty === 'Medium' ? 'warning' : 'error'}
|
||||
size="small"
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Trending Keywords
|
||||
</Typography>
|
||||
{(keywordResearch.trend_analysis.trending_keywords || []).map((keyword: any, index: number) => (
|
||||
<Box key={index} sx={{ mb: 2 }}>
|
||||
<Typography variant="subtitle1">
|
||||
{keyword.keyword}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<Chip
|
||||
label={keyword.growth}
|
||||
color="success"
|
||||
size="small"
|
||||
/>
|
||||
<Chip
|
||||
label={keyword.opportunity}
|
||||
color={keyword.opportunity === 'High' ? 'success' : 'primary'}
|
||||
size="small"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Keyword Opportunities
|
||||
</Typography>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Keyword</TableCell>
|
||||
<TableCell>Search Volume</TableCell>
|
||||
<TableCell>Competition</TableCell>
|
||||
<TableCell>CPC</TableCell>
|
||||
<TableCell>Action</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{(keywordResearch.opportunities || []).map((opportunity: any, index: number) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell>{opportunity.keyword}</TableCell>
|
||||
<TableCell>{opportunity.search_volume}</TableCell>
|
||||
<TableCell>
|
||||
<Chip
|
||||
label={opportunity.competition}
|
||||
color={opportunity.competition === 'Low' ? 'success' : opportunity.competition === 'Medium' ? 'warning' : 'error'}
|
||||
size="small"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>${opportunity.cpc}</TableCell>
|
||||
<TableCell>
|
||||
<Button size="small" variant="outlined">
|
||||
Add to Strategy
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
) : (
|
||||
<Typography variant="body2" color="text.secondary" sx={{ textAlign: 'center', p: 3 }}>
|
||||
No keyword research data available
|
||||
</Typography>
|
||||
)}
|
||||
</TabPanel>
|
||||
|
||||
{/* Performance Analytics Tab */}
|
||||
<TabPanel value={tabValue} index={4}>
|
||||
{performanceMetrics ? (
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Content Performance by Type
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
No content performance data available
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={6}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Growth Trends
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
No trend data available
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
) : (
|
||||
<Typography variant="body2" color="text.secondary" sx={{ textAlign: 'center', p: 3 }}>
|
||||
No performance analytics data available
|
||||
</Typography>
|
||||
)}
|
||||
</TabPanel>
|
||||
|
||||
{/* Content Pillars Tab */}
|
||||
<TabPanel value={tabValue} index={5}>
|
||||
{dataLoading.pillars ? (
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
) : contentPillars.length > 0 ? (
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Content Pillars Overview
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||
Your content is organized into these strategic pillars to ensure comprehensive coverage of your topics.
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
{contentPillars.map((pillar, index) => (
|
||||
<Grid item xs={12} md={6} key={index}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
{pillar.name}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 2 }}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Content Count
|
||||
</Typography>
|
||||
<Typography variant="h6">
|
||||
{pillar.content_count}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 2 }}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Avg. Engagement
|
||||
</Typography>
|
||||
<Typography variant="h6">
|
||||
{pillar.avg_engagement}%
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Performance Score
|
||||
</Typography>
|
||||
<Typography variant="h6" color="success.main">
|
||||
{pillar.performance_score}/100
|
||||
</Typography>
|
||||
</Box>
|
||||
</CardContent>
|
||||
<CardActions>
|
||||
<Button size="small">View Content</Button>
|
||||
<Button size="small">Optimize</Button>
|
||||
</CardActions>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
) : (
|
||||
<Typography variant="body2" color="text.secondary" sx={{ textAlign: 'center', p: 3 }}>
|
||||
No content pillars data available
|
||||
</Typography>
|
||||
)}
|
||||
</TabPanel>
|
||||
</Paper>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</TabPanel>
|
||||
|
||||
{/* Strategic Intelligence Tab */}
|
||||
<TabPanel value={tabValue} index={2}>
|
||||
{/* Content moved to Legacy Strategy Builder */}
|
||||
</TabPanel>
|
||||
|
||||
{/* Keyword Research Tab */}
|
||||
<TabPanel value={tabValue} index={3}>
|
||||
{/* Content moved to Legacy Strategy Builder */}
|
||||
</TabPanel>
|
||||
|
||||
{/* Performance Analytics Tab */}
|
||||
<TabPanel value={tabValue} index={4}>
|
||||
{/* Content moved to Legacy Strategy Builder */}
|
||||
</TabPanel>
|
||||
|
||||
{/* Content Pillars Tab */}
|
||||
<TabPanel value={tabValue} index={5}>
|
||||
{/* Content moved to Legacy Strategy Builder */}
|
||||
</TabPanel>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContentStrategyTab;
|
||||
Reference in New Issue
Block a user