ALwrity version 0.5.5
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import {
|
||||
Box,
|
||||
Tabs,
|
||||
@@ -72,6 +73,7 @@ function a11yProps(index: number) {
|
||||
}
|
||||
|
||||
const ContentPlanningDashboard: React.FC = () => {
|
||||
const location = useLocation();
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
const [serviceStatuses, setServiceStatuses] = useState<ServiceStatus[]>([]);
|
||||
const [dashboardData, setDashboardData] = useState<DashboardData>({
|
||||
@@ -121,6 +123,13 @@ const ContentPlanningDashboard: React.FC = () => {
|
||||
});
|
||||
}, [updateStrategies, updateCalendarEvents, updateGapAnalyses, updateAIInsights]);
|
||||
|
||||
// Handle navigation state for active tab
|
||||
useEffect(() => {
|
||||
if (location.state?.activeTab !== undefined) {
|
||||
setActiveTab(location.state.activeTab);
|
||||
}
|
||||
}, [location.state]);
|
||||
|
||||
// Load dashboard data using orchestrator
|
||||
useEffect(() => {
|
||||
const loadDashboardData = async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Box,
|
||||
Paper,
|
||||
@@ -60,6 +61,7 @@ import EnhancedTooltip from './ContentStrategyBuilder/EnhancedTooltip';
|
||||
import AIRecommendationsPanel from './AIRecommendationsPanel';
|
||||
import DataSourceTransparency from './DataSourceTransparency';
|
||||
import StrategyAutofillTransparencyModal from './StrategyAutofillTransparencyModal';
|
||||
import EnterpriseDatapointsModal from './EnterpriseDatapointsModal';
|
||||
|
||||
// Import extracted hooks
|
||||
import { useCategoryReview } from './ContentStrategyBuilder/hooks/useCategoryReview';
|
||||
@@ -83,6 +85,7 @@ import { contentPlanningApi } from '../../../services/contentPlanningApi';
|
||||
import CategoryDetailView from './ContentStrategyBuilder/components/CategoryDetailView';
|
||||
|
||||
const ContentStrategyBuilder: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const {
|
||||
formData,
|
||||
formErrors,
|
||||
@@ -143,6 +146,31 @@ const ContentStrategyBuilder: React.FC = () => {
|
||||
const [refreshError, setRefreshError] = useState<string | null>(null);
|
||||
const [showEducationalModal, setShowEducationalModal] = useState(false);
|
||||
const [localEducationalContent, setLocalEducationalContent] = useState<any>(null);
|
||||
const [showEnterpriseModal, setShowEnterpriseModal] = useState(false);
|
||||
|
||||
// Persist enterprise modal state across hot reloads
|
||||
useEffect(() => {
|
||||
const savedModalState = sessionStorage.getItem('showEnterpriseModal');
|
||||
if (savedModalState === 'true') {
|
||||
console.log('🎯 Restoring enterprise modal state from sessionStorage');
|
||||
setShowEnterpriseModal(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Save modal state to sessionStorage when it changes
|
||||
useEffect(() => {
|
||||
sessionStorage.setItem('showEnterpriseModal', showEnterpriseModal.toString());
|
||||
}, [showEnterpriseModal]);
|
||||
|
||||
// Cleanup sessionStorage on component unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
// Only clear if we're not in the middle of showing the modal
|
||||
if (!showEnterpriseModal) {
|
||||
sessionStorage.removeItem('showEnterpriseModal');
|
||||
}
|
||||
};
|
||||
}, [showEnterpriseModal]);
|
||||
const [localGenerationProgress, setLocalGenerationProgress] = useState<number>(0);
|
||||
const [showAIRecModal, setShowAIRecModal] = useState(false);
|
||||
|
||||
@@ -178,7 +206,7 @@ const ContentStrategyBuilder: React.FC = () => {
|
||||
});
|
||||
|
||||
// Use ActionButtons business logic hook
|
||||
const { handleCreateStrategy, handleSaveStrategy } = useActionButtonsBusinessLogic({
|
||||
const { handleCreateStrategy: originalHandleCreateStrategy, handleSaveStrategy } = useActionButtonsBusinessLogic({
|
||||
formData,
|
||||
error,
|
||||
currentStrategy,
|
||||
@@ -196,6 +224,92 @@ const ContentStrategyBuilder: React.FC = () => {
|
||||
contentPlanningApi
|
||||
});
|
||||
|
||||
// Enhanced handleCreateStrategy to show enterprise modal
|
||||
const handleCreateStrategy = () => {
|
||||
console.log('🎯 handleCreateStrategy called');
|
||||
console.log('🎯 completionStats.category_completion:', completionStats.category_completion);
|
||||
console.log('🎯 reviewedCategories:', reviewedCategories);
|
||||
console.log('🎯 Current showEnterpriseModal state:', showEnterpriseModal);
|
||||
console.log('🎯 Current aiGenerating state:', aiGenerating);
|
||||
|
||||
// Prevent multiple calls
|
||||
if (aiGenerating) {
|
||||
console.log('🎯 Already generating, skipping duplicate call');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if all categories are reviewed
|
||||
const allCategoriesReviewed = Object.keys(completionStats.category_completion).every(
|
||||
category => Array.from(reviewedCategories).includes(category)
|
||||
);
|
||||
|
||||
console.log('🎯 allCategoriesReviewed:', allCategoriesReviewed);
|
||||
|
||||
if (allCategoriesReviewed) {
|
||||
// Show enterprise modal instead of creating strategy immediately
|
||||
console.log('🎯 Showing enterprise modal - setting to true');
|
||||
setShowEnterpriseModal(true);
|
||||
|
||||
// Add debugging to confirm modal state change
|
||||
setTimeout(() => {
|
||||
console.log('🎯 Enterprise modal state after setShowEnterpriseModal(true):', showEnterpriseModal);
|
||||
}, 0);
|
||||
|
||||
// Return early to prevent calling originalHandleCreateStrategy
|
||||
return;
|
||||
} else {
|
||||
// If not all categories reviewed, proceed with original logic
|
||||
console.log('🎯 Not all categories reviewed, proceeding with original logic');
|
||||
originalHandleCreateStrategy();
|
||||
}
|
||||
};
|
||||
|
||||
// Handle proceed with current strategy (30 fields)
|
||||
const handleProceedWithCurrentStrategy = async () => {
|
||||
console.log('🎯 User clicked "Proceed with Current Strategy"');
|
||||
setShowEnterpriseModal(false);
|
||||
sessionStorage.removeItem('showEnterpriseModal'); // Clear sessionStorage
|
||||
|
||||
// Add a small delay to ensure modal closes properly before showing educational modal
|
||||
setTimeout(async () => {
|
||||
console.log('🎯 Calling original handleCreateStrategy after enterprise modal closes');
|
||||
try {
|
||||
// Ensure we're not already generating
|
||||
if (!aiGenerating) {
|
||||
console.log('🎯 Starting strategy generation...');
|
||||
await originalHandleCreateStrategy();
|
||||
} else {
|
||||
console.log('🎯 Already generating, skipping duplicate call');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('🎯 Error in handleProceedWithCurrentStrategy:', error);
|
||||
}
|
||||
}, 300); // Increased delay to ensure modal closes completely
|
||||
};
|
||||
|
||||
// Handle add enterprise datapoints (coming soon)
|
||||
const handleAddEnterpriseDatapoints = async () => {
|
||||
console.log('🎯 User clicked "Add Enterprise Datapoints"');
|
||||
setShowEnterpriseModal(false);
|
||||
sessionStorage.removeItem('showEnterpriseModal'); // Clear sessionStorage
|
||||
|
||||
// For now, just proceed with current strategy
|
||||
// In Phase 2, this will enable enterprise datapoints
|
||||
setTimeout(async () => {
|
||||
console.log('🎯 Calling original handleCreateStrategy for enterprise datapoints');
|
||||
try {
|
||||
// Ensure we're not already generating
|
||||
if (!aiGenerating) {
|
||||
await originalHandleCreateStrategy();
|
||||
} else {
|
||||
console.log('🎯 Already generating, skipping duplicate call');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('🎯 Error in handleAddEnterpriseDatapoints:', error);
|
||||
}
|
||||
}, 200); // Increased delay to ensure modal closes completely
|
||||
};
|
||||
|
||||
// Auto-populate from onboarding on first load
|
||||
useEffect(() => {
|
||||
if (!autoPopulateAttempted) {
|
||||
@@ -231,6 +345,24 @@ const ContentStrategyBuilder: React.FC = () => {
|
||||
console.log('🎯 Modal state changed - transparencyModalOpen:', transparencyModalOpen);
|
||||
}, [transparencyModalOpen]);
|
||||
|
||||
// Monitor enterprise modal state for debugging
|
||||
useEffect(() => {
|
||||
console.log('🎯 Enterprise modal state changed - showEnterpriseModal:', showEnterpriseModal);
|
||||
|
||||
// If modal was unexpectedly closed, log it
|
||||
if (!showEnterpriseModal && aiGenerating) {
|
||||
console.warn('🎯 WARNING: Enterprise modal closed while AI is generating');
|
||||
}
|
||||
|
||||
// Only warn about unexpected closure if it's not due to hot reload
|
||||
if (!showEnterpriseModal && !aiGenerating) {
|
||||
const savedModalState = sessionStorage.getItem('showEnterpriseModal');
|
||||
if (savedModalState !== 'true') {
|
||||
console.warn('🎯 WARNING: Enterprise modal closed unexpectedly (not due to hot reload)');
|
||||
}
|
||||
}
|
||||
}, [showEnterpriseModal, aiGenerating]);
|
||||
|
||||
// Monitor store data changes for debugging
|
||||
useEffect(() => {
|
||||
console.log('🎯 Store data changed:', {
|
||||
@@ -493,20 +625,17 @@ const ContentStrategyBuilder: React.FC = () => {
|
||||
setCurrentPhase('Complete');
|
||||
setRefreshMessage(`AI refresh completed! Generated ${Object.keys(fieldValues).length} fields.`);
|
||||
|
||||
// Close modal after a short delay to show completion
|
||||
setTimeout(() => {
|
||||
setTransparencyModalOpen(false);
|
||||
setAIGenerating(false);
|
||||
setIsRefreshing(false);
|
||||
setIsGenerating(false);
|
||||
console.log('🎯 Polling-based AI refresh completed successfully!', {
|
||||
fieldsGenerated: Object.keys(fieldValues).length,
|
||||
confidenceScoresCount: Object.keys(confidenceScores).length,
|
||||
dataSourcesCount: Object.keys(sources).length,
|
||||
approach: 'Polling (No SSE)',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}, 2000);
|
||||
// Don't close modal automatically - let user close it manually
|
||||
setAIGenerating(false);
|
||||
setIsRefreshing(false);
|
||||
setIsGenerating(false);
|
||||
console.log('🎯 Polling-based AI refresh completed successfully!', {
|
||||
fieldsGenerated: Object.keys(fieldValues).length,
|
||||
confidenceScoresCount: Object.keys(confidenceScores).length,
|
||||
dataSourcesCount: Object.keys(sources).length,
|
||||
approach: 'Polling (No SSE)',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
} else {
|
||||
throw new Error('Invalid response from AI refresh endpoint');
|
||||
}
|
||||
@@ -656,8 +785,16 @@ const ContentStrategyBuilder: React.FC = () => {
|
||||
<EducationalModal
|
||||
open={showEducationalModal}
|
||||
onClose={() => setShowEducationalModal(false)}
|
||||
educationalContent={storeEducationalContent}
|
||||
educationalContent={storeEducationalContent}
|
||||
generationProgress={storeGenerationProgress}
|
||||
onReviewStrategy={() => {
|
||||
console.log('🎯 User clicked "Next: Review Strategy and Create Calendar"');
|
||||
setShowEducationalModal(false);
|
||||
// Navigate to content planning dashboard with Content Strategy tab active
|
||||
navigate('/content-planning', {
|
||||
state: { activeTab: 0 } // 0 = Content Strategy tab
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Data Source Transparency Modal */}
|
||||
@@ -690,7 +827,13 @@ const ContentStrategyBuilder: React.FC = () => {
|
||||
{/* Strategy Autofill Transparency Modal */}
|
||||
<StrategyAutofillTransparencyModal
|
||||
open={transparencyModalOpen}
|
||||
onClose={() => setTransparencyModalOpen(false)}
|
||||
onClose={() => {
|
||||
setTransparencyModalOpen(false);
|
||||
// Ensure form data is refreshed after modal closes
|
||||
console.log('🎯 Modal closed - ensuring form data is updated');
|
||||
console.log('🎯 Current autoPopulatedFields:', Object.keys(autoPopulatedFields || {}));
|
||||
console.log('🎯 Current formData keys:', Object.keys(formData || {}));
|
||||
}}
|
||||
autoPopulatedFields={autoPopulatedFields}
|
||||
dataSources={dataSources}
|
||||
inputDataPoints={inputDataPoints}
|
||||
@@ -702,6 +845,19 @@ const ContentStrategyBuilder: React.FC = () => {
|
||||
error={error}
|
||||
/>
|
||||
|
||||
{/* Enterprise Datapoints Modal */}
|
||||
<EnterpriseDatapointsModal
|
||||
open={showEnterpriseModal}
|
||||
onClose={() => {
|
||||
console.log('🎯 Enterprise modal onClose called');
|
||||
console.log('🎯 Current aiGenerating state:', aiGenerating);
|
||||
setShowEnterpriseModal(false);
|
||||
sessionStorage.removeItem('showEnterpriseModal'); // Clear sessionStorage
|
||||
}}
|
||||
onProceedWithCurrent={handleProceedWithCurrentStrategy}
|
||||
onAddEnterpriseDatapoints={handleAddEnterpriseDatapoints}
|
||||
/>
|
||||
|
||||
{/* Tooltip */}
|
||||
{showTooltip && (
|
||||
<EnhancedTooltip
|
||||
|
||||
@@ -410,7 +410,113 @@ const StrategicInputField: React.FC<StrategicInputFieldProps> = ({
|
||||
<Autocomplete
|
||||
multiple
|
||||
options={multiSelectConfig.options || []}
|
||||
value={Array.isArray(value) ? value : []}
|
||||
isOptionEqualToValue={(option, value) => {
|
||||
// Custom equality test that handles various formats
|
||||
if (typeof option === 'string' && typeof value === 'string') {
|
||||
return option.toLowerCase() === value.toLowerCase();
|
||||
}
|
||||
return option === value;
|
||||
}}
|
||||
value={(() => {
|
||||
// Debug logging for Autocomplete value parsing
|
||||
console.log('🎯 Autocomplete value parsing:', {
|
||||
fieldId,
|
||||
originalValue: value,
|
||||
valueType: typeof value,
|
||||
isArray: Array.isArray(value),
|
||||
availableOptions: multiSelectConfig.options
|
||||
});
|
||||
|
||||
let parsedValues: string[] = [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
parsedValues = value;
|
||||
console.log('🎯 Using array value:', parsedValues);
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
// Handle object values (convert to array of keys or values)
|
||||
if (typeof value === 'object' && !Array.isArray(value)) {
|
||||
// Convert object to array of keys or values based on context
|
||||
const objectKeys = Object.keys(value);
|
||||
const objectValues = Object.values(value);
|
||||
|
||||
// For traffic_sources, we might want to use the keys or convert percentages to options
|
||||
if (fieldId === 'traffic_sources') {
|
||||
// Convert percentage object to traffic source options
|
||||
const trafficMapping: { [key: string]: string } = {
|
||||
'organic': 'Organic Search',
|
||||
'social': 'Social Media',
|
||||
'direct': 'Direct Traffic',
|
||||
'referral': 'Referral Traffic',
|
||||
'paid': 'Paid Search',
|
||||
'display': 'Display Advertising',
|
||||
'content': 'Content Marketing',
|
||||
'influencer': 'Influencer Marketing',
|
||||
'video': 'Video Platforms',
|
||||
'email': 'Email Marketing'
|
||||
};
|
||||
|
||||
parsedValues = objectKeys
|
||||
.map(key => trafficMapping[key.toLowerCase()])
|
||||
.filter(Boolean);
|
||||
|
||||
console.log('🎯 Converted object to traffic sources:', parsedValues);
|
||||
} else {
|
||||
// For other fields, use object keys
|
||||
parsedValues = objectKeys;
|
||||
console.log('🎯 Using object keys:', parsedValues);
|
||||
}
|
||||
}
|
||||
} else if (typeof value === 'string') {
|
||||
try {
|
||||
// Try to parse as JSON array
|
||||
const parsed = JSON.parse(value);
|
||||
if (Array.isArray(parsed)) {
|
||||
parsedValues = parsed;
|
||||
console.log('🎯 Parsed as JSON array:', parsedValues);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('🎯 JSON parse failed, trying alternative parsing');
|
||||
// If not valid JSON, try to extract array-like content
|
||||
if (value.startsWith('[') && value.endsWith(']')) {
|
||||
// Remove outer brackets and try to parse as comma-separated
|
||||
const content = value.slice(1, -1);
|
||||
// Split by comma but be careful with nested quotes
|
||||
parsedValues = content.split(',').map(item => {
|
||||
// Remove quotes and trim
|
||||
return item.trim().replace(/^["']|["']$/g, '');
|
||||
}).filter(item => item);
|
||||
console.log('🎯 Parsed as array-like string:', parsedValues);
|
||||
} else if (value.includes(',')) {
|
||||
// If not array-like, try simple comma splitting
|
||||
parsedValues = value.split(',').map(item => item.trim()).filter(item => item);
|
||||
console.log('🎯 Parsed as comma-separated string:', parsedValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter values to only include valid options
|
||||
const validOptions = multiSelectConfig.options || [];
|
||||
const filteredValues = parsedValues.filter(val => {
|
||||
// Check for exact match
|
||||
if (validOptions.includes(val)) {
|
||||
return true;
|
||||
}
|
||||
// Check for partial match (case-insensitive)
|
||||
const partialMatch = validOptions.find(option =>
|
||||
option.toLowerCase().includes(val.toLowerCase()) ||
|
||||
val.toLowerCase().includes(option.toLowerCase())
|
||||
);
|
||||
if (partialMatch) {
|
||||
console.log('🎯 Found partial match:', val, '->', partialMatch);
|
||||
return true;
|
||||
}
|
||||
console.log('🎯 No match found for:', val);
|
||||
return false;
|
||||
});
|
||||
|
||||
console.log('🎯 Final filtered values:', filteredValues);
|
||||
return filteredValues;
|
||||
})()}
|
||||
onChange={(_, newValue) => handleChange(newValue)}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
|
||||
@@ -38,34 +38,28 @@ export const useActionButtonsBusinessLogic = ({
|
||||
console.log('Current formData:', formData);
|
||||
console.log('FormData ID:', formData.id);
|
||||
|
||||
// If we have a saved strategy, use its ID
|
||||
if (formData.id) {
|
||||
console.log('Using existing strategy ID:', formData.id);
|
||||
await generateAIRecommendations(formData.id);
|
||||
} else {
|
||||
console.log('No strategy ID found, creating new strategy...');
|
||||
// If no strategy is saved yet, save it first, then generate AI insights
|
||||
const isValid = validateAllFields();
|
||||
console.log('Form validation result:', isValid);
|
||||
|
||||
if (isValid) {
|
||||
const completionStats = getCompletionStats();
|
||||
const strategyData = {
|
||||
...formData,
|
||||
completion_percentage: completionStats.completion_percentage,
|
||||
user_id: 1, // This would come from auth context
|
||||
name: formData.name || 'Enhanced Content Strategy',
|
||||
industry: formData.industry || 'General'
|
||||
};
|
||||
// Always use the polling-based strategy generation for consistency
|
||||
console.log('Using polling-based strategy generation...');
|
||||
const isValid = validateAllFields();
|
||||
console.log('Form validation result:', isValid);
|
||||
|
||||
if (isValid) {
|
||||
const completionStats = getCompletionStats();
|
||||
const strategyData = {
|
||||
...formData,
|
||||
completion_percentage: completionStats.completion_percentage,
|
||||
user_id: 1, // This would come from auth context
|
||||
name: formData.name || 'Enhanced Content Strategy',
|
||||
industry: formData.industry || 'General'
|
||||
};
|
||||
|
||||
console.log('Attempting to create strategy with data:', strategyData);
|
||||
|
||||
// Use SSE streaming endpoint for strategy generation with educational content
|
||||
await generateStrategyWithPolling(strategyData);
|
||||
} else {
|
||||
setError('Please fill in all required fields before generating AI insights.');
|
||||
console.error('Form validation failed. Cannot generate AI insights.');
|
||||
}
|
||||
console.log('Attempting to create strategy with data:', strategyData);
|
||||
|
||||
// Use polling-based strategy generation with educational content
|
||||
await generateStrategyWithPolling(strategyData);
|
||||
} else {
|
||||
setError('Please fill in all required fields before generating AI insights.');
|
||||
console.error('Form validation failed. Cannot generate AI insights.');
|
||||
}
|
||||
} catch (err: any) {
|
||||
setError(`Error generating AI recommendations: ${err.message || 'Unknown error'}`);
|
||||
@@ -97,49 +91,79 @@ export const useActionButtonsBusinessLogic = ({
|
||||
// Show educational modal
|
||||
setShowEducationalModal(true);
|
||||
|
||||
// Start polling-based strategy generation directly (no basic strategy creation)
|
||||
const generationResult = await contentPlanningApi.startStrategyGenerationPolling(1, 'Enhanced Content Strategy');
|
||||
// Start polling-based strategy generation with actual strategy data
|
||||
const generationResult = await contentPlanningApi.startStrategyGenerationPolling(
|
||||
strategyData.user_id || 1,
|
||||
strategyData.name || 'Enhanced Content Strategy'
|
||||
);
|
||||
console.log('Strategy generation started:', generationResult);
|
||||
console.log('Generation result structure:', generationResult);
|
||||
console.log('Generation result.data:', generationResult?.data);
|
||||
console.log('Generation result.data.task_id:', generationResult?.data?.task_id);
|
||||
|
||||
if (generationResult && generationResult.task_id) {
|
||||
const taskId = generationResult.task_id;
|
||||
// Check for task_id in the correct location based on backend response structure
|
||||
const taskId = generationResult?.data?.task_id || generationResult?.task_id;
|
||||
console.log('Task ID extracted:', taskId);
|
||||
|
||||
if (taskId) {
|
||||
console.log('Task ID received:', taskId);
|
||||
|
||||
// Start polling for status updates
|
||||
console.log('🎯 Starting polling for task ID:', taskId);
|
||||
contentPlanningApi.pollStrategyGeneration(
|
||||
taskId,
|
||||
// onProgress callback
|
||||
(status: any) => {
|
||||
console.log('📊 Progress update:', status);
|
||||
console.log('📊 Status structure:', status);
|
||||
|
||||
// Extract the actual task status from the response data
|
||||
const taskStatus = status?.data || status;
|
||||
console.log('📊 Task status:', taskStatus);
|
||||
|
||||
// Update progress
|
||||
if (status.progress !== undefined) {
|
||||
setGenerationProgress(status.progress);
|
||||
if (taskStatus.progress !== undefined) {
|
||||
console.log('📊 Setting progress:', taskStatus.progress);
|
||||
setGenerationProgress(taskStatus.progress);
|
||||
|
||||
// Debug: Check if progress reached 100%
|
||||
if (taskStatus.progress >= 100) {
|
||||
console.log('🎯 Progress reached 100% - modal should show "Next" button');
|
||||
}
|
||||
}
|
||||
|
||||
// Update educational content
|
||||
if (status.educational_content) {
|
||||
console.log('📚 Updating educational content:', status.educational_content);
|
||||
setEducationalContent(status.educational_content);
|
||||
if (taskStatus.educational_content) {
|
||||
console.log('📚 Updating educational content:', taskStatus.educational_content);
|
||||
setEducationalContent(taskStatus.educational_content);
|
||||
}
|
||||
|
||||
// Update message
|
||||
if (status.message) {
|
||||
console.log('📝 Status message:', status.message);
|
||||
if (taskStatus.message) {
|
||||
console.log('📝 Status message:', taskStatus.message);
|
||||
}
|
||||
|
||||
// Update phase if available
|
||||
if (taskStatus.step) {
|
||||
console.log('📊 Current step:', taskStatus.step);
|
||||
}
|
||||
},
|
||||
// onComplete callback
|
||||
(strategy: any) => {
|
||||
console.log('✅ Strategy generation completed successfully!');
|
||||
setCurrentStrategy(strategy);
|
||||
setShowEducationalModal(false);
|
||||
setError('Strategy created successfully! Check the Strategic Intelligence tab for detailed insights.');
|
||||
// Set progress to 100% when completion is detected
|
||||
setGenerationProgress(100);
|
||||
console.log('🎯 Setting progress to 100% in onComplete callback');
|
||||
// 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');
|
||||
},
|
||||
// onError callback
|
||||
(error: string) => {
|
||||
console.error('❌ Strategy generation failed:', error);
|
||||
setError(`Strategy generation failed: ${error}`);
|
||||
setShowEducationalModal(false);
|
||||
setShowEducationalModal(false); // Only close on error
|
||||
},
|
||||
5000, // 5 second polling interval for faster updates
|
||||
72 // 6 minutes max (72 * 5 seconds)
|
||||
|
||||
@@ -31,8 +31,11 @@ const EducationalModal: React.FC<EducationalModalProps> = ({
|
||||
open,
|
||||
onClose,
|
||||
educationalContent,
|
||||
generationProgress
|
||||
generationProgress,
|
||||
onReviewStrategy
|
||||
}) => {
|
||||
// Debug: Log progress and button state
|
||||
console.log('🎯 EducationalModal - Progress:', generationProgress, 'Show Next Button:', generationProgress >= 100);
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
@@ -528,24 +531,50 @@ const EducationalModal: React.FC<EducationalModalProps> = ({
|
||||
pt: 0,
|
||||
justifyContent: 'center'
|
||||
}}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={onClose}
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
px: 4,
|
||||
py: 1.5,
|
||||
fontWeight: 600,
|
||||
borderColor: 'rgba(102, 126, 234, 0.3)',
|
||||
color: '#667eea',
|
||||
'&:hover': {
|
||||
borderColor: '#667eea',
|
||||
backgroundColor: 'rgba(102, 126, 234, 0.05)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
{generationProgress >= 100 ? (
|
||||
// Show "Next: Review Strategy and Create Calendar" button when generation is complete
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={onReviewStrategy}
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
px: 4,
|
||||
py: 1.5,
|
||||
fontWeight: 600,
|
||||
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
color: 'white',
|
||||
'&:hover': {
|
||||
background: 'linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%)',
|
||||
transform: 'translateY(-1px)',
|
||||
boxShadow: '0 8px 25px rgba(102, 126, 234, 0.3)'
|
||||
},
|
||||
transition: 'all 0.3s ease'
|
||||
}}
|
||||
startIcon={<AutoAwesomeIcon />}
|
||||
>
|
||||
Next: Review Strategy and Create Calendar
|
||||
</Button>
|
||||
) : (
|
||||
// Show "Close" button during generation
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={onClose}
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
px: 4,
|
||||
py: 1.5,
|
||||
fontWeight: 600,
|
||||
borderColor: 'rgba(102, 126, 234, 0.3)',
|
||||
color: '#667eea',
|
||||
'&:hover': {
|
||||
borderColor: '#667eea',
|
||||
backgroundColor: 'rgba(102, 126, 234, 0.05)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
)}
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -17,6 +17,7 @@ export interface EducationalModalProps {
|
||||
onClose: () => void;
|
||||
educationalContent: EducationalContent | null;
|
||||
generationProgress: number;
|
||||
onReviewStrategy?: () => void;
|
||||
}
|
||||
|
||||
// Category Detail View Types
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Button,
|
||||
Typography,
|
||||
Box,
|
||||
Grid,
|
||||
Card,
|
||||
CardContent,
|
||||
Chip,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Divider,
|
||||
Alert,
|
||||
IconButton,
|
||||
Paper
|
||||
} from '@mui/material';
|
||||
import {
|
||||
AutoAwesome as AutoAwesomeIcon,
|
||||
TrendingUp as TrendingUpIcon,
|
||||
Business as BusinessIcon,
|
||||
Analytics as AnalyticsIcon,
|
||||
Schedule as ScheduleIcon,
|
||||
Group as GroupIcon,
|
||||
Assessment as AssessmentIcon,
|
||||
Build as BuildIcon,
|
||||
Palette as BrandingIcon,
|
||||
Storage as StorageIcon,
|
||||
CheckCircle as CheckCircleIcon,
|
||||
ArrowForward as ArrowForwardIcon,
|
||||
Close as CloseIcon,
|
||||
Star as StarIcon,
|
||||
Speed as SpeedIcon,
|
||||
Security as SecurityIcon
|
||||
} from '@mui/icons-material';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface EnterpriseDatapointsModalProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onProceedWithCurrent: () => void;
|
||||
onAddEnterpriseDatapoints: () => void;
|
||||
}
|
||||
|
||||
const EnterpriseDatapointsModal: React.FC<EnterpriseDatapointsModalProps> = ({
|
||||
open,
|
||||
onClose,
|
||||
onProceedWithCurrent,
|
||||
onAddEnterpriseDatapoints
|
||||
}) => {
|
||||
const enterpriseCategories = [
|
||||
{
|
||||
title: 'Content Distribution & Channel Strategy',
|
||||
icon: <TrendingUpIcon />,
|
||||
fields: 6,
|
||||
description: 'Multi-channel distribution and promotion strategy',
|
||||
color: 'primary'
|
||||
},
|
||||
{
|
||||
title: 'Content Calendar & Planning',
|
||||
icon: <ScheduleIcon />,
|
||||
fields: 5,
|
||||
description: 'Structured content planning and scheduling',
|
||||
color: 'secondary'
|
||||
},
|
||||
{
|
||||
title: 'Audience Segmentation & Personas',
|
||||
icon: <GroupIcon />,
|
||||
fields: 6,
|
||||
description: 'Detailed audience analysis and personas',
|
||||
color: 'success'
|
||||
},
|
||||
{
|
||||
title: 'Content Performance & Optimization',
|
||||
icon: <AnalyticsIcon />,
|
||||
fields: 5,
|
||||
description: 'Performance tracking and optimization',
|
||||
color: 'info'
|
||||
},
|
||||
{
|
||||
title: 'Content Creation & Production',
|
||||
icon: <BuildIcon />,
|
||||
fields: 5,
|
||||
description: 'Content creation workflow and processes',
|
||||
color: 'warning'
|
||||
},
|
||||
{
|
||||
title: 'Brand & Messaging Strategy',
|
||||
icon: <BrandingIcon />,
|
||||
fields: 5,
|
||||
description: 'Brand positioning and messaging',
|
||||
color: 'error'
|
||||
},
|
||||
{
|
||||
title: 'Technology & Platform Strategy',
|
||||
icon: <StorageIcon />,
|
||||
fields: 5,
|
||||
description: 'Technology stack and integrations',
|
||||
color: 'primary'
|
||||
}
|
||||
];
|
||||
|
||||
const benefits = [
|
||||
{
|
||||
icon: <StarIcon />,
|
||||
title: '3x Better Performance',
|
||||
description: 'Strategies with 60+ datapoints show significantly better results'
|
||||
},
|
||||
{
|
||||
icon: <SpeedIcon />,
|
||||
title: 'Months → Minutes',
|
||||
description: 'Get enterprise-grade analysis in minutes, not months'
|
||||
},
|
||||
{
|
||||
icon: <SecurityIcon />,
|
||||
title: 'Risk Mitigation',
|
||||
description: 'Comprehensive analysis reduces strategy risks'
|
||||
},
|
||||
{
|
||||
icon: <BusinessIcon />,
|
||||
title: '$50K+ Value',
|
||||
description: 'Enterprise consulting value democratized with AI'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={(event, reason) => {
|
||||
console.log('🎯 Enterprise modal onClose called with reason:', reason);
|
||||
// Only allow closing via the close button, not by clicking outside or pressing escape
|
||||
if (reason === 'backdropClick' || reason === 'escapeKeyDown') {
|
||||
console.log('🎯 Preventing modal close via backdrop/escape');
|
||||
return;
|
||||
}
|
||||
onClose();
|
||||
}}
|
||||
maxWidth="xl"
|
||||
fullWidth
|
||||
disableEscapeKeyDown
|
||||
PaperProps={{
|
||||
sx: {
|
||||
borderRadius: 4,
|
||||
background: 'linear-gradient(135deg, #ffffff 0%, #f8f9ff 100%)',
|
||||
boxShadow: '0 20px 60px rgba(0, 0, 0, 0.15)',
|
||||
border: '1px solid rgba(102, 126, 234, 0.1)',
|
||||
overflow: 'hidden',
|
||||
maxHeight: '95vh'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DialogTitle sx={{
|
||||
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
color: 'white',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: 'linear-gradient(45deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 100%)',
|
||||
pointerEvents: 'none'
|
||||
}
|
||||
}}>
|
||||
<Box display="flex" alignItems="center" justifyContent="space-between" sx={{ position: 'relative', zIndex: 1 }}>
|
||||
<Box display="flex" alignItems="center" gap={2}>
|
||||
<Box sx={{
|
||||
p: 1,
|
||||
borderRadius: 2,
|
||||
background: 'rgba(255, 255, 255, 0.2)',
|
||||
backdropFilter: 'blur(10px)',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)'
|
||||
}}>
|
||||
<AutoAwesomeIcon sx={{ color: 'white', fontSize: 24 }} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography variant="h4" sx={{ fontWeight: 700, mb: 0.5 }}>
|
||||
Unlock Enterprise-Grade Content Strategy
|
||||
</Typography>
|
||||
<Typography variant="body1" sx={{ opacity: 0.9, fontWeight: 500 }}>
|
||||
Transform your basic strategy into an enterprise-grade content strategy that drives real results
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<IconButton
|
||||
onClick={onClose}
|
||||
sx={{
|
||||
color: 'white',
|
||||
'&:hover': {
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.1)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent sx={{ p: 0 }}>
|
||||
<Box sx={{ p: 4 }}>
|
||||
{/* Value Proposition Section */}
|
||||
<Grid container spacing={3} sx={{ mb: 4 }}>
|
||||
<Grid item xs={12} md={8}>
|
||||
<Typography variant="h5" gutterBottom sx={{ color: '#667eea', fontWeight: 600 }}>
|
||||
Why Enterprise Datapoints Matter
|
||||
</Typography>
|
||||
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
|
||||
Access 30+ additional datapoints that enterprise teams spend months analyzing.
|
||||
Get enterprise-quality insights without the enterprise price tag.
|
||||
</Typography>
|
||||
|
||||
<Grid container spacing={2}>
|
||||
{benefits.map((benefit, index) => (
|
||||
<Grid item xs={12} sm={6} key={index}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
>
|
||||
<Card variant="outlined" sx={{
|
||||
height: '100%',
|
||||
border: '1px solid rgba(102, 126, 234, 0.1)',
|
||||
'&:hover': {
|
||||
borderColor: '#667eea',
|
||||
boxShadow: '0 4px 12px rgba(102, 126, 234, 0.15)'
|
||||
}
|
||||
}}>
|
||||
<CardContent sx={{ textAlign: 'center', py: 2 }}>
|
||||
<Box sx={{
|
||||
display: 'inline-flex',
|
||||
p: 1,
|
||||
borderRadius: 2,
|
||||
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
color: 'white',
|
||||
mb: 1
|
||||
}}>
|
||||
{benefit.icon}
|
||||
</Box>
|
||||
<Typography variant="h6" sx={{ fontWeight: 600, mb: 1 }}>
|
||||
{benefit.title}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{benefit.description}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={4}>
|
||||
<Paper sx={{
|
||||
p: 3,
|
||||
background: 'linear-gradient(135deg, #f8f9ff 0%, #eef3fb 100%)',
|
||||
border: '2px solid rgba(102, 126, 234, 0.2)',
|
||||
borderRadius: 3
|
||||
}}>
|
||||
<Typography variant="h6" gutterBottom sx={{ color: '#667eea', fontWeight: 600 }}>
|
||||
Strategy Comparison
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Typography variant="subtitle2" color="text.secondary" gutterBottom>
|
||||
Current Strategy (30 fields)
|
||||
</Typography>
|
||||
<List dense>
|
||||
<ListItem sx={{ px: 0 }}>
|
||||
<ListItemIcon sx={{ minWidth: 32 }}>
|
||||
<CheckCircleIcon color="success" fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary="Basic strategy elements"
|
||||
primaryTypographyProps={{ variant: 'body2' }}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem sx={{ px: 0 }}>
|
||||
<ListItemIcon sx={{ minWidth: 32 }}>
|
||||
<CheckCircleIcon color="success" fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary="Functional content strategy"
|
||||
primaryTypographyProps={{ variant: 'body2' }}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem sx={{ px: 0 }}>
|
||||
<ListItemIcon sx={{ minWidth: 32 }}>
|
||||
<CheckCircleIcon color="success" fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary="Quick implementation"
|
||||
primaryTypographyProps={{ variant: 'body2' }}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ my: 2 }} />
|
||||
|
||||
<Box>
|
||||
<Typography variant="subtitle2" color="text.secondary" gutterBottom>
|
||||
Enterprise Strategy (60+ fields)
|
||||
</Typography>
|
||||
<List dense>
|
||||
<ListItem sx={{ px: 0 }}>
|
||||
<ListItemIcon sx={{ minWidth: 32 }}>
|
||||
<StarIcon color="primary" fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary="Comprehensive coverage"
|
||||
primaryTypographyProps={{ variant: 'body2' }}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem sx={{ px: 0 }}>
|
||||
<ListItemIcon sx={{ minWidth: 32 }}>
|
||||
<StarIcon color="primary" fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary="Operational excellence"
|
||||
primaryTypographyProps={{ variant: 'body2' }}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem sx={{ px: 0 }}>
|
||||
<ListItemIcon sx={{ minWidth: 32 }}>
|
||||
<StarIcon color="primary" fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary="3x better performance"
|
||||
primaryTypographyProps={{ variant: 'body2' }}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Enterprise Categories Section */}
|
||||
<Box sx={{ mb: 4 }}>
|
||||
<Typography variant="h5" gutterBottom sx={{ color: '#667eea', fontWeight: 600 }}>
|
||||
Enterprise Datapoints Categories
|
||||
</Typography>
|
||||
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
|
||||
Unlock 30+ additional fields across 7 enterprise categories for comprehensive strategy coverage.
|
||||
</Typography>
|
||||
|
||||
<Grid container spacing={2}>
|
||||
{enterpriseCategories.map((category, index) => (
|
||||
<Grid item xs={12} sm={6} md={4} key={index}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
>
|
||||
<Card variant="outlined" sx={{
|
||||
height: '100%',
|
||||
border: '1px solid rgba(102, 126, 234, 0.1)',
|
||||
'&:hover': {
|
||||
borderColor: '#667eea',
|
||||
transform: 'translateY(-2px)',
|
||||
boxShadow: '0 8px 25px rgba(102, 126, 234, 0.15)'
|
||||
},
|
||||
transition: 'all 0.3s ease'
|
||||
}}>
|
||||
<CardContent>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1 }}>
|
||||
<Box sx={{
|
||||
p: 0.5,
|
||||
borderRadius: 1,
|
||||
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
color: 'white',
|
||||
display: 'flex',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
{category.icon}
|
||||
</Box>
|
||||
<Chip
|
||||
label={`${category.fields} fields`}
|
||||
size="small"
|
||||
color={category.color as any}
|
||||
sx={{ fontWeight: 600 }}
|
||||
/>
|
||||
</Box>
|
||||
<Typography variant="h6" sx={{ fontWeight: 600, mb: 1 }}>
|
||||
{category.title}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{category.description}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
|
||||
{/* Process Information */}
|
||||
<Alert severity="info" sx={{ mb: 3 }}>
|
||||
<Typography variant="subtitle2" gutterBottom>
|
||||
How It Works
|
||||
</Typography>
|
||||
<Typography variant="body2">
|
||||
AI will autofill 80% of enterprise fields using your existing data and industry insights.
|
||||
You'll only need to review and customize 20% of the fields.
|
||||
Additional time: 10-15 minutes for enterprise-grade strategy.
|
||||
</Typography>
|
||||
</Alert>
|
||||
|
||||
{/* Social Proof */}
|
||||
<Paper sx={{
|
||||
p: 3,
|
||||
background: 'linear-gradient(135deg, #f0f8ff 0%, #e6f3ff 100%)',
|
||||
border: '1px solid rgba(102, 126, 234, 0.2)',
|
||||
borderRadius: 2
|
||||
}}>
|
||||
<Typography variant="h6" gutterBottom sx={{ color: '#667eea', fontWeight: 600 }}>
|
||||
What Users Say
|
||||
</Typography>
|
||||
<Typography variant="body1" sx={{ fontStyle: 'italic', color: 'text.secondary' }}>
|
||||
"The enterprise datapoints transformed our basic strategy into a comprehensive,
|
||||
actionable plan that our entire team could follow. The AI autofill saved us hours
|
||||
of manual work while maintaining quality."
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ mt: 1, fontWeight: 600, color: '#667eea' }}>
|
||||
— Marketing Director, Tech Startup
|
||||
</Typography>
|
||||
</Paper>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions sx={{
|
||||
p: 4,
|
||||
pt: 0,
|
||||
justifyContent: 'space-between',
|
||||
flexWrap: 'wrap',
|
||||
gap: 2
|
||||
}}>
|
||||
<Box>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Limited time access to enterprise features
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Get $50K+ consulting value for free
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={onProceedWithCurrent}
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
px: 3,
|
||||
py: 1.5,
|
||||
fontWeight: 600,
|
||||
borderColor: 'rgba(102, 126, 234, 0.3)',
|
||||
color: '#667eea',
|
||||
'&:hover': {
|
||||
borderColor: '#667eea',
|
||||
backgroundColor: 'rgba(102, 126, 234, 0.05)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
Proceed with Current Strategy
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={onAddEnterpriseDatapoints}
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
px: 4,
|
||||
py: 1.5,
|
||||
fontWeight: 600,
|
||||
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
'&:hover': {
|
||||
background: 'linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%)'
|
||||
}
|
||||
}}
|
||||
endIcon={<ArrowForwardIcon />}
|
||||
>
|
||||
Add Enterprise Datapoints
|
||||
<Chip
|
||||
label="Coming Soon"
|
||||
size="small"
|
||||
sx={{
|
||||
ml: 1,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
color: 'white',
|
||||
fontSize: '0.7rem',
|
||||
height: 20
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
</Box>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default EnterpriseDatapointsModal;
|
||||
Reference in New Issue
Block a user