ALwrity version 0.5.6
This commit is contained in:
@@ -623,11 +623,18 @@ class AIStrategyGenerator:
|
||||
{json.dumps(base_strategy, indent=2)}
|
||||
|
||||
Please provide risk assessment including:
|
||||
1. Risk identification and analysis
|
||||
2. Probability and impact assessment
|
||||
3. Mitigation strategies
|
||||
4. Contingency planning
|
||||
5. Risk monitoring framework
|
||||
1. Risk identification and analysis with detailed risk descriptions
|
||||
2. Probability and impact assessment for each risk
|
||||
3. Specific mitigation strategies for each risk
|
||||
4. Contingency planning for high-impact risks
|
||||
5. Risk monitoring framework with key indicators
|
||||
6. Categorize risks into: technical_risks, market_risks, operational_risks, financial_risks
|
||||
|
||||
IMPORTANT: For risk_categories, categorize each risk into the appropriate category:
|
||||
- technical_risks: Technology, platform, tool, or technical implementation risks
|
||||
- market_risks: Market changes, competition, audience shifts, industry trends
|
||||
- operational_risks: Process, resource, team, or execution risks
|
||||
- financial_risks: Budget, ROI, cost, or financial performance risks
|
||||
|
||||
Format as structured JSON with detailed risk analysis and mitigation plans.
|
||||
"""
|
||||
@@ -652,10 +659,54 @@ class AIStrategyGenerator:
|
||||
"risk_categories": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"technical_risks": {"type": "array", "items": {"type": "string"}},
|
||||
"market_risks": {"type": "array", "items": {"type": "string"}},
|
||||
"operational_risks": {"type": "array", "items": {"type": "string"}},
|
||||
"financial_risks": {"type": "array", "items": {"type": "string"}}
|
||||
"technical_risks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"risk": {"type": "string"},
|
||||
"probability": {"type": "string"},
|
||||
"impact": {"type": "string"},
|
||||
"mitigation": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"market_risks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"risk": {"type": "string"},
|
||||
"probability": {"type": "string"},
|
||||
"impact": {"type": "string"},
|
||||
"mitigation": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"operational_risks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"risk": {"type": "string"},
|
||||
"probability": {"type": "string"},
|
||||
"impact": {"type": "string"},
|
||||
"mitigation": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"financial_risks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"risk": {"type": "string"},
|
||||
"probability": {"type": "string"},
|
||||
"impact": {"type": "string"},
|
||||
"mitigation": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"mitigation_strategies": {"type": "array", "items": {"type": "string"}},
|
||||
@@ -1079,6 +1130,8 @@ class AIStrategyGenerator:
|
||||
|
||||
def _transform_risk_assessment(self, ai_response: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Transform risk assessment to frontend format."""
|
||||
self.logger.info(f"🔍 Transforming risk assessment. Input: {json.dumps(ai_response, indent=2)}")
|
||||
|
||||
transformed = {
|
||||
"risks": [],
|
||||
"overall_risk_level": "Medium",
|
||||
@@ -1097,10 +1150,43 @@ class AIStrategyGenerator:
|
||||
}
|
||||
}
|
||||
|
||||
# Extract overall risk level
|
||||
if ai_response.get("overall_risk_level"):
|
||||
transformed["overall_risk_level"] = ai_response["overall_risk_level"]
|
||||
|
||||
# Extract risk data from AI response
|
||||
risks = ai_response.get("risks", [])
|
||||
if risks:
|
||||
transformed["risks"] = risks[:5] # Limit to 5 risks
|
||||
transformed["mitigation_strategies"] = [risk.get("mitigation", "") for risk in risks[:3]]
|
||||
|
||||
# Extract risk categories from AI response
|
||||
risk_categories = ai_response.get("risk_categories", {})
|
||||
if risk_categories:
|
||||
transformed["risk_categories"] = {
|
||||
"technical_risks": risk_categories.get("technical_risks", []),
|
||||
"market_risks": risk_categories.get("market_risks", []),
|
||||
"operational_risks": risk_categories.get("operational_risks", []),
|
||||
"financial_risks": risk_categories.get("financial_risks", [])
|
||||
}
|
||||
|
||||
# Extract mitigation strategies from AI response
|
||||
mitigation_strategies = ai_response.get("mitigation_strategies", [])
|
||||
if mitigation_strategies:
|
||||
transformed["mitigation_strategies"] = mitigation_strategies
|
||||
else:
|
||||
# Fallback: extract mitigation from individual risks
|
||||
if risks:
|
||||
transformed["mitigation_strategies"] = [risk.get("mitigation", "") for risk in risks[:3] if risk.get("mitigation")]
|
||||
|
||||
# Extract monitoring framework from AI response
|
||||
monitoring_framework = ai_response.get("monitoring_framework", {})
|
||||
if monitoring_framework:
|
||||
transformed["monitoring_framework"] = {
|
||||
"key_indicators": monitoring_framework.get("key_indicators", []),
|
||||
"monitoring_frequency": monitoring_framework.get("monitoring_frequency", "Weekly"),
|
||||
"escalation_procedures": monitoring_framework.get("escalation_procedures", []),
|
||||
"review_schedule": monitoring_framework.get("review_schedule", "Monthly")
|
||||
}
|
||||
|
||||
self.logger.info(f"🔍 Final transformed risk assessment: {json.dumps(transformed, indent=2)}")
|
||||
return transformed
|
||||
@@ -1,134 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,134 +0,0 @@
|
||||
# Educational Modal Auto-Close Fix
|
||||
|
||||
## 🎯 **Issue Summary**
|
||||
|
||||
**Problem**: The educational modal was closing automatically when strategy generation completed, instead of waiting for the user to click the "Next: Review Strategy and Create Calendar" button.
|
||||
|
||||
**Expected Behavior**:
|
||||
1. User clicks "Create Strategy"
|
||||
2. Educational modal opens and shows progress
|
||||
3. Strategy generation completes (100% progress)
|
||||
4. Modal stays open and shows "Next: Review Strategy and Create Calendar" button
|
||||
5. User clicks the button to close modal and navigate to Content Strategy tab
|
||||
|
||||
**Actual Behavior**:
|
||||
1. User clicks "Create Strategy"
|
||||
2. Educational modal opens and shows progress
|
||||
3. Strategy generation completes (100% progress)
|
||||
4. **Modal closes automatically** ❌
|
||||
5. User never sees the "Next" button or gets redirected
|
||||
|
||||
## 🔍 **Root Cause Analysis**
|
||||
|
||||
The issue was in the `ActionButtons.tsx` file in the `onComplete` callback of the polling-based strategy generation:
|
||||
|
||||
```typescript
|
||||
// onComplete callback
|
||||
(strategy: any) => {
|
||||
console.log('✅ Strategy generation completed successfully!');
|
||||
setCurrentStrategy(strategy);
|
||||
setShowEducationalModal(false); // ❌ This was the problem!
|
||||
setError('Strategy created successfully! Check the Strategic Intelligence tab for detailed insights.');
|
||||
},
|
||||
```
|
||||
|
||||
The modal was being closed programmatically when the strategy generation completed, preventing the user from seeing the completion state and clicking the "Next" button.
|
||||
|
||||
## 🛠️ **The Solution**
|
||||
|
||||
### **1. Removed Auto-Close on Completion**
|
||||
```typescript
|
||||
// onComplete callback
|
||||
(strategy: any) => {
|
||||
console.log('✅ Strategy generation completed successfully!');
|
||||
setCurrentStrategy(strategy);
|
||||
// Don't close the modal automatically - let user click the button
|
||||
// setShowEducationalModal(false); // REMOVED - let user control modal closure
|
||||
console.log('🎯 Strategy generation complete - modal should stay open for user to click "Next" button');
|
||||
},
|
||||
```
|
||||
|
||||
### **2. Kept Auto-Close on Error**
|
||||
```typescript
|
||||
// onError callback
|
||||
(error: string) => {
|
||||
console.error('❌ Strategy generation failed:', error);
|
||||
setError(`Strategy generation failed: ${error}`);
|
||||
setShowEducationalModal(false); // Only close on error
|
||||
},
|
||||
```
|
||||
|
||||
### **3. Added Debugging**
|
||||
```typescript
|
||||
// Debug: Check if progress reached 100%
|
||||
if (taskStatus.progress >= 100) {
|
||||
console.log('🎯 Progress reached 100% - modal should show "Next" button');
|
||||
}
|
||||
```
|
||||
|
||||
## 📋 **Implementation Details**
|
||||
|
||||
### **Files Modified**
|
||||
- `frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder/components/ActionButtons.tsx`
|
||||
|
||||
### **Changes Made**
|
||||
1. **Removed automatic modal closure** on successful strategy generation completion
|
||||
2. **Kept error handling** to close modal only on errors
|
||||
3. **Added debugging logs** to track progress and completion state
|
||||
4. **Added debugging to EducationalModal** to verify button state
|
||||
|
||||
### **User Flow After Fix**
|
||||
1. **User clicks "Create Strategy"** → Enterprise modal appears
|
||||
2. **User clicks "Proceed with Current Strategy"** → Educational modal opens
|
||||
3. **Strategy generation runs** → Progress updates in real-time
|
||||
4. **Generation completes (100%)** → Modal stays open, shows "Next" button
|
||||
5. **User clicks "Next: Review Strategy and Create Calendar"** → Modal closes, navigates to Content Strategy tab
|
||||
6. **User sees generated strategy** → Strategy data displayed in Strategic Intelligence section
|
||||
|
||||
## 🎯 **Expected Results**
|
||||
|
||||
### **Before Fix**
|
||||
- ❌ Modal closed automatically on completion
|
||||
- ❌ User never saw "Next" button
|
||||
- ❌ No navigation to Content Strategy tab
|
||||
- ❌ Poor user experience
|
||||
|
||||
### **After Fix**
|
||||
- ✅ Modal stays open until user clicks "Next" button
|
||||
- ✅ User sees completion state and "Next" button
|
||||
- ✅ Proper navigation to Content Strategy tab
|
||||
- ✅ Complete user workflow as designed
|
||||
|
||||
## 🔧 **Technical Benefits**
|
||||
|
||||
1. **User Control**: Users control when to close the modal
|
||||
2. **Clear Completion State**: Users can see when generation is complete
|
||||
3. **Proper Navigation**: Users are guided to the next step
|
||||
4. **Better UX**: Complete workflow as designed
|
||||
5. **Error Handling**: Modal still closes appropriately on errors
|
||||
|
||||
## 🚀 **Testing Steps**
|
||||
|
||||
1. **Generate Strategy**: Click "Create Strategy" and proceed through enterprise modal
|
||||
2. **Monitor Progress**: Watch educational modal show progress updates
|
||||
3. **Verify Completion**: Ensure modal stays open when progress reaches 100%
|
||||
4. **Check Button**: Verify "Next: Review Strategy and Create Calendar" button appears
|
||||
5. **Test Navigation**: Click button and verify navigation to Content Strategy tab
|
||||
6. **Verify Data**: Check that strategy data is displayed in Strategic Intelligence section
|
||||
|
||||
## 📊 **Success Metrics**
|
||||
|
||||
- [ ] Educational modal stays open after strategy generation completes
|
||||
- [ ] "Next: Review Strategy and Create Calendar" button appears at 100% progress
|
||||
- [ ] User can click the button to close modal
|
||||
- [ ] Navigation to Content Strategy tab works correctly
|
||||
- [ ] Strategy data is displayed in the frontend
|
||||
- [ ] No automatic modal closure on successful completion
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ **IMPLEMENTED**
|
||||
**Priority**: 🔴 **HIGH**
|
||||
**Impact**: 🎯 **CRITICAL** - Fixes core user workflow
|
||||
**Files Modified**:
|
||||
- `frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder/components/ActionButtons.tsx`
|
||||
@@ -1,222 +0,0 @@
|
||||
# Enterprise Modal Implementation Summary
|
||||
|
||||
## 🎯 **Implementation Status: COMPLETED** ✅
|
||||
|
||||
### **Issues Fixed**
|
||||
|
||||
#### **1. API Method Missing** ✅ **FIXED**
|
||||
**Problem**: `contentPlanningApi.startStrategyGenerationPolling` method didn't exist
|
||||
**Solution**: Added the missing method to `contentPlanningApi.ts`
|
||||
- **Method**: `startStrategyGenerationPolling(userId: number, strategyName: string)`
|
||||
- **Method**: `pollStrategyGeneration(taskId, onProgress, onComplete, onError, interval, maxAttempts)`
|
||||
- **Backend Endpoint**: `/api/content-planning/content-strategy/ai-generation/generate-comprehensive-strategy-polling`
|
||||
|
||||
#### **2. Enterprise Modal Integration** ✅ **FIXED**
|
||||
**Problem**: Enterprise modal wasn't showing when all categories were reviewed
|
||||
**Solution**:
|
||||
- Added proper modal state management
|
||||
- Added debugging logs to track modal state changes
|
||||
- Integrated modal with existing strategy creation flow
|
||||
- Added proper callback functions for modal actions
|
||||
|
||||
#### **3. Modal Closing Issue** ✅ **FIXED**
|
||||
**Problem**: Strategy input modal was closing automatically after 2 seconds
|
||||
**Solution**:
|
||||
- Removed automatic modal closing timeout
|
||||
- Modal now stays open until user manually closes it
|
||||
- Added logging to track modal state changes
|
||||
|
||||
#### **4. 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 Files**
|
||||
1. **`frontend/src/services/contentPlanningApi.ts`**
|
||||
- Added `startStrategyGenerationPolling` method
|
||||
- Added `pollStrategyGeneration` method
|
||||
- Enhanced API service with polling capabilities
|
||||
|
||||
2. **`frontend/src/components/ContentPlanningDashboard/components/ContentStrategyBuilder.tsx`**
|
||||
- Added enterprise modal state management
|
||||
- Enhanced `handleCreateStrategy` function to show enterprise modal
|
||||
- Added debugging logs for modal state tracking
|
||||
- Integrated enterprise modal with existing flow
|
||||
|
||||
3. **`frontend/src/components/ContentPlanningDashboard/components/EnterpriseDatapointsModal.tsx`**
|
||||
- Fixed import error (replaced `Branding` icon with `Palette`)
|
||||
- Complete enterprise modal implementation
|
||||
- Professional design with comprehensive content
|
||||
|
||||
#### **Documentation Files**
|
||||
4. **`docs/strategy_enterprise_datapoints_inputs.md`**
|
||||
- Comprehensive implementation plan
|
||||
- Enterprise datapoints breakdown
|
||||
- Progressive disclosure strategy
|
||||
|
||||
5. **`docs/strategy_modal_fixes_and_improvements.md`**
|
||||
- Summary of fixes and improvements
|
||||
- Missing datapoints analysis
|
||||
|
||||
### **Enterprise Modal Features**
|
||||
|
||||
#### **🎨 Design & Content**
|
||||
- **Professional Gradient Design**: Modern UI with gradient backgrounds
|
||||
- **Comprehensive Value Proposition**: Clear explanation of enterprise benefits
|
||||
- **Strategy Comparison**: Side-by-side comparison of current vs. enterprise
|
||||
- **Enterprise Categories**: 7 categories with field counts and descriptions
|
||||
- **Social Proof**: User testimonial and credibility indicators
|
||||
- **Process Information**: How AI autofill works for enterprise fields
|
||||
|
||||
#### **📊 Enterprise Categories (30+ Additional Fields)**
|
||||
1. **Content Distribution & Channel Strategy** (6 fields)
|
||||
2. **Content Calendar & Planning** (5 fields)
|
||||
3. **Audience Segmentation & Personas** (6 fields)
|
||||
4. **Content Performance & Optimization** (5 fields)
|
||||
5. **Content Creation & Production** (5 fields)
|
||||
6. **Brand & Messaging Strategy** (5 fields)
|
||||
7. **Technology & Platform Strategy** (5 fields)
|
||||
|
||||
#### **🚀 User Flow**
|
||||
1. User completes all 30 current fields
|
||||
2. User clicks "Create Strategy" button
|
||||
3. Enterprise modal appears with comprehensive information
|
||||
4. User chooses:
|
||||
- **"Proceed with Current Strategy"**: Uses existing 30 fields
|
||||
- **"Add Enterprise Datapoints"**: Coming soon feature (Phase 2)
|
||||
|
||||
### **Technical Implementation**
|
||||
|
||||
#### **API Integration**
|
||||
```typescript
|
||||
// New methods added to contentPlanningApi
|
||||
async startStrategyGenerationPolling(userId: number, strategyName: string)
|
||||
async pollStrategyGeneration(taskId, onProgress, onComplete, onError, interval, maxAttempts)
|
||||
```
|
||||
|
||||
#### **Modal State Management**
|
||||
```typescript
|
||||
const [showEnterpriseModal, setShowEnterpriseModal] = useState(false);
|
||||
|
||||
// Enhanced handleCreateStrategy
|
||||
const handleCreateStrategy = () => {
|
||||
const allCategoriesReviewed = Object.keys(completionStats.category_completion).every(
|
||||
category => Array.from(reviewedCategories).includes(category)
|
||||
);
|
||||
|
||||
if (allCategoriesReviewed) {
|
||||
setShowEnterpriseModal(true); // Show enterprise modal
|
||||
} else {
|
||||
originalHandleCreateStrategy(); // Proceed with original logic
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### **Modal Callbacks**
|
||||
```typescript
|
||||
// Proceed with current strategy (30 fields)
|
||||
const handleProceedWithCurrentStrategy = () => {
|
||||
setShowEnterpriseModal(false);
|
||||
originalHandleCreateStrategy();
|
||||
};
|
||||
|
||||
// Add enterprise datapoints (coming soon)
|
||||
const handleAddEnterpriseDatapoints = () => {
|
||||
setShowEnterpriseModal(false);
|
||||
// TODO: Implement enterprise datapoints functionality
|
||||
originalHandleCreateStrategy();
|
||||
};
|
||||
```
|
||||
|
||||
### **Current Status**
|
||||
|
||||
#### **✅ Phase 1: Complete**
|
||||
- Enterprise modal implemented and functional
|
||||
- Modal shows when all categories are reviewed
|
||||
- Professional design with comprehensive content
|
||||
- Proper integration with existing strategy creation flow
|
||||
- API methods added for future enterprise functionality
|
||||
|
||||
#### **🔄 Phase 2: Coming Soon**
|
||||
- Progressive disclosure system
|
||||
- Enterprise datapoints implementation
|
||||
- Advanced features and contextual display
|
||||
- Enhanced user experience with interactive features
|
||||
|
||||
### **Testing Results**
|
||||
|
||||
#### **✅ Build Status**
|
||||
- **Compilation**: Successful with no errors
|
||||
- **Warnings**: Only unused imports (non-critical)
|
||||
- **Bundle Size**: 336.44 kB (+2.3 kB) - minimal increase
|
||||
- **Performance**: No degradation in existing functionality
|
||||
|
||||
#### **✅ Functionality Tests**
|
||||
- Modal opens when all categories are reviewed
|
||||
- Modal displays comprehensive enterprise information
|
||||
- Both action buttons work correctly
|
||||
- Integration with existing strategy creation flow
|
||||
- Proper state management and debugging logs
|
||||
|
||||
### **User Experience Benefits**
|
||||
|
||||
#### **🎯 Value Proposition**
|
||||
- **3x Better Performance**: Strategies with 60+ datapoints show significantly better results
|
||||
- **Months → Minutes**: Get enterprise-grade analysis in minutes, not months
|
||||
- **Risk Mitigation**: Comprehensive analysis reduces strategy risks
|
||||
- **$50K+ Value**: Enterprise consulting value democratized with AI
|
||||
|
||||
#### **📈 Business Impact**
|
||||
- **Competitive Advantage**: More comprehensive strategy builder than competitors
|
||||
- **User Satisfaction**: Users can create more detailed and actionable strategies
|
||||
- **Revenue Potential**: More comprehensive tool can command higher pricing
|
||||
- **Market Position**: Positions ALwrity as the most comprehensive content strategy tool
|
||||
|
||||
### **Next Steps**
|
||||
|
||||
#### **Immediate (Phase 1)**
|
||||
1. **User Testing**: Test enterprise modal with real users
|
||||
2. **Feedback Collection**: Gather user feedback on modal content and design
|
||||
3. **Performance Monitoring**: Monitor modal performance and user engagement
|
||||
|
||||
#### **Future (Phase 2)**
|
||||
1. **Enterprise Datapoints Implementation**: Add the 30+ additional fields
|
||||
2. **Progressive Disclosure**: Implement contextual field display
|
||||
3. **Advanced Features**: Add interactive features and customization options
|
||||
4. **Analytics Integration**: Track enterprise feature usage and impact
|
||||
|
||||
### **Success Metrics**
|
||||
|
||||
#### **Functional Metrics**
|
||||
- ✅ Modal displays correctly when triggered
|
||||
- ✅ User can proceed with current strategy
|
||||
- ✅ User can access enterprise information
|
||||
- ✅ No degradation in existing functionality
|
||||
|
||||
#### **User Experience Metrics**
|
||||
- **Modal Engagement**: Track how long users spend viewing enterprise information
|
||||
- **Feature Adoption**: Monitor "Add Enterprise Datapoints" button clicks
|
||||
- **User Feedback**: Collect qualitative feedback on modal content and design
|
||||
- **Conversion Rate**: Track users who proceed with current strategy vs. waiting for enterprise
|
||||
|
||||
### **Documentation**
|
||||
|
||||
#### **Technical Documentation**
|
||||
- API methods documented in `contentPlanningApi.ts`
|
||||
- Modal integration documented in `ContentStrategyBuilder.tsx`
|
||||
- State management patterns documented with debugging logs
|
||||
|
||||
#### **User Documentation**
|
||||
- Enterprise datapoints plan in `docs/strategy_enterprise_datapoints_inputs.md`
|
||||
- Implementation summary in `docs/strategy_modal_fixes_and_improvements.md`
|
||||
- Comprehensive guide in `docs/strategy_inputs_autofill_transparency_implementation.md`
|
||||
|
||||
---
|
||||
|
||||
**Implementation Status**: ✅ **COMPLETED**
|
||||
**Next Review**: Ready for user testing and Phase 2 planning
|
||||
**Risk Level**: Low (successful build, no breaking changes)
|
||||
**Success Probability**: High (based on successful implementation and testing)
|
||||
@@ -1,172 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,137 +0,0 @@
|
||||
# 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.
|
||||
372
docs/strategy_and_calendar_workflow_integration.md
Normal file
372
docs/strategy_and_calendar_workflow_integration.md
Normal file
@@ -0,0 +1,372 @@
|
||||
# ALwrity Strategy & Calendar Workflow Integration Documentation
|
||||
|
||||
## 🎯 **Overview**
|
||||
|
||||
This document provides a comprehensive implementation guide for enhancing the seamless integration between ALwrity's strategy activation workflow and calendar wizard, focusing on auto-population enrichment, context preservation, and improved calendar generation capabilities. The integration transforms the platform into a unified content strategy and calendar management system.
|
||||
|
||||
## 🏗️ **Architecture Enhancement**
|
||||
|
||||
### **1. Current State Analysis**
|
||||
|
||||
**Existing Implementation**:
|
||||
- **Strategy Activation**: Independent workflow with review and confirmation system
|
||||
- **Calendar Wizard**: Standalone 4-step wizard with comprehensive data integration
|
||||
- **Data Flow**: Separate data sources and processing pipelines
|
||||
- **User Experience**: Disconnected workflows requiring manual navigation
|
||||
|
||||
**Integration Challenges**:
|
||||
- **Navigation Gap**: No seamless transition from strategy activation to calendar creation
|
||||
- **Context Loss**: Strategy context not preserved in calendar wizard
|
||||
- **Data Redundancy**: Duplicate data collection and processing
|
||||
- **User Friction**: Manual navigation and re-entry of strategy information
|
||||
|
||||
### **2. Enhanced Architecture Design**
|
||||
|
||||
**Unified Workflow Architecture**:
|
||||
```
|
||||
Strategy Generation → Strategy Review → Strategy Activation → Calendar Wizard → Calendar Generation
|
||||
```
|
||||
|
||||
**Integration Components**:
|
||||
- **Strategy Activation Service**: Enhanced activation with database persistence
|
||||
- **Navigation Orchestrator**: Automatic redirection with context preservation
|
||||
- **Context Management System**: Real-time context synchronization
|
||||
- **Enhanced Auto-Population Engine**: Strategy-aware data integration
|
||||
- **Unified State Management**: Cross-component state synchronization
|
||||
|
||||
### **3. Data Flow Architecture**
|
||||
|
||||
**Enhanced Data Flow**:
|
||||
```
|
||||
Active Strategy Data → Context Preservation → Calendar Auto-Population → Enhanced Generation → Performance Tracking
|
||||
```
|
||||
|
||||
**Data Source Hierarchy**:
|
||||
1. **Active Strategy Data** (Primary): Confirmed and activated strategy information
|
||||
2. **Enhanced Strategy Intelligence** (Secondary): Strategic insights and recommendations
|
||||
3. **Onboarding Data** (Tertiary): Website analysis and user preferences
|
||||
4. **Gap Analysis** (Quaternary): Content gaps and opportunities
|
||||
5. **Performance Data** (Quinary): Historical performance and engagement patterns
|
||||
|
||||
## 📊 **Auto-Population Enhancement Specifications**
|
||||
|
||||
### **1. Calendar Configuration Auto-Population**
|
||||
|
||||
**Industry & Business Context Enhancement**:
|
||||
- **Primary Source**: Active strategy industry analysis and business positioning
|
||||
- **Enhancement**: Incorporate strategic market positioning and competitive landscape
|
||||
- **Enrichment**: Add industry-specific best practices and seasonal considerations
|
||||
- **Validation**: Cross-reference with onboarding data for accuracy verification
|
||||
- **Reusability**: Industry context can be reused across multiple calendar generations
|
||||
|
||||
**Content Pillars & Strategy Alignment Enhancement**:
|
||||
- **Primary Source**: Confirmed content pillars from active strategy
|
||||
- **Enhancement**: Include strategic content themes and messaging frameworks
|
||||
- **Enrichment**: Add content pillar performance predictions and audience alignment
|
||||
- **Validation**: Ensure alignment with business goals and target audience
|
||||
- **Reusability**: Content pillars serve as reusable templates for future calendars
|
||||
|
||||
**Target Audience & Demographics Enhancement**:
|
||||
- **Primary Source**: Active strategy audience analysis and segmentation
|
||||
- **Enhancement**: Include behavioral patterns and engagement preferences
|
||||
- **Enrichment**: Add audience journey mapping and touchpoint optimization
|
||||
- **Validation**: Cross-reference with performance data for audience validation
|
||||
- **Reusability**: Audience profiles can be reused for multiple content strategies
|
||||
|
||||
### **2. Content Mix Optimization Enhancement**
|
||||
|
||||
**Strategic Content Distribution Enhancement**:
|
||||
- **Primary Source**: Active strategy content recommendations and priorities
|
||||
- **Enhancement**: Include content type performance predictions and audience preferences
|
||||
- **Enrichment**: Add seasonal content adjustments and trending topic integration
|
||||
- **Validation**: Ensure balanced distribution across educational, thought leadership, engagement, and promotional content
|
||||
- **Reusability**: Content mix templates can be reused and adapted for different time periods
|
||||
|
||||
**Platform-Specific Optimization Enhancement**:
|
||||
- **Primary Source**: Active strategy platform recommendations and audience behavior
|
||||
- **Enhancement**: Include platform-specific content formats and engagement patterns
|
||||
- **Enrichment**: Add cross-platform content repurposing strategies and scheduling optimization
|
||||
- **Validation**: Ensure platform alignment with target audience preferences
|
||||
- **Reusability**: Platform strategies can be reused and optimized over time
|
||||
|
||||
### **3. Advanced Configuration Auto-Population Enhancement**
|
||||
|
||||
**Optimal Timing & Scheduling Enhancement**:
|
||||
- **Primary Source**: Active strategy audience behavior analysis and engagement patterns
|
||||
- **Enhancement**: Include platform-specific optimal posting times and frequency recommendations
|
||||
- **Enrichment**: Add seasonal timing adjustments and trending topic timing optimization
|
||||
- **Validation**: Cross-reference with historical performance data for timing accuracy
|
||||
- **Reusability**: Timing patterns can be reused and refined based on performance data
|
||||
|
||||
**Performance Predictions & Metrics Enhancement**:
|
||||
- **Primary Source**: Active strategy performance predictions and success metrics
|
||||
- **Enhancement**: Include ROI projections and conversion rate predictions
|
||||
- **Enrichment**: Add competitive benchmarking and industry performance comparisons
|
||||
- **Validation**: Ensure predictions align with business goals and market conditions
|
||||
- **Reusability**: Performance models can be reused and updated with new data
|
||||
|
||||
**Target Keywords & SEO Integration Enhancement**:
|
||||
- **Primary Source**: Active strategy keyword opportunities and SEO recommendations
|
||||
- **Enhancement**: Include keyword difficulty analysis and ranking potential
|
||||
- **Enrichment**: Add long-tail keyword opportunities and semantic keyword clustering
|
||||
- **Validation**: Ensure keyword alignment with content strategy and audience intent
|
||||
- **Reusability**: Keyword strategies can be reused and expanded over time
|
||||
|
||||
## 🤖 **Calendar Generation Enhancement**
|
||||
|
||||
### **1. AI Prompt Engineering Improvements**
|
||||
|
||||
**Strategy-Aware Prompt Construction**:
|
||||
- **Context Integration**: Incorporate active strategy context and strategic intelligence
|
||||
- **Goal Alignment**: Ensure calendar generation aligns with confirmed business objectives
|
||||
- **Audience Focus**: Prioritize audience preferences and engagement patterns from active strategy
|
||||
- **Performance Optimization**: Include performance predictions and success metrics in generation logic
|
||||
- **Reusability**: Prompt templates can be reused and adapted for different industries and strategies
|
||||
|
||||
**Enhanced Data Integration**:
|
||||
- **Multi-Source Synthesis**: Combine active strategy data with historical performance and market insights
|
||||
- **Quality Assessment**: Implement data quality scoring and confidence level validation
|
||||
- **Contextual Relevance**: Ensure all data points are relevant to the active strategy context
|
||||
- **Real-time Updates**: Incorporate latest market trends and competitive intelligence
|
||||
- **Reusability**: Data integration patterns can be reused across different calendar types
|
||||
|
||||
### **2. Content Generation Intelligence Enhancement**
|
||||
|
||||
**Strategic Content Planning Enhancement**:
|
||||
- **Content Pillar Alignment**: Generate content that aligns with confirmed content pillars
|
||||
- **Audience Journey Mapping**: Create content that supports audience journey stages
|
||||
- **Competitive Differentiation**: Incorporate competitive analysis for content differentiation
|
||||
- **Performance Optimization**: Include performance predictions for content optimization
|
||||
- **Reusability**: Content planning frameworks can be reused for different strategies
|
||||
|
||||
**Advanced Content Recommendations Enhancement**:
|
||||
- **Topic Clustering**: Group related topics for comprehensive content coverage
|
||||
- **Content Repurposing**: Identify content repurposing opportunities across platforms
|
||||
- **Trending Integration**: Incorporate trending topics and seasonal content opportunities
|
||||
- **Engagement Optimization**: Focus on content types that drive maximum engagement
|
||||
- **Reusability**: Recommendation algorithms can be reused and improved over time
|
||||
|
||||
### **3. Calendar Optimization Features Enhancement**
|
||||
|
||||
**Intelligent Scheduling Enhancement**:
|
||||
- **Optimal Timing**: Use audience behavior data for optimal posting times
|
||||
- **Frequency Optimization**: Determine optimal posting frequency based on platform and audience
|
||||
- **Seasonal Adjustments**: Incorporate seasonal trends and industry-specific timing
|
||||
- **Cross-Platform Coordination**: Ensure coordinated posting across multiple platforms
|
||||
- **Reusability**: Scheduling algorithms can be reused and optimized based on performance
|
||||
|
||||
**Performance-Driven Generation Enhancement**:
|
||||
- **ROI Optimization**: Focus on content types with highest ROI potential
|
||||
- **Engagement Maximization**: Prioritize content that drives maximum engagement
|
||||
- **Conversion Optimization**: Include content that supports conversion goals
|
||||
- **Brand Consistency**: Ensure all content maintains brand voice and messaging
|
||||
- **Reusability**: Performance models can be reused and updated with new data
|
||||
|
||||
## 🔄 **Navigation & Context Preservation**
|
||||
|
||||
### **1. Seamless Navigation Flow Enhancement**
|
||||
|
||||
**Strategy Activation to Calendar Wizard Navigation**:
|
||||
- **Automatic Redirection**: Seamless transition from strategy confirmation to calendar wizard
|
||||
- **Context Preservation**: Maintain all strategy context and user preferences
|
||||
- **Progress Tracking**: Track user progress through the integrated workflow
|
||||
- **State Management**: Preserve application state and user selections
|
||||
- **Reusability**: Navigation patterns can be reused for other workflow integrations
|
||||
|
||||
**Enhanced User Experience**:
|
||||
- **Guided Workflow**: Provide clear guidance through the integrated process
|
||||
- **Progress Indicators**: Show progress through strategy activation and calendar creation
|
||||
- **Error Handling**: Graceful handling of navigation and data flow errors
|
||||
- **Accessibility**: Ensure accessibility throughout the integrated workflow
|
||||
- **Reusability**: UX patterns can be reused for other integrated workflows
|
||||
|
||||
### **2. Context Preservation Strategy Enhancement**
|
||||
|
||||
**Strategy Context Maintenance**:
|
||||
- **Active Strategy Reference**: Maintain reference to the active strategy throughout the process
|
||||
- **Strategic Intelligence**: Preserve all strategic insights and recommendations
|
||||
- **User Preferences**: Maintain user-specific configurations and preferences
|
||||
- **Session Continuity**: Ensure seamless session continuity across components
|
||||
- **Reusability**: Context preservation mechanisms can be reused for other integrations
|
||||
|
||||
**Data Synchronization Enhancement**:
|
||||
- **Real-time Updates**: Synchronize data changes across all components
|
||||
- **Conflict Resolution**: Handle data conflicts and inconsistencies
|
||||
- **Validation**: Ensure data integrity and consistency throughout the process
|
||||
- **Caching**: Implement intelligent caching for performance optimization
|
||||
- **Reusability**: Synchronization patterns can be reused for other data flows
|
||||
|
||||
## 📈 **Performance & Analytics Enhancement**
|
||||
|
||||
### **1. Enhanced Performance Tracking**
|
||||
|
||||
**Strategy-to-Calendar Metrics**:
|
||||
- **Conversion Tracking**: Track strategy activation to calendar creation conversion rates
|
||||
- **User Engagement**: Monitor user engagement throughout the integrated workflow
|
||||
- **Completion Rates**: Track completion rates for the entire strategy-to-calendar process
|
||||
- **Time Optimization**: Measure time savings from integrated workflow
|
||||
- **Reusability**: Metrics can be reused for other workflow performance tracking
|
||||
|
||||
**Quality Assessment Enhancement**:
|
||||
- **Data Quality Metrics**: Track data quality and accuracy throughout the process
|
||||
- **User Satisfaction**: Monitor user satisfaction with the integrated experience
|
||||
- **Error Rates**: Track error rates and user friction points
|
||||
- **Performance Optimization**: Monitor system performance and optimization opportunities
|
||||
- **Reusability**: Quality assessment frameworks can be reused for other processes
|
||||
|
||||
### **2. Advanced Analytics Integration Enhancement**
|
||||
|
||||
**Strategic Intelligence Analytics Enhancement**:
|
||||
- **Strategy Performance**: Track strategy performance and effectiveness
|
||||
- **Calendar Performance**: Monitor calendar performance and engagement
|
||||
- **Integration Effectiveness**: Measure the effectiveness of strategy-to-calendar integration
|
||||
- **User Behavior Analysis**: Analyze user behavior patterns and preferences
|
||||
- **Reusability**: Analytics frameworks can be reused for other integrations
|
||||
|
||||
**Predictive Analytics Enhancement**:
|
||||
- **Success Prediction**: Predict success rates for strategy-to-calendar workflows
|
||||
- **Performance Forecasting**: Forecast performance improvements from integration
|
||||
- **User Journey Optimization**: Optimize user journey based on analytics insights
|
||||
- **Continuous Improvement**: Use analytics for continuous process improvement
|
||||
- **Reusability**: Predictive models can be reused and improved over time
|
||||
|
||||
## 🔧 **Technical Implementation Considerations**
|
||||
|
||||
### **1. Data Architecture Enhancement**
|
||||
|
||||
**Enhanced Data Models**:
|
||||
- **Strategy Activation Model**: Track strategy activation status and metadata
|
||||
- **Context Preservation Model**: Maintain context across workflow components
|
||||
- **Auto-Population Model**: Store auto-population rules and data mappings
|
||||
- **Performance Tracking Model**: Track performance metrics and analytics
|
||||
- **Reusability**: Data models can be reused for other workflow integrations
|
||||
|
||||
**Data Flow Optimization**:
|
||||
- **Real-time Synchronization**: Implement real-time data synchronization
|
||||
- **Caching Strategy**: Optimize caching for performance and data consistency
|
||||
- **Error Handling**: Implement comprehensive error handling and recovery
|
||||
- **Validation**: Ensure data validation and integrity throughout the process
|
||||
- **Reusability**: Data flow patterns can be reused for other integrations
|
||||
|
||||
### **2. State Management Enhancement**
|
||||
|
||||
**Enhanced State Architecture**:
|
||||
- **Global State Management**: Implement global state for workflow context
|
||||
- **Component State Synchronization**: Ensure state synchronization across components
|
||||
- **Persistence Strategy**: Implement state persistence for session continuity
|
||||
- **Recovery Mechanisms**: Provide state recovery mechanisms for error scenarios
|
||||
- **Reusability**: State management patterns can be reused for other workflows
|
||||
|
||||
**Context Management Enhancement**:
|
||||
- **Context Provider**: Implement context provider for strategy and calendar data
|
||||
- **Context Validation**: Validate context integrity throughout the workflow
|
||||
- **Context Recovery**: Provide context recovery mechanisms
|
||||
- **Context Optimization**: Optimize context management for performance
|
||||
- **Reusability**: Context management patterns can be reused for other integrations
|
||||
|
||||
## 🚀 **Implementation Phases**
|
||||
|
||||
### **Phase 1: Foundation Enhancement (Week 1-2)**
|
||||
- **Strategy Activation Enhancement**: Implement enhanced strategy activation with database persistence
|
||||
- **Navigation Integration**: Implement seamless navigation from strategy activation to calendar wizard
|
||||
- **Context Preservation**: Implement basic context preservation mechanisms
|
||||
- **Data Flow Optimization**: Optimize data flow between strategy and calendar components
|
||||
- **Reusability Components**: Create reusable navigation and context management components
|
||||
|
||||
### **Phase 2: Auto-Population Enhancement (Week 3-4)**
|
||||
- **Active Strategy Integration**: Implement active strategy data integration for auto-population
|
||||
- **Enhanced Data Sources**: Implement enhanced data source hierarchy and prioritization
|
||||
- **Validation Mechanisms**: Implement data validation and quality assessment
|
||||
- **Performance Optimization**: Optimize auto-population performance and accuracy
|
||||
- **Reusability Components**: Create reusable auto-population and validation components
|
||||
|
||||
### **Phase 3: Calendar Generation Enhancement (Week 5-6)**
|
||||
- **AI Prompt Enhancement**: Implement enhanced AI prompts with strategy context
|
||||
- **Content Generation Intelligence**: Implement intelligent content generation and optimization
|
||||
- **Performance Tracking**: Implement enhanced performance tracking and analytics
|
||||
- **Quality Assurance**: Implement comprehensive quality assurance and testing
|
||||
- **Reusability Components**: Create reusable AI prompt and generation components
|
||||
|
||||
### **Phase 4: Advanced Features (Week 7-8)**
|
||||
- **Advanced Analytics**: Implement advanced analytics and predictive capabilities
|
||||
- **Performance Optimization**: Implement comprehensive performance optimization
|
||||
- **User Experience Enhancement**: Implement advanced user experience features
|
||||
- **Documentation and Training**: Complete documentation and user training materials
|
||||
- **Reusability Components**: Create reusable analytics and optimization components
|
||||
|
||||
## 📊 **Success Metrics**
|
||||
|
||||
### **Technical Metrics**
|
||||
- **Navigation Success Rate**: Target 98%+ successful strategy-to-calendar navigation
|
||||
- **Auto-Population Accuracy**: Target 95%+ accurate auto-population from active strategy
|
||||
- **Context Preservation**: Target 100% context preservation throughout workflow
|
||||
- **Performance Optimization**: Target <3 seconds calendar generation time
|
||||
- **Reusability Index**: Target 80%+ component reusability across workflows
|
||||
|
||||
### **User Experience Metrics**
|
||||
- **Workflow Completion Rate**: Target 90%+ completion rate for integrated workflow
|
||||
- **User Satisfaction**: Target 90%+ user satisfaction with integrated experience
|
||||
- **Time Savings**: Target 50%+ time savings from integrated workflow
|
||||
- **Error Reduction**: Target 80%+ reduction in user errors and friction
|
||||
- **Reusability Adoption**: Target 85%+ adoption of reusable components
|
||||
|
||||
### **Business Metrics**
|
||||
- **Strategy Activation Rate**: Target 85%+ strategy activation rate
|
||||
- **Calendar Creation Rate**: Target 80%+ calendar creation rate from activated strategies
|
||||
- **User Retention**: Target 90%+ user retention with integrated workflow
|
||||
- **ROI Improvement**: Target 25%+ ROI improvement from integrated workflow
|
||||
- **Component Efficiency**: Target 30%+ efficiency improvement from reusable components
|
||||
|
||||
## 🎯 **Reusability Components**
|
||||
|
||||
### **1. Navigation Components**
|
||||
- **Workflow Navigator**: Reusable component for managing workflow transitions
|
||||
- **Progress Tracker**: Reusable component for tracking workflow progress
|
||||
- **Context Router**: Reusable component for maintaining context during navigation
|
||||
- **State Synchronizer**: Reusable component for synchronizing state across components
|
||||
|
||||
### **2. Data Integration Components**
|
||||
- **Data Source Manager**: Reusable component for managing multiple data sources
|
||||
- **Auto-Population Engine**: Reusable component for intelligent field auto-population
|
||||
- **Data Validator**: Reusable component for data validation and quality assessment
|
||||
- **Context Preserver**: Reusable component for preserving context across workflows
|
||||
|
||||
### **3. AI Integration Components**
|
||||
- **Prompt Builder**: Reusable component for building context-aware AI prompts
|
||||
- **Response Parser**: Reusable component for parsing and validating AI responses
|
||||
- **Generation Optimizer**: Reusable component for optimizing AI generation processes
|
||||
- **Quality Assessor**: Reusable component for assessing AI output quality
|
||||
|
||||
### **4. Analytics Components**
|
||||
- **Performance Tracker**: Reusable component for tracking workflow performance
|
||||
- **Metrics Collector**: Reusable component for collecting and analyzing metrics
|
||||
- **Predictive Model**: Reusable component for predictive analytics and forecasting
|
||||
- **Optimization Engine**: Reusable component for continuous optimization
|
||||
|
||||
### **5. User Experience Components**
|
||||
- **Workflow Guide**: Reusable component for guiding users through workflows
|
||||
- **Progress Indicator**: Reusable component for showing workflow progress
|
||||
- **Error Handler**: Reusable component for graceful error handling
|
||||
- **Accessibility Manager**: Reusable component for ensuring accessibility
|
||||
|
||||
## 🎉 **Conclusion**
|
||||
|
||||
This enhancement will transform the ALwrity platform into a truly integrated content strategy and calendar management system. The seamless navigation, enhanced auto-population, and improved calendar generation will provide users with a comprehensive, intelligent, and efficient content planning experience that maximizes the value of their strategic investments.
|
||||
|
||||
The implementation focuses on maintaining the existing robust foundation while adding sophisticated integration capabilities that enhance user experience, improve data accuracy, and optimize content performance. The phased approach ensures smooth implementation with minimal disruption to existing functionality while delivering maximum value to users.
|
||||
|
||||
The emphasis on reusability ensures that components and patterns developed for this integration can be leveraged across other workflows, improving development efficiency and maintaining consistency across the platform.
|
||||
|
||||
**Overall Enhancement Value**:
|
||||
- **User Experience**: 50%+ improvement in workflow efficiency
|
||||
- **Data Accuracy**: 95%+ accuracy in auto-population
|
||||
- **System Performance**: 30%+ improvement in processing speed
|
||||
- **Component Reusability**: 80%+ reusability across workflows
|
||||
- **Business Impact**: 25%+ improvement in user engagement and retention
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: August 13, 2025
|
||||
**Version**: 1.0
|
||||
**Status**: Implementation Ready
|
||||
**Next Review**: September 13, 2025
|
||||
@@ -1,155 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,156 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,179 +0,0 @@
|
||||
# Strategy Empty Datapoints Fix
|
||||
|
||||
## 🎯 **Issue Summary**
|
||||
|
||||
**Problem**: Most of the existing strategy datapoints were showing up as empty arrays in the frontend, despite the backend successfully generating AI responses.
|
||||
|
||||
**Root Cause**: Data mapping mismatch between AI-generated responses and frontend-expected structure.
|
||||
|
||||
## 🔍 **Root Cause Analysis**
|
||||
|
||||
### **1. Backend Logs Showed Success**
|
||||
- ✅ Strategy generation completed successfully
|
||||
- ✅ AI calls working (strategic_intelligence, market_position_analysis, performance_prediction)
|
||||
- ✅ Strategy saved to database with ID: 63
|
||||
- ✅ All AI services completing in reasonable time (13-38 seconds)
|
||||
|
||||
### **2. Frontend Showed Empty Arrays**
|
||||
The image clearly showed empty arrays for critical fields:
|
||||
- `competitive_advantages: Array(0)` - **Empty**
|
||||
- `key_drivers: Array(0)` - **Empty**
|
||||
- `swot_analysis: {strengths: Array(0), opportunities: Array(0)}` - **Empty**
|
||||
- `key_opportunities: Array(0)` - **Empty**
|
||||
- `primary_strengths: Array(0)` - **Empty**
|
||||
|
||||
### **3. Data Quality Issues**
|
||||
From the logs, data quality problems were identified:
|
||||
```
|
||||
Data quality assessment for user 1:
|
||||
- Completeness: 0.10 (10% complete)
|
||||
- Freshness: 0.50 (50% fresh)
|
||||
- Relevance: 0.00 (0% relevant)
|
||||
- Confidence: 0.20 (20% confidence)
|
||||
```
|
||||
|
||||
## 🛠️ **The Solution**
|
||||
|
||||
### **Problem**: Data Structure Mismatch
|
||||
The AI was generating responses with different field names than what the frontend expected:
|
||||
|
||||
**AI Generated**: `insights` array with `type`, `insight`, `reasoning` fields
|
||||
**Frontend Expected**: `competitive_advantages`, `key_drivers`, `swot_analysis` fields
|
||||
|
||||
### **Solution**: Data Transformation Layer
|
||||
Added a comprehensive data transformation layer in `strategy_generator.py` that maps AI responses to frontend-expected format.
|
||||
|
||||
## 📋 **Implementation Details**
|
||||
|
||||
### **1. Added Transformation Methods**
|
||||
Created `_transform_ai_response_to_frontend_format()` method that:
|
||||
- Takes raw AI response
|
||||
- Maps it to frontend-expected structure
|
||||
- Ensures all required fields are populated
|
||||
- Limits arrays to reasonable sizes (3-5 items)
|
||||
|
||||
### **2. Specific Transformations**
|
||||
|
||||
#### **Strategic Insights Transformation**
|
||||
```python
|
||||
def _transform_strategic_insights(self, ai_response: Dict[str, Any]) -> Dict[str, Any]:
|
||||
transformed = {
|
||||
"market_positioning": {
|
||||
"positioning_strength": 75,
|
||||
"current_position": "Emerging",
|
||||
"swot_analysis": {
|
||||
"strengths": [],
|
||||
"opportunities": []
|
||||
}
|
||||
},
|
||||
"content_opportunities": [],
|
||||
"growth_potential": {
|
||||
"market_size": "Growing",
|
||||
"growth_rate": "High",
|
||||
"key_drivers": [],
|
||||
"competitive_advantages": []
|
||||
},
|
||||
"swot_summary": {
|
||||
"overall_score": 75,
|
||||
"primary_strengths": [],
|
||||
"key_opportunities": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **Competitive Analysis Transformation**
|
||||
```python
|
||||
def _transform_competitive_analysis(self, ai_response: Dict[str, Any]) -> Dict[str, Any]:
|
||||
transformed = {
|
||||
"competitors": [],
|
||||
"market_gaps": [],
|
||||
"opportunities": [],
|
||||
"recommendations": [],
|
||||
"competitive_advantages": {
|
||||
"primary": [],
|
||||
"sustainable": [],
|
||||
"development_areas": []
|
||||
},
|
||||
"swot_competitive_insights": {
|
||||
"leverage_strengths": [],
|
||||
"address_weaknesses": [],
|
||||
"capitalize_opportunities": [],
|
||||
"mitigate_threats": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **3. Smart Data Extraction**
|
||||
The transformation methods intelligently extract data from AI responses:
|
||||
|
||||
```python
|
||||
# Extract insights from AI response
|
||||
insights = ai_response.get("insights", [])
|
||||
if insights:
|
||||
for insight in insights:
|
||||
insight_type = insight.get("type", "").lower()
|
||||
insight_text = insight.get("insight", "")
|
||||
|
||||
if "opportunity" in insight_type or "opportunity" in insight_text.lower():
|
||||
if "content" in insight_text.lower():
|
||||
content_opportunities.append(insight_text)
|
||||
else:
|
||||
opportunities.append(insight_text)
|
||||
elif "strength" in insight_type or "advantage" in insight_type:
|
||||
if "competitive" in insight_text.lower():
|
||||
competitive_advantages.append(insight_text)
|
||||
else:
|
||||
strengths.append(insight_text)
|
||||
```
|
||||
|
||||
### **4. Updated Generation Methods**
|
||||
Modified all AI generation methods to use the transformation layer:
|
||||
|
||||
```python
|
||||
# Before
|
||||
return response.get("data", {})
|
||||
|
||||
# After
|
||||
transformed_response = self._transform_ai_response_to_frontend_format(response.get("data", {}), "strategic_insights")
|
||||
return transformed_response
|
||||
```
|
||||
|
||||
## 🎯 **Expected Results**
|
||||
|
||||
### **Before Fix**
|
||||
- Empty arrays: `competitive_advantages: Array(0)`
|
||||
- Missing data: `key_drivers: Array(0)`
|
||||
- No insights: `swot_analysis: {strengths: Array(0), opportunities: Array(0)}`
|
||||
|
||||
### **After Fix**
|
||||
- Populated arrays: `competitive_advantages: ["Direct lead generation capabilities", "Authentic personal brand voice", "Thought leadership positioning"]`
|
||||
- Rich insights: `key_drivers: ["Market growth", "Content demand", "Competitive gaps"]`
|
||||
- Complete SWOT: `swot_analysis: {strengths: ["Unique perspective", "Agile approach"], opportunities: ["Market gaps", "Content opportunities"]}`
|
||||
|
||||
## 🔧 **Technical Benefits**
|
||||
|
||||
1. **Data Consistency**: Ensures frontend always receives properly structured data
|
||||
2. **Fallback Values**: Provides sensible defaults when AI responses are incomplete
|
||||
3. **Array Limits**: Prevents overwhelming the UI with too many items
|
||||
4. **Error Handling**: Graceful degradation if transformation fails
|
||||
5. **Maintainability**: Centralized transformation logic for easy updates
|
||||
|
||||
## 🚀 **Next Steps**
|
||||
|
||||
1. **Test the Fix**: Generate a new strategy to verify data is properly populated
|
||||
2. **Monitor Performance**: Ensure transformation doesn't impact generation speed
|
||||
3. **Enhance AI Prompts**: Improve AI prompts to generate more structured responses
|
||||
4. **Add Validation**: Add validation to ensure transformed data meets frontend requirements
|
||||
|
||||
## 📊 **Success Metrics**
|
||||
|
||||
- [ ] All strategy datapoints show populated arrays instead of empty ones
|
||||
- [ ] Frontend displays meaningful insights and recommendations
|
||||
- [ ] No degradation in strategy generation performance
|
||||
- [ ] Improved user experience with rich, actionable data
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ **IMPLEMENTED**
|
||||
**Priority**: 🔴 **HIGH**
|
||||
**Impact**: 🎯 **CRITICAL** - Fixes core functionality issue
|
||||
@@ -1,152 +0,0 @@
|
||||
# Strategy Empty Datapoints Fix - Updated Implementation
|
||||
|
||||
## 🎯 **Issue Summary**
|
||||
|
||||
**Problem**: Most of the existing strategy datapoints were showing up as empty arrays in the frontend, despite the backend successfully generating AI responses.
|
||||
|
||||
**Root Cause**: Multiple issues identified:
|
||||
1. **API Endpoint Mismatch**: Frontend was calling wrong endpoint
|
||||
2. **Data Transformation Issues**: Transformation layer was too restrictive
|
||||
3. **Data Structure Mismatch**: AI response structure didn't match transformation expectations
|
||||
|
||||
## 🔍 **Root Cause Analysis**
|
||||
|
||||
### **1. API Endpoint Issue**
|
||||
- **Frontend was calling**: `/api/content-planning/enhanced-strategies/latest-generated`
|
||||
- **Backend endpoint is**: `/api/content-planning/content-strategy/ai-generation/latest-strategy`
|
||||
- **Result**: Frontend was getting 404 errors or empty data
|
||||
|
||||
### **2. Data Transformation Issues**
|
||||
- **Problem**: Transformation methods were too restrictive in categorizing AI insights
|
||||
- **Issue**: Only populating arrays if exact keyword matches were found
|
||||
- **Result**: Most insights were being ignored, leading to empty arrays
|
||||
|
||||
### **3. Data Structure Mismatch**
|
||||
- **AI Response Structure**: `insights` array with `type`, `insight`, `reasoning` fields
|
||||
- **Frontend Expected**: Specific fields like `competitive_advantages`, `key_drivers`, `swot_analysis`
|
||||
- **Issue**: Transformation wasn't properly mapping between these structures
|
||||
|
||||
## 🛠️ **The Solution**
|
||||
|
||||
### **1. Fixed API Endpoint**
|
||||
```typescript
|
||||
// Before (WRONG)
|
||||
const response = await apiClient.get(`${this.baseURL}/enhanced-strategies/latest-generated`, { params });
|
||||
|
||||
// After (CORRECT)
|
||||
const response = await apiClient.get(`${this.baseURL}/content-strategy/ai-generation/latest-strategy`, { params });
|
||||
```
|
||||
|
||||
### **2. Enhanced Data Transformation**
|
||||
|
||||
#### **Improved Strategic Insights Transformation**
|
||||
```python
|
||||
def _transform_strategic_insights(self, ai_response: Dict[str, Any]) -> Dict[str, Any]:
|
||||
# More flexible keyword matching
|
||||
if any(keyword in insight_type for keyword in ["opportunity", "content", "market"]) or any(keyword in insight_text.lower() for keyword in ["opportunity", "content", "market"]):
|
||||
if any(keyword in insight_text.lower() for keyword in ["content", "blog", "article", "post", "video", "social"]):
|
||||
content_opportunities.append(insight_text)
|
||||
else:
|
||||
opportunities.append(insight_text)
|
||||
|
||||
# Fallback data population
|
||||
if not content_opportunities and insights:
|
||||
content_opportunities = [insight.get("insight", "") for insight in insights[:3]]
|
||||
if not opportunities and insights:
|
||||
opportunities = [insight.get("insight", "") for insight in insights[3:6]]
|
||||
```
|
||||
|
||||
#### **Enhanced Competitive Analysis Transformation**
|
||||
```python
|
||||
def _transform_competitive_analysis(self, ai_response: Dict[str, Any]) -> Dict[str, Any]:
|
||||
# Handle both insights array and direct fields
|
||||
insights = ai_response.get("insights", [])
|
||||
competitors = ai_response.get("competitors", [])
|
||||
market_gaps = ai_response.get("market_gaps", [])
|
||||
opportunities = ai_response.get("opportunities", [])
|
||||
recommendations = ai_response.get("recommendations", [])
|
||||
|
||||
# Ensure we have some data even if categorization didn't work
|
||||
if not market_gaps and insights:
|
||||
market_gaps = [insight.get("insight", "") for insight in insights[:3]]
|
||||
```
|
||||
|
||||
### **3. Added Debugging Logging**
|
||||
```python
|
||||
# Log the raw AI response for debugging
|
||||
logger.info(f"🔍 Raw AI response for strategic insights: {json.dumps(response.get('data', {}), indent=2)}")
|
||||
|
||||
# Log the transformed response for debugging
|
||||
logger.info(f"🔄 Transformed strategic insights: {json.dumps(transformed_response, indent=2)}")
|
||||
```
|
||||
|
||||
## 📋 **Implementation Details**
|
||||
|
||||
### **1. API Endpoint Fix**
|
||||
- **File**: `frontend/src/services/contentPlanningApi.ts`
|
||||
- **Method**: `getLatestGeneratedStrategy`
|
||||
- **Change**: Updated endpoint path to match backend
|
||||
|
||||
### **2. Enhanced Transformation Methods**
|
||||
- **File**: `backend/api/content_planning/services/content_strategy/ai_generation/strategy_generator.py`
|
||||
- **Methods**:
|
||||
- `_transform_strategic_insights`
|
||||
- `_transform_competitive_analysis`
|
||||
- **Improvements**:
|
||||
- More flexible keyword matching
|
||||
- Fallback data population
|
||||
- Better error handling
|
||||
|
||||
### **3. Debugging Enhancements**
|
||||
- **Added logging** to track AI response structure
|
||||
- **Added logging** to track transformation results
|
||||
- **Better error handling** in transformation methods
|
||||
|
||||
## 🎯 **Expected Results**
|
||||
|
||||
### **Before Fix**
|
||||
- Empty arrays: `competitive_advantages: Array(0)`
|
||||
- Missing data: `key_drivers: Array(0)`
|
||||
- No insights: `swot_analysis: {strengths: Array(0), opportunities: Array(0)}`
|
||||
- API errors: 404 on strategy retrieval
|
||||
|
||||
### **After Fix**
|
||||
- Populated arrays: `competitive_advantages: ["Direct lead generation capabilities", "Authentic personal brand voice", "Thought leadership positioning"]`
|
||||
- Rich insights: `key_drivers: ["Market growth", "Content demand", "Competitive gaps"]`
|
||||
- Complete SWOT: `swot_analysis: {strengths: ["Unique perspective", "Agile approach"], opportunities: ["Market gaps", "Content opportunities"]}`
|
||||
- Successful API calls: Proper strategy data retrieval
|
||||
|
||||
## 🔧 **Technical Benefits**
|
||||
|
||||
1. **Data Consistency**: Ensures frontend always receives properly structured data
|
||||
2. **Fallback Values**: Provides sensible defaults when AI responses are incomplete
|
||||
3. **Flexible Matching**: More robust keyword matching for data categorization
|
||||
4. **Error Handling**: Graceful degradation if transformation fails
|
||||
5. **Debugging**: Comprehensive logging for troubleshooting
|
||||
6. **API Reliability**: Correct endpoint mapping for data retrieval
|
||||
|
||||
## 🚀 **Next Steps**
|
||||
|
||||
1. **Test the Fix**: Generate a new strategy to verify data is properly populated
|
||||
2. **Monitor Logs**: Check backend logs for transformation debugging information
|
||||
3. **Verify Frontend**: Ensure Content Strategy tab displays populated data
|
||||
4. **Performance Check**: Ensure transformation doesn't impact generation speed
|
||||
5. **User Testing**: Verify end-user experience with populated strategy data
|
||||
|
||||
## 📊 **Success Metrics**
|
||||
|
||||
- [ ] API endpoint returns strategy data successfully
|
||||
- [ ] All strategy datapoints show populated arrays instead of empty ones
|
||||
- [ ] Frontend displays meaningful insights and recommendations
|
||||
- [ ] No degradation in strategy generation performance
|
||||
- [ ] Improved user experience with rich, actionable data
|
||||
- [ ] Debugging logs show proper data transformation
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ **IMPLEMENTED**
|
||||
**Priority**: 🔴 **HIGH**
|
||||
**Impact**: 🎯 **CRITICAL** - Fixes core functionality issue
|
||||
**Files Modified**:
|
||||
- `frontend/src/services/contentPlanningApi.ts`
|
||||
- `backend/api/content_planning/services/content_strategy/ai_generation/strategy_generator.py`
|
||||
@@ -160,6 +160,34 @@ const ContentStrategyBuilder: React.FC = () => {
|
||||
handleShowEducationalInfo
|
||||
} = useEventHandlers();
|
||||
|
||||
// Create a state for educational modal that can be passed to both hooks
|
||||
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]);
|
||||
|
||||
// Use strategy creation hook first
|
||||
const { originalHandleCreateStrategy, handleSaveStrategy } = useStrategyCreation({
|
||||
formData,
|
||||
@@ -171,7 +199,7 @@ const ContentStrategyBuilder: React.FC = () => {
|
||||
setSaving,
|
||||
setGenerationProgress: setStoreGenerationProgress,
|
||||
setEducationalContent: setStoreEducationalContent,
|
||||
setShowEducationalModal: () => {}, // Temporary placeholder
|
||||
setShowEducationalModal, // Pass the actual setShowEducationalModal function
|
||||
validateAllFields,
|
||||
getCompletionStats,
|
||||
generateAIRecommendations: (strategyId: string) => generateAIRecommendations(strategyId),
|
||||
@@ -180,15 +208,12 @@ const ContentStrategyBuilder: React.FC = () => {
|
||||
});
|
||||
|
||||
const {
|
||||
showEducationalModal,
|
||||
setShowEducationalModal,
|
||||
showEnterpriseModal,
|
||||
setShowEnterpriseModal,
|
||||
handleProceedWithCurrentStrategy,
|
||||
handleAddEnterpriseDatapoints
|
||||
} = useModalManagement({
|
||||
aiGenerating,
|
||||
originalHandleCreateStrategy
|
||||
originalHandleCreateStrategy,
|
||||
setShowEnterpriseModal
|
||||
});
|
||||
|
||||
const {
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Box, Paper } from '@mui/material';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { ExpandMore as ExpandMoreIcon } from '@mui/icons-material';
|
||||
|
||||
interface CardExpansionWrapperProps {
|
||||
children: React.ReactNode;
|
||||
isExpanded?: boolean;
|
||||
onExpand?: (expanded: boolean) => void;
|
||||
gridSize?: {
|
||||
xs?: number;
|
||||
sm?: number;
|
||||
md?: number;
|
||||
lg?: number;
|
||||
};
|
||||
}
|
||||
|
||||
const CardExpansionWrapper: React.FC<CardExpansionWrapperProps> = ({
|
||||
children,
|
||||
isExpanded = false,
|
||||
onExpand,
|
||||
gridSize = { xs: 12, sm: 12, md: 6, lg: 4 }
|
||||
}) => {
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const [isExpandedState, setIsExpandedState] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('🎯 CardExpansionWrapper mounted');
|
||||
}, []);
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
console.log('🖱️ Mouse entered card');
|
||||
setIsHovered(true);
|
||||
setIsExpandedState(true);
|
||||
onExpand?.(true);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
console.log('🖱️ Mouse left card');
|
||||
setIsHovered(false);
|
||||
setIsExpandedState(false);
|
||||
onExpand?.(false);
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
console.log('🖱️ Card clicked');
|
||||
};
|
||||
|
||||
const isExpandedFinal = isExpanded || isExpandedState;
|
||||
|
||||
console.log('🎯 Card expansion state:', { isExpandedFinal, isHovered, isExpandedState });
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
gridColumn: isExpandedFinal ? '1 / -1' : 'auto',
|
||||
transition: 'grid-column 0.3s ease',
|
||||
zIndex: isExpandedFinal ? 10 : 1,
|
||||
border: '1px solid blue', // Debug border
|
||||
}}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<motion.div
|
||||
animate={{
|
||||
scale: isExpandedFinal ? 1.02 : 1,
|
||||
boxShadow: isExpandedFinal
|
||||
? '0 8px 32px rgba(0, 0, 0, 0.15)'
|
||||
: '0 2px 8px rgba(0, 0, 0, 0.1)',
|
||||
}}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 300,
|
||||
damping: 30,
|
||||
}}
|
||||
style={{
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Paper
|
||||
sx={{
|
||||
p: isExpandedFinal ? 3 : 2,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
borderRadius: 2,
|
||||
background: isExpandedFinal
|
||||
? 'linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%)'
|
||||
: 'background.paper',
|
||||
border: isExpandedFinal ? '3px solid' : '1px solid',
|
||||
borderColor: isExpandedFinal ? 'primary.main' : 'divider',
|
||||
transition: 'all 0.3s ease',
|
||||
cursor: 'pointer',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
'&:hover': {
|
||||
borderColor: 'primary.main',
|
||||
},
|
||||
'&::before': isExpandedFinal ? {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: '5px',
|
||||
background: 'linear-gradient(90deg, #667eea 0%, #764ba2 100%)',
|
||||
zIndex: 1,
|
||||
} : {},
|
||||
// Debug styling
|
||||
...(isExpandedFinal && {
|
||||
outline: '2px solid red',
|
||||
outlineOffset: '2px',
|
||||
}),
|
||||
}}
|
||||
>
|
||||
{/* Hover Hint - Only show when not expanded */}
|
||||
<AnimatePresence>
|
||||
{!isExpandedFinal && isHovered && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '8px',
|
||||
right: '8px',
|
||||
background: 'rgba(25, 118, 210, 0.9)',
|
||||
color: 'white',
|
||||
borderRadius: '12px',
|
||||
padding: '4px 8px',
|
||||
fontSize: '0.7rem',
|
||||
fontWeight: 500,
|
||||
zIndex: 4,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '4px',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
>
|
||||
<ExpandMoreIcon sx={{ fontSize: '0.8rem' }} />
|
||||
Expand
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<AnimatePresence>
|
||||
{isExpandedFinal && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: 'auto' }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
background: 'rgba(25, 118, 210, 0.1)',
|
||||
borderRadius: '8px 8px 0 0',
|
||||
padding: '8px 16px',
|
||||
fontSize: '0.75rem',
|
||||
color: 'primary.main',
|
||||
fontWeight: 500,
|
||||
zIndex: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px',
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: '1rem' }}>✨</span>
|
||||
Expanded for better readability
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<Box sx={{
|
||||
position: 'relative',
|
||||
zIndex: 3,
|
||||
mt: isExpandedFinal ? 3 : 0,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}>
|
||||
{children}
|
||||
</Box>
|
||||
</Paper>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardExpansionWrapper;
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
@@ -12,17 +12,19 @@ import {
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Grid,
|
||||
CircularProgress
|
||||
CircularProgress,
|
||||
Paper,
|
||||
Grid
|
||||
} from '@mui/material';
|
||||
import {
|
||||
School as SchoolIcon,
|
||||
Lightbulb as LightbulbIcon,
|
||||
Psychology as PsychologyIcon,
|
||||
Timeline as TimelineIcon,
|
||||
CheckCircle as CheckCircleIcon
|
||||
CheckCircle as CheckCircleIcon,
|
||||
ExpandMore as ExpandMoreIcon
|
||||
} from '@mui/icons-material';
|
||||
import { motion } from 'framer-motion';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import StrategicInputField from '../StrategicInputField';
|
||||
import { CategoryDetailViewProps, EducationalInfoDialogProps } from '../types/contentStrategy.types';
|
||||
import { useEnhancedStrategyStore } from '../../../../../stores/enhancedStrategyStore';
|
||||
@@ -116,8 +118,11 @@ const CategoryDetailView: React.FC<CategoryDetailViewProps> = ({
|
||||
getCategoryColor,
|
||||
getEducationalContent
|
||||
}) => {
|
||||
const [expandedCard, setExpandedCard] = useState<string | null>(null);
|
||||
|
||||
// Get confidence scores from store
|
||||
const { confidenceScores } = useEnhancedStrategyStore();
|
||||
|
||||
if (!activeCategory) {
|
||||
return (
|
||||
<motion.div
|
||||
@@ -138,6 +143,8 @@ const CategoryDetailView: React.FC<CategoryDetailViewProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
const categoryFields = STRATEGIC_INPUT_FIELDS.filter(field => field.category === activeCategory);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
@@ -167,47 +174,45 @@ const CategoryDetailView: React.FC<CategoryDetailViewProps> = ({
|
||||
getEducationalContent={getEducationalContent}
|
||||
/>
|
||||
|
||||
{/* Category Fields */}
|
||||
{/* Category Fields with Hover Expansion */}
|
||||
<Box sx={{ mt: 1 }}>
|
||||
<Grid container spacing={2}>
|
||||
{STRATEGIC_INPUT_FIELDS
|
||||
.filter(field => field.category === activeCategory)
|
||||
.map((field, index) => {
|
||||
// Determine grid size based on field type for better layout organization
|
||||
const type = field.type;
|
||||
const isWideField = type === 'json';
|
||||
const isMediumField = type === 'multiselect' || type === 'select' || type === 'text';
|
||||
const isCompactField = type === 'number' || type === 'boolean';
|
||||
const forceFullWidth = field.id === 'content_budget' || field.id === 'team_size';
|
||||
{categoryFields.map((field, index) => {
|
||||
// Determine grid size based on field type
|
||||
const type = field.type;
|
||||
const isWideField = type === 'json';
|
||||
const isMediumField = type === 'multiselect' || type === 'select' || type === 'text';
|
||||
const isCompactField = type === 'number' || type === 'boolean';
|
||||
const forceFullWidth = field.id === 'content_budget' || field.id === 'team_size';
|
||||
|
||||
const gridSm = isWideField ? 12 : isMediumField ? 6 : 4;
|
||||
const gridMd = isWideField ? 12 : isMediumField ? 6 : 4;
|
||||
const gridLg = isWideField ? 12 : isMediumField ? 6 : 4;
|
||||
|
||||
const gridMd = forceFullWidth ? 12 : (isWideField ? 12 : isMediumField ? 6 : 4);
|
||||
const gridLg = forceFullWidth ? 12 : (isWideField ? 12 : isMediumField ? 6 : 4);
|
||||
const gridSm = 12;
|
||||
|
||||
return (
|
||||
<Grid item xs={12} sm={gridSm} md={gridMd} lg={gridLg} key={field.id}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.25, delay: index * 0.03 }}
|
||||
>
|
||||
<StrategicInputField
|
||||
fieldId={field.id}
|
||||
value={formData[field.id]}
|
||||
error={formErrors[field.id]}
|
||||
autoPopulated={!!autoPopulatedFields[field.id]}
|
||||
dataSource={dataSources[field.id]}
|
||||
confidenceLevel={confidenceScores[field.id] || (autoPopulatedFields[field.id] ? 0.8 : undefined)}
|
||||
dataQuality={autoPopulatedFields[field.id] ? 'High Quality' : undefined}
|
||||
personalizationData={personalizationData[field.id]}
|
||||
onChange={(value: any) => onUpdateFormField(field.id, value)}
|
||||
onValidate={() => onValidateFormField(field.id)}
|
||||
onShowTooltip={() => onShowTooltip(field.id)}
|
||||
onViewDataSource={() => onViewDataSource(field.id)}
|
||||
accentColorKey={getCategoryColor(activeCategory) as any}
|
||||
isCompact={isCompactField}
|
||||
/>
|
||||
</motion.div>
|
||||
<Grid item xs={12} sm={gridSm} md={gridMd} lg={gridLg} key={field.id}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.25, delay: index * 0.03 }}
|
||||
>
|
||||
<StrategicInputField
|
||||
fieldId={field.id}
|
||||
value={formData[field.id]}
|
||||
error={formErrors[field.id]}
|
||||
autoPopulated={!!autoPopulatedFields[field.id]}
|
||||
dataSource={dataSources[field.id]}
|
||||
confidenceLevel={confidenceScores[field.id] || (autoPopulatedFields[field.id] ? 0.8 : undefined)}
|
||||
dataQuality={autoPopulatedFields[field.id] ? 'High Quality' : undefined}
|
||||
personalizationData={personalizationData[field.id]}
|
||||
onChange={(value: any) => onUpdateFormField(field.id, value)}
|
||||
onValidate={() => onValidateFormField(field.id)}
|
||||
onShowTooltip={() => onShowTooltip(field.id)}
|
||||
onViewDataSource={() => onViewDataSource(field.id)}
|
||||
accentColorKey={getCategoryColor(activeCategory) as any}
|
||||
isCompact={isCompactField}
|
||||
/>
|
||||
</motion.div>
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
@@ -218,18 +223,10 @@ const CategoryDetailView: React.FC<CategoryDetailViewProps> = ({
|
||||
<Box sx={{ mt: 3, display: 'flex', gap: 2 }}>
|
||||
{(() => {
|
||||
const isReviewed = reviewedCategories.has(activeCategory);
|
||||
console.log('🔍 Category review status:', {
|
||||
activeCategory,
|
||||
isReviewed,
|
||||
reviewedCategories: Array.from(reviewedCategories)
|
||||
});
|
||||
return !isReviewed ? (
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
console.log('🔘 Button clicked! activeCategory:', activeCategory);
|
||||
console.log('🔘 reviewedCategories:', Array.from(reviewedCategories));
|
||||
console.log('🔘 isMarkingReviewed:', isMarkingReviewed);
|
||||
onConfirmCategoryReview();
|
||||
}}
|
||||
startIcon={isMarkingReviewed ? <CircularProgress size={20} /> : <CheckCircleIcon />}
|
||||
|
||||
@@ -1,55 +1,29 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
interface UseModalManagementProps {
|
||||
aiGenerating: boolean;
|
||||
originalHandleCreateStrategy: (() => Promise<void>) | null;
|
||||
originalHandleCreateStrategy?: (() => Promise<void>) | null;
|
||||
setShowEnterpriseModal: (show: boolean) => void;
|
||||
}
|
||||
|
||||
export const useModalManagement = ({ aiGenerating, originalHandleCreateStrategy }: UseModalManagementProps) => {
|
||||
const [showEducationalModal, setShowEducationalModal] = useState(false);
|
||||
const [showEnterpriseModal, setShowEnterpriseModal] = useState(false);
|
||||
export const useModalManagement = ({
|
||||
aiGenerating,
|
||||
originalHandleCreateStrategy,
|
||||
setShowEnterpriseModal
|
||||
}: UseModalManagementProps) => {
|
||||
const originalHandleCreateStrategyRef = useRef<(() => Promise<void>) | null>(null);
|
||||
|
||||
// Persist enterprise modal state across hot reloads
|
||||
// Update ref when originalHandleCreateStrategy changes
|
||||
useEffect(() => {
|
||||
const savedModalState = sessionStorage.getItem('showEnterpriseModal');
|
||||
if (savedModalState === 'true') {
|
||||
console.log('🎯 Restoring enterprise modal state from sessionStorage');
|
||||
setShowEnterpriseModal(true);
|
||||
if (originalHandleCreateStrategy) {
|
||||
originalHandleCreateStrategyRef.current = originalHandleCreateStrategy;
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 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]);
|
||||
}, [originalHandleCreateStrategy]);
|
||||
|
||||
// Monitor enterprise modal state for debugging
|
||||
// Monitor aiGenerating 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]);
|
||||
console.log('🎯 useModalManagement: aiGenerating state changed:', aiGenerating);
|
||||
}, [aiGenerating]);
|
||||
|
||||
// Handle proceed with current strategy (30 fields)
|
||||
const handleProceedWithCurrentStrategy = async () => {
|
||||
@@ -62,9 +36,9 @@ export const useModalManagement = ({ aiGenerating, originalHandleCreateStrategy
|
||||
console.log('🎯 Calling original handleCreateStrategy after enterprise modal closes');
|
||||
try {
|
||||
// Ensure we're not already generating
|
||||
if (!aiGenerating && originalHandleCreateStrategy) {
|
||||
if (!aiGenerating && originalHandleCreateStrategyRef.current) {
|
||||
console.log('🎯 Starting strategy generation...');
|
||||
await originalHandleCreateStrategy();
|
||||
await originalHandleCreateStrategyRef.current();
|
||||
} else {
|
||||
console.log('🎯 Already generating, skipping duplicate call');
|
||||
}
|
||||
@@ -86,8 +60,8 @@ export const useModalManagement = ({ aiGenerating, originalHandleCreateStrategy
|
||||
console.log('🎯 Calling original handleCreateStrategy for enterprise datapoints');
|
||||
try {
|
||||
// Ensure we're not already generating
|
||||
if (!aiGenerating && originalHandleCreateStrategy) {
|
||||
await originalHandleCreateStrategy();
|
||||
if (!aiGenerating && originalHandleCreateStrategyRef.current) {
|
||||
await originalHandleCreateStrategyRef.current();
|
||||
} else {
|
||||
console.log('🎯 Already generating, skipping duplicate call');
|
||||
}
|
||||
@@ -98,10 +72,6 @@ export const useModalManagement = ({ aiGenerating, originalHandleCreateStrategy
|
||||
};
|
||||
|
||||
return {
|
||||
showEducationalModal,
|
||||
setShowEducationalModal,
|
||||
showEnterpriseModal,
|
||||
setShowEnterpriseModal,
|
||||
handleProceedWithCurrentStrategy,
|
||||
handleAddEnterpriseDatapoints
|
||||
};
|
||||
|
||||
@@ -1,41 +1,22 @@
|
||||
import React from 'react';
|
||||
import { Box, CircularProgress, Alert, Typography, Grid } from '@mui/material';
|
||||
import React, { useState } from 'react';
|
||||
import { Box, CircularProgress, Alert, Typography } from '@mui/material';
|
||||
import { useStrategyData } from './hooks/useStrategyData';
|
||||
import { useStrategyActions } from './hooks/useStrategyActions';
|
||||
import StrategyHeader from './components/StrategyHeader';
|
||||
import StrategicInsightsCard from './components/StrategicInsightsCard';
|
||||
import CompetitiveAnalysisCard from './components/CompetitiveAnalysisCard';
|
||||
import PerformancePredictionsCard from './components/PerformancePredictionsCard';
|
||||
import ImplementationRoadmapCard from './components/ImplementationRoadmapCard';
|
||||
import RiskAssessmentCard from './components/RiskAssessmentCard';
|
||||
import StrategyActions from './components/StrategyActions';
|
||||
import ConfirmationDialog from './components/ConfirmationDialog';
|
||||
import ReviewProgressHeader from './components/ReviewProgressHeader';
|
||||
|
||||
const StrategyIntelligenceTab: React.FC = () => {
|
||||
const { strategyData, loading, error, loadStrategyData } = useStrategyData();
|
||||
const {
|
||||
strategyConfirmed,
|
||||
showConfirmDialog,
|
||||
setShowConfirmDialog,
|
||||
handleConfirmStrategy,
|
||||
confirmStrategy,
|
||||
handleGenerateContentCalendar
|
||||
} = useStrategyActions();
|
||||
const { strategyData, loading, error } = useStrategyData();
|
||||
|
||||
// State to control review progress visibility
|
||||
const [showReviewProgress, setShowReviewProgress] = useState(false);
|
||||
|
||||
const handleConfirmStrategyClick = () => {
|
||||
handleConfirmStrategy();
|
||||
};
|
||||
|
||||
const handleConfirmStrategyAction = async () => {
|
||||
await confirmStrategy(strategyData);
|
||||
};
|
||||
|
||||
const handleGenerateContentCalendarAction = async () => {
|
||||
try {
|
||||
await handleGenerateContentCalendar(strategyData);
|
||||
} catch (error) {
|
||||
console.error('Error generating content calendar:', error);
|
||||
}
|
||||
const handleStartReviewProcess = () => {
|
||||
setShowReviewProgress(true);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
@@ -70,32 +51,52 @@ const StrategyIntelligenceTab: React.FC = () => {
|
||||
return (
|
||||
<Box sx={{ p: 3 }}>
|
||||
{/* Header Section */}
|
||||
<StrategyHeader strategyData={strategyData} strategyConfirmed={strategyConfirmed} />
|
||||
<StrategyHeader
|
||||
strategyData={strategyData}
|
||||
strategyConfirmed={false}
|
||||
onStartReview={handleStartReviewProcess}
|
||||
/>
|
||||
|
||||
{/* Review Progress Header - Only shown when review process is started */}
|
||||
{showReviewProgress && <ReviewProgressHeader />}
|
||||
|
||||
{/* Strategy Components Grid */}
|
||||
<Grid container spacing={2}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: {
|
||||
xs: '1fr',
|
||||
sm: '1fr',
|
||||
md: 'repeat(2, 1fr)',
|
||||
lg: 'repeat(2, 1fr)',
|
||||
xl: 'repeat(3, 1fr)'
|
||||
},
|
||||
gridAutoRows: 'minmax(min-content, auto)',
|
||||
gap: 3,
|
||||
position: 'relative',
|
||||
minHeight: '400px',
|
||||
padding: 2,
|
||||
'& > *': {
|
||||
minHeight: 'fit-content',
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
transition: 'z-index 0.3s ease, transform 0.3s ease',
|
||||
},
|
||||
'& > *:hover': {
|
||||
zIndex: 10,
|
||||
}
|
||||
}}
|
||||
>
|
||||
<StrategicInsightsCard strategyData={strategyData} />
|
||||
<CompetitiveAnalysisCard strategyData={strategyData} />
|
||||
<PerformancePredictionsCard strategyData={strategyData} />
|
||||
<ImplementationRoadmapCard strategyData={strategyData} />
|
||||
<RiskAssessmentCard strategyData={strategyData} />
|
||||
</Grid>
|
||||
</Box>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<StrategyActions
|
||||
strategyData={strategyData}
|
||||
strategyConfirmed={strategyConfirmed}
|
||||
onConfirmStrategy={handleConfirmStrategyClick}
|
||||
onGenerateContentCalendar={handleGenerateContentCalendarAction}
|
||||
onRefreshData={loadStrategyData}
|
||||
/>
|
||||
{/* Action Buttons - Removed, functionality moved to "Confirm & Activate Strategy" button in ReviewProgressHeader */}
|
||||
|
||||
{/* Confirmation Dialog */}
|
||||
<ConfirmationDialog
|
||||
open={showConfirmDialog}
|
||||
onClose={() => setShowConfirmDialog(false)}
|
||||
onConfirm={handleConfirmStrategyAction}
|
||||
/>
|
||||
{/* Confirmation Dialog - Removed, functionality moved to "Confirm & Activate Strategy" button */}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -70,29 +70,27 @@ const CompetitiveAnalysisCard: React.FC<CompetitiveAnalysisCardProps> = ({ strat
|
||||
|
||||
if (!strategyData?.competitive_analysis) {
|
||||
return (
|
||||
<Grid item xs={12} lg={6}>
|
||||
<ProgressiveCard
|
||||
title="Competitive Analysis"
|
||||
subtitle="Market positioning insights"
|
||||
icon={<TrendingUpIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="body1" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Competitive analysis data not available
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
details={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Available data keys: {strategyData ? Object.keys(strategyData).join(', ') : 'No data'}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
/>
|
||||
</Grid>
|
||||
<ProgressiveCard
|
||||
title="Competitive Analysis"
|
||||
subtitle="Market positioning insights"
|
||||
icon={<TrendingUpIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="body1" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Competitive analysis data not available
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
details={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Available data keys: {strategyData ? Object.keys(strategyData).join(', ') : 'No data'}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -630,7 +628,7 @@ const CompetitiveAnalysisCard: React.FC<CompetitiveAnalysisCardProps> = ({ strat
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid item xs={12} lg={6}>
|
||||
<>
|
||||
<ProgressiveCard
|
||||
title="Competitive Analysis"
|
||||
subtitle="Market positioning insights"
|
||||
@@ -639,6 +637,7 @@ const CompetitiveAnalysisCard: React.FC<CompetitiveAnalysisCardProps> = ({ strat
|
||||
details={detailedContent}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
componentId="competitive_analysis"
|
||||
/>
|
||||
|
||||
{/* Chip Modal for detailed view */}
|
||||
@@ -681,7 +680,7 @@ const CompetitiveAnalysisCard: React.FC<CompetitiveAnalysisCardProps> = ({ strat
|
||||
{chipModal.content}
|
||||
</Typography>
|
||||
</Popover>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -52,29 +52,27 @@ const ImplementationRoadmapCard: React.FC<ImplementationRoadmapCardProps> = ({ s
|
||||
|
||||
if (!strategyData?.implementation_roadmap) {
|
||||
return (
|
||||
<Grid item xs={12} lg={6}>
|
||||
<ProgressiveCard
|
||||
title="Implementation Roadmap"
|
||||
subtitle="Project timeline and phases"
|
||||
icon={<TimelineIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="body1" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Implementation roadmap data not available
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
details={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Available data keys: {strategyData ? Object.keys(strategyData).join(', ') : 'No data'}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
/>
|
||||
</Grid>
|
||||
<ProgressiveCard
|
||||
title="Implementation Roadmap"
|
||||
subtitle="Strategic execution plan"
|
||||
icon={<TimelineIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="body1" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Implementation roadmap data not available
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
details={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Available data keys: {strategyData ? Object.keys(strategyData).join(', ') : 'No data'}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -550,17 +548,16 @@ const ImplementationRoadmapCard: React.FC<ImplementationRoadmapCardProps> = ({ s
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid item xs={12} lg={6}>
|
||||
<ProgressiveCard
|
||||
title="Implementation Roadmap"
|
||||
subtitle="Project timeline and phases"
|
||||
icon={<TimelineIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={summaryContent}
|
||||
details={detailedContent}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
/>
|
||||
</Grid>
|
||||
<ProgressiveCard
|
||||
title="Implementation Roadmap"
|
||||
subtitle="Project timeline and phases"
|
||||
icon={<TimelineIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={summaryContent}
|
||||
details={detailedContent}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
componentId="implementation_roadmap"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -36,29 +36,27 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
|
||||
|
||||
if (!strategyData?.performance_predictions) {
|
||||
return (
|
||||
<Grid item xs={12} lg={6}>
|
||||
<ProgressiveCard
|
||||
title="Performance Predictions"
|
||||
subtitle="ROI and success metrics"
|
||||
icon={<ShowChartIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="body1" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Performance predictions data not available
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
details={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Available data keys: {strategyData ? Object.keys(strategyData).join(', ') : 'No data'}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
/>
|
||||
</Grid>
|
||||
<ProgressiveCard
|
||||
title="Performance Predictions"
|
||||
subtitle="AI-powered forecasting"
|
||||
icon={<TrendingUpIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="body1" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Performance predictions data not available
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
details={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Available data keys: {strategyData ? Object.keys(strategyData).join(', ') : 'No data'}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -80,8 +78,7 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
overflow: 'hidden'
|
||||
minWidth: 0
|
||||
}}>
|
||||
<Box sx={{
|
||||
width: 40,
|
||||
@@ -102,8 +99,7 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
|
||||
</Box>
|
||||
<Box sx={{
|
||||
minWidth: 0,
|
||||
flex: 1,
|
||||
overflow: 'hidden'
|
||||
flex: 1
|
||||
}}>
|
||||
<Typography variant="h6" sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.text.primary,
|
||||
@@ -558,17 +554,16 @@ const PerformancePredictionsCard: React.FC<PerformancePredictionsCardProps> = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid item xs={12} lg={6}>
|
||||
<ProgressiveCard
|
||||
title="Performance Predictions"
|
||||
subtitle="ROI and success metrics"
|
||||
icon={<ShowChartIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={summaryContent}
|
||||
details={detailedContent}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
/>
|
||||
</Grid>
|
||||
<ProgressiveCard
|
||||
title="Performance Predictions"
|
||||
subtitle="ROI and success metrics"
|
||||
icon={<ShowChartIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={summaryContent}
|
||||
details={detailedContent}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
componentId="performance_predictions"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ import {
|
||||
getAnalysisCardStyles,
|
||||
getEnhancedChipStyles
|
||||
} from '../styles';
|
||||
import ReviewStatusIndicator from './ReviewStatusIndicator';
|
||||
import ReviewConfirmationDialog from './ReviewConfirmationDialog';
|
||||
import { useStrategyReviewStore } from '../../../../../stores/strategyReviewStore';
|
||||
|
||||
interface ProgressiveCardProps {
|
||||
summary: React.ReactNode;
|
||||
@@ -29,6 +32,7 @@ interface ProgressiveCardProps {
|
||||
icon?: React.ReactNode;
|
||||
autoCollapseDelay?: number; // milliseconds
|
||||
className?: string;
|
||||
componentId?: string; // For review functionality
|
||||
}
|
||||
|
||||
const ProgressiveCard: React.FC<ProgressiveCardProps> = ({
|
||||
@@ -39,14 +43,30 @@ const ProgressiveCard: React.FC<ProgressiveCardProps> = ({
|
||||
subtitle,
|
||||
icon,
|
||||
autoCollapseDelay = 3000, // 3 seconds default
|
||||
className
|
||||
className,
|
||||
componentId
|
||||
}) => {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const [showReviewDialog, setShowReviewDialog] = useState(false);
|
||||
const [isConfirmingReview, setIsConfirmingReview] = useState(false);
|
||||
const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const theme = useTheme();
|
||||
|
||||
const cardStyles = getAnalysisCardStyles();
|
||||
|
||||
// Get review state for this component
|
||||
const {
|
||||
components,
|
||||
isReviewing,
|
||||
startReview,
|
||||
completeReview,
|
||||
resetReview
|
||||
} = useStrategyReviewStore();
|
||||
|
||||
const component = componentId ? components.find(c => c.id === componentId) : null;
|
||||
const componentStatus = component?.status || 'not_reviewed';
|
||||
const componentReviewedAt = component?.reviewedAt;
|
||||
|
||||
// Handle hover interactions
|
||||
const handleMouseEnter = () => {
|
||||
if (trigger === 'hover') {
|
||||
@@ -76,183 +96,277 @@ const ProgressiveCard: React.FC<ProgressiveCardProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
// Review handlers
|
||||
const handleStartReview = () => {
|
||||
if (componentId) {
|
||||
// Open the review dialog directly instead of setting to "in_review"
|
||||
setShowReviewDialog(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCompleteReview = () => {
|
||||
if (componentId) {
|
||||
setShowReviewDialog(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleResetReview = () => {
|
||||
if (componentId) {
|
||||
resetReview(componentId);
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirmReview = async (notes?: string) => {
|
||||
if (componentId) {
|
||||
setIsConfirmingReview(true);
|
||||
try {
|
||||
// Complete the review directly from "not_reviewed" to "reviewed"
|
||||
completeReview(componentId, notes);
|
||||
setShowReviewDialog(false);
|
||||
} finally {
|
||||
setIsConfirmingReview(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.1 }}
|
||||
whileHover={{ y: -4 }}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
className={className}
|
||||
>
|
||||
<Card sx={{
|
||||
...cardStyles.card,
|
||||
'& .shimmer-text': {
|
||||
background: `linear-gradient(135deg, ${ANALYSIS_CARD_STYLES.colors.primary} 0%, ${ANALYSIS_CARD_STYLES.colors.secondary} 100%)`,
|
||||
backgroundClip: 'text',
|
||||
WebkitBackgroundClip: 'text',
|
||||
WebkitTextFillColor: 'transparent',
|
||||
animation: 'shimmer 2s ease-in-out infinite'
|
||||
},
|
||||
'& .bounce-icon': {
|
||||
animation: 'bounce 2s infinite'
|
||||
},
|
||||
'@keyframes shimmer': {
|
||||
'0%, 100%': { opacity: 1 },
|
||||
'50%': { opacity: 0.8 }
|
||||
},
|
||||
'@keyframes bounce': {
|
||||
'0%, 20%, 50%, 80%, 100%': { transform: 'translateY(0)' },
|
||||
'40%': { transform: 'translateY(-4px)' },
|
||||
'60%': { transform: 'translateY(-2px)' }
|
||||
}
|
||||
}}>
|
||||
<CardContent sx={cardStyles.cardContent}>
|
||||
{/* Header Section */}
|
||||
{title && (
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
mb: 2
|
||||
}}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
{icon && (
|
||||
<Box sx={{
|
||||
p: 1,
|
||||
borderRadius: 2,
|
||||
background: `linear-gradient(135deg, ${ANALYSIS_CARD_STYLES.colors.primary} 0%, ${ANALYSIS_CARD_STYLES.colors.secondary} 100%)`,
|
||||
mr: 1.5,
|
||||
boxShadow: `0 4px 12px ${ANALYSIS_CARD_STYLES.colors.primary}30`
|
||||
}}>
|
||||
{icon}
|
||||
</Box>
|
||||
)}
|
||||
<Box>
|
||||
<Typography variant="h6" className="shimmer-text" sx={{
|
||||
fontWeight: 600
|
||||
}}>
|
||||
{title}
|
||||
</Typography>
|
||||
{subtitle && (
|
||||
<Typography variant="caption" sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
|
||||
fontSize: '0.75rem'
|
||||
}}>
|
||||
{subtitle}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Trigger Button */}
|
||||
{trigger === 'click' && (
|
||||
<Button
|
||||
onClick={handleToggle}
|
||||
variant="text"
|
||||
size="small"
|
||||
sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.primary,
|
||||
'&:hover': {
|
||||
background: 'rgba(102, 126, 234, 0.1)'
|
||||
},
|
||||
minWidth: 'auto',
|
||||
px: 1.5,
|
||||
py: 0.5,
|
||||
borderRadius: 2,
|
||||
fontSize: '0.75rem',
|
||||
fontWeight: 600,
|
||||
textTransform: 'none'
|
||||
}}
|
||||
endIcon={
|
||||
isExpanded ? (
|
||||
<ExpandLessIcon sx={{ fontSize: 16 }} />
|
||||
) : (
|
||||
<ExpandMoreIcon sx={{ fontSize: 16 }} />
|
||||
)
|
||||
}
|
||||
>
|
||||
{isExpanded ? 'Show Less' : 'Read More'}
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Summary Section - Always Visible */}
|
||||
<Box sx={{ mb: trigger === 'click' ? 2 : 0 }}>
|
||||
{summary}
|
||||
</Box>
|
||||
|
||||
{/* Progressive Details Section */}
|
||||
<AnimatePresence>
|
||||
{isExpanded && (
|
||||
<motion.div
|
||||
initial={{
|
||||
height: 0,
|
||||
opacity: 0,
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
animate={{
|
||||
height: 'auto',
|
||||
opacity: 1,
|
||||
overflow: 'visible'
|
||||
}}
|
||||
exit={{
|
||||
height: 0,
|
||||
opacity: 0,
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
transition={{
|
||||
duration: 0.4,
|
||||
ease: [0.4, 0.0, 0.2, 1],
|
||||
opacity: { duration: 0.3 }
|
||||
}}
|
||||
>
|
||||
<Fade in={isExpanded} timeout={300}>
|
||||
<Box sx={{
|
||||
pt: 2,
|
||||
borderTop: `1px solid ${ANALYSIS_CARD_STYLES.colors.border.secondary}`,
|
||||
opacity: 0.9
|
||||
}}>
|
||||
{details}
|
||||
</Box>
|
||||
</Fade>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* Hover Indicator (for hover trigger) */}
|
||||
{trigger === 'hover' && !isExpanded && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 0.6 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.1 }}
|
||||
whileHover={{ y: -4 }}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
className={className}
|
||||
style={{
|
||||
gridColumn: isExpanded && trigger === 'hover' ? '1 / -1' : 'auto',
|
||||
zIndex: isExpanded && trigger === 'hover' ? 10 : 1,
|
||||
transition: 'grid-column 0.3s ease, z-index 0.3s ease, margin 0.3s ease',
|
||||
margin: isExpanded && trigger === 'hover' ? '16px 0' : '0',
|
||||
padding: isExpanded && trigger === 'hover' ? '8px 0' : '0',
|
||||
}}
|
||||
>
|
||||
<Card sx={{
|
||||
...cardStyles.card,
|
||||
transform: isExpanded && trigger === 'hover' ? 'scale(1.02)' : 'scale(1)',
|
||||
boxShadow: isExpanded && trigger === 'hover'
|
||||
? '0 8px 32px rgba(0, 0, 0, 0.15)'
|
||||
: cardStyles.card.boxShadow,
|
||||
transition: 'all 0.3s ease',
|
||||
margin: isExpanded && trigger === 'hover' ? '8px 0' : '0',
|
||||
'& .bounce-icon': {
|
||||
animation: 'bounce 2s infinite'
|
||||
},
|
||||
'@keyframes bounce': {
|
||||
'0%, 20%, 50%, 80%, 100%': { transform: 'translateY(0)' },
|
||||
'40%': { transform: 'translateY(-4px)' },
|
||||
'60%': { transform: 'translateY(-2px)' }
|
||||
}
|
||||
}}>
|
||||
<CardContent sx={cardStyles.cardContent}>
|
||||
{/* Header Section */}
|
||||
{title && (
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
mt: 1,
|
||||
py: 0.5
|
||||
justifyContent: 'space-between',
|
||||
mb: 2
|
||||
}}>
|
||||
<ArrowDownIcon className="bounce-icon" sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
|
||||
fontSize: 16
|
||||
}} />
|
||||
<Typography variant="caption" sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
|
||||
ml: 0.5,
|
||||
fontSize: '0.7rem'
|
||||
}}>
|
||||
Hover to see more
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
{icon && (
|
||||
<Box sx={{
|
||||
p: 1,
|
||||
borderRadius: 2,
|
||||
background: `linear-gradient(135deg, ${ANALYSIS_CARD_STYLES.colors.primary} 0%, ${ANALYSIS_CARD_STYLES.colors.secondary} 100%)`,
|
||||
mr: 1.5,
|
||||
boxShadow: `0 4px 12px ${ANALYSIS_CARD_STYLES.colors.primary}30`
|
||||
}}>
|
||||
{icon}
|
||||
</Box>
|
||||
)}
|
||||
<Box>
|
||||
<Typography variant="h6" sx={{
|
||||
fontWeight: 600,
|
||||
color: ANALYSIS_CARD_STYLES.colors.text.primary
|
||||
}}>
|
||||
{title}
|
||||
</Typography>
|
||||
{subtitle && (
|
||||
<Typography variant="caption" sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
|
||||
fontSize: '0.75rem'
|
||||
}}>
|
||||
{subtitle}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Review Status Indicator */}
|
||||
{componentId && (
|
||||
<Box sx={{ ml: 2 }}>
|
||||
<ReviewStatusIndicator
|
||||
status={componentStatus}
|
||||
reviewedAt={componentReviewedAt}
|
||||
onStartReview={handleStartReview}
|
||||
onCompleteReview={handleCompleteReview}
|
||||
onResetReview={handleResetReview}
|
||||
isReviewing={isReviewing}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Trigger Button */}
|
||||
{trigger === 'click' && (
|
||||
<Button
|
||||
onClick={handleToggle}
|
||||
variant="text"
|
||||
size="small"
|
||||
sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.primary,
|
||||
'&:hover': {
|
||||
background: 'rgba(102, 126, 234, 0.1)'
|
||||
},
|
||||
minWidth: 'auto',
|
||||
px: 1.5,
|
||||
py: 0.5,
|
||||
borderRadius: 2,
|
||||
fontSize: '0.75rem',
|
||||
fontWeight: 600,
|
||||
textTransform: 'none'
|
||||
}}
|
||||
endIcon={
|
||||
isExpanded ? (
|
||||
<ExpandLessIcon sx={{ fontSize: 16 }} />
|
||||
) : (
|
||||
<ExpandMoreIcon sx={{ fontSize: 16 }} />
|
||||
)
|
||||
}
|
||||
>
|
||||
{isExpanded ? 'Show Less' : 'Read More'}
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</motion.div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* Summary Section - Always Visible */}
|
||||
<Box sx={{ mb: trigger === 'click' ? 2 : 0 }}>
|
||||
{summary}
|
||||
</Box>
|
||||
|
||||
{/* Progressive Details Section */}
|
||||
<AnimatePresence>
|
||||
{isExpanded && (
|
||||
<motion.div
|
||||
initial={{
|
||||
height: 0,
|
||||
opacity: 0,
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
animate={{
|
||||
height: 'auto',
|
||||
opacity: 1,
|
||||
overflow: 'visible'
|
||||
}}
|
||||
exit={{
|
||||
height: 0,
|
||||
opacity: 0,
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
transition={{
|
||||
duration: 0.4,
|
||||
ease: [0.4, 0.0, 0.2, 1],
|
||||
opacity: { duration: 0.3 }
|
||||
}}
|
||||
>
|
||||
<Fade in={isExpanded} timeout={300}>
|
||||
<Box sx={{
|
||||
pt: 2,
|
||||
borderTop: `1px solid ${ANALYSIS_CARD_STYLES.colors.border.secondary}`,
|
||||
opacity: 0.9
|
||||
}}>
|
||||
{details}
|
||||
</Box>
|
||||
</Fade>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* Hover Indicator (for hover trigger) */}
|
||||
{trigger === 'hover' && !isExpanded && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 0.6 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
mt: 1,
|
||||
py: 0.5
|
||||
}}>
|
||||
<ArrowDownIcon className="bounce-icon" sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
|
||||
fontSize: 16
|
||||
}} />
|
||||
<Typography variant="caption" sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
|
||||
ml: 0.5,
|
||||
fontSize: '0.7rem'
|
||||
}}>
|
||||
Hover to see more
|
||||
</Typography>
|
||||
</Box>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* Full Width Expansion Indicator */}
|
||||
{trigger === 'hover' && isExpanded && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: 'auto' }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
mt: 1,
|
||||
py: 0.5,
|
||||
background: 'rgba(102, 126, 234, 0.1)',
|
||||
borderRadius: 1,
|
||||
border: '1px solid rgba(102, 126, 234, 0.2)'
|
||||
}}>
|
||||
<Typography variant="caption" sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.primary,
|
||||
fontSize: '0.7rem',
|
||||
fontWeight: 500
|
||||
}}>
|
||||
✨ Expanded to full width for better readability
|
||||
</Typography>
|
||||
</Box>
|
||||
</motion.div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
|
||||
{/* Review Confirmation Dialog */}
|
||||
{componentId && (
|
||||
<ReviewConfirmationDialog
|
||||
open={showReviewDialog}
|
||||
onClose={() => setShowReviewDialog(false)}
|
||||
onConfirm={handleConfirmReview}
|
||||
componentId={componentId}
|
||||
componentTitle={title || ''}
|
||||
componentSubtitle={subtitle || ''}
|
||||
isConfirming={isConfirmingReview}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Button,
|
||||
Typography,
|
||||
Box,
|
||||
TextField,
|
||||
Chip,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
CircularProgress
|
||||
} from '@mui/material';
|
||||
import {
|
||||
CheckCircle as CheckCircleIcon,
|
||||
Lightbulb as LightbulbIcon,
|
||||
TrendingUp as TrendingUpIcon,
|
||||
ShowChart as ShowChartIcon,
|
||||
Timeline as TimelineIcon,
|
||||
Warning as WarningIcon,
|
||||
Close as CloseIcon
|
||||
} from '@mui/icons-material';
|
||||
import { motion } from 'framer-motion';
|
||||
import { ANALYSIS_CARD_STYLES } from '../styles';
|
||||
|
||||
interface ReviewConfirmationDialogProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onConfirm: (notes?: string) => void;
|
||||
componentId: string;
|
||||
componentTitle: string;
|
||||
componentSubtitle: string;
|
||||
isConfirming?: boolean;
|
||||
}
|
||||
|
||||
const ReviewConfirmationDialog: React.FC<ReviewConfirmationDialogProps> = ({
|
||||
open,
|
||||
onClose,
|
||||
onConfirm,
|
||||
componentId,
|
||||
componentTitle,
|
||||
componentSubtitle,
|
||||
isConfirming = false
|
||||
}) => {
|
||||
const [notes, setNotes] = useState('');
|
||||
|
||||
const getComponentIcon = (id: string) => {
|
||||
switch (id) {
|
||||
case 'strategic_insights':
|
||||
return <LightbulbIcon />;
|
||||
case 'competitive_analysis':
|
||||
return <TrendingUpIcon />;
|
||||
case 'performance_predictions':
|
||||
return <ShowChartIcon />;
|
||||
case 'implementation_roadmap':
|
||||
return <TimelineIcon />;
|
||||
case 'risk_assessment':
|
||||
return <WarningIcon />;
|
||||
default:
|
||||
return <CheckCircleIcon />;
|
||||
}
|
||||
};
|
||||
|
||||
const getComponentSummary = (id: string) => {
|
||||
switch (id) {
|
||||
case 'strategic_insights':
|
||||
return [
|
||||
'Market positioning analysis',
|
||||
'Growth potential assessment',
|
||||
'SWOT analysis summary',
|
||||
'Content opportunities identification'
|
||||
];
|
||||
case 'competitive_analysis':
|
||||
return [
|
||||
'Competitor landscape analysis',
|
||||
'Market gaps identification',
|
||||
'Competitive advantages',
|
||||
'Strategic recommendations'
|
||||
];
|
||||
case 'performance_predictions':
|
||||
return [
|
||||
'ROI projections',
|
||||
'Traffic growth forecasts',
|
||||
'Engagement metrics predictions',
|
||||
'Success probability assessment'
|
||||
];
|
||||
case 'implementation_roadmap':
|
||||
return [
|
||||
'Project timeline and phases',
|
||||
'Resource allocation plan',
|
||||
'Milestone tracking',
|
||||
'Success metrics definition'
|
||||
];
|
||||
case 'risk_assessment':
|
||||
return [
|
||||
'Risk identification and analysis',
|
||||
'Mitigation strategies',
|
||||
'Monitoring framework',
|
||||
'Contingency planning'
|
||||
];
|
||||
default:
|
||||
return ['Strategy component analysis'];
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
onConfirm(notes.trim() || undefined);
|
||||
setNotes('');
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setNotes('');
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
maxWidth="md"
|
||||
fullWidth
|
||||
PaperProps={{
|
||||
sx: {
|
||||
borderRadius: 3,
|
||||
background: 'linear-gradient(135deg, #ffffff 0%, #f8fafc 100%)',
|
||||
backdropFilter: 'blur(20px)',
|
||||
border: '1px solid rgba(102, 126, 234, 0.3)',
|
||||
boxShadow: '0 20px 60px rgba(0, 0, 0, 0.15), 0 0 40px rgba(102, 126, 234, 0.1)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DialogTitle sx={{
|
||||
pb: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 2,
|
||||
background: 'linear-gradient(135deg, rgba(102, 126, 234, 0.08) 0%, rgba(118, 75, 162, 0.08) 100%)',
|
||||
borderBottom: '1px solid rgba(102, 126, 234, 0.15)'
|
||||
}}>
|
||||
<Box sx={{
|
||||
p: 1.5,
|
||||
borderRadius: 2,
|
||||
background: `linear-gradient(135deg, ${ANALYSIS_CARD_STYLES.colors.primary} 0%, ${ANALYSIS_CARD_STYLES.colors.secondary} 100%)`,
|
||||
color: 'white',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
boxShadow: '0 4px 12px rgba(102, 126, 234, 0.3)'
|
||||
}}>
|
||||
{getComponentIcon(componentId)}
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography variant="h5" sx={{
|
||||
color: '#1a1a1a',
|
||||
fontWeight: 700,
|
||||
mb: 0.5
|
||||
}}>
|
||||
Review Strategy Component
|
||||
</Typography>
|
||||
<Typography variant="body1" sx={{
|
||||
color: '#666666',
|
||||
fontSize: '1rem',
|
||||
fontWeight: 500
|
||||
}}>
|
||||
{componentSubtitle}
|
||||
</Typography>
|
||||
</Box>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent sx={{ pt: 3, pb: 2 }}>
|
||||
<Box sx={{ mb: 4 }}>
|
||||
<Typography variant="h6" sx={{
|
||||
color: '#1a1a1a',
|
||||
mb: 2,
|
||||
fontWeight: 600,
|
||||
fontSize: '1.1rem'
|
||||
}}>
|
||||
You're reviewing <strong style={{ color: ANALYSIS_CARD_STYLES.colors.primary }}>"{componentTitle}"</strong>
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body1" sx={{
|
||||
color: '#666666',
|
||||
mb: 3,
|
||||
fontSize: '1rem',
|
||||
fontWeight: 500
|
||||
}}>
|
||||
This component includes the following analysis:
|
||||
</Typography>
|
||||
|
||||
<List dense sx={{ mb: 3 }}>
|
||||
{getComponentSummary(componentId).map((item, index) => (
|
||||
<ListItem key={index} sx={{ py: 1, px: 0 }}>
|
||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
||||
<Box sx={{
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: '50%',
|
||||
background: ANALYSIS_CARD_STYLES.colors.primary,
|
||||
opacity: 0.8
|
||||
}} />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={item}
|
||||
primaryTypographyProps={{
|
||||
variant: 'body1',
|
||||
fontSize: '1rem',
|
||||
color: '#1a1a1a',
|
||||
fontWeight: 500
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
|
||||
<Box sx={{
|
||||
p: 2.5,
|
||||
borderRadius: 2,
|
||||
background: 'linear-gradient(135deg, rgba(102, 126, 234, 0.08) 0%, rgba(118, 75, 162, 0.08) 100%)',
|
||||
border: '1px solid rgba(102, 126, 234, 0.2)',
|
||||
boxShadow: '0 2px 8px rgba(102, 126, 234, 0.1)'
|
||||
}}>
|
||||
<Typography variant="body1" sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.primary,
|
||||
fontWeight: 600,
|
||||
fontSize: '1rem',
|
||||
lineHeight: 1.5
|
||||
}}>
|
||||
💡 Tip: Review all the insights and data, then confirm to mark this component as reviewed.
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Typography variant="body1" sx={{
|
||||
color: '#1a1a1a',
|
||||
mb: 1.5,
|
||||
fontWeight: 600,
|
||||
fontSize: '1rem'
|
||||
}}>
|
||||
Optional Notes (for your reference):
|
||||
</Typography>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
rows={4}
|
||||
variant="outlined"
|
||||
placeholder="Add any notes or observations about this strategy component..."
|
||||
value={notes}
|
||||
onChange={(e) => setNotes(e.target.value)}
|
||||
sx={{
|
||||
'& .MuiOutlinedInput-root': {
|
||||
fontSize: '1rem',
|
||||
borderRadius: 2,
|
||||
'&:hover fieldset': {
|
||||
borderColor: ANALYSIS_CARD_STYLES.colors.primary,
|
||||
borderWidth: '2px'
|
||||
},
|
||||
'&.Mui-focused fieldset': {
|
||||
borderColor: ANALYSIS_CARD_STYLES.colors.primary,
|
||||
borderWidth: '2px'
|
||||
}
|
||||
},
|
||||
'& .MuiInputBase-input': {
|
||||
fontSize: '1rem',
|
||||
lineHeight: 1.5
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions sx={{ p: 3, pt: 2, background: 'rgba(102, 126, 234, 0.05)', borderTop: '1px solid rgba(102, 126, 234, 0.15)' }}>
|
||||
<Button
|
||||
onClick={handleClose}
|
||||
disabled={isConfirming}
|
||||
startIcon={<CloseIcon />}
|
||||
sx={{
|
||||
color: '#666666',
|
||||
fontWeight: 600,
|
||||
fontSize: '1rem',
|
||||
px: 3,
|
||||
py: 1,
|
||||
borderRadius: 2,
|
||||
'&:hover': {
|
||||
background: 'rgba(0, 0, 0, 0.05)',
|
||||
transform: 'translateY(-1px)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleConfirm}
|
||||
disabled={isConfirming}
|
||||
variant="contained"
|
||||
startIcon={isConfirming ? <CircularProgress size={18} /> : <CheckCircleIcon />}
|
||||
sx={{
|
||||
background: `linear-gradient(135deg, ${ANALYSIS_CARD_STYLES.colors.success} 0%, ${ANALYSIS_CARD_STYLES.colors.success}80 100%)`,
|
||||
fontWeight: 600,
|
||||
fontSize: '1rem',
|
||||
px: 3,
|
||||
py: 1,
|
||||
borderRadius: 2,
|
||||
boxShadow: '0 4px 12px rgba(76, 175, 80, 0.3)',
|
||||
'&:hover': {
|
||||
background: `linear-gradient(135deg, ${ANALYSIS_CARD_STYLES.colors.success}80 0%, ${ANALYSIS_CARD_STYLES.colors.success} 100%)`,
|
||||
boxShadow: '0 6px 16px rgba(76, 175, 80, 0.4)',
|
||||
transform: 'translateY(-1px)'
|
||||
},
|
||||
'&:active': {
|
||||
transform: 'translateY(0)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{isConfirming ? 'Confirming...' : 'Mark as Reviewed'}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReviewConfirmationDialog;
|
||||
@@ -0,0 +1,489 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
Chip,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
Card,
|
||||
CardContent,
|
||||
Badge,
|
||||
Button,
|
||||
CircularProgress
|
||||
} from '@mui/material';
|
||||
import {
|
||||
Refresh as RefreshIcon,
|
||||
CheckCircle as CheckCircleIcon,
|
||||
Schedule as ScheduleIcon,
|
||||
Warning as WarningIcon,
|
||||
PlayArrow as PlayArrowIcon
|
||||
} from '@mui/icons-material';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useStrategyReviewStore } from '../../../../../stores/strategyReviewStore';
|
||||
import { ANALYSIS_CARD_STYLES } from '../styles';
|
||||
import { contentPlanningApi } from '../../../../../services/contentPlanningApi';
|
||||
|
||||
const ReviewProgressHeader: React.FC = () => {
|
||||
const {
|
||||
components,
|
||||
reviewProgress,
|
||||
isAllReviewed,
|
||||
resetAllReviews,
|
||||
getUnreviewedComponents,
|
||||
getReviewedComponents
|
||||
} = useStrategyReviewStore();
|
||||
|
||||
// Extract domain name from strategy data (you can pass this as prop if needed)
|
||||
const getDomainName = () => {
|
||||
// For now, return a default domain - you can enhance this to get from strategy data
|
||||
return "alwrity.com";
|
||||
};
|
||||
|
||||
const unreviewedCount = getUnreviewedComponents().length;
|
||||
const reviewedCount = getReviewedComponents().length;
|
||||
const totalCount = components.length;
|
||||
|
||||
// Debug logging
|
||||
console.log('🔍 ReviewProgressHeader Debug:', {
|
||||
components,
|
||||
reviewProgress,
|
||||
unreviewedCount,
|
||||
reviewedCount,
|
||||
totalCount,
|
||||
isAllReviewed: isAllReviewed()
|
||||
});
|
||||
|
||||
const getProgressColor = () => {
|
||||
if (reviewProgress === 100) return ANALYSIS_CARD_STYLES.colors.success;
|
||||
if (reviewProgress >= 60) return ANALYSIS_CARD_STYLES.colors.primary;
|
||||
if (reviewProgress >= 30) return ANALYSIS_CARD_STYLES.colors.warning;
|
||||
return ANALYSIS_CARD_STYLES.colors.error;
|
||||
};
|
||||
|
||||
const getProgressText = () => {
|
||||
if (reviewProgress === 100) return 'All components reviewed!';
|
||||
if (reviewProgress >= 60) return 'Great progress!';
|
||||
if (reviewProgress >= 30) return 'Making good progress';
|
||||
return 'Getting started';
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, ease: "easeOut" }}
|
||||
>
|
||||
<Card
|
||||
sx={{
|
||||
mb: 3,
|
||||
background: 'linear-gradient(135deg, #0f0f23 0%, #1a1a2e 25%, #16213e 50%, #0f3460 75%, #533483 100%)',
|
||||
color: 'white',
|
||||
boxShadow: '0 20px 60px rgba(0, 0, 0, 0.5), 0 0 40px rgba(102, 126, 234, 0.3)',
|
||||
borderRadius: 3,
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
border: '1px solid rgba(102, 126, 234, 0.3)',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: 'radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.3) 0%, transparent 50%), radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.3) 0%, transparent 50%)',
|
||||
pointerEvents: 'none'
|
||||
},
|
||||
'&::after': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: 'linear-gradient(45deg, transparent 30%, rgba(255,255,255,0.1) 50%, transparent 70%)',
|
||||
animation: 'shimmer 3s infinite',
|
||||
pointerEvents: 'none'
|
||||
},
|
||||
'@keyframes shimmer': {
|
||||
'0%': { transform: 'translateX(-100%)' },
|
||||
'100%': { transform: 'translateX(100%)' }
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* Animated Border Lights */}
|
||||
<motion.div
|
||||
animate={{
|
||||
boxShadow: [
|
||||
'0 0 20px rgba(102, 126, 234, 0.5)',
|
||||
'0 0 40px rgba(102, 126, 234, 0.8)',
|
||||
'0 0 20px rgba(102, 126, 234, 0.5)'
|
||||
]
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
borderRadius: '12px',
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
/>
|
||||
|
||||
<CardContent sx={{ position: 'relative', zIndex: 1, p: 2 }}>
|
||||
{/* Header with Circular Progress and Status Chips */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 1.5 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||
{/* Circular Progress */}
|
||||
<Box sx={{ position: 'relative', display: 'inline-flex' }}>
|
||||
<CircularProgress
|
||||
variant="determinate"
|
||||
value={reviewProgress}
|
||||
size={50}
|
||||
thickness={4}
|
||||
sx={{
|
||||
color: getProgressColor(),
|
||||
'& .MuiCircularProgress-circle': {
|
||||
strokeLinecap: 'round',
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
position: 'absolute',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption" sx={{
|
||||
color: getProgressColor(),
|
||||
fontWeight: 700,
|
||||
fontSize: '0.7rem'
|
||||
}}>
|
||||
{Math.round(reviewProgress)}%
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Typography variant="h6" sx={{
|
||||
color: 'white',
|
||||
fontWeight: 600,
|
||||
mb: 0.25
|
||||
}}>
|
||||
Strategy Review Progress
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
fontSize: '0.8rem'
|
||||
}}>
|
||||
{getProgressText()}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Status Chips */}
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<Chip
|
||||
icon={<CheckCircleIcon />}
|
||||
label={`${reviewedCount} Reviewed`}
|
||||
size="small"
|
||||
sx={{
|
||||
background: ANALYSIS_CARD_STYLES.colors.success,
|
||||
color: 'white',
|
||||
fontWeight: 500,
|
||||
fontSize: '0.65rem',
|
||||
height: 24,
|
||||
'& .MuiChip-icon': {
|
||||
color: 'white',
|
||||
fontSize: 14
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
{unreviewedCount > 0 && (
|
||||
<Chip
|
||||
icon={<ScheduleIcon />}
|
||||
label={`${unreviewedCount} Pending`}
|
||||
size="small"
|
||||
sx={{
|
||||
background: ANALYSIS_CARD_STYLES.colors.warning,
|
||||
color: 'white',
|
||||
fontWeight: 500,
|
||||
fontSize: '0.65rem',
|
||||
height: 24,
|
||||
'& .MuiChip-icon': {
|
||||
color: 'white',
|
||||
fontSize: 14
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Reset Button */}
|
||||
<Tooltip title="Reset all reviews">
|
||||
<IconButton
|
||||
onClick={resetAllReviews}
|
||||
size="small"
|
||||
sx={{
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
'&:hover': {
|
||||
color: '#f44336',
|
||||
background: 'rgba(244, 67, 54, 0.2)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<RefreshIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
{/* Progress Summary */}
|
||||
<Box sx={{ mb: 1.5 }}>
|
||||
<Typography variant="body2" sx={{
|
||||
color: 'white',
|
||||
fontWeight: 500,
|
||||
fontSize: '0.8rem'
|
||||
}}>
|
||||
{reviewedCount} of {totalCount} components reviewed
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Informative Text */}
|
||||
<Box sx={{ mb: 1.5 }}>
|
||||
<Typography variant="body2" sx={{
|
||||
color: 'rgba(255, 255, 255, 0.9)',
|
||||
fontSize: '0.8rem',
|
||||
lineHeight: 1.4,
|
||||
background: 'rgba(255, 255, 255, 0.05)',
|
||||
p: 1.5,
|
||||
borderRadius: 1,
|
||||
border: '1px solid rgba(255, 255, 255, 0.1)'
|
||||
}}>
|
||||
<strong>Complete review by clicking 'Not Reviewed' button and confirming datapoints of 5 analysis components below.</strong>
|
||||
<br />
|
||||
<span style={{ color: 'rgba(255, 255, 255, 0.7)' }}>
|
||||
Important: Content strategy for <strong>{getDomainName()}</strong> will shape content generation next.
|
||||
</span>
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Individual Component Status and Activate Strategy Button */}
|
||||
<Box sx={{ mb: 1.5 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 0.75 }}>
|
||||
<Typography variant="caption" sx={{
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
fontWeight: 500,
|
||||
fontSize: '0.7rem'
|
||||
}}>
|
||||
Component Status
|
||||
</Typography>
|
||||
|
||||
{/* Confirm & Activate Strategy Button */}
|
||||
<Tooltip
|
||||
title={isAllReviewed() ? "Confirm strategy and activate content generation" : "Complete all component reviews to confirm and activate strategy"}
|
||||
arrow
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
disabled={!isAllReviewed()}
|
||||
startIcon={<PlayArrowIcon />}
|
||||
onClick={async () => {
|
||||
if (isAllReviewed()) {
|
||||
try {
|
||||
// Handle strategy confirmation and activation
|
||||
console.log('Confirming and activating strategy...');
|
||||
|
||||
// 1. Save the strategy confirmation to backend
|
||||
// Note: You'll need to get the actual strategy ID from context/props
|
||||
const strategyId = "current_strategy_id"; // Replace with actual strategy ID
|
||||
|
||||
try {
|
||||
await contentPlanningApi.updateEnhancedStrategy(
|
||||
strategyId,
|
||||
{
|
||||
confirmed: true,
|
||||
confirmed_at: new Date().toISOString(),
|
||||
review_completed: true,
|
||||
review_completed_at: new Date().toISOString()
|
||||
}
|
||||
);
|
||||
console.log('Strategy confirmation saved to backend');
|
||||
} catch (updateError) {
|
||||
console.warn('Could not save confirmation to backend:', updateError);
|
||||
}
|
||||
|
||||
// 2. Show success message
|
||||
alert('Strategy confirmed and activated! You can now proceed to create your content calendar.');
|
||||
|
||||
// 3. Navigate to content calendar creation
|
||||
// You can add navigation logic here
|
||||
// navigate('/content-calendar');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error confirming and activating strategy:', error);
|
||||
alert('Error confirming strategy. Please try again.');
|
||||
}
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
background: isAllReviewed()
|
||||
? 'linear-gradient(135deg, #4caf50 0%, #66bb6a 100%)'
|
||||
: 'rgba(255, 255, 255, 0.1)',
|
||||
color: isAllReviewed() ? 'white' : 'rgba(255, 255, 255, 0.5)',
|
||||
fontWeight: 600,
|
||||
fontSize: '0.7rem',
|
||||
px: 2,
|
||||
py: 0.5,
|
||||
borderRadius: 2,
|
||||
boxShadow: isAllReviewed()
|
||||
? '0 2px 8px rgba(76, 175, 80, 0.3)'
|
||||
: 'none',
|
||||
border: isAllReviewed()
|
||||
? '1px solid rgba(76, 175, 80, 0.4)'
|
||||
: '1px solid rgba(255, 255, 255, 0.2)',
|
||||
textTransform: 'none',
|
||||
minWidth: 'auto',
|
||||
'&:hover': {
|
||||
background: isAllReviewed()
|
||||
? 'linear-gradient(135deg, #66bb6a 0%, #81c784 100%)'
|
||||
: 'rgba(255, 255, 255, 0.1)',
|
||||
boxShadow: isAllReviewed()
|
||||
? '0 4px 12px rgba(76, 175, 80, 0.4)'
|
||||
: 'none',
|
||||
transform: isAllReviewed() ? 'translateY(-1px)' : 'none'
|
||||
},
|
||||
'&:active': {
|
||||
transform: isAllReviewed() ? 'translateY(0)' : 'none'
|
||||
},
|
||||
'&:disabled': {
|
||||
background: 'rgba(255, 255, 255, 0.05)',
|
||||
color: 'rgba(255, 255, 255, 0.3)',
|
||||
boxShadow: 'none',
|
||||
transform: 'none'
|
||||
},
|
||||
'& .MuiButton-startIcon': {
|
||||
marginRight: 0.5
|
||||
}
|
||||
}}
|
||||
>
|
||||
Confirm & Activate Strategy
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ display: 'flex', gap: 0.75, flexWrap: 'wrap' }}>
|
||||
{components.map((component) => (
|
||||
<Tooltip
|
||||
key={component.id}
|
||||
title={`${component.title}: ${component.status === 'reviewed' ? 'Reviewed' : 'Pending Review'}`}
|
||||
arrow
|
||||
>
|
||||
<Badge
|
||||
badgeContent={
|
||||
component.status === 'reviewed' ? (
|
||||
<CheckCircleIcon sx={{ fontSize: 10, color: 'white' }} />
|
||||
) : (
|
||||
<ScheduleIcon sx={{ fontSize: 10, color: 'white' }} />
|
||||
)
|
||||
}
|
||||
color={component.status === 'reviewed' ? 'success' : 'warning'}
|
||||
>
|
||||
<Chip
|
||||
label={component.title}
|
||||
size="small"
|
||||
sx={{
|
||||
background: component.status === 'reviewed'
|
||||
? 'rgba(76, 175, 80, 0.3)'
|
||||
: 'rgba(255, 152, 0, 0.3)',
|
||||
color: component.status === 'reviewed' ? '#4caf50' : '#ff9800',
|
||||
border: `1px solid ${component.status === 'reviewed' ? 'rgba(76, 175, 80, 0.5)' : 'rgba(255, 152, 0, 0.5)'}`,
|
||||
fontWeight: 600,
|
||||
fontSize: '0.65rem',
|
||||
height: 22,
|
||||
'&:hover': {
|
||||
background: component.status === 'reviewed'
|
||||
? 'rgba(76, 175, 80, 0.4)'
|
||||
: 'rgba(255, 152, 0, 0.4)',
|
||||
transform: 'translateY(-1px)'
|
||||
},
|
||||
transition: 'all 0.2s ease'
|
||||
}}
|
||||
/>
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Completion Status */}
|
||||
{isAllReviewed() && (
|
||||
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
|
||||
<Chip
|
||||
icon={<CheckCircleIcon />}
|
||||
label="Ready for Calendar Creation"
|
||||
size="small"
|
||||
sx={{
|
||||
background: ANALYSIS_CARD_STYLES.colors.success,
|
||||
color: 'white',
|
||||
fontWeight: 500,
|
||||
animation: 'pulse 2s infinite',
|
||||
fontSize: '0.65rem',
|
||||
height: 22,
|
||||
'@keyframes pulse': {
|
||||
'0%, 100%': { opacity: 1 },
|
||||
'50%': { opacity: 0.7 }
|
||||
},
|
||||
'& .MuiChip-icon': {
|
||||
color: 'white',
|
||||
fontSize: 14
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Completion Message */}
|
||||
{isAllReviewed() && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.3, delay: 0.2 }}
|
||||
>
|
||||
<Box sx={{
|
||||
mt: 1.5,
|
||||
p: 1.5,
|
||||
borderRadius: 1,
|
||||
background: 'rgba(76, 175, 80, 0.1)',
|
||||
border: '1px solid rgba(76, 175, 80, 0.2)',
|
||||
textAlign: 'center'
|
||||
}}>
|
||||
<Typography variant="body2" sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.success,
|
||||
fontWeight: 600,
|
||||
fontSize: '0.8rem'
|
||||
}}>
|
||||
🎉 All strategy components have been reviewed! You can now proceed to create your content calendar.
|
||||
</Typography>
|
||||
</Box>
|
||||
</motion.div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReviewProgressHeader;
|
||||
@@ -0,0 +1,244 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Chip,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
Typography,
|
||||
Button
|
||||
} from '@mui/material';
|
||||
import {
|
||||
CheckCircle as CheckCircleIcon,
|
||||
Schedule as ScheduleIcon,
|
||||
Warning as WarningIcon,
|
||||
Edit as EditIcon,
|
||||
Undo as UndoIcon
|
||||
} from '@mui/icons-material';
|
||||
import { motion } from 'framer-motion';
|
||||
import { ReviewStatus } from '../../../../../stores/strategyReviewStore';
|
||||
import { ANALYSIS_CARD_STYLES } from '../styles';
|
||||
|
||||
interface ReviewStatusIndicatorProps {
|
||||
status: ReviewStatus;
|
||||
reviewedAt?: Date;
|
||||
onStartReview?: () => void;
|
||||
onCompleteReview?: () => void;
|
||||
onResetReview?: () => void;
|
||||
isReviewing?: boolean;
|
||||
}
|
||||
|
||||
const ReviewStatusIndicator: React.FC<ReviewStatusIndicatorProps> = ({
|
||||
status,
|
||||
reviewedAt,
|
||||
onStartReview,
|
||||
onCompleteReview,
|
||||
onResetReview,
|
||||
isReviewing = false
|
||||
}) => {
|
||||
const getStatusConfig = () => {
|
||||
switch (status) {
|
||||
case 'reviewed':
|
||||
return {
|
||||
icon: <CheckCircleIcon />,
|
||||
label: 'Reviewed',
|
||||
color: ANALYSIS_CARD_STYLES.colors.success,
|
||||
bgColor: 'rgba(76, 175, 80, 0.1)',
|
||||
borderColor: 'rgba(76, 175, 80, 0.3)',
|
||||
textColor: ANALYSIS_CARD_STYLES.colors.success
|
||||
};
|
||||
case 'not_reviewed':
|
||||
default:
|
||||
return {
|
||||
icon: <WarningIcon />,
|
||||
label: 'Not Reviewed',
|
||||
color: ANALYSIS_CARD_STYLES.colors.warning,
|
||||
bgColor: 'rgba(255, 152, 0, 0.1)',
|
||||
borderColor: 'rgba(255, 152, 0, 0.3)',
|
||||
textColor: ANALYSIS_CARD_STYLES.colors.warning
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const config = getStatusConfig();
|
||||
|
||||
const formatReviewDate = (date: Date) => {
|
||||
return new Intl.DateTimeFormat('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
}).format(date);
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1,
|
||||
p: 1,
|
||||
borderRadius: 1,
|
||||
background: config.bgColor,
|
||||
border: '1px solid',
|
||||
borderColor: config.borderColor,
|
||||
minHeight: 32,
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.2s ease',
|
||||
'&:hover': {
|
||||
background: `${config.bgColor}80`,
|
||||
transform: 'translateY(-1px)',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
|
||||
}
|
||||
}}
|
||||
onClick={() => {
|
||||
if (status === 'not_reviewed' && onStartReview) {
|
||||
onStartReview();
|
||||
} else if (status === 'reviewed' && onResetReview) {
|
||||
onResetReview();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* Status Icon */}
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
color: config.color
|
||||
}}>
|
||||
{config.icon}
|
||||
</Box>
|
||||
|
||||
{/* Status Label */}
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
color: config.textColor,
|
||||
fontWeight: 600,
|
||||
fontSize: '0.75rem',
|
||||
flex: 1
|
||||
}}
|
||||
>
|
||||
{config.label}
|
||||
</Typography>
|
||||
|
||||
{/* Review Date */}
|
||||
{status === 'reviewed' && reviewedAt && (
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.text.secondary,
|
||||
fontSize: '0.7rem',
|
||||
fontStyle: 'italic'
|
||||
}}
|
||||
>
|
||||
{formatReviewDate(reviewedAt)}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{/* Action Buttons - Enhanced for better UX */}
|
||||
<Box sx={{ display: 'flex', gap: 0.5 }}>
|
||||
{status === 'not_reviewed' && onStartReview && (
|
||||
<Tooltip title="Review Component">
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onStartReview();
|
||||
}}
|
||||
disabled={isReviewing}
|
||||
startIcon={<EditIcon />}
|
||||
sx={{
|
||||
background: 'linear-gradient(135deg, #ff9800 0%, #ffb74d 100%)',
|
||||
color: 'white',
|
||||
fontWeight: 600,
|
||||
fontSize: '0.7rem',
|
||||
px: 1.5,
|
||||
py: 0.5,
|
||||
borderRadius: 2,
|
||||
boxShadow: '0 2px 8px rgba(255, 152, 0, 0.3)',
|
||||
border: '1px solid rgba(255, 152, 0, 0.4)',
|
||||
textTransform: 'none',
|
||||
minWidth: 'auto',
|
||||
'&:hover': {
|
||||
background: 'linear-gradient(135deg, #ffb74d 0%, #ffcc02 100%)',
|
||||
boxShadow: '0 4px 12px rgba(255, 152, 0, 0.4)',
|
||||
transform: 'translateY(-1px)'
|
||||
},
|
||||
'&:active': {
|
||||
transform: 'translateY(0)',
|
||||
boxShadow: '0 2px 4px rgba(255, 152, 0, 0.3)'
|
||||
},
|
||||
'&:disabled': {
|
||||
background: 'rgba(255, 152, 0, 0.3)',
|
||||
color: 'rgba(255, 255, 255, 0.7)',
|
||||
boxShadow: 'none',
|
||||
transform: 'none'
|
||||
},
|
||||
'& .MuiButton-startIcon': {
|
||||
marginRight: 0.5
|
||||
}
|
||||
}}
|
||||
>
|
||||
Review
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{status === 'reviewed' && onResetReview && (
|
||||
<Tooltip title="Reset Review">
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onResetReview();
|
||||
}}
|
||||
disabled={isReviewing}
|
||||
startIcon={<UndoIcon />}
|
||||
sx={{
|
||||
color: ANALYSIS_CARD_STYLES.colors.warning,
|
||||
borderColor: 'rgba(255, 152, 0, 0.5)',
|
||||
fontWeight: 600,
|
||||
fontSize: '0.7rem',
|
||||
px: 1.5,
|
||||
py: 0.5,
|
||||
borderRadius: 2,
|
||||
textTransform: 'none',
|
||||
minWidth: 'auto',
|
||||
background: 'rgba(255, 152, 0, 0.05)',
|
||||
'&:hover': {
|
||||
background: 'rgba(255, 152, 0, 0.1)',
|
||||
borderColor: 'rgba(255, 152, 0, 0.7)',
|
||||
transform: 'translateY(-1px)',
|
||||
boxShadow: '0 2px 8px rgba(255, 152, 0, 0.2)'
|
||||
},
|
||||
'&:active': {
|
||||
transform: 'translateY(0)'
|
||||
},
|
||||
'&:disabled': {
|
||||
color: 'rgba(255, 152, 0, 0.4)',
|
||||
borderColor: 'rgba(255, 152, 0, 0.2)',
|
||||
background: 'rgba(255, 152, 0, 0.02)',
|
||||
transform: 'none'
|
||||
},
|
||||
'& .MuiButton-startIcon': {
|
||||
marginRight: 0.5
|
||||
}
|
||||
}}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReviewStatusIndicator;
|
||||
@@ -35,6 +35,8 @@ interface RiskAssessmentCardProps {
|
||||
}
|
||||
|
||||
const RiskAssessmentCard: React.FC<RiskAssessmentCardProps> = ({ strategyData }) => {
|
||||
|
||||
|
||||
// Get style objects
|
||||
const sectionStyles = getSectionStyles();
|
||||
const accordionStyles = getAccordionStyles();
|
||||
@@ -51,29 +53,27 @@ const RiskAssessmentCard: React.FC<RiskAssessmentCardProps> = ({ strategyData })
|
||||
|
||||
if (!strategyData?.risk_assessment) {
|
||||
return (
|
||||
<Grid item xs={12} lg={6}>
|
||||
<ProgressiveCard
|
||||
title="Risk Assessment"
|
||||
subtitle="Risk analysis and mitigation"
|
||||
icon={<SecurityIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="body1" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Risk assessment data not available
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
details={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Available data keys: {strategyData ? Object.keys(strategyData).join(', ') : 'No data'}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
/>
|
||||
</Grid>
|
||||
<ProgressiveCard
|
||||
title="Risk Assessment"
|
||||
subtitle="Strategic risk analysis"
|
||||
icon={<WarningIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="body1" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Risk assessment data not available
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
details={
|
||||
<Box sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Typography variant="caption" sx={{ color: ANALYSIS_CARD_STYLES.colors.text.secondary }}>
|
||||
Available data keys: {strategyData ? Object.keys(strategyData).join(', ') : 'No data'}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -395,17 +395,16 @@ const RiskAssessmentCard: React.FC<RiskAssessmentCardProps> = ({ strategyData })
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid item xs={12} lg={6}>
|
||||
<ProgressiveCard
|
||||
title="Risk Assessment"
|
||||
subtitle="Risk analysis and mitigation"
|
||||
icon={<SecurityIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={summaryContent}
|
||||
details={detailedContent}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
/>
|
||||
</Grid>
|
||||
<ProgressiveCard
|
||||
title="Risk Assessment"
|
||||
subtitle="Risk analysis and mitigation"
|
||||
icon={<SecurityIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={summaryContent}
|
||||
details={detailedContent}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={3000}
|
||||
componentId="risk_assessment"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -40,15 +40,7 @@ const StrategicInsightsCard: React.FC<StrategicInsightsCardProps> = ({ strategyD
|
||||
const accordionStyles = getAccordionStyles();
|
||||
const listItemStyles = getListItemStyles();
|
||||
|
||||
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 (
|
||||
@@ -587,17 +579,16 @@ const StrategicInsightsCard: React.FC<StrategicInsightsCardProps> = ({ strategyD
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid item xs={12} lg={6}>
|
||||
<ProgressiveCard
|
||||
title="Strategic Insights"
|
||||
subtitle="AI-powered market analysis"
|
||||
icon={<LightbulbIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={summaryContent}
|
||||
details={detailedContent}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={2000}
|
||||
/>
|
||||
</Grid>
|
||||
<ProgressiveCard
|
||||
title="Strategic Insights"
|
||||
subtitle="AI-powered market analysis"
|
||||
icon={<LightbulbIcon sx={{ color: 'white', fontSize: 20 }} />}
|
||||
summary={summaryContent}
|
||||
details={detailedContent}
|
||||
trigger="hover"
|
||||
autoCollapseDelay={2000}
|
||||
componentId="strategic_insights"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -42,9 +42,10 @@ import { getStrategyName, getStrategyGenerationDate } from '../utils/strategyTra
|
||||
interface StrategyHeaderProps {
|
||||
strategyData: StrategyData | null;
|
||||
strategyConfirmed: boolean;
|
||||
onStartReview?: () => void;
|
||||
}
|
||||
|
||||
const StrategyHeader: React.FC<StrategyHeaderProps> = ({ strategyData, strategyConfirmed }) => {
|
||||
const StrategyHeader: React.FC<StrategyHeaderProps> = ({ strategyData, strategyConfirmed, onStartReview }) => {
|
||||
const [showNextStepText, setShowNextStepText] = useState(false);
|
||||
|
||||
if (!strategyData) return null;
|
||||
@@ -577,13 +578,14 @@ const StrategyHeader: React.FC<StrategyHeaderProps> = ({ strategyData, strategyC
|
||||
{/* Next Steps Button - Area B */}
|
||||
<Box sx={{ mt: 1.5, display: 'flex', justifyContent: 'center' }}>
|
||||
<Tooltip
|
||||
title={strategyData.summary?.next_step || "Review strategy and generate content calendar"}
|
||||
title="Start reviewing strategy components and create content calendar"
|
||||
arrow
|
||||
open={showNextStepText}
|
||||
onClose={() => setShowNextStepText(false)}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={onStartReview}
|
||||
onMouseEnter={() => setShowNextStepText(true)}
|
||||
onMouseLeave={() => setShowNextStepText(false)}
|
||||
sx={{
|
||||
@@ -606,7 +608,7 @@ const StrategyHeader: React.FC<StrategyHeaderProps> = ({ strategyData, strategyC
|
||||
}}
|
||||
startIcon={<ArrowForwardIcon />}
|
||||
>
|
||||
Next Step
|
||||
Next: Review Strategy and Create Content Calendar
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Main Strategy Intelligence Tab
|
||||
export { default as StrategyIntelligenceTab } from '../StrategyIntelligenceTab';
|
||||
export { default as StrategyIntelligenceTab } from './StrategyIntelligenceTab';
|
||||
|
||||
// Components
|
||||
export { default as StrategyHeader } from './components/StrategyHeader';
|
||||
|
||||
@@ -165,6 +165,13 @@ export const transformPollingStrategyData = (strategyData: any): StrategyData =>
|
||||
competitive_risks: riskAssessment.risk_categories?.competitive_risks || [],
|
||||
technical_risks: riskAssessment.risk_categories?.technical_risks || [],
|
||||
financial_risks: riskAssessment.risk_categories?.financial_risks || []
|
||||
},
|
||||
mitigation_strategies: riskAssessment.mitigation_strategies || [],
|
||||
monitoring_framework: riskAssessment.monitoring_framework || {
|
||||
key_indicators: [],
|
||||
monitoring_frequency: "Weekly",
|
||||
escalation_procedures: [],
|
||||
review_schedule: "Monthly"
|
||||
}
|
||||
} : undefined,
|
||||
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Box, CircularProgress, Alert, Typography, Grid } from '@mui/material';
|
||||
import { useStrategyData } from './StrategyIntelligence/hooks/useStrategyData';
|
||||
import { useStrategyActions } from './StrategyIntelligence/hooks/useStrategyActions';
|
||||
import StrategyHeader from './StrategyIntelligence/components/StrategyHeader';
|
||||
import StrategicInsightsCard from './StrategyIntelligence/components/StrategicInsightsCard';
|
||||
import CompetitiveAnalysisCard from './StrategyIntelligence/components/CompetitiveAnalysisCard';
|
||||
import PerformancePredictionsCard from './StrategyIntelligence/components/PerformancePredictionsCard';
|
||||
import ImplementationRoadmapCard from './StrategyIntelligence/components/ImplementationRoadmapCard';
|
||||
import RiskAssessmentCard from './StrategyIntelligence/components/RiskAssessmentCard';
|
||||
import StrategyActions from './StrategyIntelligence/components/StrategyActions';
|
||||
import ConfirmationDialog from './StrategyIntelligence/components/ConfirmationDialog';
|
||||
|
||||
const StrategyIntelligenceTab: React.FC = () => {
|
||||
const { strategyData, loading, error, loadStrategyData } = useStrategyData();
|
||||
const {
|
||||
strategyConfirmed,
|
||||
showConfirmDialog,
|
||||
setShowConfirmDialog,
|
||||
handleConfirmStrategy,
|
||||
confirmStrategy,
|
||||
handleGenerateContentCalendar
|
||||
} = useStrategyActions();
|
||||
|
||||
const handleConfirmStrategyClick = () => {
|
||||
handleConfirmStrategy();
|
||||
};
|
||||
|
||||
const handleConfirmStrategyAction = async () => {
|
||||
await confirmStrategy(strategyData);
|
||||
};
|
||||
|
||||
const handleGenerateContentCalendarAction = async () => {
|
||||
try {
|
||||
await handleGenerateContentCalendar(strategyData);
|
||||
} catch (error) {
|
||||
console.error('Error generating content calendar:', error);
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: 400 }}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<Alert severity="error" sx={{ m: 2 }}>
|
||||
{error}
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
if (!strategyData) {
|
||||
return (
|
||||
<Box sx={{ textAlign: 'center', p: 4 }}>
|
||||
<Typography variant="h6" color="text.secondary" gutterBottom>
|
||||
No Strategy Data Available
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Generate a comprehensive strategy first to view strategic intelligence.
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box sx={{ p: 3 }}>
|
||||
{/* Header Section */}
|
||||
<StrategyHeader strategyData={strategyData} strategyConfirmed={strategyConfirmed} />
|
||||
|
||||
{/* Strategy Components Grid */}
|
||||
<Grid container spacing={2}>
|
||||
<StrategicInsightsCard strategyData={strategyData} />
|
||||
<CompetitiveAnalysisCard strategyData={strategyData} />
|
||||
<PerformancePredictionsCard strategyData={strategyData} />
|
||||
<ImplementationRoadmapCard strategyData={strategyData} />
|
||||
<RiskAssessmentCard strategyData={strategyData} />
|
||||
</Grid>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<StrategyActions
|
||||
strategyData={strategyData}
|
||||
strategyConfirmed={strategyConfirmed}
|
||||
onConfirmStrategy={handleConfirmStrategyClick}
|
||||
onGenerateContentCalendar={handleGenerateContentCalendarAction}
|
||||
onRefreshData={loadStrategyData}
|
||||
/>
|
||||
|
||||
{/* Confirmation Dialog */}
|
||||
<ConfirmationDialog
|
||||
open={showConfirmDialog}
|
||||
onClose={() => setShowConfirmDialog(false)}
|
||||
onConfirm={handleConfirmStrategyAction}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default StrategyIntelligenceTab;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -51,7 +51,7 @@ import {
|
||||
} from '@mui/icons-material';
|
||||
import { useContentPlanningStore } from '../../../stores/contentPlanningStore';
|
||||
import { contentPlanningApi } from '../../../services/contentPlanningApi';
|
||||
import StrategyIntelligenceTab from '../components/StrategyIntelligenceTab';
|
||||
import StrategyIntelligenceTab from '../components/StrategyIntelligence/StrategyIntelligenceTab';
|
||||
import StrategyOnboardingDialog from '../components/StrategyOnboardingDialog';
|
||||
|
||||
const ContentStrategyTab: React.FC = () => {
|
||||
@@ -96,25 +96,70 @@ const ContentStrategyTab: React.FC = () => {
|
||||
|
||||
// Check strategy status when strategies are loaded
|
||||
useEffect(() => {
|
||||
if (strategies && strategies.length > 0 && !hasCheckedStrategy) {
|
||||
console.log('🔄 useEffect triggered - strategies changed:', strategies);
|
||||
console.log('🔄 Strategies type:', typeof strategies);
|
||||
console.log('🔄 Is Array:', Array.isArray(strategies));
|
||||
console.log('🔄 Strategies length:', strategies?.length);
|
||||
console.log('🔄 Has checked strategy:', hasCheckedStrategy);
|
||||
|
||||
// Handle different response formats
|
||||
let strategiesArray: any[] = [];
|
||||
|
||||
if (Array.isArray(strategies)) {
|
||||
// Direct array
|
||||
strategiesArray = strategies;
|
||||
} else if (strategies && typeof strategies === 'object' && 'strategies' in strategies && Array.isArray((strategies as any).strategies)) {
|
||||
// API response object with strategies array
|
||||
strategiesArray = (strategies as any).strategies;
|
||||
}
|
||||
|
||||
console.log('🔄 StrategiesArray length:', strategiesArray.length);
|
||||
|
||||
if (strategiesArray.length > 0) {
|
||||
console.log('✅ Strategies found, checking status...');
|
||||
checkStrategyStatus();
|
||||
} else if ((!strategies || strategies.length === 0) && !hasCheckedStrategy) {
|
||||
} else if (strategiesArray.length === 0 && hasCheckedStrategy) {
|
||||
// Only set to 'none' if we've already checked and confirmed no strategies
|
||||
console.log('❌ No strategies found, setting status to none...');
|
||||
setStrategyStatus('none');
|
||||
setHasCheckedStrategy(true);
|
||||
setShowOnboarding(true);
|
||||
}
|
||||
}, [strategies, hasCheckedStrategy]);
|
||||
// If strategiesArray.length === 0 and !hasCheckedStrategy, do nothing (wait for data to load)
|
||||
}, [strategies, loadStrategies]);
|
||||
|
||||
const checkStrategyStatus = () => {
|
||||
if (strategies && strategies.length > 0) {
|
||||
console.log('🔍 Checking strategy status...');
|
||||
console.log('🔍 Strategies from store:', strategies);
|
||||
console.log('🔍 Strategies type:', typeof strategies);
|
||||
console.log('🔍 Is Array:', Array.isArray(strategies));
|
||||
console.log('🔍 Strategies length:', strategies?.length);
|
||||
|
||||
// Handle different response formats
|
||||
let strategiesArray: any[] = [];
|
||||
|
||||
if (Array.isArray(strategies)) {
|
||||
// Direct array
|
||||
strategiesArray = strategies;
|
||||
} else if (strategies && typeof strategies === 'object' && 'strategies' in strategies && Array.isArray((strategies as any).strategies)) {
|
||||
// API response object with strategies array
|
||||
strategiesArray = (strategies as any).strategies;
|
||||
}
|
||||
|
||||
console.log('🔍 StrategiesArray length:', strategiesArray.length);
|
||||
|
||||
if (strategiesArray.length > 0) {
|
||||
// Find the most recent strategy
|
||||
const latestStrategy = strategies[0]; // Assuming strategies are sorted by date
|
||||
const latestStrategy = strategiesArray[0]; // Assuming strategies are sorted by date
|
||||
|
||||
console.log('✅ Found strategies in database:', strategiesArray.length);
|
||||
console.log('📊 Latest strategy:', latestStrategy);
|
||||
|
||||
// For now, we'll assume strategies are active if they exist
|
||||
// In a real implementation, you would check a status field from the database
|
||||
setStrategyStatus('active');
|
||||
setShowOnboarding(false);
|
||||
} else {
|
||||
console.log('❌ No strategies found in database');
|
||||
setStrategyStatus('none');
|
||||
setShowOnboarding(true);
|
||||
}
|
||||
@@ -154,20 +199,16 @@ const ContentStrategyTab: React.FC = () => {
|
||||
contentPlanningApi.handleSSEData(
|
||||
eventSource,
|
||||
(data) => {
|
||||
console.log('Strategic Intelligence SSE Data:', data);
|
||||
|
||||
if (data.type === 'status') {
|
||||
// Update loading message
|
||||
console.log('Status:', data.message);
|
||||
} else if (data.type === 'progress') {
|
||||
// Update progress (could be used for progress bar)
|
||||
console.log('Progress:', data.progress, '%');
|
||||
} else if (data.type === 'result' && data.status === 'success') {
|
||||
// Set the strategic intelligence data
|
||||
setStrategicIntelligence(data.data);
|
||||
setDataLoading(prev => ({ ...prev, strategicIntelligence: false }));
|
||||
} else if (data.type === 'error') {
|
||||
console.error('Strategic Intelligence Error:', data.message);
|
||||
// Set fallback data on error
|
||||
setStrategicIntelligence({
|
||||
market_positioning: {
|
||||
@@ -188,7 +229,6 @@ const ContentStrategyTab: React.FC = () => {
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.error('Strategic Intelligence SSE Error:', error);
|
||||
// Set fallback data on error
|
||||
setStrategicIntelligence({
|
||||
market_positioning: {
|
||||
@@ -356,13 +396,7 @@ const ContentStrategyTab: React.FC = () => {
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{strategyStatus === 'active' && (
|
||||
<Alert severity="success" sx={{ mb: 3 }}>
|
||||
<Typography variant="body1">
|
||||
<strong>Strategy Active:</strong> Your content strategy is running and ALwrity is managing your content marketing automatically.
|
||||
</Typography>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
|
||||
{/* Strategic Intelligence */}
|
||||
<Paper sx={{ width: '100%', mb: 3 }}>
|
||||
|
||||
@@ -476,9 +476,24 @@ export const useContentPlanningStore = create<ContentPlanningStore>((set, get) =
|
||||
loadStrategies: async () => {
|
||||
set({ loading: true, error: null });
|
||||
try {
|
||||
console.log('🔍 Loading strategies from API...');
|
||||
const strategies = await contentPlanningApi.getStrategiesSafe();
|
||||
set({ strategies, loading: false });
|
||||
console.log('🔍 API response for strategies:', strategies);
|
||||
console.log('🔍 Strategies type:', typeof strategies);
|
||||
console.log('🔍 Is Array:', Array.isArray(strategies));
|
||||
|
||||
if (Array.isArray(strategies)) {
|
||||
console.log('✅ Strategies loaded successfully (direct array):', strategies.length);
|
||||
set({ strategies, loading: false });
|
||||
} else if (strategies && strategies.strategies && Array.isArray(strategies.strategies)) {
|
||||
console.log('✅ Strategies found in response.strategies:', strategies.strategies.length);
|
||||
set({ strategies: strategies.strategies, loading: false });
|
||||
} else {
|
||||
console.log('❌ No strategies found in response');
|
||||
set({ strategies: [], loading: false });
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('❌ Error loading strategies:', error);
|
||||
set({ error: error.message || 'Failed to load strategies', loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
189
frontend/src/stores/strategyReviewStore.ts
Normal file
189
frontend/src/stores/strategyReviewStore.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
import { create } from 'zustand';
|
||||
import { devtools } from 'zustand/middleware';
|
||||
|
||||
export type ReviewStatus = 'not_reviewed' | 'in_review' | 'reviewed';
|
||||
|
||||
export interface StrategyComponent {
|
||||
id: string;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
status: ReviewStatus;
|
||||
reviewedAt?: Date;
|
||||
reviewedBy?: string;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export interface ReviewState {
|
||||
// Review state
|
||||
components: StrategyComponent[];
|
||||
isReviewing: boolean;
|
||||
reviewProgress: number;
|
||||
|
||||
// Actions
|
||||
initializeComponents: (components: Omit<StrategyComponent, 'status' | 'reviewedAt' | 'reviewedBy' | 'notes'>[]) => void;
|
||||
startReview: (componentId: string) => void;
|
||||
completeReview: (componentId: string, notes?: string) => void;
|
||||
resetReview: (componentId: string) => void;
|
||||
resetAllReviews: () => void;
|
||||
updateReviewProgress: () => void;
|
||||
getReviewProgress: () => number;
|
||||
isAllReviewed: () => boolean;
|
||||
getUnreviewedComponents: () => StrategyComponent[];
|
||||
getReviewedComponents: () => StrategyComponent[];
|
||||
}
|
||||
|
||||
const STRATEGY_COMPONENTS = [
|
||||
{
|
||||
id: 'strategic_insights',
|
||||
title: 'Strategic Insights',
|
||||
subtitle: 'AI-powered market analysis'
|
||||
},
|
||||
{
|
||||
id: 'competitive_analysis',
|
||||
title: 'Competitive Analysis',
|
||||
subtitle: 'Market positioning insights'
|
||||
},
|
||||
{
|
||||
id: 'performance_predictions',
|
||||
title: 'Performance Predictions',
|
||||
subtitle: 'ROI and success metrics'
|
||||
},
|
||||
{
|
||||
id: 'implementation_roadmap',
|
||||
title: 'Implementation Roadmap',
|
||||
subtitle: 'Project timeline and phases'
|
||||
},
|
||||
{
|
||||
id: 'risk_assessment',
|
||||
title: 'Risk Assessment',
|
||||
subtitle: 'Risk analysis and mitigation'
|
||||
}
|
||||
];
|
||||
|
||||
export const useStrategyReviewStore = create<ReviewState>()(
|
||||
devtools(
|
||||
(set, get) => ({
|
||||
// Initial state
|
||||
components: [],
|
||||
isReviewing: false,
|
||||
reviewProgress: 0,
|
||||
|
||||
// Initialize components with default review status
|
||||
initializeComponents: (components) => {
|
||||
const initializedComponents = components.map(component => ({
|
||||
...component,
|
||||
status: 'not_reviewed' as ReviewStatus
|
||||
}));
|
||||
|
||||
set({ components: initializedComponents });
|
||||
get().updateReviewProgress();
|
||||
},
|
||||
|
||||
// Start reviewing a component
|
||||
startReview: (componentId: string) => {
|
||||
set(state => ({
|
||||
isReviewing: true,
|
||||
components: state.components.map(comp =>
|
||||
comp.id === componentId
|
||||
? { ...comp, status: 'in_review' as ReviewStatus }
|
||||
: comp
|
||||
)
|
||||
}));
|
||||
},
|
||||
|
||||
// Complete review for a component
|
||||
completeReview: (componentId: string, notes?: string) => {
|
||||
set(state => ({
|
||||
isReviewing: false,
|
||||
components: state.components.map(comp =>
|
||||
comp.id === componentId
|
||||
? {
|
||||
...comp,
|
||||
status: 'reviewed' as ReviewStatus,
|
||||
reviewedAt: new Date(),
|
||||
reviewedBy: 'current_user', // In real app, get from auth
|
||||
notes
|
||||
}
|
||||
: comp
|
||||
)
|
||||
}));
|
||||
|
||||
get().updateReviewProgress();
|
||||
},
|
||||
|
||||
// Reset review for a component
|
||||
resetReview: (componentId: string) => {
|
||||
set(state => ({
|
||||
components: state.components.map(comp =>
|
||||
comp.id === componentId
|
||||
? {
|
||||
...comp,
|
||||
status: 'not_reviewed' as ReviewStatus,
|
||||
reviewedAt: undefined,
|
||||
reviewedBy: undefined,
|
||||
notes: undefined
|
||||
}
|
||||
: comp
|
||||
)
|
||||
}));
|
||||
|
||||
get().updateReviewProgress();
|
||||
},
|
||||
|
||||
// Reset all reviews
|
||||
resetAllReviews: () => {
|
||||
set(state => ({
|
||||
components: state.components.map(comp => ({
|
||||
...comp,
|
||||
status: 'not_reviewed' as ReviewStatus,
|
||||
reviewedAt: undefined,
|
||||
reviewedBy: undefined,
|
||||
notes: undefined
|
||||
}))
|
||||
}));
|
||||
|
||||
get().updateReviewProgress();
|
||||
},
|
||||
|
||||
// Update review progress
|
||||
updateReviewProgress: () => {
|
||||
const { components } = get();
|
||||
const reviewedCount = components.filter(comp => comp.status === 'reviewed').length;
|
||||
const totalCount = components.length;
|
||||
const progress = totalCount > 0 ? (reviewedCount / totalCount) * 100 : 0;
|
||||
|
||||
set({ reviewProgress: progress });
|
||||
},
|
||||
|
||||
// Get review progress percentage
|
||||
getReviewProgress: () => {
|
||||
return get().reviewProgress;
|
||||
},
|
||||
|
||||
// Check if all components are reviewed
|
||||
isAllReviewed: () => {
|
||||
const { components } = get();
|
||||
return components.every(comp => comp.status === 'reviewed');
|
||||
},
|
||||
|
||||
// Get unreviewed components
|
||||
getUnreviewedComponents: () => {
|
||||
const { components } = get();
|
||||
return components.filter(comp => comp.status !== 'reviewed');
|
||||
},
|
||||
|
||||
// Get reviewed components
|
||||
getReviewedComponents: () => {
|
||||
const { components } = get();
|
||||
return components.filter(comp => comp.status === 'reviewed');
|
||||
}
|
||||
}),
|
||||
{
|
||||
name: 'strategy-review-store',
|
||||
enabled: process.env.NODE_ENV === 'development'
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Initialize components when store is created
|
||||
useStrategyReviewStore.getState().initializeComponents(STRATEGY_COMPONENTS);
|
||||
Reference in New Issue
Block a user