import React, { useState, useEffect } from 'react'; import { Box, Button, TextField, Typography, Alert, CircularProgress, Card, CardContent, Grid, Accordion, AccordionSummary, AccordionDetails, LinearProgress, Stepper, Step, StepLabel, Dialog, DialogTitle, DialogContent, DialogActions, DialogContentText, Chip, Divider, Checkbox, FormControlLabel, Paper, Fade, Slide, Zoom, Tooltip, IconButton } from '@mui/material'; import { ExpandMore as ExpandMoreIcon, CheckCircle as CheckIcon, Info as InfoIcon, Language as LanguageIcon, Web as WebIcon, Analytics as AnalyticsIcon, Psychology as PsychologyIcon, TrendingUp as TrendingUpIcon, History as HistoryIcon, Star as StarIcon, Warning as WarningIcon, Lightbulb as LightbulbIcon, Palette as PaletteIcon, Speed as SpeedIcon, Group as GroupIcon, Business as BusinessIcon, LocationOn as LocationIcon, AutoAwesome as AutoAwesomeIcon, Verified as VerifiedIcon, Close as CloseIcon } from '@mui/icons-material'; interface WebsiteStepProps { onContinue: () => void; updateHeaderContent: (content: { title: string; description: string }) => void; } interface StyleAnalysis { writing_style?: { tone: string; voice: string; complexity: string; engagement_level: string; brand_personality?: string; formality_level?: string; emotional_appeal?: string; }; content_characteristics?: { sentence_structure: string; vocabulary_level: string; paragraph_organization: string; content_flow: string; readability_score?: string; content_density?: string; visual_elements_usage?: string; }; target_audience?: { demographics: string[]; expertise_level: string; industry_focus: string; geographic_focus: string; psychographic_profile?: string; pain_points?: string[]; motivations?: string[]; }; content_type?: { primary_type: string; secondary_types: string[]; purpose: string; call_to_action: string; conversion_focus?: string; educational_value?: string; }; brand_analysis?: { brand_voice: string; brand_values: string[]; brand_positioning: string; competitive_differentiation: string; trust_signals: string[]; authority_indicators: string[]; }; content_strategy_insights?: { strengths: string[]; weaknesses: string[]; opportunities: string[]; threats: string[]; recommended_improvements: string[]; content_gaps: string[]; }; recommended_settings?: { writing_tone: string; target_audience: string; content_type: string; creativity_level: string; geographic_location: string; industry_context?: string; brand_alignment?: string; }; // New comprehensive analysis fields guidelines?: { tone_recommendations: string[]; structure_guidelines: string[]; vocabulary_suggestions: string[]; engagement_tips: string[]; audience_considerations: string[]; brand_alignment?: string[]; seo_optimization?: string[]; conversion_optimization?: string[]; }; best_practices?: string[]; avoid_elements?: string[]; content_strategy?: string; ai_generation_tips?: string[]; competitive_advantages?: string[]; content_calendar_suggestions?: string[]; style_patterns?: { sentence_length: string; vocabulary_patterns: string[]; rhetorical_devices: string[]; paragraph_structure: string; transition_phrases: string[]; }; style_consistency?: string; unique_elements?: string[]; } interface AnalysisProgress { step: number; message: string; completed: boolean; } interface ExistingAnalysis { exists: boolean; analysis_date?: string; analysis_id?: number; summary?: { writing_style?: any; target_audience?: any; content_type?: any; }; error?: string; } const WebsiteStep: React.FC = ({ onContinue, updateHeaderContent }) => { const [website, setWebsite] = useState(''); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(null); const [analysis, setAnalysis] = useState(null); const [existingAnalysis, setExistingAnalysis] = useState(null); const [showConfirmationDialog, setShowConfirmationDialog] = useState(false); const [useAnalysisForGenAI, setUseAnalysisForGenAI] = useState(true); const [domainName, setDomainName] = useState(''); const [hasCheckedExisting, setHasCheckedExisting] = useState(false); const [progress, setProgress] = useState([ { step: 1, message: 'Validating website URL', completed: false }, { step: 2, message: 'Crawling website content', completed: false }, { step: 3, message: 'Extracting content structure', completed: false }, { step: 4, message: 'Analyzing writing style', completed: false }, { step: 5, message: 'Identifying content characteristics', completed: false }, { step: 6, message: 'Determining target audience', completed: false }, { step: 7, message: 'Generating recommendations', completed: false } ]); useEffect(() => { // Update header content when component mounts updateHeaderContent({ title: 'Analyze Your Website', description: 'Let Alwrity analyze your website to understand your brand voice, writing style, and content characteristics. This helps us generate content that matches your existing tone and resonates with your audience.' }); }, [updateHeaderContent]); useEffect(() => { // Prefill from last session analysis on mount const fetchLastAnalysis = async () => { try { const res = await fetch('/api/style-detection/session-analyses'); const data = await res.json(); if (data.success && Array.isArray(data.analyses) && data.analyses.length > 0) { // Pick the most recent analysis (assuming sorted by date desc, else sort here) const last = data.analyses[0]; if (last && last.website_url) { setWebsite(last.website_url); } if (last && last.style_analysis) { setAnalysis(last.style_analysis); } } } catch (err) { console.error('WebsiteStep: Error pre-filling from last analysis', err); } }; fetchLastAnalysis(); }, []); // Reset existing analysis check when URL changes significantly useEffect(() => { if (website.trim()) { setHasCheckedExisting(false); setExistingAnalysis(null); setShowConfirmationDialog(false); } }, [website]); // Check for existing analysis when URL changes useEffect(() => { if (website.trim() && !hasCheckedExisting) { const checkExisting = async () => { const fixedUrl = fixUrlFormat(website); if (fixedUrl) { console.log('WebsiteStep: Checking for existing analysis for URL:', fixedUrl); const hasExisting = await checkExistingAnalysis(fixedUrl); if (hasExisting) { console.log('WebsiteStep: Found existing analysis, showing confirmation dialog'); setShowConfirmationDialog(true); } setHasCheckedExisting(true); } }; // Debounce the check to avoid too many API calls const timeoutId = setTimeout(checkExisting, 1000); return () => clearTimeout(timeoutId); } }, [website, hasCheckedExisting]); const checkExistingAnalysis = async (url: string) => { try { console.log('WebsiteStep: Checking existing analysis for URL:', url); const response = await fetch(`/api/onboarding/style-detection/check-existing/${encodeURIComponent(url)}`); const result = await response.json(); if (result.exists) { console.log('WebsiteStep: Existing analysis found:', result); setExistingAnalysis(result); return true; } else { console.log('WebsiteStep: No existing analysis found'); setExistingAnalysis(null); return false; } } catch (error) { console.error('WebsiteStep: Error checking existing analysis:', error); setExistingAnalysis(null); return false; } }; const loadExistingAnalysis = async (analysisId: number) => { try { const response = await fetch(`/api/onboarding/style-detection/analysis/${analysisId}`); const result = await response.json(); if (result.success && result.analysis) { // Extract domain name for personalization const extractedDomain = extractDomainName(website); setDomainName(extractedDomain); // Combine all analysis data into a comprehensive object const comprehensiveAnalysis = { ...result.analysis.style_analysis, guidelines: result.analysis.style_guidelines, best_practices: result.analysis.style_guidelines?.best_practices, avoid_elements: result.analysis.style_guidelines?.avoid_elements, content_strategy: result.analysis.style_guidelines?.content_strategy, style_patterns: result.analysis.style_patterns, style_consistency: result.analysis.style_patterns?.style_consistency, unique_elements: result.analysis.style_patterns?.unique_elements }; setAnalysis(comprehensiveAnalysis); setSuccess('Loaded previous analysis successfully!'); return true; } return false; } catch (error) { console.error('Error loading existing analysis:', error); return false; } }; const handleAnalyze = async () => { setError(null); setSuccess(null); setLoading(true); setAnalysis(null); // Reset progress setProgress(prev => prev.map(p => ({ ...p, completed: false }))); try { // Validate and fix URL format const fixedUrl = fixUrlFormat(website); if (!fixedUrl) { setError('Please enter a valid website URL (starting with http:// or https://)'); setLoading(false); return; } // Check for existing analysis const hasExisting = await checkExistingAnalysis(fixedUrl); if (hasExisting && existingAnalysis) { setShowConfirmationDialog(true); setLoading(false); return; } // Proceed with new analysis await performAnalysis(fixedUrl); } catch (err) { console.error('Analysis error:', err); setError('Failed to analyze website. Please check your internet connection and try again.'); } finally { setLoading(false); } }; const performAnalysis = async (fixedUrl: string) => { // Simulate progress updates const updateProgress = (step: number, message: string) => { setProgress(prev => prev.map(p => p.step === step ? { ...p, message, completed: true } : p )); }; updateProgress(1, 'Website URL validated'); const requestData = { url: fixedUrl, include_patterns: true, include_guidelines: true }; updateProgress(2, 'Starting content crawl...'); const response = await fetch('/api/onboarding/style-detection/complete', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestData), }); updateProgress(3, 'Content extracted successfully'); updateProgress(4, 'Style analysis in progress...'); updateProgress(5, 'Content characteristics analyzed'); updateProgress(6, 'Target audience identified'); updateProgress(7, 'Recommendations generated'); const result = await response.json(); if (result.success) { // Extract domain name for personalization const extractedDomain = extractDomainName(fixedUrl); setDomainName(extractedDomain); // Combine all analysis data into a comprehensive object const comprehensiveAnalysis = { ...result.style_analysis, guidelines: result.style_guidelines, best_practices: result.style_guidelines?.best_practices, avoid_elements: result.style_guidelines?.avoid_elements, content_strategy: result.style_guidelines?.content_strategy, style_patterns: result.style_patterns, style_consistency: result.style_patterns?.style_consistency, unique_elements: result.style_patterns?.unique_elements }; setAnalysis(comprehensiveAnalysis); // Check if there's a warning about fallback data if (result.warning) { setSuccess(`Website style analysis completed successfully! Note: ${result.warning}`); } else { setSuccess('Website style analysis completed successfully!'); } } else { // Handle specific error cases let errorMessage = result.error || 'Analysis failed'; if (errorMessage.includes('API key') || errorMessage.includes('configure')) { errorMessage = 'API keys not configured. Please complete step 1 of onboarding to configure your AI provider API keys.'; } else if (errorMessage.includes('library not available')) { errorMessage = 'AI provider library not available. Please ensure your AI provider is properly configured in step 1.'; } else if (errorMessage.includes('crawl') || errorMessage.includes('website')) { errorMessage = 'Unable to access the website. Please check the URL and ensure the website is publicly accessible.'; } setError(errorMessage); } }; const handleLoadExisting = async () => { if (existingAnalysis?.analysis_id) { setLoading(true); const success = await loadExistingAnalysis(existingAnalysis.analysis_id); if (!success) { setError('Failed to load existing analysis. Please try a new analysis.'); } setLoading(false); } setShowConfirmationDialog(false); }; const handleNewAnalysis = async () => { setShowConfirmationDialog(false); setExistingAnalysis(null); if (website) { const fixedUrl = fixUrlFormat(website); if (fixedUrl) { setLoading(true); await performAnalysis(fixedUrl); setLoading(false); } } }; const fixUrlFormat = (url: string): string | null => { if (!url) return null; // Remove leading/trailing whitespace let fixedUrl = url.trim(); // Check if URL already has a protocol but is missing slashes if (fixedUrl.startsWith('https:/') && !fixedUrl.startsWith('https://')) { fixedUrl = fixedUrl.replace('https:/', 'https://'); } else if (fixedUrl.startsWith('http:/') && !fixedUrl.startsWith('http://')) { fixedUrl = fixedUrl.replace('http:/', 'http://'); } // Add protocol if missing if (!fixedUrl.startsWith('http://') && !fixedUrl.startsWith('https://')) { fixedUrl = 'https://' + fixedUrl; } // Fix missing slash after protocol if (fixedUrl.includes('://') && !fixedUrl.split('://')[1].startsWith('/')) { fixedUrl = fixedUrl.replace('://', ':///'); } // Ensure only two slashes after protocol if (fixedUrl.includes(':///')) { fixedUrl = fixedUrl.replace(':///', '://'); } // Basic URL validation try { new URL(fixedUrl); return fixedUrl; } catch { return null; } }; const handleContinue = () => { setError(null); const fixedUrl = fixUrlFormat(website); if (!fixedUrl) { setError('Please enter a valid website URL (starting with http:// or https://)'); return; } onContinue(); }; const renderAnalysisSection = (title: string, data: any, icon: React.ReactNode, description?: string) => ( }> {icon} {title} {description && ( {description} )} {Object.entries(data).map(([key, value]) => ( {key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}: {Array.isArray(value) ? value.join(', ') : String(value)} ))} ); const renderGuidelinesSection = (guidelines: any) => ( }> Content Guidelines Personalized recommendations for improving your content creation based on your writing style analysis. {guidelines.tone_recommendations && ( Tone Recommendations {guidelines.tone_recommendations.map((rec: string, index: number) => ( {rec} ))} )} {guidelines.structure_guidelines && ( Structure Guidelines {guidelines.structure_guidelines.map((guideline: string, index: number) => ( {guideline} ))} )} {guidelines.vocabulary_suggestions && ( Vocabulary Suggestions {guidelines.vocabulary_suggestions.map((suggestion: string, index: number) => ( {suggestion} ))} )} {guidelines.engagement_tips && ( Engagement Tips {guidelines.engagement_tips.map((tip: string, index: number) => ( {tip} ))} )} {guidelines.audience_considerations && ( Audience Considerations {guidelines.audience_considerations.map((consideration: string, index: number) => ( {consideration} ))} )} ); const renderBestPracticesSection = (bestPractices: string[]) => ( }> Best Practices Recommended practices to enhance your content quality and effectiveness. {bestPractices.map((practice: string, index: number) => ( {practice} ))} ); const renderAvoidElementsSection = (avoidElements: string[]) => ( }> Elements to Avoid Elements that may detract from your content's effectiveness based on your writing style. {avoidElements.map((element: string, index: number) => ( {element} ))} ); const renderContentStrategySection = (contentStrategy: string) => ( }> Content Strategy Overall content strategy recommendation based on your writing style analysis. {contentStrategy} ); const renderStylePatternsSection = (patterns: any) => ( }> Style Patterns Recurring patterns and characteristics identified in your writing style. {Object.entries(patterns).map(([key, value]) => ( {key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}: {Array.isArray(value) ? value.join(', ') : String(value)} ))} ); const getProgressPercentage = () => { const completedSteps = progress.filter(p => p.completed).length; return (completedSteps / progress.length) * 100; }; const extractDomainName = (url: string): string => { try { const domain = new URL(url).hostname.replace('www.', ''); return domain.charAt(0).toUpperCase() + domain.slice(1); } catch { return 'Your Website'; } }; const renderKeyInsight = (title: string, value: string | string[], icon: React.ReactNode, color: string = 'primary') => ( {icon} {title} {Array.isArray(value) ? value.join(', ') : value} ); const renderGuidelinesCard = (title: string, items: string[], icon: React.ReactNode, color: string = 'primary') => ( {icon} {title} {items.map((item, index) => ( {item} ))} ); const renderProUpgradeAlert = () => ( Learn More } > Limited Analysis Scope This analysis is based on your homepage only. ALwrity Pro can index your entire website and social media content for comprehensive personalized content generation. ); const renderBrandAnalysisSection = (brandAnalysis: any) => ( Brand Analysis {brandAnalysis.brand_voice && ( Brand Voice: {brandAnalysis.brand_voice} )} {brandAnalysis.brand_positioning && ( Brand Positioning: {brandAnalysis.brand_positioning} )} {brandAnalysis.brand_values && brandAnalysis.brand_values.length > 0 && ( Brand Values: {brandAnalysis.brand_values.map((value: string, index: number) => ( {value} ))} )} ); const renderContentStrategyInsightsSection = (insights: any) => ( Content Strategy Insights {insights.strengths && insights.strengths.length > 0 && ( ✅ Strengths: {insights.strengths.map((strength: string, index: number) => ( {strength} ))} )} {insights.opportunities && insights.opportunities.length > 0 && ( 🎯 Opportunities: {insights.opportunities.map((opportunity: string, index: number) => ( {opportunity} ))} )} {insights.recommended_improvements && insights.recommended_improvements.length > 0 && ( 🔧 Recommended Improvements: {insights.recommended_improvements.map((improvement: string, index: number) => ( {improvement} ))} )} ); const renderAIGenerationTipsSection = (tips: string[]) => ( AI Content Generation Tips {tips.map((tip: string, index: number) => ( {tip} ))} ); return ( {/* Enhanced Explanatory Text */} Provide your website URL to enable comprehensive content analysis and style detection. We'll analyze your content to understand your writing style, target audience, and provide personalized recommendations for better content creation. {/* API Key Configuration Notice */} Note: To perform accurate style analysis, you need to configure AI provider API keys in step 1. If you haven't completed step 1 yet, please go back and configure your API keys for the best experience. setWebsite(e.target.value)} fullWidth placeholder="https://yourwebsite.com" disabled={loading} /> {loading && ( Analysis Progress {Math.round(getProgressPercentage())}% Complete p.completed).length}> {progress.map((step) => ( {step.message} ))} )} {error && ( {error} )} {success && ( {success} )} {analysis && ( {/* Pro Upgrade Alert */} {renderProUpgradeAlert()} {/* Main Analysis Results */} {domainName} Style Analysis Comprehensive content analysis and personalized recommendations {/* Key Insights Grid */} {analysis.writing_style?.tone && ( {renderKeyInsight( 'Writing Tone', analysis.writing_style.tone, , 'primary' )} )} {analysis.writing_style?.complexity && ( {renderKeyInsight( 'Content Complexity', analysis.writing_style.complexity, , 'secondary' )} )} {analysis.target_audience?.expertise_level && ( {renderKeyInsight( 'Target Audience', analysis.target_audience.expertise_level, , 'info' )} )} {analysis.content_type?.primary_type && ( {renderKeyInsight( 'Content Type', analysis.content_type.primary_type, , 'warning' )} )} {/* Content Strategy */} {analysis.content_strategy && ( Content Strategy {analysis.content_strategy} )} {/* Brand Analysis */} {analysis.brand_analysis && renderBrandAnalysisSection(analysis.brand_analysis)} {/* Content Strategy Insights */} {analysis.content_strategy_insights && renderContentStrategyInsightsSection(analysis.content_strategy_insights)} {/* AI Generation Tips */} {analysis.ai_generation_tips && renderAIGenerationTipsSection(analysis.ai_generation_tips)} {/* Enhanced Guidelines Section */} {analysis.guidelines && ( Enhanced Content Guidelines for {domainName} {analysis.guidelines.tone_recommendations && ( {renderGuidelinesCard( 'Tone Recommendations', analysis.guidelines.tone_recommendations, , 'primary' )} )} {analysis.guidelines.structure_guidelines && ( {renderGuidelinesCard( 'Structure Guidelines', analysis.guidelines.structure_guidelines, , 'secondary' )} )} {analysis.guidelines.engagement_tips && ( {renderGuidelinesCard( 'Engagement Tips', analysis.guidelines.engagement_tips, , 'success' )} )} {analysis.guidelines.vocabulary_suggestions && ( {renderGuidelinesCard( 'Vocabulary Suggestions', analysis.guidelines.vocabulary_suggestions, , 'info' )} )} {analysis.guidelines.brand_alignment && ( {renderGuidelinesCard( 'Brand Alignment', analysis.guidelines.brand_alignment, , 'warning' )} )} {analysis.guidelines.seo_optimization && ( {renderGuidelinesCard( 'SEO Optimization', analysis.guidelines.seo_optimization, , 'primary' )} )} {analysis.guidelines.conversion_optimization && ( {renderGuidelinesCard( 'Conversion Optimization', analysis.guidelines.conversion_optimization, , 'success' )} )} )} {/* Best Practices & Avoid Elements */} {analysis.best_practices && ( Best Practices {analysis.best_practices.map((practice, index) => ( {practice} ))} )} {analysis.avoid_elements && ( Elements to Avoid {analysis.avoid_elements.map((element, index) => ( {element} ))} )} {/* GenAI Integration Checkbox */} setUseAnalysisForGenAI(e.target.checked)} color="primary" size="large" /> } label={ Use Analysis for AI Content Generation Apply this style analysis to personalize AI-generated content, ensuring it matches {domainName}'s voice and tone. } /> {/* Success Message */} ✅ Analysis complete! Your content style has been analyzed and personalized recommendations are ready. )} {/* Confirmation Dialog for Existing Analysis */} setShowConfirmationDialog(false)} maxWidth="sm" fullWidth > Previous Analysis Found We found a previous analysis for this website from{' '} {existingAnalysis?.analysis_date ? new Date(existingAnalysis.analysis_date).toLocaleDateString() : 'a previous session' }. Would you like to load the previous analysis or perform a new one? {existingAnalysis?.summary && ( Previous Analysis Summary: {existingAnalysis.summary.writing_style?.tone && ( Tone: {existingAnalysis.summary.writing_style.tone} )} {existingAnalysis.summary.target_audience?.expertise_level && ( Target Audience: {existingAnalysis.summary.target_audience.expertise_level} )} {existingAnalysis.summary.content_type?.primary_type && ( Content Type: {existingAnalysis.summary.content_type.primary_type} )} )} ); }; export default WebsiteStep;