ALwrity version 0.5.5

This commit is contained in:
ajaysi
2025-08-15 23:02:18 +05:30
parent 6bfa9f0fce
commit 234eefb4bc
27 changed files with 2806 additions and 1417 deletions

View File

@@ -659,14 +659,19 @@ async def get_latest_generated_strategy(
from models.enhanced_strategy_models import EnhancedContentStrategy
from sqlalchemy import desc
logger.info(f"🔍 Querying database for strategies with user_id: {user_id}")
# Query for the most recent strategy with comprehensive AI analysis
latest_db_strategy = db.query(EnhancedContentStrategy).filter(
EnhancedContentStrategy.user_id == user_id,
EnhancedContentStrategy.comprehensive_ai_analysis.isnot(None)
).order_by(desc(EnhancedContentStrategy.created_at)).first()
logger.info(f"🔍 Database query result: {latest_db_strategy}")
if latest_db_strategy and latest_db_strategy.comprehensive_ai_analysis:
logger.info(f"✅ Found latest strategy in database: {latest_db_strategy.id}")
logger.info(f"🔍 Strategy comprehensive_ai_analysis keys: {list(latest_db_strategy.comprehensive_ai_analysis.keys()) if isinstance(latest_db_strategy.comprehensive_ai_analysis, dict) else 'Not a dict'}")
return ResponseBuilder.create_success_response(
message="Latest generated strategy retrieved successfully from database",
data={
@@ -676,8 +681,15 @@ async def get_latest_generated_strategy(
"strategy_id": latest_db_strategy.id
}
)
else:
logger.info(f"⚠️ No strategy found in database for user: {user_id}")
if latest_db_strategy:
logger.info(f"🔍 Strategy found but no comprehensive_ai_analysis: {latest_db_strategy.id}")
else:
logger.info(f"🔍 No strategy record found at all for user: {user_id}")
except Exception as db_error:
logger.warning(f"⚠️ Database query failed: {str(db_error)}")
logger.error(f"❌ Database error details: {type(db_error).__name__}: {str(db_error)}")
# Fallback: Check in-memory task status
if not hasattr(generate_comprehensive_strategy_polling, '_task_status'):
@@ -705,6 +717,7 @@ async def get_latest_generated_strategy(
completion_time = task_status.get("completed_at")
logger.info(f"✅ Found completed strategy for user {user_id} at {completion_time}")
logger.info(f"🔍 Strategy keys: {list(task_status.get('strategy', {}).keys())}")
if completion_time and (latest_completion_time is None or completion_time > latest_completion_time):
latest_strategy = task_status.get("strategy")
@@ -726,7 +739,7 @@ async def get_latest_generated_strategy(
return ResponseBuilder.create_not_found_response(
message="No completed strategy generation found",
data={"user_id": user_id, "strategy": None}
)
)
except Exception as e:
logger.error(f"❌ Error getting latest generated strategy: {str(e)}")

View File

@@ -592,9 +592,11 @@ class AIStrategyGenerator:
raise RuntimeError("AI service returned empty implementation roadmap")
logger.info("✅ Implementation roadmap generated successfully")
logger.info(f"🔍 Raw AI response for implementation roadmap: {json.dumps(response.get('data', {}), indent=2)}")
# Transform AI response to frontend format
transformed_response = self._transform_ai_response_to_frontend_format(response.get("data", {}), "implementation_roadmap")
logger.info(f"🔍 Transformed implementation roadmap: {json.dumps(transformed_response, indent=2)}")
return transformed_response
except Exception as e:
@@ -1019,6 +1021,8 @@ class AIStrategyGenerator:
def _transform_implementation_roadmap(self, ai_response: Dict[str, Any]) -> Dict[str, Any]:
"""Transform implementation roadmap to frontend format."""
self.logger.info(f"🔍 Transforming implementation roadmap. Input: {json.dumps(ai_response, indent=2)}")
transformed = {
"phases": [],
"timeline": "12 months",
@@ -1028,16 +1032,49 @@ class AIStrategyGenerator:
"success_metrics": []
}
# Extract roadmap data from AI response
roadmap = ai_response.get("roadmap", {})
if roadmap:
if "phases" in roadmap:
transformed["phases"] = roadmap["phases"][:4] # Limit to 4 phases
if "timeline" in roadmap:
transformed["timeline"] = roadmap["timeline"]
if "milestones" in roadmap:
transformed["milestones"] = roadmap["milestones"][:6] # Limit to 6 milestones
# Extract roadmap data from AI response - data is at top level, not nested under "roadmap"
if ai_response:
# Extract phases
phases = ai_response.get("phases", [])
if phases:
transformed["phases"] = phases[:4] # Limit to 4 phases
# Extract timeline
timeline = ai_response.get("timeline", {})
if timeline:
if isinstance(timeline, dict):
# If timeline is an object, extract the duration or use total_duration
transformed["timeline"] = timeline.get("total_duration", "12 months")
# Extract milestones from timeline object
milestones = timeline.get("key_milestones", [])
if milestones:
transformed["milestones"] = milestones[:6]
# Extract critical path from timeline object
critical_path = timeline.get("critical_path", [])
if critical_path:
transformed["critical_path"] = critical_path[:5]
else:
# If timeline is a string, use it directly
transformed["timeline"] = str(timeline)
# Extract total_duration if available
total_duration = ai_response.get("total_duration")
if total_duration:
transformed["timeline"] = str(total_duration)
# Extract resource allocation
resource_allocation = ai_response.get("resource_allocation", {})
if resource_allocation:
team_requirements = resource_allocation.get("team_requirements", [])
if team_requirements:
transformed["resource_requirements"] = team_requirements[:5]
# Extract success metrics
success_metrics = ai_response.get("success_metrics", [])
if success_metrics:
transformed["success_metrics"] = success_metrics[:5]
self.logger.info(f"🔍 Final transformed implementation roadmap: {json.dumps(transformed, indent=2)}")
return transformed
def _transform_risk_assessment(self, ai_response: Dict[str, Any]) -> Dict[str, Any]:

View File

@@ -0,0 +1,134 @@
# API Response Structure Fix
## 🚨 **Issue Summary**
The frontend was not receiving the correct data from backend API endpoints because the backend uses `ResponseBuilder.create_success_response()` which wraps the actual data in a nested structure, but the frontend API methods were returning the entire response instead of extracting the data.
## 🔍 **Root Cause Analysis**
### **Backend Response Structure**
The backend uses `ResponseBuilder.create_success_response()` which creates responses like:
```json
{
"status": "success",
"message": "Operation completed successfully",
"data": {
"user_id": 1,
"strategy": { ... }, // Actual data is nested here
"completed_at": "...",
"strategy_id": 71
},
"status_code": 200,
"timestamp": "..."
}
```
### **Frontend API Issue**
The frontend API methods were returning `response.data` directly, which included the entire response structure instead of just the actual data.
## 🛠️ **Solution Implemented**
### **1. Fixed getLatestGeneratedStrategy**
Updated to extract strategy data from nested structure:
```typescript
// Before: Returning entire response
return response.data;
// After: Extracting strategy data
const result = response.data?.data?.strategy;
return result;
```
### **2. Fixed All Strategy-Related API Methods**
Updated all strategy-related methods to handle nested response structure:
```typescript
// Content Strategy APIs
async getStrategies(userId?: number) {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies`, { params });
return response.data?.data || response.data;
}
// Enhanced Strategy APIs
async getEnhancedStrategies(userId?: number): Promise<any> {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies`, { params });
return response.data?.data || response.data;
}
// Calendar Event APIs
async getEvents(userId?: number, filters?: any) {
const response = await apiClient.get(`${this.baseURL}/calendar-events/`, { params });
return response.data?.data || response.data;
}
// Gap Analysis APIs
async getGapAnalyses(userId?: number) {
const response = await apiClient.get(`${this.baseURL}/gap-analysis/`, { params });
return response.data?.data || response.data;
}
```
### **3. Updated Hook Logic**
Updated `useStrategyData.ts` to handle the corrected data structure:
```typescript
if (latestStrategyResponse && latestStrategyResponse.strategic_insights) {
// Now receiving the actual strategy data directly
const transformedStrategy = transformPollingStrategyData(latestStrategyResponse);
setStrategyData(transformedStrategy);
}
```
## 📊 **Expected Results**
### **Before Fix:**
-**API Methods**: Returning entire response structure
-**Transformation**: Receiving wrong data structure
-**Components**: Showing "data not available"
-**Data Flow**: Broken from API to components
### **After Fix:**
-**API Methods**: Extracting actual data from nested structure
-**Transformation**: Receiving correct strategy data
-**Components**: Displaying rich AI-generated data
-**Data Flow**: Complete from API to components
## 🔧 **Files Modified**
1. **`frontend/src/services/contentPlanningApi.ts`**
- Fixed `getLatestGeneratedStrategy` to extract strategy data
- Updated all strategy-related API methods
- Updated calendar event API methods
- Updated gap analysis API methods
- Updated enhanced strategy API methods
- Updated onboarding data API methods
2. **`frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/hooks/useStrategyData.ts`**
- Updated to handle corrected API response structure
- Simplified logic since API now returns actual data
## 🎯 **Testing**
To verify the fix:
1. Generate a new strategy using the polling system
2. Navigate to the Content Strategy tab
3. Check browser console for API response logs
4. Verify that all Strategic Intelligence cards display rich data:
- Strategic insights with SWOT analysis
- Competitive analysis with detailed competitors
- Performance predictions with metrics
- Risk assessment with mitigation strategies
- Implementation roadmap with phases
## 🚀 **Impact**
This fix resolves the core data flow issue that was preventing the frontend from displaying the rich backend data. All strategy-related functionality should now work correctly, including:
-**Strategy Generation**: Complete data flow from backend to frontend
-**Strategy Display**: Rich data in all Strategic Intelligence cards
-**Strategy Management**: Proper CRUD operations
-**Calendar Integration**: Correct data for calendar generation
-**Gap Analysis**: Proper data extraction and display
The system now properly handles the backend's nested response structure and extracts the actual data for frontend consumption.

View File

@@ -0,0 +1,172 @@
# Performance Predictions Card Enhancement
## 🚨 **Issue Summary**
The PerformancePredictionsCard component was not displaying all the rich performance prediction data available from the backend. The component was looking for data in the wrong structure, causing many values to show as empty or missing.
## 🔍 **Root Cause Analysis**
### **Backend Data Structure (from console logs):**
The backend provides comprehensive performance predictions including:
- **Estimated ROI**: "20-30%"
- **Success Probability**: "85%"
- **Traffic Growth**: { month_3: "25%", month_6: "50%", month_12: "100%" }
- **Engagement Metrics**: { bounce_rate: "35-45%", social_shares: "15-25 per post", time_on_page: "3-5 minutes" }
- **Conversion Predictions**: { content_downloads: "8-12%", email_signups: "3-5%", lead_generation: "5-8%" }
### **Frontend Issue:**
The component was looking for nested objects like `roi_predictions`, `traffic_predictions`, etc., but the actual data was structured as direct properties.
## 🛠️ **Solution Implemented**
### **1. Fixed Data Structure Mapping**
Updated the component to use the correct data structure:
```typescript
// Before: Looking for nested objects
strategyData.performance_predictions.roi_predictions?.estimated_roi
strategyData.performance_predictions.traffic_predictions?.growth_rate
// After: Using direct properties
strategyData.performance_predictions.estimated_roi
strategyData.performance_predictions.traffic_growth.month_12
```
### **2. Updated TypeScript Interface**
Updated `PerformancePredictions` interface to match actual backend structure:
```typescript
export interface PerformancePredictions {
estimated_roi?: string;
success_probability?: string;
traffic_growth?: {
month_3?: string;
month_6?: string;
month_12?: string;
};
engagement_metrics?: {
bounce_rate?: string;
social_shares?: string;
time_on_page?: string;
};
conversion_predictions?: {
content_downloads?: string;
email_signups?: string;
lead_generation?: string;
};
// ... other properties
}
```
### **3. Enhanced Summary Content**
Updated summary to show real data instead of hardcoded values:
```typescript
// Before: Hardcoded values
85%
"ROI Predictions"
"Expected return on investment"
// After: Dynamic data from backend
{strategyData.performance_predictions.estimated_roi || '20-30%'}
"Performance Predictions"
"Expected ROI and success metrics"
```
### **4. Added Missing Sections**
Added comprehensive sections to display all available data:
#### **Traffic Growth Projections**
- Month 3: 25%
- Month 6: 50%
- Month 12: 100%
- Visual grid layout with color-coded cards
#### **Engagement Metrics**
- Bounce Rate: 35-45%
- Time on Page: 3-5 minutes
- Social Shares: 15-25 per post
- Detailed list with color-coded indicators
#### **Conversion Predictions**
- Content Downloads: 8-12%
- Email Signups: 3-5%
- Lead Generation: 5-8%
- Comprehensive conversion metrics
#### **Success Factors**
- High success probability of 85%
- Expected ROI of 20-30%
- Traffic growth projections
- Lead generation improvements
## 📊 **Expected Results**
### **Before Enhancement:**
-**Summary**: Hardcoded values (85%, "ROI Predictions")
-**Content**: Missing traffic growth, engagement metrics, conversion predictions
-**Data Utilization**: ~20% of available data
-**TypeScript Errors**: Interface mismatch with backend data
### **After Enhancement:**
-**Summary**: Dynamic values from backend data
-**Content**: All performance prediction sections displayed
-**Complete**: Traffic growth, engagement metrics, conversion predictions
-**Data Utilization**: 100% of available data
-**TypeScript Compliant**: Interface matches backend structure
## 🔧 **Files Modified**
1. **`frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/components/PerformancePredictionsCard.tsx`**
- Fixed data structure mapping to use direct properties
- Enhanced summary content with dynamic data
- Added Traffic Growth Projections section
- Added Engagement Metrics section
- Added Conversion Predictions section
- Added Success Factors section
- Updated key metrics preview with real data
2. **`frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/types/strategy.types.ts`**
- Updated `PerformancePredictions` interface to match backend structure
- Added `success_probability`, `traffic_growth`, `engagement_metrics`, `conversion_predictions` as direct properties
- Maintained backward compatibility with legacy nested objects
## 🎯 **Data Sections Now Displayed**
### **1. ROI Summary**
- Estimated ROI: 20-30%
- Success Probability: 85%
### **2. Traffic Growth Projections**
- Month 3: 25%
- Month 6: 50%
- Month 12: 100%
### **3. Engagement Metrics**
- Bounce Rate: 35-45%
- Time on Page: 3-5 minutes
- Social Shares: 15-25 per post
### **4. Conversion Predictions**
- Content Downloads: 8-12%
- Email Signups: 3-5%
- Lead Generation: 5-8%
### **5. Success Factors**
- High success probability of 85%
- Expected ROI of 20-30%
- Traffic growth from 25% to 100%
- Lead generation improvement of 5-8%
## 🚀 **Impact**
This enhancement ensures that users can see the complete performance predictions generated by the AI, including:
-**Complete ROI Analysis**: Estimated ROI and success probability
-**Traffic Projections**: Month-by-month growth predictions
-**Engagement Insights**: User interaction metrics
-**Conversion Metrics**: Lead generation and content performance
-**Success Factors**: Key drivers and risk mitigation
-**Data Transparency**: All backend data now visible in UI
The PerformancePredictionsCard now provides a comprehensive view of the AI-generated performance predictions, enabling users to make informed decisions based on the complete performance dataset.

View File

@@ -0,0 +1,137 @@
# Strategic Insights Card Enhancement
## 🚨 **Issue Summary**
The StrategicInsightsCard component was not displaying all the rich strategic insights data available from the backend. While the data was being parsed correctly, the UI was only showing a limited subset of the available information.
## 🔍 **Root Cause Analysis**
### **Available Data (from logs):**
The backend provides comprehensive strategic insights including:
- **Market Positioning**: Current position, positioning strength, SWOT analysis
- **Growth Potential**: Market size, growth rate, key drivers
- **SWOT Summary**: Overall score, primary strengths, key opportunities
- **Content Opportunities**: 3 detailed content opportunities
- **Strategic Insights**: Detailed insights with metadata
### **UI Limitation:**
The component was only displaying:
- Basic market analysis summary
- Limited insights preview
- Content opportunities
- Detailed strategic insights (if available)
## 🛠️ **Solution Implemented**
### **1. Enhanced Summary Content**
Updated the summary to show real data instead of hardcoded values:
```typescript
// Before: Hardcoded values
85%
"Strong market positioning identified"
"High Growth"
"6 months"
// After: Dynamic data from backend
{strategyData.strategic_insights.market_positioning?.positioning_strength ||
strategyData.strategic_insights.swot_summary?.overall_score || 85}%
{strategyData.strategic_insights.market_positioning?.current_position || 'Strong'} market positioning
{strategyData.strategic_insights.growth_potential?.growth_rate || "High Growth"}
{strategyData.strategic_insights.growth_potential?.market_size || "Growing Market"}
```
### **2. Added Missing Sections**
Added comprehensive sections to display all available data:
#### **Market Positioning Section**
- Current position and positioning strength
- Complete SWOT analysis with strengths and opportunities
- Color-coded chips for easy identification
#### **Growth Potential Section**
- Market size and growth rate indicators
- Key growth drivers with detailed explanations
- Visual indicators for growth metrics
#### **SWOT Summary Section**
- Overall SWOT score
- Primary strengths list
- Key opportunities list
- Comprehensive analysis summary
### **3. Enhanced Key Insights Preview**
Updated preview to show meaningful data:
```typescript
// Show content opportunities as key insights
{strategyData.strategic_insights.content_opportunities?.slice(0, 2).map(...)}
// Show growth drivers as key insights
{strategyData.strategic_insights.growth_potential?.key_drivers?.slice(0, 1).map(...)}
// Show SWOT insights
{strategyData.strategic_insights.market_positioning?.swot_analysis?.strengths?.length > 0 && (
<Chip label={`${strengths.length} Strengths`} />
)}
```
## 📊 **Expected Results**
### **Before Enhancement:**
-**Summary**: Hardcoded values (85%, "Strong", "High Growth")
-**Content**: Only basic insights and content opportunities
-**Missing**: Market positioning, growth potential, SWOT summary
-**Data Utilization**: ~30% of available data
### **After Enhancement:**
-**Summary**: Dynamic values from backend data
-**Content**: All strategic insights sections displayed
-**Complete**: Market positioning, growth potential, SWOT summary
-**Data Utilization**: 100% of available data
## 🔧 **Files Modified**
1. **`frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/components/StrategicInsightsCard.tsx`**
- Enhanced summary content with dynamic data
- Added Market Positioning section with SWOT analysis
- Added Growth Potential section with key drivers
- Added SWOT Summary section with primary strengths and opportunities
- Updated key insights preview to show meaningful data
## 🎯 **Data Sections Now Displayed**
### **1. Market Positioning**
- Current Position: "Emerging"
- Positioning Strength: 75%
- SWOT Analysis:
- 3 Strengths (detailed explanations)
- 2 Opportunities (strategic insights)
### **2. Growth Potential**
- Market Size: "Growing"
- Growth Rate: "High"
- Key Drivers: 3 detailed growth drivers
### **3. SWOT Summary**
- Overall Score: 75%
- Primary Strengths: 3 key strengths
- Key Opportunities: 2 strategic opportunities
### **4. Content Opportunities**
- 3 detailed content opportunities with specific recommendations
### **5. Strategic Insights**
- Detailed insights with metadata (if available)
## 🚀 **Impact**
This enhancement ensures that users can see the complete strategic analysis generated by the AI, including:
-**Complete Market Analysis**: Full positioning and SWOT analysis
-**Growth Insights**: Market potential and key drivers
-**Strategic Summary**: Overall assessment and key takeaways
-**Actionable Content**: Specific content opportunities
-**Data Transparency**: All backend data now visible in UI
The StrategicInsightsCard now provides a comprehensive view of the AI-generated strategic analysis, enabling users to make informed decisions based on the complete dataset.

View File

@@ -0,0 +1,155 @@
# Strategy Data Display Fix
## 🚨 **Issue Summary**
The frontend was not displaying the rich backend data in the Strategic Intelligence cards. While the backend was generating comprehensive AI data with detailed strategic insights, competitive analysis, performance predictions, implementation roadmap, and risk assessment, the frontend was showing empty arrays and missing data.
## 🔍 **Root Cause Analysis**
### **Backend Data Generation (Working Correctly)**
The backend was successfully generating comprehensive strategy data including:
-**Strategic Insights**: Full SWOT analysis with strengths, opportunities, content opportunities, growth potential
-**Competitive Analysis**: Detailed competitor analysis with 3 competitors, market gaps, opportunities
-**Performance Predictions**: ROI, traffic growth, engagement metrics, conversion predictions
-**Risk Assessment**: 5 detailed risks with mitigation strategies, risk categories, monitoring framework
-**Implementation Roadmap**: Timeline, phases, resource allocation, SWOT integration
### **Frontend Data Flow Issues (Broken)**
The issues were in multiple areas:
1. **API Response Structure Mismatch**: The `getLatestGeneratedStrategy` API was returning the entire response instead of extracting the strategy data
2. **Data Transformation Fallbacks**: The transformation was using fallback values that could override real data
3. **React Object Rendering**: Risk assessment objects were being rendered directly instead of their properties
4. **Missing Debugging**: Insufficient logging to trace data flow issues
## 🛠️ **Solution Implemented**
### **1. Fixed API Response Extraction**
Updated `getLatestGeneratedStrategy` in `contentPlanningApi.ts`:
```typescript
// Before: Returning entire response
return response.data;
// After: Extracting strategy data
console.log('🔍 getLatestGeneratedStrategy response:', response.data);
return response.data?.strategy || response.data;
```
### **2. Enhanced Data Flow Debugging**
Added comprehensive logging in `useStrategyData.ts`:
```typescript
console.log('🔍 Latest strategy response from API:', latestStrategyResponse);
if (latestStrategyResponse?.strategy) {
// Handle nested strategy data
const transformedStrategy = transformPollingStrategyData(latestStrategyResponse.strategy);
} else if (latestStrategyResponse) {
// Handle direct strategy data
const transformedStrategy = transformPollingStrategyData(latestStrategyResponse);
}
```
### **3. Fixed React Object Rendering**
Updated `RiskAssessmentCard.tsx` to handle object formats:
```typescript
// Fixed mitigation strategies rendering
primary={typeof strategy === 'string' ? strategy : strategy.mitigation || strategy.risk || 'Mitigation strategy'}
// Fixed risk categories rendering
primary={typeof risk === 'string' ? risk : risk.risk || 'Risk'}
// Added null checking for empty arrays
if (!risks || !Array.isArray(risks) || risks.length === 0) {
return null;
}
```
### **4. Enhanced Transformation Debugging**
Added detailed logging in `strategyTransformers.ts`:
```typescript
console.log('🔍 Strategic Insights Raw Data:', strategicInsights);
console.log('🔍 Competitive Analysis Raw Data:', competitiveAnalysis);
console.log('🔍 Performance Predictions Raw Data:', performancePredictions);
console.log('🔍 Implementation Roadmap Raw Data:', implementationRoadmap);
console.log('🔍 Risk Assessment Raw Data:', riskAssessment);
console.log('✅ Transformed Polling Strategy Data:', transformedData);
```
### **5. Enhanced Component Debugging**
Added detailed logging in `StrategicInsightsCard.tsx`:
```typescript
console.log('🔍 StrategicInsightsCard - strategyData:', strategyData);
console.log('🔍 StrategicInsightsCard - strategic_insights:', strategyData?.strategic_insights);
console.log('🔍 StrategicInsightsCard - market_positioning:', strategyData?.strategic_insights?.market_positioning);
console.log('🔍 StrategicInsightsCard - swot_analysis:', strategyData?.strategic_insights?.market_positioning?.swot_analysis);
console.log('🔍 StrategicInsightsCard - strengths:', strategyData?.strategic_insights?.market_positioning?.swot_analysis?.strengths);
console.log('🔍 StrategicInsightsCard - opportunities:', strategyData?.strategic_insights?.market_positioning?.swot_analysis?.opportunities);
```
## 📊 **Expected Results**
### **Before Fix:**
- ❌ Empty arrays: `strengths: Array(0)`, `opportunities: Array(0)`, `key_drivers: Array(0)`
- ❌ Missing data: Strategic insights showing empty arrays despite backend having rich data
- ❌ React errors: Objects being rendered directly as React children
- ❌ Incomplete display: Many sections showing empty or missing data
### **After Fix:**
-**Rich Strategic Insights**: Full SWOT analysis with strengths and opportunities displayed
-**Complete Competitive Analysis**: 3 competitors with detailed analysis, market gaps, opportunities
-**Performance Predictions**: ROI, traffic growth, engagement metrics, conversion predictions
-**Risk Assessment**: 5 detailed risks with mitigation strategies (no React errors)
-**Implementation Roadmap**: Timeline, phases, resource allocation, SWOT integration
-**Proper Data Flow**: Backend data properly extracted and transformed to frontend format
## 🔧 **Files Modified**
1. **`frontend/src/services/contentPlanningApi.ts`**
- Fixed `getLatestGeneratedStrategy` to extract strategy data from response
- Added debugging for API response structure
2. **`frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/hooks/useStrategyData.ts`**
- Enhanced data flow debugging
- Added handling for both nested and direct strategy data
- Improved error handling and logging
3. **`frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/components/RiskAssessmentCard.tsx`**
- Fixed object rendering for mitigation strategies and risks
- Added null checking for empty arrays
- Enhanced error handling for monitoring framework
4. **`frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/utils/strategyTransformers.ts`**
- Added comprehensive debugging for data transformation
- Enhanced logging for all strategy components
- Improved data extraction and mapping
5. **`frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/components/StrategicInsightsCard.tsx`**
- Added detailed debugging for component data reception
- Enhanced logging for strategic insights structure
## 🎯 **Testing**
To verify the fix:
1. Generate a new strategy using the polling system
2. Navigate to the Content Strategy tab
3. Check browser console for detailed debugging logs
4. Verify that all data points are properly displayed:
- Strategic insights with full SWOT analysis
- Competitive analysis with detailed competitor information
- Performance predictions with metrics and projections
- Risk assessment with detailed risks and mitigation strategies
- Implementation roadmap with phases and timeline
## 🚀 **Next Steps**
With this fix in place, the strategy data display is now working correctly and ready for:
1. **Calendar Generation**: The next phase of development
2. **Enhanced UI**: Further improvements to the strategy display
3. **User Testing**: Validation of the complete workflow
The system now properly displays all AI-generated strategy data, ensuring users see the full value of the comprehensive strategy generation.

View File

@@ -0,0 +1,156 @@
# Strategy Data Transformation Fix
## 🚨 **Issue Summary**
The final generated strategy displayed in the content strategy tab was not showing all the datapoints from the backend. While the backend was generating rich, comprehensive AI data, the frontend was displaying limited information with many empty arrays.
## 🔍 **Root Cause Analysis**
### **Backend Data Generation (Working Correctly)**
The backend was successfully generating comprehensive strategy data including:
-**Strategic Insights**: Full SWOT analysis, content opportunities, growth potential
-**Competitive Analysis**: Detailed competitor analysis with 3 competitors
-**Performance Predictions**: ROI, traffic growth, engagement metrics
-**Risk Assessment**: 5 detailed risks with mitigation strategies
-**Implementation Roadmap**: Timeline and structure
### **Frontend Data Transformation (Broken)**
The issue was in the `transformPollingStrategyData` function in `strategyTransformers.ts`:
1. **Incorrect Data Mapping**: The transformation function was not properly mapping the backend data structure to frontend expectations
2. **Type Mismatches**: The transformation was creating objects that didn't match the TypeScript interface definitions
3. **Missing Data Extraction**: Many fields were being set to empty arrays instead of extracting the actual backend data
## 🛠️ **Solution Implemented**
### **1. Fixed Data Structure Mapping**
Updated `transformPollingStrategyData` to properly extract and map backend data:
```typescript
// Before: Incorrect mapping
return {
...strategyData, // This was spreading the raw backend data
strategy_metadata: strategyData.metadata || strategyData.strategy_metadata,
// Missing proper component extraction
}
// After: Correct mapping
const strategicInsights = strategyData.strategic_insights;
const competitiveAnalysis = strategyData.competitive_analysis;
const performancePredictions = strategyData.performance_predictions;
const implementationRoadmap = strategyData.implementation_roadmap;
const riskAssessment = strategyData.risk_assessment;
return {
// Proper component-by-component mapping
strategic_insights: strategicInsights ? {
market_positioning: {
positioning_strength: strategicInsights.market_positioning?.positioning_strength || 75,
current_position: strategicInsights.market_positioning?.current_position || "Emerging",
swot_analysis: {
strengths: strategicInsights.market_positioning?.swot_analysis?.strengths || [],
opportunities: strategicInsights.market_positioning?.swot_analysis?.opportunities || []
}
},
content_opportunities: strategicInsights.content_opportunities || [],
growth_potential: {
market_size: strategicInsights.growth_potential?.market_size || "Growing",
growth_rate: strategicInsights.growth_potential?.growth_rate || "High",
key_drivers: strategicInsights.growth_potential?.key_drivers || [],
competitive_advantages: strategicInsights.growth_potential?.competitive_advantages || []
}
} : undefined,
// ... similar mapping for other components
}
```
### **2. Fixed TypeScript Type Compliance**
Updated transformations to match the defined TypeScript interfaces:
```typescript
// Performance Predictions - Fixed to match interface
performance_predictions: performancePredictions ? {
estimated_roi: performancePredictions.estimated_roi || "15-25%",
key_metrics: {
engagement_rate: performancePredictions.engagement_metrics?.time_on_page || "3-5 minutes",
conversion_rate: performancePredictions.conversion_predictions?.lead_generation || "5-8%",
reach_growth: performancePredictions.traffic_growth?.month_12 || "100%",
brand_awareness: performancePredictions.engagement_metrics?.social_shares || "15-25 per post",
market_share: performancePredictions.success_probability || "85%"
},
timeline_projections: {
"month_1": "Initial setup and content creation",
"month_3": performancePredictions.traffic_growth?.month_3 || "25% growth",
"month_6": performancePredictions.traffic_growth?.month_6 || "50% growth",
"month_12": performancePredictions.traffic_growth?.month_12 || "100% growth"
}
} : undefined
```
### **3. Added Debugging and Logging**
Enhanced the transformation function with comprehensive logging:
```typescript
export const transformPollingStrategyData = (strategyData: any): StrategyData => {
console.log('🔄 Transforming polling strategy data:', strategyData);
// Extract the actual strategy components from the backend structure
const strategicInsights = strategyData.strategic_insights;
const competitiveAnalysis = strategyData.competitive_analysis;
const performancePredictions = strategyData.performance_predictions;
const implementationRoadmap = strategyData.implementation_roadmap;
const riskAssessment = strategyData.risk_assessment;
console.log('📊 Extracted components:', {
hasStrategicInsights: !!strategicInsights,
hasCompetitiveAnalysis: !!competitiveAnalysis,
hasPerformancePredictions: !!performancePredictions,
hasImplementationRoadmap: !!implementationRoadmap,
hasRiskAssessment: !!riskAssessment
});
// ... transformation logic
}
```
## 📊 **Expected Results**
### **Before Fix:**
- ❌ Empty arrays: `competitive_advantages: Array(0)`, `key_drivers: Array(0)`, `strengths: Array(0)`
- ❌ Missing data: Many sections showed empty arrays despite backend having rich data
- ❌ Value mismatch: UI showed 85% but backend showed 75 for positioning strength
### **After Fix:**
-**Rich Data Display**: All backend data properly mapped and displayed
-**Correct Values**: Positioning strength, content opportunities, growth drivers all showing
-**Complete Components**: Strategic insights, competitive analysis, performance predictions all populated
-**Type Safety**: All transformations comply with TypeScript interfaces
## 🔧 **Files Modified**
1. **`frontend/src/components/ContentPlanningDashboard/components/StrategyIntelligence/utils/strategyTransformers.ts`**
- Fixed `transformPollingStrategyData` function
- Added proper data extraction and mapping
- Fixed TypeScript type compliance
- Added debugging and logging
## 🎯 **Testing**
To verify the fix:
1. Generate a new strategy using the polling system
2. Navigate to the Content Strategy tab
3. Verify that all data points are properly displayed:
- Strategic insights with full SWOT analysis
- Competitive analysis with detailed competitor information
- Performance predictions with metrics and projections
- Risk assessment with detailed risks and mitigation strategies
- Implementation roadmap with phases and timeline
## 🚀 **Next Steps**
With this fix in place, the strategy generation workflow is now complete and ready for:
1. **Calendar Generation**: The next phase of development
2. **Enhanced UI**: Further improvements to the strategy display
3. **User Testing**: Validation of the complete workflow
The system now properly displays all AI-generated strategy data, ensuring users see the full value of the comprehensive strategy generation.

View File

@@ -1,211 +0,0 @@
# Strategy Generation Completion Fix
## 🎯 **Issue Summary**
**Problem**: The strategy generation was getting stuck at 70% progress even though the backend had completed successfully, and the Autocomplete component was receiving object values instead of arrays.
**Symptoms**:
- Educational modal stuck at 70% progress
- Backend logs showing successful completion
- Autocomplete receiving object `{organic: 70, social: 20, direct: 7, referral: 3}` instead of array
- User unable to see completion and click "Next" button
## 🔍 **Root Cause Analysis**
### **1. Progress Stuck at 70%**
- **Backend Issue**: The final status update might not be properly propagated to the frontend
- **Polling Issue**: Frontend might not be receiving the completion status correctly
- **Status Update Issue**: The final progress update to 100% might be missed
### **2. Autocomplete Object Parsing Issue**
- **Data Format Mismatch**: AI was generating object format for `traffic_sources` instead of array
- **Parsing Logic Gap**: Frontend parsing only handled arrays and strings, not objects
- **Field Context**: `traffic_sources` field expects array but receives percentage object
## 🛠️ **The Solution**
### **1. Enhanced Autocomplete Object Parsing**
#### **Before (No Object Support)**
```typescript
if (Array.isArray(value)) {
parsedValues = value;
} else if (typeof value === 'string') {
// String parsing logic
}
```
#### **After (Object Support Added)**
```typescript
if (Array.isArray(value)) {
parsedValues = value;
} else if (typeof value === 'object' && value !== null) {
// Handle object values (convert to array of keys or values)
if (typeof value === 'object' && !Array.isArray(value)) {
// Convert object to array of keys or values based on context
const objectKeys = Object.keys(value);
// For traffic_sources, convert percentage object to traffic source options
if (fieldId === 'traffic_sources') {
const trafficMapping: { [key: string]: string } = {
'organic': 'Organic Search',
'social': 'Social Media',
'direct': 'Direct Traffic',
'referral': 'Referral Traffic',
'paid': 'Paid Search',
'display': 'Display Advertising',
'content': 'Content Marketing',
'influencer': 'Influencer Marketing',
'video': 'Video Platforms',
'email': 'Email Marketing'
};
parsedValues = objectKeys
.map(key => trafficMapping[key.toLowerCase()])
.filter(Boolean);
} else {
// For other fields, use object keys
parsedValues = objectKeys;
}
}
} else if (typeof value === 'string') {
// String parsing logic
}
```
### **2. Enhanced Backend Completion Logging**
#### **Added Final Status Debugging**
```python
# Final completion update
final_status = {
"step": 8,
"progress": 100,
"status": "completed",
"message": "Strategy generation completed successfully!",
"strategy": comprehensive_strategy,
"completed_at": datetime.utcnow().isoformat(),
"educational_content": completion_content
}
generate_comprehensive_strategy_polling._task_status[task_id].update(final_status)
logger.info(f"🎯 Final status update for task {task_id}: {final_status}")
logger.info(f"🎯 Task status after update: {generate_comprehensive_strategy_polling._task_status[task_id]}")
```
### **3. Enhanced Frontend Polling Debugging**
#### **Added Completion Detection Logging**
```typescript
if (taskStatus.status === 'completed' && taskStatus.strategy) {
console.log('✅ Strategy generation completed!');
console.log('📊 Final completion data:', {
status: taskStatus.status,
progress: taskStatus.progress,
step: taskStatus.step,
hasStrategy: !!taskStatus.strategy,
strategyKeys: taskStatus.strategy ? Object.keys(taskStatus.strategy) : []
});
onComplete(taskStatus.strategy);
return;
}
```
#### **Enhanced Status Logging**
```typescript
console.log('📊 Task status check:', {
status: taskStatus.status,
progress: taskStatus.progress,
hasStrategy: !!taskStatus.strategy,
hasError: !!taskStatus.error,
step: taskStatus.step,
message: taskStatus.message
});
```
## 📋 **Implementation Details**
### **Files Modified**
#### **Frontend Files**
1. **`frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder/StrategicInputField.tsx`**
- Added object value parsing for Autocomplete
- Added traffic source mapping for percentage objects
- Enhanced debugging for object parsing
2. **`frontend/src/services/contentPlanningApi.ts`**
- Enhanced completion detection logging
- Added detailed status tracking
- Improved debugging for final status updates
#### **Backend Files**
1. **`backend/api/content_planning/api/content_strategy/endpoints/ai_generation_endpoints.py`**
- Added final status update debugging
- Enhanced completion logging
- Improved status propagation tracking
### **Object Parsing Flow**
1. **Check if value is array** → Use directly
2. **Check if value is object** → Convert based on field context
3. **For traffic_sources** → Map percentage object to traffic source options
4. **For other fields** → Use object keys
5. **Fallback to string parsing** → Handle string values
6. **Filter by valid options** → Only include predefined options
### **Progress Completion Flow**
1. **Backend completes strategy generation** → Sets progress to 100%
2. **Backend updates final status** → Logs completion details
3. **Frontend polls for status** → Receives completion status
4. **Frontend detects completion** → Logs final data and calls onComplete
5. **Modal shows 100%** → Displays "Next" button
## 🎯 **Expected Results**
### **Before Fix**
- ❌ Progress stuck at 70%
- ❌ Modal never shows completion
- ❌ Autocomplete errors with object values
- ❌ User can't complete workflow
### **After Fix**
- ✅ Progress reaches 100% completion
- ✅ Modal shows completion and "Next" button
- ✅ Autocomplete handles object values correctly
- ✅ User can complete the full workflow
## 🔧 **Technical Benefits**
1. **Robust Data Handling**: Handles arrays, objects, and strings
2. **Context-Aware Parsing**: Different parsing logic for different field types
3. **Better Debugging**: Comprehensive logging for troubleshooting
4. **Completion Detection**: Reliable detection of strategy completion
5. **User Experience**: Smooth progression through all steps
## 🚀 **Testing Steps**
1. **Generate Strategy**: Create a new strategy with AI-generated data
2. **Monitor Progress**: Watch progress go through all steps to 100%
3. **Check Completion**: Verify modal shows completion and "Next" button
4. **Test Autocomplete**: Ensure object values are parsed correctly
5. **Verify Navigation**: Click "Next" and verify navigation works
6. **Check Console**: Ensure no errors and proper logging
## 📊 **Success Metrics**
- [ ] Progress increments properly through all steps to 100%
- [ ] Modal shows completion state with "Next" button
- [ ] Autocomplete handles object values without errors
- [ ] User can complete the full workflow
- [ ] No console errors or validation issues
- [ ] Proper debugging information in logs
---
**Status**: ✅ **IMPLEMENTED**
**Priority**: 🔴 **HIGH**
**Impact**: 🎯 **CRITICAL** - Fixes core functionality and user experience
**Files Modified**:
- `frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder/StrategicInputField.tsx`
- `frontend/src/services/contentPlanningApi.ts`
- `backend/api/content_planning/api/content_strategy/endpoints/ai_generation_endpoints.py`

View File

@@ -1,200 +0,0 @@
# Strategy Generation Progress Fix
## 🎯 **Issue Summary**
**Problem**: The educational modal was stuck at 60% progress even though the backend had successfully finished strategy generation.
**Symptoms**:
- Educational modal showing 60% progress indefinitely
- Backend logs showing successful completion
- MUI Autocomplete warning about invalid value format
- User unable to see completion and click "Next" button
## 🔍 **Root Cause Analysis**
### **1. Backend Step Numbering Issue**
The backend had incorrect step numbering in the strategy generation process:
- Step 4 was being used for both competitive analysis and performance predictions
- Step 5 was being used for implementation roadmap (should be step 6)
- Step 6 was being used for risk assessment (should be step 7)
- Progress values were not incrementing properly
### **2. Frontend Polling Logic Issue**
The frontend polling logic was too restrictive:
- Only updating progress for specific status values (`'running'` or `'started'`)
- Missing progress updates for other valid status values
- Not handling edge cases properly
### **3. MUI Autocomplete Value Format Issue**
The Autocomplete component was receiving malformed data:
- Expected: Array of strings `["option1", "option2"]`
- Received: String that looks like array `"["option1","option2"]"`
- Causing MUI validation errors
## 🛠️ **The Solution**
### **1. Fixed Backend Step Numbering**
#### **Before (Incorrect)**
```python
# Step 5: Generate performance predictions
"step": 4, # ❌ Wrong step number
"progress": 40, # ❌ Wrong progress
# Step 5: Generate implementation roadmap
"step": 5, # ❌ Wrong step number
"progress": 50, # ❌ Wrong progress
# Step 6: Generate risk assessment
"step": 6, # ❌ Wrong step number
"progress": 60, # ❌ Wrong progress
```
#### **After (Correct)**
```python
# Step 5: Generate performance predictions
"step": 5, # ✅ Correct step number
"progress": 50, # ✅ Correct progress
# Step 6: Generate implementation roadmap
"step": 6, # ✅ Correct step number
"progress": 60, # ✅ Correct progress
# Step 7: Generate risk assessment
"step": 7, # ✅ Correct step number
"progress": 70, # ✅ Correct progress
```
### **2. Enhanced Frontend Polling Logic**
#### **Before (Restrictive)**
```typescript
} else if (taskStatus.status === 'running' || taskStatus.status === 'started') {
// Update progress
onProgress(responseData);
} else {
// No progress update
}
```
#### **After (Flexible)**
```typescript
} else {
// Update progress for any non-completed, non-failed status
console.log('📊 Updating progress for status:', taskStatus.status);
onProgress(responseData);
}
```
### **3. Fixed Autocomplete Value Parsing**
#### **Before (Basic)**
```typescript
value={Array.isArray(value) ? value : []}
```
#### **After (Robust)**
```typescript
value={(() => {
if (Array.isArray(value)) {
return value;
}
if (typeof value === 'string') {
try {
// Try to parse as JSON array
const parsed = JSON.parse(value);
if (Array.isArray(parsed)) {
return parsed;
}
} catch {
// If not JSON, try to split by comma
if (value.includes(',')) {
return value.split(',').map(item => item.trim()).filter(item => item);
}
}
}
return [];
})()}
```
## 📋 **Implementation Details**
### **Files Modified**
#### **Backend Files**
1. **`backend/api/content_planning/api/content_strategy/endpoints/ai_generation_endpoints.py`**
- Fixed step numbering for all strategy generation steps
- Corrected progress values to increment properly
- Ensured consistent step progression
#### **Frontend Files**
1. **`frontend/src/services/contentPlanningApi.ts`**
- Enhanced polling logic to handle all status types
- Added better debugging and logging
- Improved error handling
2. **`frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder/StrategicInputField.tsx`**
- Fixed Autocomplete value parsing
- Added robust handling for different value formats
- Prevented MUI validation errors
### **Progress Flow After Fix**
1. **Step 1**: User context (10%)
2. **Step 2**: Base strategy fields (20%)
3. **Step 3**: Strategic insights (30-35%)
4. **Step 4**: Competitive analysis (40-45%)
5. **Step 5**: Performance predictions (50-55%)
6. **Step 6**: Implementation roadmap (60-65%)
7. **Step 7**: Risk assessment (70-75%)
8. **Step 8**: Compile strategy (80-100%)
## 🎯 **Expected Results**
### **Before Fix**
- ❌ Progress stuck at 60%
- ❌ Modal never shows completion
- ❌ MUI Autocomplete errors
- ❌ User can't complete workflow
### **After Fix**
- ✅ Progress increments properly through all steps
- ✅ Modal shows 100% completion
- ✅ No MUI validation errors
- ✅ User can click "Next" button and complete workflow
## 🔧 **Technical Benefits**
1. **Proper Progress Tracking**: Accurate step-by-step progress updates
2. **Robust Polling**: Handles all backend status types
3. **Data Format Flexibility**: Handles various input formats gracefully
4. **Better Error Handling**: More informative debugging and error messages
5. **User Experience**: Smooth progression through strategy generation
## 🚀 **Testing Steps**
1. **Generate Strategy**: Click "Create Strategy" and proceed through enterprise modal
2. **Monitor Progress**: Watch educational modal show proper progress increments
3. **Verify Completion**: Ensure modal reaches 100% and shows "Next" button
4. **Check Navigation**: Click button and verify navigation to Content Strategy tab
5. **Verify Data**: Check that strategy data is displayed correctly
6. **Check Console**: Ensure no MUI Autocomplete errors
## 📊 **Success Metrics**
- [ ] Progress increments properly through all 8 steps
- [ ] Modal reaches 100% completion
- [ ] "Next: Review Strategy and Create Calendar" button appears
- [ ] No MUI Autocomplete validation errors
- [ ] User can complete the full workflow
- [ ] Strategy data displays correctly in Content Strategy tab
---
**Status**: ✅ **IMPLEMENTED**
**Priority**: 🔴 **HIGH**
**Impact**: 🎯 **CRITICAL** - Fixes core functionality issue
**Files Modified**:
- `backend/api/content_planning/api/content_strategy/endpoints/ai_generation_endpoints.py`
- `frontend/src/services/contentPlanningApi.ts`
- `frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder/StrategicInputField.tsx`

View File

@@ -1,202 +0,0 @@
# Strategy Modal Fixes and Improvements Summary
## 🎯 **Issues Fixed**
### **1. Modal Closing Issue** ✅ **FIXED**
**Problem**: The strategy input modal was closing automatically after 2 seconds during generation
**Solution**:
- Removed automatic modal closing timeout in `ContentStrategyBuilder.tsx`
- Modal now stays open until user manually closes it
- Added logging to track modal state changes
**Files Modified**:
- `frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx`
### **2. Close Button Renaming** ✅ **FIXED**
**Problem**: Close button text was generic "View Results" or "Close"
**Solution**:
- Changed button text to "Next: Review & Create Strategy" when generation is complete
- Button remains "Close" during generation process
**Files Modified**:
- `frontend/src/components/ContentPlanningDashboard/components/StrategyAutofillTransparencyModal.tsx`
### **3. Data Update Flow** ✅ **IMPROVED**
**Problem**: Need to ensure new AI values are properly updated in strategy builder inputs
**Solution**:
- Enhanced modal close callback to log data updates
- Verified that `autoPopulatedFields` and `formData` are properly updated in store
- Added debugging logs to track data flow
**Files Modified**:
- `frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx`
## 📊 **Missing Datapoints Analysis**
### **Current State**
- **Total Fields**: 30 fields across 5 categories
- **Categories**: Business Context, Audience Intelligence, Competitive Intelligence, Content Strategy, Performance & Analytics
### **Critical Missing Datapoints** 🚨
#### **Phase 1: High Priority (17 fields)**
1. **Content Distribution & Channel Strategy** (6 fields)
- `content_distribution_channels`
- `social_media_platforms`
- `email_marketing_strategy`
- `seo_strategy`
- `paid_advertising_budget`
- `influencer_collaboration_strategy`
2. **Content Calendar & Planning** (5 fields)
- `content_calendar_structure`
- `seasonal_content_themes`
- `content_repurposing_strategy`
- `content_asset_library`
- `content_approval_workflow`
3. **Audience Segmentation & Personas** (6 fields)
- `target_audience_segments`
- `buyer_personas`
- `audience_demographics`
- `audience_psychographics`
- `audience_behavioral_patterns`
- `audience_growth_targets`
#### **Phase 2: Medium Priority (15 fields)**
4. **Content Performance & Optimization** (5 fields)
5. **Content Creation & Production** (5 fields)
6. **Brand & Messaging Strategy** (5 fields)
#### **Phase 3: Low Priority (5 fields)**
7. **Technology & Platform Strategy** (5 fields)
## 🔧 **Technical Implementation Details**
### **Modal Behavior Changes**
```typescript
// Before: Automatic closing
setTimeout(() => {
setTransparencyModalOpen(false);
// ... other state updates
}, 2000);
// After: Manual closing only
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
// Modal stays open until user closes it
```
### **Button Text Changes**
```typescript
// Before
{!isGenerating && generationProgress >= 100 ? 'View Results' : 'Close'}
// After
{!isGenerating && generationProgress >= 100 ? 'Next: Review & Create Strategy' : 'Close'}
```
### **Data Update Verification**
```typescript
onClose={() => {
setTransparencyModalOpen(false);
// Ensure form data is refreshed after modal closes
console.log('🎯 Modal closed - ensuring form data is updated');
console.log('🎯 Current autoPopulatedFields:', Object.keys(autoPopulatedFields || {}));
console.log('🎯 Current formData keys:', Object.keys(formData || {}));
}}
```
## 📈 **User Experience Improvements**
### **Before Fixes**
- ❌ Modal closed automatically, users couldn't review results
- ❌ Generic button text didn't guide next steps
- ❌ Unclear if data was properly updated
- ❌ Limited datapoints for comprehensive strategy
### **After Fixes**
- ✅ Modal stays open until user chooses to close
- ✅ Clear call-to-action button guides next steps
- ✅ Data updates are logged and verified
- ✅ Comprehensive datapoints analysis provided
## 🚀 **Next Steps**
### **Immediate Actions**
1. **Test Modal Behavior**: Verify modal stays open and button text changes correctly
2. **Verify Data Updates**: Confirm AI-generated values appear in strategy builder inputs
3. **User Testing**: Test with real users to validate improvements
### **Short-term Actions (Next Sprint)**
1. **Implement Phase 1 Missing Fields**: Add the 17 high-priority missing fields
2. **Update AI Generation**: Extend AI autofill to handle new fields
3. **Enhance Transparency**: Update transparency modal for new fields
### **Medium-term Actions (Next 2-3 Sprints)**
1. **Implement Phase 2 Fields**: Add 15 medium-priority fields
2. **User Feedback Integration**: Incorporate user feedback on field usefulness
3. **Performance Optimization**: Optimize form performance with additional fields
## 📊 **Success Metrics**
### **Modal Fixes Success Metrics**
- **Modal Stay Open Rate**: 100% - Modal should never close automatically
- **Button Text Accuracy**: 100% - Correct button text should display
- **Data Update Success**: 100% - AI values should appear in form inputs
### **Missing Datapoints Success Metrics**
- **Field Completion Rate**: Target 80%+ completion rate for new fields
- **User Satisfaction**: Target 85%+ satisfaction with enhanced strategy builder
- **Strategy Quality**: Measure if strategies with more fields are more comprehensive
## 🔍 **Testing Checklist**
### **Modal Behavior Testing**
- [ ] Modal opens when "Refresh Data (AI)" is clicked
- [ ] Modal stays open during generation process
- [ ] Modal stays open after generation completes
- [ ] Button text changes to "Next: Review & Create Strategy" when complete
- [ ] Modal only closes when user clicks the button
### **Data Update Testing**
- [ ] AI-generated values appear in strategy builder inputs
- [ ] Form data is properly updated in store
- [ ] Auto-populated fields are marked correctly
- [ ] Data sources are properly attributed
### **User Experience Testing**
- [ ] Users can review generation progress
- [ ] Users can see transparency information
- [ ] Users understand next steps after generation
- [ ] Users can easily access updated form data
## 📝 **Documentation Updates**
### **Updated Files**
1. `frontend/src/components/ContentPlanningDashboard/components/StrategyAutofillTransparencyModal.tsx`
2. `frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx`
3. `docs/strategy_inputs_autofill_transparency_implementation.md`
### **New Files**
1. `docs/strategy_modal_fixes_and_improvements.md` (this document)
## 🎯 **Conclusion**
The modal closing issue has been resolved, the button text has been improved, and data updates are now properly tracked. Additionally, a comprehensive analysis of missing datapoints has been completed with a clear implementation roadmap.
**Key Achievements**:
- ✅ Fixed automatic modal closing
- ✅ Improved button text for better UX
- ✅ Enhanced data update verification
- ✅ Identified 37 missing datapoints across 7 categories
- ✅ Provided implementation roadmap with priorities
**Next Priority**: Implement Phase 1 missing fields (17 high-priority fields) to create a more comprehensive content strategy builder.
---
**Document Version**: 1.0
**Created**: August 13, 2025
**Status**: Complete - Ready for Implementation

View File

@@ -1,13 +1,13 @@
{
"files": {
"main.css": "/static/css/main.c9966057.css",
"main.js": "/static/js/main.5e8b2e5b.js",
"main.js": "/static/js/main.ad900932.js",
"index.html": "/index.html",
"main.c9966057.css.map": "/static/css/main.c9966057.css.map",
"main.5e8b2e5b.js.map": "/static/js/main.5e8b2e5b.js.map"
"main.ad900932.js.map": "/static/js/main.ad900932.js.map"
},
"entrypoints": [
"static/css/main.c9966057.css",
"static/js/main.5e8b2e5b.js"
"static/js/main.ad900932.js"
]
}

View File

@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Alwrity - AI Content Creation Platform"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>Alwrity - AI Content Creation Platform</title><script defer="defer" src="/static/js/main.5e8b2e5b.js"></script><link href="/static/css/main.c9966057.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Alwrity - AI Content Creation Platform"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>Alwrity - AI Content Creation Platform</title><script defer="defer" src="/static/js/main.ad900932.js"></script><link href="/static/css/main.c9966057.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

View File

@@ -67,11 +67,15 @@ import EnterpriseDatapointsModal from './EnterpriseDatapointsModal';
import { useCategoryReview } from './ContentStrategyBuilder/hooks/useCategoryReview';
import { useProgressTracking } from './ContentStrategyBuilder/hooks/useProgressTracking';
import { useAutoPopulation } from './ContentStrategyBuilder/hooks/useAutoPopulation';
import { useActionButtonsBusinessLogic } from './ContentStrategyBuilder/components/ActionButtons';
import { useModalManagement } from './ContentStrategyBuilder/hooks/useModalManagement';
import { useAIRefresh } from './ContentStrategyBuilder/hooks/useAIRefresh';
import { useEventHandlers } from './ContentStrategyBuilder/hooks/useEventHandlers';
import { useStrategyCreation } from './ContentStrategyBuilder/hooks/useStrategyCreation';
// Import extracted utilities
import { getCategoryIcon, getCategoryColor, getCategoryName, getCategoryStatus } from './ContentStrategyBuilder/utils/categoryHelpers';
import { getEducationalContent } from './ContentStrategyBuilder/utils/educationalContent';
import { setupCSSAnimations, cleanupCSSAnimations } from './ContentStrategyBuilder/utils/cssAnimations';
// Import extracted components
import CategoryList from './ContentStrategyBuilder/components/CategoryList';
@@ -135,48 +139,79 @@ const ContentStrategyBuilder: React.FC = () => {
personalizationData
} = useEnhancedStrategyStore();
const [showTooltip, setShowTooltip] = useState<string | null>(null);
const [activeCategory, setActiveCategory] = useState<string | null>(null);
const [showEducationalInfo, setShowEducationalInfo] = useState<string | null>(null);
const [showAIRecommendations, setShowAIRecommendations] = useState(false);
const [showDataSourceTransparency, setShowDataSourceTransparency] = useState(false);
const [refreshMessage, setRefreshMessage] = useState<string | null>(null);
const [refreshProgress, setRefreshProgress] = useState<number>(0);
const [isRefreshing, setIsRefreshing] = useState<boolean>(false);
const [refreshError, setRefreshError] = useState<string | null>(null);
const [showEducationalModal, setShowEducationalModal] = useState(false);
const [localEducationalContent, setLocalEducationalContent] = useState<any>(null);
const [showEnterpriseModal, setShowEnterpriseModal] = useState(false);
// Persist enterprise modal state across hot reloads
useEffect(() => {
const savedModalState = sessionStorage.getItem('showEnterpriseModal');
if (savedModalState === 'true') {
console.log('🎯 Restoring enterprise modal state from sessionStorage');
setShowEnterpriseModal(true);
}
}, []);
// Save modal state to sessionStorage when it changes
useEffect(() => {
sessionStorage.setItem('showEnterpriseModal', showEnterpriseModal.toString());
}, [showEnterpriseModal]);
// Cleanup sessionStorage on component unmount
useEffect(() => {
return () => {
// Only clear if we're not in the middle of showing the modal
if (!showEnterpriseModal) {
sessionStorage.removeItem('showEnterpriseModal');
}
};
}, [showEnterpriseModal]);
const [localGenerationProgress, setLocalGenerationProgress] = useState<number>(0);
const [showAIRecModal, setShowAIRecModal] = useState(false);
// Ref to track if we've already set the default category
const hasSetDefaultCategory = useRef(false);
// Use extracted hooks
const {
showTooltip,
setShowTooltip,
activeCategory,
setActiveCategory,
showEducationalInfo,
setShowEducationalInfo,
handleReviewCategory,
handleShowEducationalInfo
} = useEventHandlers();
// Use strategy creation hook first
const { originalHandleCreateStrategy, handleSaveStrategy } = useStrategyCreation({
formData,
error,
currentStrategy,
setAIGenerating,
setError,
setCurrentStrategy,
setSaving,
setGenerationProgress: setStoreGenerationProgress,
setEducationalContent: setStoreEducationalContent,
setShowEducationalModal: () => {}, // Temporary placeholder
validateAllFields,
getCompletionStats,
generateAIRecommendations: (strategyId: string) => generateAIRecommendations(strategyId),
createEnhancedStrategy,
contentPlanningApi
});
const {
showEducationalModal,
setShowEducationalModal,
showEnterpriseModal,
setShowEnterpriseModal,
handleProceedWithCurrentStrategy,
handleAddEnterpriseDatapoints
} = useModalManagement({
aiGenerating,
originalHandleCreateStrategy
});
const {
refreshMessage,
setRefreshMessage,
refreshProgress,
setRefreshProgress,
isRefreshing,
setIsRefreshing,
refreshError,
setRefreshError,
handleAIRefresh
} = useAIRefresh({
setTransparencyModalOpen,
setIsGenerating,
setStoreGenerationProgress,
setCurrentPhase,
clearTransparencyMessages,
addTransparencyMessage,
setAIGenerating,
setError
});
const completionStats = getCompletionStats();
const completionPercentage = calculateCompletionPercentage();
@@ -205,24 +240,7 @@ const ContentStrategyBuilder: React.FC = () => {
completionStats
});
// Use ActionButtons business logic hook
const { handleCreateStrategy: originalHandleCreateStrategy, handleSaveStrategy } = useActionButtonsBusinessLogic({
formData,
error,
currentStrategy,
setAIGenerating,
setError,
setCurrentStrategy,
setSaving,
setGenerationProgress: setStoreGenerationProgress,
setEducationalContent: setStoreEducationalContent,
setShowEducationalModal,
validateAllFields,
getCompletionStats,
generateAIRecommendations,
createEnhancedStrategy,
contentPlanningApi
});
// Enhanced handleCreateStrategy to show enterprise modal
const handleCreateStrategy = () => {
@@ -264,51 +282,7 @@ const ContentStrategyBuilder: React.FC = () => {
}
};
// Handle proceed with current strategy (30 fields)
const handleProceedWithCurrentStrategy = async () => {
console.log('🎯 User clicked "Proceed with Current Strategy"');
setShowEnterpriseModal(false);
sessionStorage.removeItem('showEnterpriseModal'); // Clear sessionStorage
// Add a small delay to ensure modal closes properly before showing educational modal
setTimeout(async () => {
console.log('🎯 Calling original handleCreateStrategy after enterprise modal closes');
try {
// Ensure we're not already generating
if (!aiGenerating) {
console.log('🎯 Starting strategy generation...');
await originalHandleCreateStrategy();
} else {
console.log('🎯 Already generating, skipping duplicate call');
}
} catch (error) {
console.error('🎯 Error in handleProceedWithCurrentStrategy:', error);
}
}, 300); // Increased delay to ensure modal closes completely
};
// Handle add enterprise datapoints (coming soon)
const handleAddEnterpriseDatapoints = async () => {
console.log('🎯 User clicked "Add Enterprise Datapoints"');
setShowEnterpriseModal(false);
sessionStorage.removeItem('showEnterpriseModal'); // Clear sessionStorage
// For now, just proceed with current strategy
// In Phase 2, this will enable enterprise datapoints
setTimeout(async () => {
console.log('🎯 Calling original handleCreateStrategy for enterprise datapoints');
try {
// Ensure we're not already generating
if (!aiGenerating) {
await originalHandleCreateStrategy();
} else {
console.log('🎯 Already generating, skipping duplicate call');
}
} catch (error) {
console.error('🎯 Error in handleAddEnterpriseDatapoints:', error);
}
}, 200); // Increased delay to ensure modal closes completely
};
// Auto-populate from onboarding on first load
useEffect(() => {
@@ -375,37 +349,13 @@ const ContentStrategyBuilder: React.FC = () => {
// Add CSS keyframes for pulse animation
useEffect(() => {
const style = document.createElement('style');
style.textContent = `
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
`;
document.head.appendChild(style);
const style = setupCSSAnimations();
return () => {
if (document.head.contains(style)) {
document.head.removeChild(style);
}
cleanupCSSAnimations(style);
};
}, []);
const handleReviewCategory = (categoryId: string) => {
setActiveCategory(activeCategory === categoryId ? null : categoryId);
};
const handleShowEducationalInfo = (categoryId: string) => {
setShowEducationalInfo(showEducationalInfo === categoryId ? null : categoryId);
};
// Wrapper for the hook function to maintain the same interface
const handleConfirmCategoryReviewWrapper = () => {
@@ -447,208 +397,7 @@ const ContentStrategyBuilder: React.FC = () => {
onShowAIRecommendations={() => setShowAIRecommendations(true)}
onShowDataSourceTransparency={() => setShowDataSourceTransparency(true)}
onRefreshData={() => autoPopulateFromOnboarding()}
onRefreshAI={async () => {
try {
// 🚀 POLLING-BASED AI REFRESH (No SSE)
// We switched from SSE to polling for better reliability
// This approach uses direct HTTP calls with visual feedback
// Open transparency modal and initialize transparency state
console.log('🎯 Opening transparency modal...');
setTransparencyModalOpen(true);
setIsGenerating(true);
setStoreGenerationProgress(0);
setCurrentPhase('autofill_initialization');
clearTransparencyMessages();
addTransparencyMessage('Starting strategy inputs generation process...');
console.log('🎯 Modal state set, transparency initialized');
setAIGenerating(true);
setIsRefreshing(true);
setRefreshError(null);
setRefreshMessage('Initializing AI refresh…');
setRefreshProgress(5);
// Start transparency message polling for visual feedback
const transparencyMessages = [
{ type: 'autofill_initialization', message: 'Starting strategy inputs generation process...', progress: 5 },
{ type: 'autofill_data_collection', message: 'Collecting and analyzing data sources...', progress: 15 },
{ type: 'autofill_data_quality', message: 'Assessing data quality and completeness...', progress: 25 },
{ type: 'autofill_context_analysis', message: 'Analyzing business context and strategic framework...', progress: 35 },
{ type: 'autofill_strategy_generation', message: 'Generating strategic insights and recommendations...', progress: 45 },
{ type: 'autofill_field_generation', message: 'Generating individual strategy input fields...', progress: 55 },
{ type: 'autofill_quality_validation', message: 'Validating generated strategy inputs...', progress: 65 },
{ type: 'autofill_alignment_check', message: 'Checking strategy alignment and consistency...', progress: 75 },
{ type: 'autofill_final_review', message: 'Performing final review and optimization...', progress: 85 },
{ type: 'autofill_complete', message: 'Strategy inputs generation completed successfully...', progress: 95 }
];
let messageIndex = 0;
const transparencyInterval = setInterval(() => {
if (messageIndex < transparencyMessages.length) {
const message = transparencyMessages[messageIndex];
console.log('🎯 Raw Polling Message:', {
type: message.type,
message: message.message,
progress: message.progress,
timestamp: new Date().toISOString()
});
setCurrentPhase(message.type);
addTransparencyMessage(message.message);
setStoreGenerationProgress(message.progress);
setRefreshProgress(message.progress);
messageIndex++;
} else {
clearInterval(transparencyInterval);
}
}, 2000); // Send a message every 2 seconds for better UX
// Call the non-streaming refresh endpoint (Polling-based approach)
console.log('🎯 Calling AI refresh endpoint (Polling-based)...');
const response = await contentPlanningApi.refreshAutofill(1, true, true);
console.log('🎯 Raw Polling Response:', {
success: !!response,
hasData: !!response?.data,
responseStructure: {
hasDataProperty: !!response?.data?.data,
hasFieldsDirect: !!response?.data?.fields,
hasFieldsInData: !!response?.data?.data?.fields
},
fieldsCount: Object.keys(response?.data?.data?.fields || response?.data?.fields || {}).length,
sourcesCount: Object.keys(response?.data?.data?.sources || response?.data?.sources || {}).length,
meta: response?.data?.data?.meta || response?.data?.meta || {},
timestamp: new Date().toISOString()
});
// Clear the transparency interval since we got the response
clearInterval(transparencyInterval);
// Process the response
if (response && response.data) {
// The API response is wrapped in ResponseBuilder format:
// { status: "success", message: "...", data: { fields: {...}, sources: {...}, meta: {...} } }
// So we need to access payload.data.fields, not payload.fields
const payload = response.data;
const fields = payload.data?.fields || payload.fields || {};
const sources = payload.data?.sources || payload.sources || {};
const inputDataPoints = payload.data?.input_data_points || payload.input_data_points || {};
const meta = payload.data?.meta || payload.meta || {};
console.log('🎯 AI Refresh Result - Payload:', payload);
console.log('🎯 AI Refresh Result - Fields:', fields);
console.log('🎯 AI Refresh Result - Meta:', meta);
console.log('🎯 Fields structure check:', {
fieldsType: typeof fields,
fieldsKeys: Object.keys(fields),
sampleField: fields[Object.keys(fields)[0]],
hasValueProperty: fields[Object.keys(fields)[0]]?.hasOwnProperty('value')
});
// 🚨 CRITICAL: Check if AI generation failed
if (meta.error || !meta.ai_used || meta.ai_overrides_count === 0) {
console.error('❌ AI generation failed:', meta.error || 'No AI data generated');
setError(`AI generation failed: ${meta.error || 'No real AI data was generated. Please try again.'}`);
setTransparencyModalOpen(false);
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
setRefreshError('AI generation failed. Please try again.');
setRefreshMessage('Refresh failed.');
return;
}
// 🚨 CRITICAL: Validate data source
if (meta.data_source === 'ai_generation_failed' || meta.data_source === 'ai_generation_error' || meta.data_source === 'ai_disabled') {
console.error('❌ Invalid data source:', meta.data_source);
setError(`AI generation failed: ${meta.error || 'Invalid data source. Please try again.'}`);
setTransparencyModalOpen(false);
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
setRefreshError('AI generation failed. Please try again.');
setRefreshMessage('Refresh failed.');
return;
}
console.log('✅ AI generation successful - processing real AI data');
const fieldValues: Record<string, any> = {};
const confidenceScores: Record<string, number> = {};
Object.keys(fields).forEach((fieldId) => {
const fieldData = fields[fieldId];
console.log(`🎯 Processing field ${fieldId}:`, fieldData);
if (fieldData && typeof fieldData === 'object' && 'value' in fieldData) {
fieldValues[fieldId] = fieldData.value;
console.log(`✅ Field ${fieldId} value extracted:`, fieldData.value);
// Extract confidence score if available
if (fieldData.confidence) {
confidenceScores[fieldId] = fieldData.confidence;
console.log(`🎯 Field ${fieldId} confidence: ${fieldData.confidence}`);
}
// Extract personalization data if available
if (fieldData.personalization_data) {
console.log(`🎯 Field ${fieldId} personalization:`, fieldData.personalization_data);
}
} else {
console.warn(`⚠️ Field ${fieldId} has invalid structure:`, fieldData);
}
});
console.log('🎯 Processed field values:', Object.keys(fieldValues));
console.log('🎯 Confidence scores:', confidenceScores);
console.log('🎯 Field values details:', fieldValues);
// Update the store with the new data
useEnhancedStrategyStore.setState((state) => {
const newState = {
autoPopulatedFields: { ...state.autoPopulatedFields, ...fieldValues },
dataSources: { ...state.dataSources, ...sources },
inputDataPoints: { ...state.inputDataPoints, ...inputDataPoints },
confidenceScores: { ...state.confidenceScores, ...confidenceScores },
formData: { ...state.formData, ...fieldValues }
};
console.log('🎯 Updated store state:', newState);
console.log('🎯 Field values being added:', fieldValues);
console.log('🎯 Confidence scores being added:', confidenceScores);
console.log('🎯 Store autoPopulatedFields count:', Object.keys(newState.autoPopulatedFields).length);
return newState;
});
// Add final completion message
addTransparencyMessage(`✅ AI generation completed successfully! Generated ${Object.keys(fieldValues).length} real AI values.`);
setStoreGenerationProgress(100);
setRefreshProgress(100);
setCurrentPhase('Complete');
setRefreshMessage(`AI refresh completed! Generated ${Object.keys(fieldValues).length} fields.`);
// Don't close modal automatically - let user close it manually
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
console.log('🎯 Polling-based AI refresh completed successfully!', {
fieldsGenerated: Object.keys(fieldValues).length,
confidenceScoresCount: Object.keys(confidenceScores).length,
dataSourcesCount: Object.keys(sources).length,
approach: 'Polling (No SSE)',
timestamp: new Date().toISOString()
});
} else {
throw new Error('Invalid response from AI refresh endpoint');
}
} catch (e) {
console.error('AI refresh error', e);
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
setRefreshError('AI refresh failed. Please try again.');
setRefreshMessage('Refresh failed.');
setError(`AI refresh failed: ${e instanceof Error ? e.message : 'Unknown error'}`);
}
}}
onRefreshAI={handleAIRefresh}
refreshMessage={refreshMessage}
refreshProgress={refreshProgress}
isRefreshing={isRefreshing}
@@ -757,7 +506,7 @@ const ContentStrategyBuilder: React.FC = () => {
saving={saving}
reviewProgressPercentage={reviewProgressPercentage}
onCreateStrategy={handleCreateStrategy}
onSaveStrategy={handleSaveStrategy}
onSaveStrategy={() => handleSaveStrategy()}
/>
{/* AI Recommendations Modal */}
@@ -785,7 +534,7 @@ const ContentStrategyBuilder: React.FC = () => {
<EducationalModal
open={showEducationalModal}
onClose={() => setShowEducationalModal(false)}
educationalContent={storeEducationalContent}
educationalContent={storeEducationalContent}
generationProgress={storeGenerationProgress}
onReviewStrategy={() => {
console.log('🎯 User clicked "Next: Review Strategy and Create Calendar"');

View File

@@ -0,0 +1,302 @@
import { useState } from 'react';
import { contentPlanningApi } from '../../../../../services/contentPlanningApi';
import { useEnhancedStrategyStore } from '../../../../../stores/enhancedStrategyStore';
interface UseAIRefreshProps {
setTransparencyModalOpen: (open: boolean) => void;
setIsGenerating: (generating: boolean) => void;
setStoreGenerationProgress: (progress: number) => void;
setCurrentPhase: (phase: string) => void;
clearTransparencyMessages: () => void;
addTransparencyMessage: (message: string) => void;
setAIGenerating: (generating: boolean) => void;
setError: (error: string | null) => void;
}
export const useAIRefresh = ({
setTransparencyModalOpen,
setIsGenerating,
setStoreGenerationProgress,
setCurrentPhase,
clearTransparencyMessages,
addTransparencyMessage,
setAIGenerating,
setError
}: UseAIRefreshProps) => {
const [refreshMessage, setRefreshMessage] = useState<string | null>(null);
const [refreshProgress, setRefreshProgress] = useState<number>(0);
const [isRefreshing, setIsRefreshing] = useState<boolean>(false);
const [refreshError, setRefreshError] = useState<string | null>(null);
const handleAIRefresh = async () => {
try {
// 🚀 POLLING-BASED AI REFRESH (No SSE)
// We switched from SSE to polling for better reliability
// This approach uses direct HTTP calls with visual feedback
// Open transparency modal and initialize transparency state
console.log('🎯 Opening transparency modal...');
setTransparencyModalOpen(true);
setIsGenerating(true);
setStoreGenerationProgress(0);
setCurrentPhase('autofill_initialization');
clearTransparencyMessages();
addTransparencyMessage('Starting strategy inputs generation process...');
console.log('🎯 Modal state set, transparency initialized');
setAIGenerating(true);
setIsRefreshing(true);
setRefreshError(null);
setRefreshMessage('Initializing AI refresh…');
setRefreshProgress(5);
// Start transparency message polling for visual feedback
const transparencyMessages = [
{ type: 'autofill_initialization', message: 'Starting strategy inputs generation process...', progress: 5 },
{ type: 'autofill_data_collection', message: 'Collecting and analyzing data sources...', progress: 15 },
{ type: 'autofill_data_quality', message: 'Assessing data quality and completeness...', progress: 25 },
{ type: 'autofill_context_analysis', message: 'Analyzing business context and strategic framework...', progress: 35 },
{ type: 'autofill_strategy_generation', message: 'Generating strategic insights and recommendations...', progress: 45 },
{ type: 'autofill_field_generation', message: 'Generating individual strategy input fields...', progress: 55 },
{ type: 'autofill_quality_validation', message: 'Validating generated strategy inputs...', progress: 65 },
{ type: 'autofill_alignment_check', message: 'Checking strategy alignment and consistency...', progress: 75 },
{ type: 'autofill_final_review', message: 'Performing final review and optimization...', progress: 85 },
{ type: 'autofill_complete', message: 'Strategy inputs generation completed successfully...', progress: 95 }
];
let messageIndex = 0;
const transparencyInterval = setInterval(() => {
if (messageIndex < transparencyMessages.length) {
const message = transparencyMessages[messageIndex];
console.log('🎯 Raw Polling Message:', {
type: message.type,
message: message.message,
progress: message.progress,
timestamp: new Date().toISOString()
});
setCurrentPhase(message.type);
addTransparencyMessage(message.message);
setStoreGenerationProgress(message.progress);
setRefreshProgress(message.progress);
messageIndex++;
} else {
clearInterval(transparencyInterval);
}
}, 2000); // Send a message every 2 seconds for better UX
// Call the non-streaming refresh endpoint (Polling-based approach)
console.log('🎯 Calling AI refresh endpoint (Polling-based)...');
const response = await contentPlanningApi.refreshAutofill(1, true, true);
console.log('🎯 Raw Polling Response:', {
success: !!response,
hasData: !!response?.fields,
responseStructure: {
hasFieldsProperty: !!response?.fields,
hasSourcesProperty: !!response?.sources,
hasMetaProperty: !!response?.meta
},
fieldsCount: Object.keys(response?.fields || {}).length,
sourcesCount: Object.keys(response?.sources || {}).length,
meta: response?.meta || {},
timestamp: new Date().toISOString()
});
// Clear the transparency interval since we got the response
clearInterval(transparencyInterval);
// Process the response
// The API method already returns the extracted data, not the full response
if (response) {
// Debug the actual response structure
console.log('🎯 Raw response structure:', {
responseType: typeof response,
responseKeys: Object.keys(response),
hasFieldsProperty: response?.hasOwnProperty('fields'),
hasSourcesProperty: response?.hasOwnProperty('sources'),
hasMetaProperty: response?.hasOwnProperty('meta')
});
// Debug the actual response data
console.log('🎯 Raw response:', response);
console.log('🎯 Raw response.fields:', response?.fields);
console.log('🎯 Raw response.sources:', response?.sources);
console.log('🎯 Raw response.meta:', response?.meta);
// The API method already returns the extracted payload from ResponseBuilder
// So response is already the payload with fields, sources, meta, etc.
const payload = response;
// Debug the payload structure
console.log('🎯 Payload structure:', {
payloadType: typeof payload,
payloadKeys: Object.keys(payload),
hasFieldsProperty: payload?.hasOwnProperty('fields'),
hasSourcesProperty: payload?.hasOwnProperty('sources'),
hasMetaProperty: payload?.hasOwnProperty('meta'),
fieldsKeys: payload?.fields ? Object.keys(payload.fields) : 'no fields'
});
const fields = payload.fields || {};
const sources = payload.sources || {};
const inputDataPoints = payload.input_data_points || {};
const meta = payload.meta || {};
// Debug the extracted data
console.log('🎯 Extracted fields:', fields);
console.log('🎯 Extracted sources:', sources);
console.log('🎯 Extracted inputDataPoints:', inputDataPoints);
console.log('🎯 Extracted meta:', meta);
console.log('🎯 Fields count:', Object.keys(fields).length);
console.log('🎯 Sources count:', Object.keys(sources).length);
console.log('🎯 InputDataPoints count:', Object.keys(inputDataPoints).length);
console.log('🎯 AI Refresh Result - Payload:', payload);
console.log('🎯 AI Refresh Result - Fields:', fields);
console.log('🎯 AI Refresh Result - Meta:', meta);
console.log('🎯 Fields structure check:', {
fieldsType: typeof fields,
fieldsKeys: Object.keys(fields),
sampleField: fields[Object.keys(fields)[0]],
hasValueProperty: fields[Object.keys(fields)[0]]?.hasOwnProperty('value')
});
// 🚨 CRITICAL: Check if AI generation failed
if (meta.error || !meta.ai_used) {
console.error('❌ AI generation failed:', meta.error || 'AI not used');
setError(`AI generation failed: ${meta.error || 'AI was not used for generation. Please try again.'}`);
setTransparencyModalOpen(false);
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
setRefreshError('AI generation failed. Please try again.');
setRefreshMessage('Refresh failed.');
return;
}
// Check if we have any fields generated (more lenient validation)
const fieldsCount = Object.keys(fields).length;
if (fieldsCount === 0) {
console.error('❌ No fields generated');
setError('No fields were generated. Please try again.');
setTransparencyModalOpen(false);
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
setRefreshError('No fields generated. Please try again.');
setRefreshMessage('Refresh failed.');
return;
}
console.log(`✅ AI generation successful - generated ${fieldsCount} fields, AI overrides: ${meta.ai_overrides_count || 0}`);
// 🚨 CRITICAL: Validate data source (only check for explicit failure states)
if (meta.data_source === 'ai_generation_failed' || meta.data_source === 'ai_generation_error') {
console.error('❌ Invalid data source:', meta.data_source);
setError(`AI generation failed: ${meta.error || 'Invalid data source. Please try again.'}`);
setTransparencyModalOpen(false);
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
setRefreshError('AI generation failed. Please try again.');
setRefreshMessage('Refresh failed.');
return;
}
console.log('✅ AI generation successful - processing real AI data');
const fieldValues: Record<string, any> = {};
const confidenceScores: Record<string, number> = {};
Object.keys(fields).forEach((fieldId) => {
const fieldData = fields[fieldId];
console.log(`🎯 Processing field ${fieldId}:`, fieldData);
if (fieldData && typeof fieldData === 'object' && 'value' in fieldData) {
fieldValues[fieldId] = fieldData.value;
console.log(`✅ Field ${fieldId} value extracted:`, fieldData.value);
// Extract confidence score if available
if (fieldData.confidence) {
confidenceScores[fieldId] = fieldData.confidence;
console.log(`🎯 Field ${fieldId} confidence: ${fieldData.confidence}`);
}
// Extract personalization data if available
if (fieldData.personalization_data) {
console.log(`🎯 Field ${fieldId} personalization:`, fieldData.personalization_data);
}
} else {
console.warn(`⚠️ Field ${fieldId} has invalid structure:`, fieldData);
}
});
console.log('🎯 Processed field values:', Object.keys(fieldValues));
console.log('🎯 Confidence scores:', confidenceScores);
console.log('🎯 Field values details:', fieldValues);
// Update the store with the new data
useEnhancedStrategyStore.setState((state) => {
const newState = {
autoPopulatedFields: { ...state.autoPopulatedFields, ...fieldValues },
dataSources: { ...state.dataSources, ...sources },
inputDataPoints: { ...state.inputDataPoints, ...inputDataPoints },
confidenceScores: { ...state.confidenceScores, ...confidenceScores },
formData: { ...state.formData, ...fieldValues }
};
console.log('🎯 Updated store state:', newState);
console.log('🎯 Field values being added:', fieldValues);
console.log('🎯 Confidence scores being added:', confidenceScores);
console.log('🎯 Store autoPopulatedFields count:', Object.keys(newState.autoPopulatedFields).length);
return newState;
});
// Add final completion message
addTransparencyMessage(`✅ AI generation completed successfully! Generated ${Object.keys(fieldValues).length} real AI values.`);
setStoreGenerationProgress(100);
setRefreshProgress(100);
setCurrentPhase('Complete');
setRefreshMessage(`AI refresh completed! Generated ${Object.keys(fieldValues).length} fields.`);
// Ensure the educational modal shows the completion state
setTimeout(() => {
setStoreGenerationProgress(100);
setRefreshProgress(100);
}, 100);
// Reset refresh state
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
console.log('🎯 Polling-based AI refresh completed successfully!', {
fieldsGenerated: Object.keys(fieldValues).length,
confidenceScoresCount: Object.keys(confidenceScores).length,
dataSourcesCount: Object.keys(sources).length,
approach: 'Polling (No SSE)',
timestamp: new Date().toISOString()
});
} else {
throw new Error('Invalid response from AI refresh endpoint');
}
} catch (e) {
console.error('AI refresh error', e);
setAIGenerating(false);
setIsRefreshing(false);
setIsGenerating(false);
setRefreshError('AI refresh failed. Please try again.');
setRefreshMessage('Refresh failed.');
setError(`AI refresh failed: ${e instanceof Error ? e.message : 'Unknown error'}`);
}
};
return {
refreshMessage,
setRefreshMessage,
refreshProgress,
setRefreshProgress,
isRefreshing,
setIsRefreshing,
refreshError,
setRefreshError,
handleAIRefresh
};
};

View File

@@ -0,0 +1,26 @@
import { useState } from 'react';
export const useEventHandlers = () => {
const [showTooltip, setShowTooltip] = useState<string | null>(null);
const [activeCategory, setActiveCategory] = useState<string | null>(null);
const [showEducationalInfo, setShowEducationalInfo] = useState<string | null>(null);
const handleReviewCategory = (categoryId: string) => {
setActiveCategory(activeCategory === categoryId ? null : categoryId);
};
const handleShowEducationalInfo = (categoryId: string) => {
setShowEducationalInfo(showEducationalInfo === categoryId ? null : categoryId);
};
return {
showTooltip,
setShowTooltip,
activeCategory,
setActiveCategory,
showEducationalInfo,
setShowEducationalInfo,
handleReviewCategory,
handleShowEducationalInfo
};
};

View File

@@ -0,0 +1,108 @@
import { useState, useEffect } from 'react';
interface UseModalManagementProps {
aiGenerating: boolean;
originalHandleCreateStrategy: (() => Promise<void>) | null;
}
export const useModalManagement = ({ aiGenerating, originalHandleCreateStrategy }: UseModalManagementProps) => {
const [showEducationalModal, setShowEducationalModal] = useState(false);
const [showEnterpriseModal, setShowEnterpriseModal] = useState(false);
// Persist enterprise modal state across hot reloads
useEffect(() => {
const savedModalState = sessionStorage.getItem('showEnterpriseModal');
if (savedModalState === 'true') {
console.log('🎯 Restoring enterprise modal state from sessionStorage');
setShowEnterpriseModal(true);
}
}, []);
// Save modal state to sessionStorage when it changes
useEffect(() => {
sessionStorage.setItem('showEnterpriseModal', showEnterpriseModal.toString());
}, [showEnterpriseModal]);
// Cleanup sessionStorage on component unmount
useEffect(() => {
return () => {
// Only clear if we're not in the middle of showing the modal
if (!showEnterpriseModal) {
sessionStorage.removeItem('showEnterpriseModal');
}
};
}, [showEnterpriseModal]);
// Monitor enterprise modal state for debugging
useEffect(() => {
console.log('🎯 Enterprise modal state changed - showEnterpriseModal:', showEnterpriseModal);
// If modal was unexpectedly closed, log it
if (!showEnterpriseModal && aiGenerating) {
console.warn('🎯 WARNING: Enterprise modal closed while AI is generating');
}
// Only warn about unexpected closure if it's not due to hot reload
if (!showEnterpriseModal && !aiGenerating) {
const savedModalState = sessionStorage.getItem('showEnterpriseModal');
if (savedModalState !== 'true') {
console.warn('🎯 WARNING: Enterprise modal closed unexpectedly (not due to hot reload)');
}
}
}, [showEnterpriseModal, aiGenerating]);
// Handle proceed with current strategy (30 fields)
const handleProceedWithCurrentStrategy = async () => {
console.log('🎯 User clicked "Proceed with Current Strategy"');
setShowEnterpriseModal(false);
sessionStorage.removeItem('showEnterpriseModal'); // Clear sessionStorage
// Add a small delay to ensure modal closes properly before showing educational modal
setTimeout(async () => {
console.log('🎯 Calling original handleCreateStrategy after enterprise modal closes');
try {
// Ensure we're not already generating
if (!aiGenerating && originalHandleCreateStrategy) {
console.log('🎯 Starting strategy generation...');
await originalHandleCreateStrategy();
} else {
console.log('🎯 Already generating, skipping duplicate call');
}
} catch (error) {
console.error('🎯 Error in handleProceedWithCurrentStrategy:', error);
}
}, 300); // Increased delay to ensure modal closes completely
};
// Handle add enterprise datapoints (coming soon)
const handleAddEnterpriseDatapoints = async () => {
console.log('🎯 User clicked "Add Enterprise Datapoints"');
setShowEnterpriseModal(false);
sessionStorage.removeItem('showEnterpriseModal'); // Clear sessionStorage
// For now, just proceed with current strategy
// In Phase 2, this will enable enterprise datapoints
setTimeout(async () => {
console.log('🎯 Calling original handleCreateStrategy for enterprise datapoints');
try {
// Ensure we're not already generating
if (!aiGenerating && originalHandleCreateStrategy) {
await originalHandleCreateStrategy();
} else {
console.log('🎯 Already generating, skipping duplicate call');
}
} catch (error) {
console.error('🎯 Error in handleAddEnterpriseDatapoints:', error);
}
}, 200); // Increased delay to ensure modal closes completely
};
return {
showEducationalModal,
setShowEducationalModal,
showEnterpriseModal,
setShowEnterpriseModal,
handleProceedWithCurrentStrategy,
handleAddEnterpriseDatapoints
};
};

View File

@@ -0,0 +1,61 @@
import { useActionButtonsBusinessLogic } from '../components/ActionButtons';
interface UseStrategyCreationProps {
formData: any;
error: string | null;
currentStrategy: any;
setAIGenerating: (generating: boolean) => void;
setError: (error: string | null) => void;
setCurrentStrategy: (strategy: any) => void;
setSaving: (saving: boolean) => void;
setGenerationProgress: (progress: number) => void;
setEducationalContent: (content: any) => void;
setShowEducationalModal: (show: boolean) => void;
validateAllFields: () => boolean;
getCompletionStats: () => any;
generateAIRecommendations: (strategyId: string) => Promise<void>;
createEnhancedStrategy: (data: any) => Promise<any>;
contentPlanningApi: any;
}
export const useStrategyCreation = ({
formData,
error,
currentStrategy,
setAIGenerating,
setError,
setCurrentStrategy,
setSaving,
setGenerationProgress,
setEducationalContent,
setShowEducationalModal,
validateAllFields,
getCompletionStats,
generateAIRecommendations,
createEnhancedStrategy,
contentPlanningApi
}: UseStrategyCreationProps) => {
// Use ActionButtons business logic hook
const { handleCreateStrategy: originalHandleCreateStrategy, handleSaveStrategy } = useActionButtonsBusinessLogic({
formData,
error,
currentStrategy,
setAIGenerating,
setError,
setCurrentStrategy,
setSaving,
setGenerationProgress,
setEducationalContent,
setShowEducationalModal,
validateAllFields,
getCompletionStats,
generateAIRecommendations,
createEnhancedStrategy,
contentPlanningApi
});
return {
originalHandleCreateStrategy: () => originalHandleCreateStrategy(),
handleSaveStrategy: () => handleSaveStrategy()
};
};

View File

@@ -0,0 +1,26 @@
export const setupCSSAnimations = () => {
const style = document.createElement('style');
style.textContent = `
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
`;
document.head.appendChild(style);
return style;
};
export const cleanupCSSAnimations = (style: HTMLStyleElement) => {
if (document.head.contains(style)) {
document.head.removeChild(style);
}
};

View File

@@ -373,6 +373,259 @@ const CompetitiveAnalysisCard: React.FC<CompetitiveAnalysisCardProps> = ({ strat
</Box>
</Box>
)}
{/* Competitive Advantages */}
{strategyData.competitive_analysis.competitive_advantages && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Competitive Advantages
</Typography>
<Box sx={sectionStyles.sectionContainer}>
{/* Development Areas */}
{strategyData.competitive_analysis.competitive_advantages.development_areas &&
strategyData.competitive_analysis.competitive_advantages.development_areas.length > 0 && (
<Box sx={{ mb: 2 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.info, fontWeight: 600, mb: 1 }}>
Development Areas ({strategyData.competitive_analysis.competitive_advantages.development_areas.length})
</Typography>
<List dense>
{strategyData.competitive_analysis.competitive_advantages.development_areas.map((area: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.info,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={area}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
{/* Primary Advantages */}
{strategyData.competitive_analysis.competitive_advantages.primary &&
strategyData.competitive_analysis.competitive_advantages.primary.length > 0 && (
<Box sx={{ mb: 2 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.primary, fontWeight: 600, mb: 1 }}>
Primary Advantages ({strategyData.competitive_analysis.competitive_advantages.primary.length})
</Typography>
<List dense>
{strategyData.competitive_analysis.competitive_advantages.primary.map((advantage: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.primary,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={advantage}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
{/* Sustainable Advantages */}
{strategyData.competitive_analysis.competitive_advantages.sustainable &&
strategyData.competitive_analysis.competitive_advantages.sustainable.length > 0 && (
<Box>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.success, fontWeight: 600, mb: 1 }}>
Sustainable Advantages ({strategyData.competitive_analysis.competitive_advantages.sustainable.length})
</Typography>
<List dense>
{strategyData.competitive_analysis.competitive_advantages.sustainable.map((advantage: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.success,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={advantage}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
</Box>
</Box>
)}
{/* SWOT Competitive Insights */}
{strategyData.competitive_analysis.swot_competitive_insights && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
SWOT Competitive Insights
</Typography>
<Box sx={sectionStyles.sectionContainer}>
{/* Leverage Strengths */}
{strategyData.competitive_analysis.swot_competitive_insights.leverage_strengths &&
strategyData.competitive_analysis.swot_competitive_insights.leverage_strengths.length > 0 && (
<Box sx={{ mb: 2 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.success, fontWeight: 600, mb: 1 }}>
Leverage Strengths ({strategyData.competitive_analysis.swot_competitive_insights.leverage_strengths.length})
</Typography>
<List dense>
{strategyData.competitive_analysis.swot_competitive_insights.leverage_strengths.map((strength: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.success,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={strength}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
{/* Address Weaknesses */}
{strategyData.competitive_analysis.swot_competitive_insights.address_weaknesses &&
strategyData.competitive_analysis.swot_competitive_insights.address_weaknesses.length > 0 && (
<Box sx={{ mb: 2 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.warning, fontWeight: 600, mb: 1 }}>
Address Weaknesses ({strategyData.competitive_analysis.swot_competitive_insights.address_weaknesses.length})
</Typography>
<List dense>
{strategyData.competitive_analysis.swot_competitive_insights.address_weaknesses.map((weakness: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.warning,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={weakness}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
{/* Capitalize Opportunities */}
{strategyData.competitive_analysis.swot_competitive_insights.capitalize_opportunities &&
strategyData.competitive_analysis.swot_competitive_insights.capitalize_opportunities.length > 0 && (
<Box sx={{ mb: 2 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.info, fontWeight: 600, mb: 1 }}>
Capitalize Opportunities ({strategyData.competitive_analysis.swot_competitive_insights.capitalize_opportunities.length})
</Typography>
<List dense>
{strategyData.competitive_analysis.swot_competitive_insights.capitalize_opportunities.map((opportunity: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.info,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={opportunity}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
{/* Mitigate Threats */}
{strategyData.competitive_analysis.swot_competitive_insights.mitigate_threats &&
strategyData.competitive_analysis.swot_competitive_insights.mitigate_threats.length > 0 && (
<Box>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.error, fontWeight: 600, mb: 1 }}>
Mitigate Threats ({strategyData.competitive_analysis.swot_competitive_insights.mitigate_threats.length})
</Typography>
<List dense>
{strategyData.competitive_analysis.swot_competitive_insights.mitigate_threats.map((threat: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.error,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={threat}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
</Box>
</Box>
)}
</Box>
);

View File

@@ -97,27 +97,28 @@ const ImplementationRoadmapCard: React.FC<ImplementationRoadmapCardProps> = ({ s
color: 'white',
fontSize: '1.2rem',
fontWeight: 600,
boxShadow: `0 4px 12px ${ANALYSIS_CARD_STYLES.colors.info}30`
boxShadow: `0 4px 12px ${ANALYSIS_CARD_STYLES.colors.info}30`,
flexShrink: 0
}}>
{strategyData.implementation_roadmap.phases?.length || 0}
{strategyData.implementation_roadmap.timeline}
</Box>
<Box>
<Typography variant="h6" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, fontWeight: 600 }}>
Project Phases
Implementation Roadmap
</Typography>
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
{strategyData.implementation_roadmap.total_duration || '6 months'} implementation
{strategyData.implementation_roadmap.timeline} implementation timeline
</Typography>
</Box>
</Box>
<Box sx={{ display: 'flex', gap: 1 }}>
<Chip
label={`${strategyData.implementation_roadmap.phases?.reduce((total: number, phase: any) => total + (phase.tasks?.length || 0), 0) || 0} Tasks`}
label={`${strategyData.implementation_roadmap.phases?.length || 0} Phases`}
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.info).chip}
/>
<Chip
label={`${strategyData.implementation_roadmap.phases?.reduce((total: number, phase: any) => total + (phase.milestones?.length || 0), 0) || 0} Milestones`}
label={`${strategyData.implementation_roadmap.milestones?.length || 0} Milestones`}
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.primary).chip}
/>
@@ -125,26 +126,40 @@ const ImplementationRoadmapCard: React.FC<ImplementationRoadmapCardProps> = ({ s
</Box>
</Box>
{/* Phases Preview */}
{/* Timeline Preview */}
<Box sx={{ mt: 2 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 1, fontWeight: 600 }}>
Implementation Phases
Project Timeline
</Typography>
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
{strategyData.implementation_roadmap.phases?.slice(0, 4).map((phase: any, index: number) => (
<Chip
label={`Duration: ${strategyData.implementation_roadmap.timeline}`}
size="small"
icon={<TimelineIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.primary).chip}
/>
{strategyData.implementation_roadmap.phases && strategyData.implementation_roadmap.phases.length > 0 && (
<Chip
key={index}
label={`Phase ${index + 1}`}
label={`${strategyData.implementation_roadmap.phases.length} Phases`}
size="small"
icon={<TimelineIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.primary).chip}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.info).chip}
/>
))}
{(strategyData.implementation_roadmap.phases?.length || 0) > 4 && (
)}
{strategyData.implementation_roadmap.milestones && strategyData.implementation_roadmap.milestones.length > 0 && (
<Chip
label={`+${(strategyData.implementation_roadmap.phases?.length || 0) - 4} more`}
label={`${strategyData.implementation_roadmap.milestones.length} Milestones`}
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.secondary).chip}
icon={<CheckCircleIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.success).chip}
/>
)}
{strategyData.implementation_roadmap.resource_requirements && strategyData.implementation_roadmap.resource_requirements.length > 0 && (
<Chip
label={`${strategyData.implementation_roadmap.resource_requirements.length} Resources`}
size="small"
icon={<GroupIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.warning).chip}
/>
)}
</Box>
@@ -156,60 +171,63 @@ const ImplementationRoadmapCard: React.FC<ImplementationRoadmapCardProps> = ({ s
const detailedContent = (
<Box>
{/* Project Timeline */}
{strategyData.implementation_roadmap.timeline && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Project Timeline
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
Duration: {strategyData.implementation_roadmap.total_duration || '6 months'}
</Typography>
</Box>
{strategyData.implementation_roadmap.timeline.start_date && (
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary, mb: 1 }}>
Start Date: {strategyData.implementation_roadmap.timeline.start_date}
</Typography>
)}
{strategyData.implementation_roadmap.timeline.end_date && (
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary, mb: 1 }}>
End Date: {strategyData.implementation_roadmap.timeline.end_date}
</Typography>
)}
{strategyData.implementation_roadmap.timeline.key_milestones && strategyData.implementation_roadmap.timeline.key_milestones.length > 0 && (
<Box sx={{ mt: 2 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, fontWeight: 600, mb: 1 }}>
Key Milestones:
</Typography>
<List dense>
{strategyData.implementation_roadmap.timeline.key_milestones.map((milestone: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.success,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={milestone}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Project Timeline
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
Duration: {strategyData.implementation_roadmap.timeline}
</Typography>
</Box>
{strategyData.implementation_roadmap.timeline && (
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary, mb: 1 }}>
Timeline: {strategyData.implementation_roadmap.timeline}
</Typography>
)}
{strategyData.implementation_roadmap.timeline_object?.start_date && (
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary, mb: 1 }}>
Start Date: {strategyData.implementation_roadmap.timeline_object.start_date}
</Typography>
)}
{strategyData.implementation_roadmap.timeline_object?.end_date && (
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary, mb: 1 }}>
End Date: {strategyData.implementation_roadmap.timeline_object.end_date}
</Typography>
)}
{strategyData.implementation_roadmap.timeline_object?.key_milestones && strategyData.implementation_roadmap.timeline_object.key_milestones.length > 0 && (
<Box sx={{ mt: 2 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, fontWeight: 600, mb: 1 }}>
Key Milestones:
</Typography>
<List dense>
{strategyData.implementation_roadmap.timeline_object.key_milestones.map((milestone: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.success,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={milestone}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
</Box>
)}
</Box>
{/* Implementation Phases */}
{strategyData.implementation_roadmap.phases && strategyData.implementation_roadmap.phases.length > 0 && (
@@ -242,10 +260,10 @@ const ImplementationRoadmapCard: React.FC<ImplementationRoadmapCardProps> = ({ s
</Box>
<Box sx={{ flex: 1 }}>
<Typography variant="body2" sx={accordionStyles.accordionTitle}>
{phase.name || `Phase ${index + 1}`}
{phase.phase || `Phase ${index + 1}`}
</Typography>
<Typography variant="caption" sx={accordionStyles.accordionSubtitle}>
{phase.duration || '2 months'} {phase.tasks?.length || 0} tasks {phase.milestones?.length || 0} milestones
{phase.duration} {phase.tasks?.length || 0} tasks {phase.milestones?.length || 0} milestones
</Typography>
</Box>
</Box>
@@ -357,6 +375,102 @@ const ImplementationRoadmapCard: React.FC<ImplementationRoadmapCardProps> = ({ s
</Box>
)}
{/* Milestones */}
{strategyData.implementation_roadmap.milestones && strategyData.implementation_roadmap.milestones.length > 0 && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Project Milestones ({strategyData.implementation_roadmap.milestones.length})
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<List dense>
{strategyData.implementation_roadmap.milestones.map((milestone: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<CheckCircleIcon sx={{ color: ANALYSIS_CARD_STYLES.colors.success, fontSize: 16 }} />
</ListItemIcon>
<ListItemText
primary={milestone}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
</Box>
)}
{/* Resource Requirements */}
{strategyData.implementation_roadmap.resource_requirements && strategyData.implementation_roadmap.resource_requirements.length > 0 && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Resource Requirements ({strategyData.implementation_roadmap.resource_requirements.length})
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<List dense>
{strategyData.implementation_roadmap.resource_requirements.map((requirement: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.warning,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={requirement}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
</Box>
)}
{/* Critical Path */}
{strategyData.implementation_roadmap.critical_path && strategyData.implementation_roadmap.critical_path.length > 0 && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Critical Path ({strategyData.implementation_roadmap.critical_path.length})
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<List dense>
{strategyData.implementation_roadmap.critical_path.map((path: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.error,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={path}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
</Box>
)}
{/* Resource Allocation */}
{strategyData.implementation_roadmap.resource_allocation && (
<Box sx={{ mb: 3 }}>

View File

@@ -98,7 +98,7 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
boxShadow: `0 4px 12px ${ANALYSIS_CARD_STYLES.colors.success}30`,
flexShrink: 0
}}>
{strategyData.performance_predictions.roi_predictions?.estimated_roi || '25%'}
{strategyData.performance_predictions.estimated_roi || '25%'}
</Box>
<Box sx={{
minWidth: 0,
@@ -113,7 +113,7 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
mb: 0.5,
wordBreak: 'break-word'
}}>
ROI Predictions
Performance Predictions
</Typography>
<Typography variant="caption" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
@@ -121,7 +121,7 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
lineHeight: 1.2,
wordBreak: 'break-word'
}}>
Expected return on investment
Expected ROI and success metrics
</Typography>
</Box>
</Box>
@@ -133,12 +133,12 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
flexShrink: 0
}}>
<Chip
label={`${(strategyData.performance_predictions as any)?.success_probability || '85%'} Success`}
label={`${strategyData.performance_predictions.success_probability || '85%'} Success`}
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.success).chip}
/>
<Chip
label={`${(strategyData.performance_predictions as any)?.implementation_timeline || '6 months'}`}
label="12 months"
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.info).chip}
/>
@@ -154,7 +154,7 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
wordBreak: 'break-word',
textAlign: 'left'
}}>
ROI of {strategyData.performance_predictions.roi_predictions?.estimated_roi || '300-350%'} is achievable leveraging the strong cost-per-lead to lifetime-value ratio.
ROI of {strategyData.performance_predictions.estimated_roi || '20-30%'} is achievable with {strategyData.performance_predictions.success_probability || '85%'} success probability.
</Typography>
</Box>
</Box>
@@ -175,24 +175,30 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
gap: 1,
justifyContent: 'flex-start'
}}>
<Chip
label="Traffic Growth"
size="small"
icon={<TrendingUpIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.primary).chip}
/>
<Chip
label="Engagement"
size="small"
icon={<AssessmentIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.secondary).chip}
/>
<Chip
label="Conversion"
size="small"
icon={<ShowChartIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.accent).chip}
/>
{strategyData.performance_predictions.traffic_growth && (
<Chip
label={`${strategyData.performance_predictions.traffic_growth.month_12 || '100%'} Traffic`}
size="small"
icon={<TrendingUpIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.primary).chip}
/>
)}
{strategyData.performance_predictions.engagement_metrics && (
<Chip
label={`${strategyData.performance_predictions.engagement_metrics.time_on_page || '3-5 min'}`}
size="small"
icon={<AssessmentIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.secondary).chip}
/>
)}
{strategyData.performance_predictions.conversion_predictions && (
<Chip
label={`${strategyData.performance_predictions.conversion_predictions.lead_generation || '5-8%'} Leads`}
size="small"
icon={<ShowChartIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.accent).chip}
/>
)}
</Box>
</Box>
</Box>
@@ -214,7 +220,7 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
lineHeight: 1.5,
wordBreak: 'break-word'
}}>
Estimated ROI: {strategyData.performance_predictions.roi_predictions?.estimated_roi || '25%'}
Estimated ROI: {strategyData.performance_predictions.estimated_roi || '20-30%'}
</Typography>
<Typography variant="body2" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
@@ -222,268 +228,298 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
lineHeight: 1.5,
wordBreak: 'break-word'
}}>
Success Probability: {(strategyData.performance_predictions as any)?.success_probability || '85%'}
Success Probability: {strategyData.performance_predictions.success_probability || '85%'}
</Typography>
<Typography variant="body2" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
fontSize: '0.85rem',
lineHeight: 1.5,
wordBreak: 'break-word'
</Box>
</Box>
</Box>
{/* Traffic Growth */}
{strategyData.performance_predictions.traffic_growth && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Traffic Growth Projections
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<Box sx={{
display: 'grid',
gridTemplateColumns: { xs: '1fr', sm: 'repeat(auto-fit, minmax(150px, 1fr))' },
gap: 2
}}>
Implementation Timeline: {(strategyData.performance_predictions as any)?.implementation_timeline || '6 months'}
</Typography>
{strategyData.performance_predictions.traffic_growth.month_3 && (
<Box sx={{
p: 2,
border: `1px solid ${ANALYSIS_CARD_STYLES.colors.success}`,
borderRadius: 2,
background: `rgba(76, 175, 80, 0.1)`,
textAlign: 'center'
}}>
<Typography variant="body2" sx={{
color: ANALYSIS_CARD_STYLES.colors.success,
fontWeight: 600,
mb: 1,
fontSize: '0.8rem'
}}>
Month 3
</Typography>
<Typography variant="h6" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.primary,
fontSize: '1.2rem',
fontWeight: 700
}}>
{strategyData.performance_predictions.traffic_growth.month_3}
</Typography>
</Box>
)}
{strategyData.performance_predictions.traffic_growth.month_6 && (
<Box sx={{
p: 2,
border: `1px solid ${ANALYSIS_CARD_STYLES.colors.primary}`,
borderRadius: 2,
background: `rgba(63, 81, 181, 0.1)`,
textAlign: 'center'
}}>
<Typography variant="body2" sx={{
color: ANALYSIS_CARD_STYLES.colors.primary,
fontWeight: 600,
mb: 1,
fontSize: '0.8rem'
}}>
Month 6
</Typography>
<Typography variant="h6" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.primary,
fontSize: '1.2rem',
fontWeight: 700
}}>
{strategyData.performance_predictions.traffic_growth.month_6}
</Typography>
</Box>
)}
{strategyData.performance_predictions.traffic_growth.month_12 && (
<Box sx={{
p: 2,
border: `1px solid ${ANALYSIS_CARD_STYLES.colors.accent}`,
borderRadius: 2,
background: `rgba(240, 147, 251, 0.1)`,
textAlign: 'center'
}}>
<Typography variant="body2" sx={{
color: ANALYSIS_CARD_STYLES.colors.accent,
fontWeight: 600,
mb: 1,
fontSize: '0.8rem'
}}>
Month 12
</Typography>
<Typography variant="h6" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.primary,
fontSize: '1.2rem',
fontWeight: 700
}}>
{strategyData.performance_predictions.traffic_growth.month_12}
</Typography>
</Box>
)}
</Box>
</Box>
</Box>
</Box>
)}
{/* Key Metrics */}
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Key Metrics
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<Box sx={{
display: 'grid',
gridTemplateColumns: { xs: '1fr', sm: 'repeat(auto-fit, minmax(200px, 1fr))' },
gap: 2
}}>
{/* Traffic Predictions */}
{strategyData.performance_predictions.traffic_predictions && (
<Box sx={{
p: 2,
border: `1px solid ${ANALYSIS_CARD_STYLES.colors.success}`,
borderRadius: 2,
background: `rgba(76, 175, 80, 0.1)`,
minHeight: 80,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
overflow: 'hidden'
}}>
<Typography variant="body2" sx={{
color: ANALYSIS_CARD_STYLES.colors.success,
fontWeight: 600,
mb: 1,
fontSize: '0.8rem',
lineHeight: 1.2,
wordBreak: 'break-word'
}}>
Traffic Growth
</Typography>
<Typography variant="caption" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
fontSize: '0.7rem',
lineHeight: 1.3,
wordBreak: 'break-word'
}}>
{strategyData.performance_predictions.traffic_predictions.growth_rate || '150% increase'}
</Typography>
</Box>
)}
{/* Engagement Predictions */}
{strategyData.performance_predictions.engagement_predictions && (
<Box sx={{
p: 2,
border: `1px solid ${ANALYSIS_CARD_STYLES.colors.secondary}`,
borderRadius: 2,
background: `rgba(118, 75, 162, 0.1)`,
minHeight: 80,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
overflow: 'hidden'
}}>
<Typography variant="body2" sx={{
color: ANALYSIS_CARD_STYLES.colors.secondary,
fontWeight: 600,
mb: 1,
fontSize: '0.8rem',
lineHeight: 1.2,
wordBreak: 'break-word'
}}>
Engagement Rate
</Typography>
<Typography variant="caption" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
fontSize: '0.7rem',
lineHeight: 1.3,
wordBreak: 'break-word'
}}>
{strategyData.performance_predictions.engagement_predictions.engagement_rate || '45% improvement'}
</Typography>
</Box>
)}
{/* Conversion Predictions */}
{strategyData.performance_predictions.conversion_predictions && (
<Box sx={{
p: 2,
border: `1px solid ${ANALYSIS_CARD_STYLES.colors.accent}`,
borderRadius: 2,
background: `rgba(240, 147, 251, 0.1)`,
minHeight: 80,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
overflow: 'hidden'
}}>
<Typography variant="body2" sx={{
color: ANALYSIS_CARD_STYLES.colors.accent,
fontWeight: 600,
mb: 1,
fontSize: '0.8rem',
lineHeight: 1.2,
wordBreak: 'break-word'
}}>
Conversion Rate
</Typography>
<Typography variant="caption" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
fontSize: '0.7rem',
lineHeight: 1.3,
wordBreak: 'break-word'
}}>
{strategyData.performance_predictions.conversion_predictions.conversion_rate || '3.2% to 5.8%'}
</Typography>
</Box>
)}
{/* Engagement Metrics */}
{strategyData.performance_predictions.engagement_metrics && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Engagement Metrics
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<List dense>
{strategyData.performance_predictions.engagement_metrics.bounce_rate && (
<ListItem sx={{ ...listItemStyles.listItem, py: 1.5 }}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.warning,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary="Bounce Rate"
secondary={strategyData.performance_predictions.engagement_metrics.bounce_rate}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.warning, fontWeight: 600, mb: 0.5 }
}}
secondaryTypographyProps={{
variant: 'caption',
fontSize: '0.75rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.text.secondary, lineHeight: 1.4 }
}}
/>
</ListItem>
)}
{strategyData.performance_predictions.engagement_metrics.time_on_page && (
<ListItem sx={{ ...listItemStyles.listItem, py: 1.5 }}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.success,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary="Time on Page"
secondary={strategyData.performance_predictions.engagement_metrics.time_on_page}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.success, fontWeight: 600, mb: 0.5 }
}}
secondaryTypographyProps={{
variant: 'caption',
fontSize: '0.75rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.text.secondary, lineHeight: 1.4 }
}}
/>
</ListItem>
)}
{strategyData.performance_predictions.engagement_metrics.social_shares && (
<ListItem sx={{ ...listItemStyles.listItem, py: 1.5 }}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.info,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary="Social Shares"
secondary={strategyData.performance_predictions.engagement_metrics.social_shares}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.info, fontWeight: 600, mb: 0.5 }
}}
secondaryTypographyProps={{
variant: 'caption',
fontSize: '0.75rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.text.secondary, lineHeight: 1.4 }
}}
/>
</ListItem>
)}
</List>
</Box>
</Box>
</Box>
)}
{/* Conversion Predictions */}
{strategyData.performance_predictions.conversion_predictions && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Conversion Predictions
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<List dense>
{strategyData.performance_predictions.conversion_predictions.content_downloads && (
<ListItem sx={{ ...listItemStyles.listItem, py: 1.5 }}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.primary,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary="Content Downloads"
secondary={strategyData.performance_predictions.conversion_predictions.content_downloads}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.primary, fontWeight: 600, mb: 0.5 }
}}
secondaryTypographyProps={{
variant: 'caption',
fontSize: '0.75rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.text.secondary, lineHeight: 1.4 }
}}
/>
</ListItem>
)}
{strategyData.performance_predictions.conversion_predictions.email_signups && (
<ListItem sx={{ ...listItemStyles.listItem, py: 1.5 }}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.secondary,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary="Email Signups"
secondary={strategyData.performance_predictions.conversion_predictions.email_signups}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.secondary, fontWeight: 600, mb: 0.5 }
}}
secondaryTypographyProps={{
variant: 'caption',
fontSize: '0.75rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.text.secondary, lineHeight: 1.4 }
}}
/>
</ListItem>
)}
{strategyData.performance_predictions.conversion_predictions.lead_generation && (
<ListItem sx={{ ...listItemStyles.listItem, py: 1.5 }}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.accent,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary="Lead Generation"
secondary={strategyData.performance_predictions.conversion_predictions.lead_generation}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.accent, fontWeight: 600, mb: 0.5 }
}}
secondaryTypographyProps={{
variant: 'caption',
fontSize: '0.75rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.text.secondary, lineHeight: 1.4 }
}}
/>
</ListItem>
)}
</List>
</Box>
</Box>
)}
<Divider sx={{ my: 2, opacity: 0.2, borderColor: ANALYSIS_CARD_STYLES.colors.border.secondary }} />
{/* Detailed Predictions */}
{/* Success Factors */}
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Detailed Predictions
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<List dense>
{/* Traffic Predictions */}
{strategyData.performance_predictions.traffic_predictions && (
<ListItem sx={{ ...listItemStyles.listItem, py: 1.5 }}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.success,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary="Traffic Growth"
secondary={`${strategyData.performance_predictions.traffic_predictions.growth_rate || '150% increase'} in organic visitors`}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.success, fontWeight: 600, mb: 0.5 }
}}
secondaryTypographyProps={{
variant: 'caption',
fontSize: '0.75rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.text.secondary, lineHeight: 1.4 }
}}
/>
</ListItem>
)}
{/* Engagement Predictions */}
{strategyData.performance_predictions.engagement_predictions && (
<ListItem sx={{ ...listItemStyles.listItem, py: 1.5 }}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.secondary,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary="Engagement Rate"
secondary={`${strategyData.performance_predictions.engagement_predictions.engagement_rate || '45% improvement'} in user interaction`}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.secondary, fontWeight: 600, mb: 0.5 }
}}
secondaryTypographyProps={{
variant: 'caption',
fontSize: '0.75rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.text.secondary, lineHeight: 1.4 }
}}
/>
</ListItem>
)}
{/* Conversion Predictions */}
{strategyData.performance_predictions.conversion_predictions && (
<ListItem sx={{ ...listItemStyles.listItem, py: 1.5 }}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.accent,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary="Conversion Rate"
secondary={`${strategyData.performance_predictions.conversion_predictions.conversion_rate || '3.2% to 5.8%'} improvement`}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.accent, fontWeight: 600, mb: 0.5 }
}}
secondaryTypographyProps={{
variant: 'caption',
fontSize: '0.75rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.text.secondary, lineHeight: 1.4 }
}}
/>
</ListItem>
)}
{/* ROI Predictions */}
{strategyData.performance_predictions.roi_predictions && (
<ListItem sx={{ ...listItemStyles.listItem, py: 1.5 }}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.success,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary="Revenue Impact"
secondary={`${(strategyData.performance_predictions.roi_predictions as any)?.revenue_impact || '$50K'} additional monthly revenue`}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.success, fontWeight: 600, mb: 0.5 }
}}
secondaryTypographyProps={{
variant: 'caption',
fontSize: '0.75rem',
sx: { color: ANALYSIS_CARD_STYLES.colors.text.secondary, lineHeight: 1.4 }
}}
/>
</ListItem>
)}
</List>
</Box>
</Box>
{/* Timeline Projections */}
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Timeline Projections
Success Factors
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
@@ -492,28 +528,28 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
fontSize: '0.8rem',
lineHeight: 1.5
}}>
Month 1-2: Initial setup and foundation building
High success probability of {strategyData.performance_predictions.success_probability || '85%'}
</Typography>
<Typography variant="body2" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
fontSize: '0.8rem',
lineHeight: 1.5
}}>
Month 3-4: Content creation and optimization
Expected ROI of {strategyData.performance_predictions.estimated_roi || '20-30%'}
</Typography>
<Typography variant="body2" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
fontSize: '0.8rem',
lineHeight: 1.5
}}>
Month 5-6: Scaling and performance optimization
Traffic growth from {strategyData.performance_predictions.traffic_growth?.month_3 || '25%'} to {strategyData.performance_predictions.traffic_growth?.month_12 || '100%'}
</Typography>
<Typography variant="body2" sx={{
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
fontSize: '0.8rem',
lineHeight: 1.5
}}>
Ongoing: Continuous monitoring and improvement
Lead generation improvement of {strategyData.performance_predictions.conversion_predictions?.lead_generation || '5-8%'}
</Typography>
</Box>
</Box>

View File

@@ -278,13 +278,13 @@ const RiskAssessmentCard: React.FC<RiskAssessmentCardProps> = ({ strategyData })
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<List dense>
{strategyData.risk_assessment.mitigation_strategies.map((strategy: string, index: number) => (
{strategyData.risk_assessment.mitigation_strategies.map((strategy: any, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<CheckCircleIcon sx={{ color: ANALYSIS_CARD_STYLES.colors.success, fontSize: 16 }} />
</ListItemIcon>
<ListItemText
primary={strategy}
primary={typeof strategy === 'string' ? strategy : strategy.mitigation || strategy.risk || 'Mitigation strategy'}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
@@ -305,31 +305,36 @@ const RiskAssessmentCard: React.FC<RiskAssessmentCardProps> = ({ strategyData })
Risk Categories
</Typography>
{Object.entries(strategyData.risk_assessment.risk_categories).map(([category, risks]: [string, any]) => (
<Accordion key={category} defaultExpanded={false} sx={accordionStyles.accordion}>
<AccordionSummary
expandIcon={<ExpandMoreIcon sx={accordionStyles.expandIcon} />}
sx={accordionStyles.accordionSummary}
>
<Box sx={{ display: 'flex', alignItems: 'center', width: '100%' }}>
<Box sx={{ mr: 1.5 }}>
<WarningIcon sx={{ color: ANALYSIS_CARD_STYLES.colors.warning, fontSize: 20 }} />
{Object.entries(strategyData.risk_assessment.risk_categories).map(([category, risks]: [string, any]) => {
// Skip empty arrays or null values
if (!risks || !Array.isArray(risks) || risks.length === 0) {
return null;
}
return (
<Accordion key={category} defaultExpanded={false} sx={accordionStyles.accordion}>
<AccordionSummary
expandIcon={<ExpandMoreIcon sx={accordionStyles.expandIcon} />}
sx={accordionStyles.accordionSummary}
>
<Box sx={{ display: 'flex', alignItems: 'center', width: '100%' }}>
<Box sx={{ mr: 1.5 }}>
<WarningIcon sx={{ color: ANALYSIS_CARD_STYLES.colors.warning, fontSize: 20 }} />
</Box>
<Box sx={{ flex: 1 }}>
<Typography variant="body2" sx={accordionStyles.accordionTitle}>
{category.replace(/_/g, ' ')}
</Typography>
<Typography variant="caption" sx={accordionStyles.accordionSubtitle}>
{risks.length} risks
</Typography>
</Box>
</Box>
<Box sx={{ flex: 1 }}>
<Typography variant="body2" sx={accordionStyles.accordionTitle}>
{category.replace(/_/g, ' ')}
</Typography>
<Typography variant="caption" sx={accordionStyles.accordionSubtitle}>
{Array.isArray(risks) ? `${risks.length} risks` : 'Risk category'}
</Typography>
</Box>
</Box>
</AccordionSummary>
<AccordionDetails sx={{ pt: 0 }}>
<Box sx={sectionStyles.sectionContainer}>
{Array.isArray(risks) ? (
</AccordionSummary>
<AccordionDetails sx={{ pt: 0 }}>
<Box sx={sectionStyles.sectionContainer}>
<List dense>
{risks.map((risk: string, index: number) => (
{risks.map((risk: any, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
@@ -341,7 +346,7 @@ const RiskAssessmentCard: React.FC<RiskAssessmentCardProps> = ({ strategyData })
}} />
</ListItemIcon>
<ListItemText
primary={risk}
primary={typeof risk === 'string' ? risk : risk.risk || 'Risk'}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
@@ -351,35 +356,38 @@ const RiskAssessmentCard: React.FC<RiskAssessmentCardProps> = ({ strategyData })
</ListItem>
))}
</List>
) : (
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, fontSize: '0.875rem' }}>
{typeof risks === 'string' ? risks : 'Risk category details'}
</Typography>
)}
</Box>
</AccordionDetails>
</Accordion>
))}
</Box>
</AccordionDetails>
</Accordion>
);
})}
</Box>
)}
{/* Monitoring Framework */}
{strategyData.risk_assessment.monitoring_framework && (
{strategyData.risk_assessment.monitoring_framework && Object.keys(strategyData.risk_assessment.monitoring_framework).length > 0 && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Monitoring Framework
</Typography>
<Box sx={sectionStyles.sectionContainer}>
{Object.entries(strategyData.risk_assessment.monitoring_framework).map(([key, value]: [string, any]) => (
<Box key={key} sx={{ mb: 1 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.primary, fontWeight: 600, mb: 0.5 }}>
{key.replace(/_/g, ' ')}
</Typography>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, fontSize: '0.875rem' }}>
{typeof value === 'string' ? value : JSON.stringify(value)}
</Typography>
</Box>
))}
{Object.entries(strategyData.risk_assessment.monitoring_framework).map(([key, value]: [string, any]) => {
// Skip empty values
if (!value || (Array.isArray(value) && value.length === 0)) {
return null;
}
return (
<Box key={key} sx={{ mb: 1 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.primary, fontWeight: 600, mb: 0.5 }}>
{key.replace(/_/g, ' ')}
</Typography>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, fontSize: '0.875rem' }}>
{typeof value === 'string' ? value : JSON.stringify(value)}
</Typography>
</Box>
);
})}
</Box>
</Box>
)}

View File

@@ -20,15 +20,13 @@ import {
Business as BusinessIcon,
Analytics as AnalyticsIcon
} from '@mui/icons-material';
import { motion } from 'framer-motion';
import { StrategyData } from '../types/strategy.types';
import {
ANALYSIS_CARD_STYLES,
getSectionStyles,
getAccordionStyles,
getEnhancedChipStyles,
getListItemStyles,
getAnimationStyles
getListItemStyles
} from '../styles';
import ProgressiveCard from './ProgressiveCard';
@@ -41,10 +39,16 @@ const StrategicInsightsCard: React.FC<StrategicInsightsCardProps> = ({ strategyD
const sectionStyles = getSectionStyles();
const accordionStyles = getAccordionStyles();
const listItemStyles = getListItemStyles();
const animationStyles = getAnimationStyles();
console.log('🔍 StrategicInsightsCard - strategyData:', strategyData);
console.log('🔍 StrategicInsightsCard - strategic_insights:', strategyData?.strategic_insights);
console.log('🔍 StrategicInsightsCard - market_positioning:', strategyData?.strategic_insights?.market_positioning);
console.log('🔍 StrategicInsightsCard - swot_analysis:', strategyData?.strategic_insights?.market_positioning?.swot_analysis);
console.log('🔍 StrategicInsightsCard - strengths:', strategyData?.strategic_insights?.market_positioning?.swot_analysis?.strengths);
console.log('🔍 StrategicInsightsCard - opportunities:', strategyData?.strategic_insights?.market_positioning?.swot_analysis?.opportunities);
console.log('🔍 StrategicInsightsCard - content_opportunities:', strategyData?.strategic_insights?.content_opportunities);
console.log('🔍 StrategicInsightsCard - growth_potential:', strategyData?.strategic_insights?.growth_potential);
console.log('🔍 StrategicInsightsCard - swot_summary:', strategyData?.strategic_insights?.swot_summary);
if (!strategyData?.strategic_insights) {
return (
@@ -105,25 +109,27 @@ const StrategicInsightsCard: React.FC<StrategicInsightsCardProps> = ({ strategyD
fontWeight: 600,
boxShadow: `0 4px 12px ${ANALYSIS_CARD_STYLES.colors.success}30`
}}>
85%
{strategyData.strategic_insights.market_positioning?.positioning_strength ||
strategyData.strategic_insights.swot_summary?.overall_score ||
85}%
</Box>
<Box>
<Typography variant="h6" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, fontWeight: 600 }}>
Market Analysis
</Typography>
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
Strong market positioning identified
{strategyData.strategic_insights.market_positioning?.current_position || 'Strong'} market positioning identified
</Typography>
</Box>
</Box>
<Box sx={{ display: 'flex', gap: 1 }}>
<Chip
label="High Growth"
label={strategyData.strategic_insights.growth_potential?.growth_rate || "High Growth"}
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.success).chip}
/>
<Chip
label="6 months"
label={strategyData.strategic_insights.growth_potential?.market_size || "Growing Market"}
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.info).chip}
/>
@@ -137,22 +143,52 @@ const StrategicInsightsCard: React.FC<StrategicInsightsCardProps> = ({ strategyD
Key Insights Preview
</Typography>
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
{strategyData.strategic_insights.insights?.slice(0, 3).map((insight: any, index: number) => (
{/* Show content opportunities as key insights */}
{strategyData.strategic_insights.content_opportunities?.slice(0, 2).map((opportunity: string, index: number) => (
<Chip
key={index}
label={insight.type}
key={`content-${index}`}
label={`Opportunity ${index + 1}`}
size="small"
icon={getInsightIcon(insight.type)}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.primary).chip}
icon={<LightbulbIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.success).chip}
/>
))}
{(strategyData.strategic_insights.insights?.length || 0) > 3 && (
{/* Show growth drivers as key insights */}
{strategyData.strategic_insights.growth_potential?.key_drivers?.slice(0, 1).map((driver: string, index: number) => (
<Chip
label={`+${(strategyData.strategic_insights.insights?.length || 0) - 3} more`}
key={`driver-${index}`}
label="Growth Driver"
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.secondary).chip}
icon={<TrendingUpIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.warning).chip}
/>
)}
))}
{/* Show SWOT insights */}
{(() => {
const strengthsLength = strategyData.strategic_insights.market_positioning?.swot_analysis?.strengths?.length || 0;
const opportunitiesLength = strategyData.strategic_insights.market_positioning?.swot_analysis?.opportunities?.length || 0;
return (
<>
{strengthsLength > 0 && (
<Chip
label={`${strengthsLength} Strengths`}
size="small"
icon={<AnalyticsIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.primary).chip}
/>
)}
{opportunitiesLength > 0 && (
<Chip
label={`${opportunitiesLength} Opportunities`}
size="small"
icon={<PsychologyIcon />}
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.info).chip}
/>
)}
</>
);
})()}
</Box>
</Box>
</Box>
@@ -161,6 +197,244 @@ const StrategicInsightsCard: React.FC<StrategicInsightsCardProps> = ({ strategyD
// Detailed content - shown on expansion
const detailedContent = (
<Box>
{/* Market Positioning */}
{strategyData.strategic_insights.market_positioning && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Market Positioning
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<Box sx={{ display: 'flex', gap: 2, mb: 2 }}>
<Chip
label={`Position: ${strategyData.strategic_insights.market_positioning.current_position}`}
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.primary).chip}
/>
<Chip
label={`Strength: ${strategyData.strategic_insights.market_positioning.positioning_strength}%`}
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.success).chip}
/>
</Box>
{/* SWOT Analysis */}
{strategyData.strategic_insights.market_positioning.swot_analysis && (
<Box>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 1, fontWeight: 500 }}>
SWOT Analysis
</Typography>
{/* Strengths */}
{strategyData.strategic_insights.market_positioning.swot_analysis.strengths &&
strategyData.strategic_insights.market_positioning.swot_analysis.strengths.length > 0 && (
<Box sx={{ mb: 2 }}>
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.success, fontWeight: 600, display: 'block', mb: 1 }}>
Strengths ({strategyData.strategic_insights.market_positioning.swot_analysis.strengths.length})
</Typography>
<List dense>
{strategyData.strategic_insights.market_positioning.swot_analysis.strengths.map((strength: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.success,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={strength}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
{/* Opportunities */}
{strategyData.strategic_insights.market_positioning.swot_analysis.opportunities &&
strategyData.strategic_insights.market_positioning.swot_analysis.opportunities.length > 0 && (
<Box sx={{ mb: 2 }}>
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.info, fontWeight: 600, display: 'block', mb: 1 }}>
Opportunities ({strategyData.strategic_insights.market_positioning.swot_analysis.opportunities.length})
</Typography>
<List dense>
{strategyData.strategic_insights.market_positioning.swot_analysis.opportunities.map((opportunity: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.info,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={opportunity}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
</Box>
)}
</Box>
</Box>
)}
{/* Growth Potential */}
{strategyData.strategic_insights.growth_potential && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
Growth Potential
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<Box sx={{ display: 'flex', gap: 2, mb: 2 }}>
<Chip
label={`Market: ${strategyData.strategic_insights.growth_potential.market_size}`}
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.primary).chip}
/>
<Chip
label={`Growth: ${strategyData.strategic_insights.growth_potential.growth_rate}`}
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.success).chip}
/>
</Box>
{/* Key Drivers */}
{strategyData.strategic_insights.growth_potential.key_drivers &&
strategyData.strategic_insights.growth_potential.key_drivers.length > 0 && (
<Box>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 1, fontWeight: 500 }}>
Key Growth Drivers ({strategyData.strategic_insights.growth_potential.key_drivers.length})
</Typography>
<List dense>
{strategyData.strategic_insights.growth_potential.key_drivers.map((driver: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.warning,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={driver}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
</Box>
</Box>
)}
{/* SWOT Summary */}
{strategyData.strategic_insights.swot_summary && (
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.primary, mb: 2, fontWeight: 600 }}>
SWOT Summary
</Typography>
<Box sx={sectionStyles.sectionContainer}>
<Box sx={{ display: 'flex', gap: 2, mb: 2 }}>
<Chip
label={`Overall Score: ${strategyData.strategic_insights.swot_summary.overall_score}%`}
size="small"
sx={getEnhancedChipStyles(ANALYSIS_CARD_STYLES.colors.success).chip}
/>
</Box>
{/* Primary Strengths */}
{strategyData.strategic_insights.swot_summary.primary_strengths &&
strategyData.strategic_insights.swot_summary.primary_strengths.length > 0 && (
<Box sx={{ mb: 2 }}>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.success, fontWeight: 600, mb: 1 }}>
Primary Strengths ({strategyData.strategic_insights.swot_summary.primary_strengths.length})
</Typography>
<List dense>
{strategyData.strategic_insights.swot_summary.primary_strengths.map((strength: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.success,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={strength}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
{/* Key Opportunities */}
{strategyData.strategic_insights.swot_summary.key_opportunities &&
strategyData.strategic_insights.swot_summary.key_opportunities.length > 0 && (
<Box>
<Typography variant="body2" sx={{ color: ANALYSIS_CARD_STYLES.colors.info, fontWeight: 600, mb: 1 }}>
Key Opportunities ({strategyData.strategic_insights.swot_summary.key_opportunities.length})
</Typography>
<List dense>
{strategyData.strategic_insights.swot_summary.key_opportunities.map((opportunity: string, index: number) => (
<ListItem key={index} sx={listItemStyles.listItem}>
<ListItemIcon sx={listItemStyles.listItemIcon}>
<Box sx={{
width: 6,
height: 6,
borderRadius: '50%',
background: ANALYSIS_CARD_STYLES.colors.info,
opacity: 0.7
}} />
</ListItemIcon>
<ListItemText
primary={opportunity}
primaryTypographyProps={{
variant: 'body2',
fontSize: '0.875rem',
sx: { lineHeight: 1.4, color: ANALYSIS_CARD_STYLES.colors.text.primary }
}}
/>
</ListItem>
))}
</List>
</Box>
)}
</Box>
</Box>
)}
{/* Strategic Insights by Type */}
{strategyData.strategic_insights.insights && strategyData.strategic_insights.insights.length > 0 && (
<Box sx={{ mb: 3 }}>

View File

@@ -25,15 +25,23 @@ export const useStrategyData = () => {
try {
const latestStrategyResponse = await contentPlanningApi.getLatestGeneratedStrategy(userId);
if (latestStrategyResponse?.strategy) {
console.log('✅ Found latest generated strategy from polling system:', latestStrategyResponse.strategy);
console.log('🔍 Latest strategy response from API:', latestStrategyResponse);
console.log('🔍 Response type:', typeof latestStrategyResponse);
console.log('🔍 Response keys:', Object.keys(latestStrategyResponse || {}));
if (latestStrategyResponse && latestStrategyResponse.strategic_insights) {
// If the response itself is the strategy data (after API extraction)
console.log('✅ Found latest generated strategy (direct response):', latestStrategyResponse);
console.log('🔍 Direct response keys:', Object.keys(latestStrategyResponse));
const transformedStrategy = transformPollingStrategyData(latestStrategyResponse.strategy);
const transformedStrategy = transformPollingStrategyData(latestStrategyResponse);
console.log('🔄 Transformed strategy data:', transformedStrategy);
setStrategyData(transformedStrategy);
setLoading(false);
return;
} else {
console.log('❌ No strategy data found in response');
}
} catch (pollingError) {
console.log('No latest strategy found in polling system, checking database...', pollingError);

View File

@@ -71,6 +71,22 @@ export interface CompetitiveAnalysis {
export interface PerformancePredictions {
estimated_roi?: string;
success_probability?: string;
traffic_growth?: {
month_3?: string;
month_6?: string;
month_12?: string;
};
engagement_metrics?: {
bounce_rate?: string;
social_shares?: string;
time_on_page?: string;
};
conversion_predictions?: {
content_downloads?: string;
email_signups?: string;
lead_generation?: string;
};
key_metrics?: {
engagement_rate?: string;
conversion_rate?: string;
@@ -92,7 +108,7 @@ export interface PerformancePredictions {
weakness_mitigation: string;
threat_management: string;
};
// Nested prediction objects from backend
// Legacy nested prediction objects (keeping for backward compatibility)
traffic_predictions?: {
monthly_traffic?: string;
growth_rate?: string;
@@ -106,7 +122,7 @@ export interface PerformancePredictions {
month_3?: string;
success_factors?: string[];
};
conversion_predictions?: {
conversion_predictions_legacy?: {
conversion_rate?: string;
lead_generation?: string;
month_6?: string;
@@ -122,6 +138,7 @@ export interface PerformancePredictions {
export interface ImplementationRoadmap {
total_duration?: string;
timeline?: string;
phases?: Array<{
phase: string;
duration: string;
@@ -130,6 +147,10 @@ export interface ImplementationRoadmap {
resources: string[]; // Added to match backend
swot_focus?: string;
}>;
milestones?: string[]; // Added to match backend data
resource_requirements?: string[]; // Added to match backend data
critical_path?: string[]; // Added to match backend data
success_metrics?: string[]; // Added to match backend
resource_allocation?: {
team_members?: string[]; // Changed from team_requirements to match backend
team_requirements?: string[]; // Added to match backend data
@@ -146,8 +167,7 @@ export interface ImplementationRoadmap {
low_priority: string[];
};
};
success_metrics?: string[]; // Added to match backend
timeline?: {
timeline_object?: {
start_date?: string;
end_date?: string;
key_milestones?: string[];

View File

@@ -11,18 +11,175 @@ export const getUserId = (): number => {
* Transform polling system strategy data to frontend format
*/
export const transformPollingStrategyData = (strategyData: any): StrategyData => {
return {
...strategyData,
console.log('🔄 Transforming polling strategy data:', strategyData);
console.log('🔄 Strategy data type:', typeof strategyData);
console.log('🔄 Strategy data keys:', Object.keys(strategyData || {}));
// Extract the actual strategy components from the backend structure
const strategicInsights = strategyData.strategic_insights;
const competitiveAnalysis = strategyData.competitive_analysis;
const performancePredictions = strategyData.performance_predictions;
const implementationRoadmap = strategyData.implementation_roadmap;
const riskAssessment = strategyData.risk_assessment;
console.log('📊 Extracted components:', {
hasStrategicInsights: !!strategicInsights,
hasCompetitiveAnalysis: !!competitiveAnalysis,
hasPerformancePredictions: !!performancePredictions,
hasImplementationRoadmap: !!implementationRoadmap,
hasRiskAssessment: !!riskAssessment
});
console.log('🔍 Strategic Insights Raw Data:', strategicInsights);
console.log('🔍 Competitive Analysis Raw Data:', competitiveAnalysis);
console.log('🔍 Performance Predictions Raw Data:', performancePredictions);
console.log('🔍 Implementation Roadmap Raw Data:', implementationRoadmap);
console.log('🔍 Risk Assessment Raw Data:', riskAssessment);
const transformedData = {
// Map metadata
strategy_metadata: strategyData.metadata || strategyData.strategy_metadata,
// Add summary if not present
metadata: strategyData.metadata || strategyData.strategy_metadata,
// Transform Strategic Insights - map the actual backend structure
strategic_insights: strategicInsights ? {
market_positioning: {
positioning_strength: strategicInsights.market_positioning?.positioning_strength || 75,
current_position: strategicInsights.market_positioning?.current_position || "Emerging",
swot_analysis: {
strengths: strategicInsights.market_positioning?.swot_analysis?.strengths || [],
opportunities: strategicInsights.market_positioning?.swot_analysis?.opportunities || []
}
},
content_opportunities: strategicInsights.content_opportunities || [],
growth_potential: {
market_size: strategicInsights.growth_potential?.market_size || "Growing",
growth_rate: strategicInsights.growth_potential?.growth_rate || "High",
key_drivers: strategicInsights.growth_potential?.key_drivers || [],
competitive_advantages: strategicInsights.growth_potential?.competitive_advantages || []
},
swot_summary: {
overall_score: strategicInsights.swot_summary?.overall_score || 75,
primary_strengths: strategicInsights.swot_summary?.primary_strengths || [],
key_opportunities: strategicInsights.swot_summary?.key_opportunities || []
},
// Add insights array if it exists in the backend data
insights: strategicInsights.insights || []
} : undefined,
// Transform Competitive Analysis - map the actual backend structure
competitive_analysis: competitiveAnalysis ? {
competitors: competitiveAnalysis.competitors || [],
market_gaps: competitiveAnalysis.market_gaps || [],
opportunities: competitiveAnalysis.opportunities || [],
recommendations: competitiveAnalysis.recommendations || [],
competitive_advantages: {
primary: competitiveAnalysis.competitive_advantages?.primary || [],
sustainable: competitiveAnalysis.competitive_advantages?.sustainable || [],
development_areas: competitiveAnalysis.competitive_advantages?.development_areas || []
},
swot_competitive_insights: {
leverage_strengths: competitiveAnalysis.swot_competitive_insights?.leverage_strengths || [],
address_weaknesses: competitiveAnalysis.swot_competitive_insights?.address_weaknesses || [],
capitalize_opportunities: competitiveAnalysis.swot_competitive_insights?.capitalize_opportunities || [],
mitigate_threats: competitiveAnalysis.swot_competitive_insights?.mitigate_threats || []
}
} : undefined,
// Transform Performance Predictions - map the actual backend structure
performance_predictions: performancePredictions ? {
estimated_roi: performancePredictions.estimated_roi || "15-25%",
key_metrics: {
engagement_rate: performancePredictions.engagement_metrics?.time_on_page || "3-5 minutes",
conversion_rate: performancePredictions.conversion_predictions?.lead_generation || "5-8%",
reach_growth: performancePredictions.traffic_growth?.month_12 || "100%",
brand_awareness: performancePredictions.engagement_metrics?.social_shares || "15-25 per post",
market_share: performancePredictions.success_probability || "85%"
},
timeline_projections: {
"month_1": "Initial setup and content creation",
"month_3": performancePredictions.traffic_growth?.month_3 || "25% growth",
"month_6": performancePredictions.traffic_growth?.month_6 || "50% growth",
"month_12": performancePredictions.traffic_growth?.month_12 || "100% growth"
},
success_factors: {
primary: performancePredictions.conversion_predictions ? [
`Lead generation: ${performancePredictions.conversion_predictions.lead_generation}`,
`Email signups: ${performancePredictions.conversion_predictions.email_signups}`,
`Content downloads: ${performancePredictions.conversion_predictions.content_downloads}`
] : [],
secondary: performancePredictions.engagement_metrics ? [
`Time on page: ${performancePredictions.engagement_metrics.time_on_page}`,
`Bounce rate: ${performancePredictions.engagement_metrics.bounce_rate}`
] : [],
risk_mitigation: performancePredictions.success_probability ? [
`Success probability: ${performancePredictions.success_probability}`
] : []
},
swot_based_predictions: {
strength_impact: "High positive impact from identified strengths",
opportunity_impact: "Significant growth potential from market opportunities",
weakness_mitigation: "Addressing weaknesses through strategic content planning",
threat_management: "Proactive threat management through diversified approach"
}
} : undefined,
// Transform Implementation Roadmap - map the actual backend structure
implementation_roadmap: implementationRoadmap ? {
timeline: implementationRoadmap.timeline || "12 months",
phases: implementationRoadmap.phases || [],
milestones: implementationRoadmap.milestones || [],
resource_requirements: implementationRoadmap.resource_requirements || [],
critical_path: implementationRoadmap.critical_path || [],
success_metrics: implementationRoadmap.success_metrics || [],
timeline_object: {
start_date: "2024-09-01",
end_date: "2025-08-31",
key_milestones: implementationRoadmap.milestones || []
},
resource_allocation: {
team_members: implementationRoadmap.resource_requirements || [],
team_requirements: implementationRoadmap.resource_requirements || [],
budget_allocation: {
total_budget: "$60,000",
content_creation: "$30,000",
technology_tools: "$5,000",
marketing_promotion: "$20,000",
external_resources: "$5,000"
},
swot_priorities: {
high_priority: implementationRoadmap.success_metrics?.slice(0, 3) || [],
medium_priority: implementationRoadmap.success_metrics?.slice(3, 6) || [],
low_priority: implementationRoadmap.success_metrics?.slice(6, 9) || []
}
}
} : undefined,
// Transform Risk Assessment - map the actual backend structure
risk_assessment: riskAssessment ? {
overall_risk_level: riskAssessment.overall_risk_level || "Medium",
risks: riskAssessment.risks || [],
risk_categories: {
market_risks: riskAssessment.risk_categories?.market_risks || [],
operational_risks: riskAssessment.risk_categories?.operational_risks || [],
competitive_risks: riskAssessment.risk_categories?.competitive_risks || [],
technical_risks: riskAssessment.risk_categories?.technical_risks || [],
financial_risks: riskAssessment.risk_categories?.financial_risks || []
}
} : undefined,
// Add summary
summary: strategyData.summary || {
estimated_roi: strategyData.performance_predictions?.estimated_roi || "15-25%",
implementation_timeline: strategyData.implementation_roadmap?.total_duration || "12 months",
risk_level: strategyData.risk_assessment?.overall_risk_level || "Medium",
success_probability: strategyData.performance_predictions?.success_probability || "85%",
estimated_roi: performancePredictions?.estimated_roi || "15-25%",
implementation_timeline: implementationRoadmap?.timeline || "12 months",
risk_level: riskAssessment?.overall_risk_level || "Medium",
success_probability: performancePredictions?.success_probability || "85%",
next_step: "Review strategy and generate content calendar"
}
};
console.log('✅ Transformed Polling Strategy Data:', transformedData);
return transformedData;
};
/**
@@ -115,21 +272,22 @@ export const transformFullStructureData = (latestStrategy: any): StrategyData =>
// Transform Implementation Roadmap
implementation_roadmap: comprehensiveData.implementation_roadmap ? {
total_duration: comprehensiveData.implementation_roadmap.total_duration || "6 months",
timeline: comprehensiveData.implementation_roadmap.timeline || "6 months",
phases: comprehensiveData.implementation_roadmap.phases || [],
milestones: comprehensiveData.implementation_roadmap.milestones || [],
resource_requirements: comprehensiveData.implementation_roadmap.resource_requirements || [],
critical_path: comprehensiveData.implementation_roadmap.critical_path || [],
success_metrics: comprehensiveData.implementation_roadmap.success_metrics || [],
timeline: comprehensiveData.implementation_roadmap.timeline || {
timeline_object: comprehensiveData.implementation_roadmap.timeline_object || {
start_date: "2024-09-01",
end_date: "2025-02-28",
key_milestones: []
},
resource_allocation: {
team_members: comprehensiveData.implementation_roadmap.resource_allocation?.team_members ||
comprehensiveData.implementation_roadmap.resource_allocation?.team_requirements ||
["Content Strategist", "SEO Specialist", "Content Writer", "Editor"],
comprehensiveData.implementation_roadmap.resource_allocation?.team_requirements || [],
team_requirements: comprehensiveData.implementation_roadmap.resource_allocation?.team_requirements ||
comprehensiveData.implementation_roadmap.resource_allocation?.team_members ||
["Content Strategist", "SEO Specialist", "Content Writer", "Editor"],
comprehensiveData.implementation_roadmap.resource_allocation?.team_members || [],
budget_allocation: comprehensiveData.implementation_roadmap.resource_allocation?.budget_allocation || {
total_budget: "$60,000",
content_creation: "$30,000",
@@ -290,7 +448,7 @@ export const transformSwotToComprehensiveStructure = (latestStrategy: any): Stra
},
// Enhanced Implementation Roadmap with SWOT considerations
implementation_roadmap: {
total_duration: "12 months",
timeline: "12 months",
phases: [
{
phase: "Foundation (Months 1-3)",
@@ -329,8 +487,36 @@ export const transformSwotToComprehensiveStructure = (latestStrategy: any): Stra
swot_focus: "Strengths and Weaknesses"
}
],
milestones: [
"Brand guidelines", "Content calendar", "SWOT action plan",
"Content library", "Engaged audience", "Risk management framework",
"Market leadership", "Optimized strategy", "Long-term competitive position"
],
resource_requirements: [
"Content Strategist", "SEO Specialist", "Content Writer", "Editor", "Marketing Manager"
],
critical_path: [
"Brand positioning leveraging identified strengths",
"Content execution based on competitive advantages",
"Market expansion capitalizing on strengths"
],
success_metrics: [
"Brand guidelines", "Content calendar", "SWOT action plan",
"Content library", "Engaged audience", "Risk management framework",
"Market leadership", "Optimized strategy", "Long-term competitive position"
],
timeline_object: {
start_date: "2024-01-01",
end_date: "2024-12-31",
key_milestones: [
"Brand guidelines", "Content calendar", "SWOT action plan",
"Content library", "Engaged audience", "Risk management framework",
"Market leadership", "Optimized strategy", "Long-term competitive position"
]
},
resource_allocation: {
team_members: ["Content Strategist", "SEO Specialist", "Content Writer", "Editor", "Marketing Manager"],
team_requirements: ["Content Strategist", "SEO Specialist", "Content Writer", "Editor", "Marketing Manager"],
budget_allocation: {
total_budget: "$60,000",
content_creation: "$30,000",
@@ -343,12 +529,6 @@ export const transformSwotToComprehensiveStructure = (latestStrategy: any): Stra
medium_priority: swotData.strengths || [],
low_priority: swotData.weaknesses || []
}
},
swot_integration: {
strength_leverage: swotData.strengths || [],
weakness_improvement: swotData.weaknesses || [],
opportunity_capitalization: swotData.opportunities || [],
threat_mitigation: swotData.threats || []
}
},
// Enhanced Risk Assessment with SWOT threats

View File

@@ -191,83 +191,83 @@ class ContentPlanningAPI {
// Content Strategy APIs
async createStrategy(strategy: ContentStrategyCreate) {
const response = await apiClient.post(`${this.baseURL}/strategies/`, strategy);
return response.data;
return response.data?.data || response.data;
}
async getStrategies(userId?: number) {
const params = userId ? { user_id: userId } : {};
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies`, { params });
return response.data;
return response.data?.data || response.data;
}
async getStrategy(id: string) {
const response = await apiClient.get(`${this.baseURL}/strategies/${id}`);
return response.data;
return response.data?.data || response.data;
}
async updateStrategy(id: string, updates: ContentStrategyUpdate) {
const response = await apiClient.put(`${this.baseURL}/strategies/${id}`, updates);
return response.data;
return response.data?.data || response.data;
}
async deleteStrategy(id: string) {
const response = await apiClient.delete(`${this.baseURL}/strategies/${id}`);
return response.data;
return response.data?.data || response.data;
}
// Calendar Event APIs
async createEvent(event: CalendarEventCreate) {
const response = await apiClient.post(`${this.baseURL}/calendar-events/`, event);
return response.data;
return response.data?.data || response.data;
}
async getEvents(userId?: number, filters?: any) {
const params = { ...filters };
if (userId) params.user_id = userId;
const response = await apiClient.get(`${this.baseURL}/calendar-events/`, { params });
return response.data;
return response.data?.data || response.data;
}
async getEvent(id: string) {
const response = await apiClient.get(`${this.baseURL}/calendar-events/${id}`);
return response.data;
return response.data?.data || response.data;
}
async updateEvent(id: string, updates: CalendarEventUpdate) {
const response = await apiClient.put(`${this.baseURL}/calendar-events/${id}`, updates);
return response.data;
return response.data?.data || response.data;
}
async deleteEvent(id: string) {
const response = await apiClient.delete(`${this.baseURL}/calendar-events/${id}`);
return response.data;
return response.data?.data || response.data;
}
// Gap Analysis APIs
async createGapAnalysis(analysis: GapAnalysisCreate) {
const response = await apiClient.post(`${this.baseURL}/gap-analysis/`, analysis);
return response.data;
return response.data?.data || response.data;
}
async getGapAnalyses(userId?: number) {
const params = userId ? { user_id: userId } : {};
const response = await apiClient.get(`${this.baseURL}/gap-analysis/`, { params });
return response.data;
return response.data?.data || response.data;
}
async getGapAnalysis(id: string) {
const response = await apiClient.get(`${this.baseURL}/gap-analysis/${id}`);
return response.data;
return response.data?.data || response.data;
}
async updateGapAnalysis(id: string, updates: GapAnalysisUpdate) {
const response = await apiClient.put(`${this.baseURL}/gap-analysis/${id}`, updates);
return response.data;
return response.data?.data || response.data;
}
async deleteGapAnalysis(id: string) {
const response = await apiClient.delete(`${this.baseURL}/gap-analysis/${id}`);
return response.data;
return response.data?.data || response.data;
}
// AI-Powered Gap Analysis - Using AI client for longer timeout
@@ -544,14 +544,14 @@ class ContentPlanningAPI {
const params: any = {};
if (userId) params.user_id = userId;
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies`, { params });
return response.data;
return response.data?.data || response.data;
});
}
async getEnhancedStrategy(strategyId: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/${strategyId}`);
return response.data;
return response.data?.data || response.data;
});
}
@@ -565,21 +565,21 @@ class ContentPlanningAPI {
async getEnhancedStrategyCompletion(strategyId: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/${strategyId}/completion`);
return response.data;
return response.data?.data || response.data;
});
}
async getEnhancedStrategyTooltips(): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/tooltips`);
return response.data;
return response.data?.data || response.data;
});
}
async getEnhancedStrategyDisclosureSteps(): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/disclosure-steps`);
return response.data;
return response.data?.data || response.data;
});
}
@@ -588,7 +588,7 @@ class ContentPlanningAPI {
const params: any = {};
if (userId) params.user_id = userId;
const response = await apiClient.post(`${this.baseURL}/enhanced-strategies/cache/clear`, null, { params });
return response.data;
return response.data?.data || response.data;
}
// Non-streaming autofill refresh method
@@ -596,7 +596,29 @@ class ContentPlanningAPI {
const params: any = { use_ai: useAI, ai_only: aiOnly };
if (userId) params.user_id = userId;
const response = await apiClient.post(`${this.baseURL}/enhanced-strategies/autofill/refresh`, null, { params });
return response.data;
// Debug the API response
console.log('🎯 API refreshAutofill response:', {
responseType: typeof response,
responseKeys: Object.keys(response),
dataType: typeof response.data,
dataKeys: response.data ? Object.keys(response.data) : 'no data',
hasDataProperty: response.data?.hasOwnProperty('data'),
hasFieldsProperty: response.data?.hasOwnProperty('fields'),
dataDataKeys: response.data?.data ? Object.keys(response.data.data) : 'no data.data'
});
// The backend returns ResponseBuilder format: { status, message, data, status_code, timestamp }
// We need to return the actual payload from response.data.data
const result = response.data?.data || response.data;
console.log('🎯 API refreshAutofill returning:', {
resultType: typeof result,
resultKeys: Object.keys(result),
hasFields: result?.hasOwnProperty('fields'),
fieldsCount: result?.fields ? Object.keys(result.fields).length : 0
});
return result;
}
// Enhanced Strategy CRUD Operations
@@ -619,14 +641,14 @@ class ContentPlanningAPI {
return this.handleRequest(async () => {
const params = userId ? { user_id: userId } : {};
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/onboarding-data`, { params });
return response.data;
return response.data?.data || response.data;
});
}
async getOnboardingIntegration(strategyId: string): Promise<any> {
return this.handleRequest(async () => {
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/${strategyId}/onboarding-integration`);
return response.data;
return response.data?.data || response.data;
});
}
@@ -692,7 +714,18 @@ class ContentPlanningAPI {
return this.handleRequest(async () => {
const params = userId ? { user_id: userId } : {};
const response = await apiClient.get(`${this.baseURL}/content-strategy/ai-generation/latest-strategy`, { params });
return response.data;
console.log('🔍 getLatestGeneratedStrategy response:', response.data);
console.log('🔍 Response structure:', {
hasData: !!response.data,
dataKeys: Object.keys(response.data || {}),
hasStrategy: !!response.data?.data?.strategy,
strategyKeys: response.data?.data?.strategy ? Object.keys(response.data.data.strategy) : []
});
// Return the strategy data from the nested response structure
const result = response.data?.data?.strategy;
console.log('🔍 Returning result:', result);
console.log('🔍 Result keys:', Object.keys(result || {}));
return result;
});
}