import React, { useState, useEffect, useCallback } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { useOrg } from '../contexts/OrgContext'; import { secureApi } from '../services/secureApi'; import { CompanyReport, Employee, EmployeeReport } from '../types'; import { SAMPLE_COMPANY_REPORT } from '../constants'; import RadarPerformanceChart from '../components/charts/RadarPerformanceChart'; import { downloadCompanyReportPDF, downloadEmployeeReportPDF } from '../utils/pdfUtils'; import FigmaPrimaryButton from '../components/figma/FigmaButton'; import { DownloadIcon } from '../components/figma/figmaIcon'; import MarkdownRenderer from '../components/MarkdownRenderer'; const Reports: React.FC = () => { const location = useLocation(); const navigate = useNavigate(); // Helper function to extract company report context for AI const extractCompanyReportContext = (report: CompanyReport, orgName: string): string => { const sections = []; if (report.overview) { sections.push(`Company Overview: - Total Employees: ${report.overview.totalEmployees} - Average Performance Score: ${report.overview.averagePerformanceScore} - Risk Level: ${report.overview.riskLevel} - Submission Rate: ${report.overview.submissionRate}%`); if (report.overview.departmentBreakdown?.length > 0) { const deptInfo = report.overview.departmentBreakdown .map(dept => `${dept.department}: ${dept.count} employees`) .join(', '); sections.push(`Department Breakdown: ${deptInfo}`); } } if (report.strengths?.length > 0) { sections.push(`Company Strengths:\n${report.strengths.map(s => `- ${s}`).join('\n')}`); } if (report.weaknesses?.length > 0) { sections.push(`Company Weaknesses:\n${report.weaknesses.map(w => `- ${w.title}: ${w.description}`).join('\n')}`); } if (report.immediateHiringNeeds?.length > 0) { sections.push(`Immediate Hiring Needs:\n${report.immediateHiringNeeds.map(need => `- ${need.role}: ${need.priority} priority - ${need.reasoning}`).join('\n')}`); } if (report.personnelChanges) { const changes = []; if (report.personnelChanges.newHires?.length > 0) { changes.push(`New Hires: ${report.personnelChanges.newHires.map(hire => `${hire.name} (${hire.role} in ${hire.department})`).join(', ')}`); } if (report.personnelChanges.promotions?.length > 0) { changes.push(`Promotions: ${report.personnelChanges.promotions.map(promo => `${promo.name}: ${promo.fromRole} → ${promo.toRole}`).join(', ')}`); } if (report.personnelChanges.departures?.length > 0) { changes.push(`Departures: ${report.personnelChanges.departures.map(dep => `${dep.name} (${dep.department}) - ${dep.reason}`).join(', ')}`); } if (changes.length > 0) { sections.push(`Personnel Changes:\n${changes.join('\n')}`); } } if (report.forwardOperatingPlan?.length > 0) { sections.push(`Forward Operating Plan:\n${report.forwardOperatingPlan.map(plan => `- ${plan.title}: ${plan.details.join(', ')}`).join('\n')}`); } if (report.gradingBreakdown?.length > 0) { const gradingInfo = report.gradingBreakdown.map(dept => `${dept.departmentName}: ${dept.departmentGrade} (Lead: ${dept.lead})` ).join('\n'); sections.push(`Performance Grading by Department:\n${gradingInfo}`); } return sections.join('\n\n'); }; // Helper function to extract employee report context for AI const extractEmployeeReportContext = (report: EmployeeReport, employeeName: string, companyReport?: CompanyReport): { employeeContext: string; companyContext?: string } => { const employeeSections = []; if (report.roleAndOutput) { employeeSections.push(`Role & Responsibilities: ${report.roleAndOutput.responsibilities}`); if (report.roleAndOutput.selfRatedOutput) { employeeSections.push(`Self-Rated Output: ${report.roleAndOutput.selfRatedOutput}`); } } if (report.insights) { employeeSections.push(`Personality Traits: ${report.insights.personalityTraits}`); if (report.insights.selfAwareness) { employeeSections.push(`Self-Awareness: ${report.insights.selfAwareness}`); } if (report.insights.growthDesire) { employeeSections.push(`Growth Desire: ${report.insights.growthDesire}`); } } if (report.strengths?.length > 0) { employeeSections.push(`Strengths:\n${report.strengths.map(s => `- ${s}`).join('\n')}`); } if (report.weaknesses?.length > 0) { employeeSections.push(`Areas for Improvement:\n${report.weaknesses.map(w => `- ${w}`).join('\n')}`); } if (report.recommendations?.length > 0) { employeeSections.push(`Recommendations:\n${report.recommendations.map(r => `- ${r}`).join('\n')}`); } if (report.gradingOverview) { const gradingInfo = `Grade: ${report.gradingOverview.grade}, Reliability: ${report.gradingOverview.reliability}, Role Fit: ${report.gradingOverview.roleFit}, Scalability: ${report.gradingOverview.scalability}, Output: ${report.gradingOverview.output}, Initiative: ${report.gradingOverview.initiative}`; employeeSections.push(`Performance Scores: ${gradingInfo}`); } const employeeContext = employeeSections.join('\n\n'); let companyContext; if (companyReport && org?.companyName) { companyContext = extractCompanyReportContext(companyReport, org.companyName); } return { employeeContext, companyContext }; }; // Handle Chat with AI navigation for company reports const handleCompanyChatWithAI = () => { if (!companyReport || !org?.companyName) return; const context = extractCompanyReportContext(companyReport, org.companyName); navigate('/chat', { state: { initialContext: context, contextType: 'company', companyName: org.companyName } }); }; // Handle Chat with AI navigation for employee reports const handleEmployeeChatWithAI = (employeeName: string, employeeReport: EmployeeReport) => { const { employeeContext, companyContext } = extractEmployeeReportContext(employeeReport, employeeName, companyReport); navigate('/chat', { state: { initialContext: employeeContext, companyContext: companyContext, contextType: 'employee', employeeName: employeeName, companyName: org?.companyName } }); }; const { employees, reports, submissions, user, isOwner, getFullCompanyReportHistory, generateEmployeeReport, generateCompanyReport, orgId, org } = useOrg(); const [companyReport, setCompanyReport] = useState(null); const [selectedReport, setSelectedReport] = useState<{ report: CompanyReport | EmployeeReport; type: 'company' | 'employee'; employeeName?: string; employeeEmail?: string } | null>(null); const [searchQuery, setSearchQuery] = useState(''); const [generatingEmployeeReport, setGeneratingEmployeeReport] = useState(null); const [generatingCompanyReport, setGeneratingCompanyReport] = useState(false); const currentUserIsOwner = isOwner(user?.uid || ''); // Get selected employee ID from navigation state (from Submissions page) const selectedEmployeeId = location.state?.selectedEmployeeId; console.log('Reports page state:', { employeesCount: employees.length, reportsCount: Object.keys(reports).length, submissionsCount: Object.keys(submissions).length, currentUserIsOwner, companyReport: !!companyReport, selectedReport: selectedReport?.type, employeesList: employees.map(emp => ({ id: emp.id, name: emp.name })) }); const handleGenerateEmployeeReport = async (employee: Employee) => { if (generatingEmployeeReport === employee.id) return; // Prevent double-click setGeneratingEmployeeReport(employee.id); try { console.log('Generating employee report for:', employee.name); const newReport = await generateEmployeeReport(employee); if (newReport) { setSelectedReport({ report: newReport, type: 'employee', employeeName: employee.name }); console.log('Employee report generated successfully'); } } catch (error) { console.error('Failed to generate employee report:', error); alert(`Failed to generate report for ${employee.name}. Please try again.`); } finally { setGeneratingEmployeeReport(null); } }; // Load company report on component mount useEffect(() => { const loadCompanyReport = async () => { try { console.log('Loading company report history...'); const history = await getFullCompanyReportHistory(); console.log('Company report history loaded:', history.length, 'reports'); if (history.length > 0) { console.log('Setting existing company report as default'); setCompanyReport(history[0]); // Auto-select company report by default setSelectedReport({ report: history[0], type: 'company' }); } else { console.log('No company reports found, setting placeholder report'); // Create a placeholder that shows generate button const placeholderReport = { ...SAMPLE_COMPANY_REPORT, isPlaceholder: true } as CompanyReport; setCompanyReport(placeholderReport); setSelectedReport({ report: placeholderReport, type: 'company' }); } } catch (error) { console.error('Failed to load company report:', error); // On error, show placeholder with generate option const placeholderReport = { ...SAMPLE_COMPANY_REPORT, isPlaceholder: true } as CompanyReport; setCompanyReport(placeholderReport); setSelectedReport({ report: placeholderReport, type: 'company' }); } }; loadCompanyReport(); }, [currentUserIsOwner, getFullCompanyReportHistory, employees, user?.uid]); const handleEmployeeSelect = useCallback(async (employee: Employee) => { const employeeReport = reports[employee.id]; if (employeeReport) { setSelectedReport({ report: employeeReport, type: 'employee', employeeName: employee.name, employeeEmail: employee.email }); } else { // FIXED: Only check if employee has submission - do NOT auto-generate const hasSubmission = submissions[employee.id]; if (hasSubmission) { // Show placeholder encouraging manual generation setSelectedReport({ report: { employeeId: employee.id, roleAndOutput: { responsibilities: `${employee.name} has completed their questionnaire but no report has been generated yet.`, selfRatedOutput: 'Report generation is available. Click "Generate Report" to create it.' }, insights: { personalityTraits: 'Report not generated yet. Employee has completed their questionnaire.', selfAwareness: '', growthDesire: '' }, strengths: ['Report generation available - click Generate Report button'], recommendations: ['Generate the report to view detailed analysis and recommendations'] } as EmployeeReport, type: 'employee', employeeName: employee.name, employeeEmail: employee.email }); } else { // No submission available - show message setSelectedReport({ report: { employeeId: employee.id, roleAndOutput: { responsibilities: `${employee.name} has not completed the employee questionnaire yet.`, selfRatedOutput: 'No submission data available.' }, insights: { personalityTraits: 'Please ask the employee to complete their questionnaire first.', selfAwareness: '', growthDesire: '' }, strengths: ['Complete questionnaire to view strengths'], recommendations: ['Employee should complete the questionnaire first'] } as EmployeeReport, type: 'employee', employeeName: employee.name, employeeEmail: employee.email }); } } }, [reports, submissions]); // FIXED: Removed generateEmployeeReport and generatingReports dependencies // Handle navigation from Submissions page useEffect(() => { if (selectedEmployeeId) { const employee = employees.find(emp => emp.id === selectedEmployeeId); if (employee) { handleEmployeeSelect(employee); } } }, [selectedEmployeeId, employees, handleEmployeeSelect]); // Filter and sort employees const visibleEmployees = employees; console.log('Visible employees:', visibleEmployees.length, 'out of', employees.length, 'total employees'); console.log('Search query:', searchQuery); console.log('Current user is owner:', currentUserIsOwner); const handleCompanyReportSelect = () => { if (companyReport) { setSelectedReport({ report: companyReport, type: 'company' }); } }; const handleGenerateCompanyReport = async () => { setGeneratingCompanyReport(true); try { console.log('Generating new company report with current data...'); const newReport = await generateCompanyReport(); setCompanyReport(newReport); setSelectedReport({ report: newReport, type: 'company' }); console.log('Company report generated successfully'); } catch (error) { console.error('Error generating company report:', error); // Show error message to user alert('Failed to generate company report. Please try again.'); } finally { setGeneratingCompanyReport(false); } }; return ( <> {/* Middle Section - Employee List */}
Employees
{/* Search */}
setSearchQuery(e.target.value)} className="flex-1 bg-transparent text-[--Text-Gray-500] text-sm font-normal font-['Inter'] leading-tight outline-none" />
{/* Employee List */}
{/* Company Report Item - Always show for consistency */} {companyReport && (
{org?.companyName?.charAt(0)?.toUpperCase() || 'C'}
{org?.companyName || 'Company Report'}
{/* Status indicator for company report */} {(companyReport as any)?.isPlaceholder ? (
) : (
)}
)} {/* Employee Items */} {visibleEmployees.map((employee) => { const hasSubmission = submissions[employee.id]; const hasReport = reports[employee.id]; const isGenerating = generatingEmployeeReport === employee.id; return (
handleEmployeeSelect(employee)} >
{employee.initials}
{/* Status indicator */} {isGenerating ? (
) : hasReport ? (
) : hasSubmission ? (
) : (
)}
{employee.name}
{isGenerating && (
)}
); })}
{/* Main Content Area */}
{selectedReport ? ( selectedReport.type === 'company' ? ( ) : ( (() => { const employeeReport = selectedReport.report as EmployeeReport; const employeeId = employeeReport.employeeId; return ( { const employee = employees.find(emp => emp.email === selectedReport.employeeEmail); if (employee) handleGenerateEmployeeReport(employee); }} isGenerating={generatingEmployeeReport === employeeId} hasSubmission={!!submissions[employeeId]} showGenerateButton={!reports[employeeId] && !!submissions[employeeId]} employees={employees} org={org} onChatWithAI={() => handleEmployeeChatWithAI(selectedReport.employeeName!, employeeReport)} /> ); })() ) ) : (

Select a Report

Choose a company or employee report from the list to view details.

)}
); }; // Component for displaying company report content const CompanyReportContent: React.FC<{ report: CompanyReport; onRegenerate: () => void; isGenerating: boolean; org?: any; onChatWithAI?: () => void; }> = ({ report, onRegenerate, isGenerating, org, onChatWithAI }) => { // Default to the first department in the array const [activeDepartmentTab, setActiveDepartmentTab] = useState(() => report?.gradingBreakdown?.[0]?.departmentNameShort || 'Campaigns' ); const [activeImpactSummary, setActiveImpactSummary] = useState(() => report?.organizationalImpactSummary?.[0]?.category || 'Mission Critical' ); return ( <> {/* Header */}
Company Report
downloadCompanyReportPDF(report, org?.companyName || 'Company')} text="Download as PDF" size="tiny" iconLeft={} />
{/* Content */}
{/* Company Weaknesses */}
Company Weaknesses
{report?.weaknesses?.map((weakness, index) => (
{weakness.title}:
{weakness.description}
{index < (report?.weaknesses?.length || 0) - 1 && (
)}
)) || (
Lack of Structure:
People are confused about their roles. No one knows who's responsible.
)}
{/* Personnel Changes */} {report?.personnelChanges && (
Personnel Changes
{/* New Hires */} {report.personnelChanges.newHires && report.personnelChanges.newHires.length > 0 && (
New Hires
{report.personnelChanges.newHires.map((hire, index) => (
{hire.name} - {hire.role}
Department: {hire.department}
{hire.impact &&
{hire.impact}
}
))}
)} {/* Promotions */} {report.personnelChanges.promotions && report.personnelChanges.promotions.length > 0 && (
Promotions
{report.personnelChanges.promotions.map((promotion, index) => (
{promotion.name}
{promotion.fromRole} → {promotion.toRole}
{promotion.impact &&
{promotion.impact}
}
))}
)} {/* Departures */} {report.personnelChanges.departures && report.personnelChanges.departures.length > 0 && (
Departures
{report.personnelChanges.departures.map((departure, index) => (
{departure.name}
Department: {departure.department}
Reason: {departure.reason}
{departure.impact &&
{departure.impact}
}
))}
)} {/* No changes message */} {(!report.personnelChanges.newHires || report.personnelChanges.newHires.length === 0) && (!report.personnelChanges.promotions || report.personnelChanges.promotions.length === 0) && (!report.personnelChanges.departures || report.personnelChanges.departures.length === 0) && (
No personnel changes to report.
)}
)} {/* Hiring Needs */} {report?.immediateHiringNeeds && report.immediateHiringNeeds.length > 0 && (
Immediate Hiring Needs
{report.immediateHiringNeeds.map((need, index) => (
{need.role} - {need.department}
{need.reasoning}
{index !== report.immediateHiringNeeds.length - 1 && (
)}
))}
)} {/* Forward Plan */} {report?.forwardOperatingPlan && (
Forward Plan
{ report.forwardOperatingPlan.map((plan, index) => (
{plan.title}
    {plan.details.map((detail, idx) => (
  • {detail}
  • ))}
{index !== report.forwardOperatingPlan.length - 1 &&
}
)) }
)} {/* Strengths goes here */} {report?.strengths && (
Strengths
{report.strengths.map((strength, idx) => (
{strength}
))}
)} {/* Organizational Impact Summary */} {/** {report?.organizationalImpactSummary && (
Organizational Impact Summary
Mission Critical
{report.organizationalImpactSummary.missionCritical.map((employee, index) => (
{employee.employeeName}
{employee.description}
))}
Highly Valuable
{report.organizationalImpactSummary.highlyValuable.map((employee, index) => (
{employee.employeeName}
{employee.description}
))}
Core Support
{report.organizationalImpactSummary.coreSupport.map((employee, index) => (
{employee.employeeName}
{employee.description}
))}
Low Criticality
{report.organizationalImpactSummary.lowCriticality.map((employee, index) => (
{employee.employeeName}
{employee.description}
))}
)} **/}
Organizational Impact Summary
{/* Department Tabs */} {report.organizationalImpactSummary && report.organizationalImpactSummary.map((dept, index) => (
setActiveImpactSummary(dept.category)} >
{dept.category}
))}
{/* Content for the currently selected department */} {report.organizationalImpactSummary && (() => { const currentImpact = report.organizationalImpactSummary.find(dept => dept.category === activeImpactSummary); if (!currentImpact) return null; return (
{/* Department Overview Section */} { currentImpact && currentImpact?.employees.map((item) => (
{item.employeeName} - {item.impact}
{item.suggestedPay}
{item.description}
)) }
); })()}
{/* Grading Overview */}
Grading Overview
{/* Department Tabs */} {report.gradingBreakdown && report?.gradingBreakdown?.map(dept => (
setActiveDepartmentTab(dept.departmentNameShort)} >
{dept.departmentNameShort}
))}
{/* Content for the currently selected department */} {report.gradingBreakdown && (() => { const currentDepartment = report?.gradingBreakdown?.find(dept => dept.departmentNameShort === activeDepartmentTab); if (!currentDepartment) return null; return (
{/* Department Overview Section */}
Department Overview
Overall Grade
A
Overall company performance shows strong collaboration and delivery with opportunities for process improvement.
{/* Employee Radar Charts Section */}
Team Performance Analysis
{currentDepartment.teamScores?.map((teamScore, index) => { const radarData = [ { label: 'Reliability', value: teamScore.reliability }, { label: 'Role Fit', value: teamScore.roleFit }, { label: 'Scalability', value: teamScore.scalability }, { label: 'Output', value: teamScore.output }, { label: 'Initiative', value: teamScore.initiative } ]; return (

{teamScore.employeeName}

Grade: {teamScore.grade}
); })}
); })()}
); }; // Component for displaying employee report content const EmployeeReportContent: React.FC<{ report: EmployeeReport; employeeName: string; employeeEmail: string; onGenerateReport?: () => void; isGenerating?: boolean; hasSubmission?: boolean; showGenerateButton?: boolean; employees?: Employee[]; org?: any; onChatWithAI?: () => void; }> = ({ report, employeeName, onGenerateReport, isGenerating = false, hasSubmission = false, showGenerateButton = false, employees, org, onChatWithAI }) => { return ( <> {/* Header */}
{employeeName}'s Report
{/* Generate Report Button - only show when needed */} {showGenerateButton && hasSubmission && onGenerateReport && ( )} {/* Chat with AI Button - only show for actual reports */} {!showGenerateButton && onChatWithAI && ( )} {/* Download PDF Button - only show for actual reports */} {!showGenerateButton && ( { const employee = employees.find(emp => emp.email === employeeName); if (employee) { downloadEmployeeReportPDF(employee, report, org?.companyName || 'Company'); } }} size="tiny" iconLeft={} /> )}
{/* Content */}
{/* Role & Responsibilities */}
Role & Responsibilities

{report.roleAndOutput?.responsibilities || 'No role information available.'}

{/* Self-Rated Output */} {report.roleAndOutput && report.roleAndOutput?.selfRatedOutput && (
Self-Rated Output

{report.roleAndOutput.selfRatedOutput}

)} {/* Insights */} {report.insights && (
Insights & Traits
{report.insights.personalityTraits && (
Personality Traits

{report.insights.personalityTraits}

)} {report.insights.selfAwareness && (
Self Awareness

{report.insights.selfAwareness}

)} {report.insights.growthDesire && (
Growth Desire

{report.insights.growthDesire}

)}
)} {/* Strengths */} {report.strengths && report.strengths.length > 0 && (
Strengths
{report.strengths.map((strength, index) => (
{strength}
))}
)} {/* Recommendations */} {report.recommendations && report.recommendations.length > 0 && (
Recommendations
{report.recommendations.map((recommendation, index) => (
))}
)}
); }; export default Reports;