Files
auditly/src/pages/Reports.tsx
2025-09-23 09:53:05 -07:00

1166 lines
80 KiB
TypeScript

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<CompanyReport | null>(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<string | null>(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 */}
<div className="h-full flex-1 self-stretch bg-[--Neutrals-NeutralSlate0] flex justify-start items-center">
<div className="flex-1 self-stretch max-w-64 min-w-64 border-r border-[--Neutrals-NeutralSlate200] inline-flex flex-col justify-start items-start">
<div className="self-stretch p-5 inline-flex justify-start items-center gap-2.5">
<div className="flex-1 justify-start text-[--Text-Gray-950] text-base font-medium font-['Inter'] leading-normal">Employees</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-2">
{/* Search */}
<div className="self-stretch px-2.5 flex flex-col justify-start items-start gap-2">
<div className="self-stretch flex flex-col justify-start items-start gap-1">
<div className="self-stretch px-4 py-3 bg-[--Neutrals-NeutralSlate100] rounded-[999px] inline-flex justify-start items-center gap-2 overflow-hidden">
<div className="relative">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.5 17.5L14.5834 14.5833M16.6667 9.58333C16.6667 13.4954 13.4954 16.6667 9.58333 16.6667C5.67132 16.6667 2.5 13.4954 2.5 9.58333C2.5 5.67132 5.67132 2.5 9.58333 2.5C13.4954 2.5 16.6667 5.67132 16.6667 9.58333Z" stroke="var(--Neutrals-NeutralSlate500, #717680)" strokeWidth="1.5" strokeMiterlimit="10" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
<input
type="text"
placeholder="Search"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="flex-1 bg-transparent text-[--Text-Gray-500] text-sm font-normal font-['Inter'] leading-tight outline-none"
/>
</div>
</div>
</div>
{/* Employee List */}
<div className="self-stretch px-3 flex flex-col justify-start items-start">
{/* Company Report Item - Always show for consistency */}
{companyReport && (
<div
className={`self-stretch p-2 rounded-full shadow-[0px_1px_2px_0px_rgba(10,13,20,0.03)] inline-flex justify-start items-center gap-2 overflow-hidden cursor-pointer ${selectedReport?.type === 'company' ? 'bg-[--Neutrals-NeutralSlate100]' : ''
}`}
onClick={handleCompanyReportSelect}
>
<div className="w-7 h-7 p-1 bg-[--Brand-Orange] rounded-[666.67px] flex justify-center items-center">
<div className="text-center justify-start text-[--Text-Gray-0] text-xs font-medium font-['Inter'] leading-none">
{org?.companyName?.charAt(0)?.toUpperCase() || 'C'}
</div>
</div>
<div className="flex-1 justify-start text-[--Text-Gray-950] text-sm font-normal font-['Inter'] leading-tight">
{org?.companyName || 'Company Report'}
</div>
{/* Status indicator for company report */}
{(companyReport as any)?.isPlaceholder ? (
<div className="w-3 h-3 bg-gray-300 rounded-full" title="Report not generated yet" />
) : (
<div className="w-3 h-3 bg-green-400 rounded-full" title="Report available" />
)}
</div>
)}
{/* Employee Items */}
{visibleEmployees.map((employee) => {
const hasSubmission = submissions[employee.id];
const hasReport = reports[employee.id];
const isGenerating = generatingEmployeeReport === employee.id;
return (
<div
key={employee.id}
className={`self-stretch p-2 rounded-full shadow-[0px_1px_2px_0px_rgba(10,13,20,0.03)] inline-flex justify-start items-center gap-2 overflow-hidden cursor-pointer ${selectedReport?.type === 'employee' && selectedReport?.employeeEmail === employee.email ? 'bg-[--Neutrals-NeutralSlate100]' : ''
}`}
onClick={() => handleEmployeeSelect(employee)}
>
<div className={`w-7 h-7 p-1 ${selectedReport?.type === 'employee' && selectedReport?.employeeEmail === employee.email ? 'bg-[--Neutrals-NeutralSlate700] text-[--Neutrals-NeutralSlate0]' : 'bg-[--Neutrals-NeutralSlate100] text-[--Neutrals-NeutralSlate500]'} rounded-[666.67px] flex justify-center items-center relative`}>
<div className="text-center justify-start text-xs font-medium font-['Inter'] leading-none">
{employee.initials}
</div>
{/* Status indicator */}
{isGenerating ? (
<div className="absolute -top-1 -right-1 w-3 h-3 bg-yellow-400 rounded-full animate-pulse" title="Generating report..." />
) : hasReport ? (
<div className="absolute -top-1 -right-1 w-3 h-3 bg-green-400 rounded-full" title="Report available" />
) : hasSubmission ? (
<div className="absolute -top-1 -right-1 w-3 h-3 bg-blue-400 rounded-full" title="Submission available, click to generate report" />
) : (
<div className="absolute -top-1 -right-1 w-3 h-3 bg-gray-300 rounded-full" title="No submission yet" />
)}
</div>
<div className="flex-1 justify-start text-[--Text-Gray-800] text-sm font-normal font-['Inter'] leading-tight">
{employee.name}
</div>
{isGenerating && (
<div className="w-4 h-4 animate-spin rounded-full border-2 border-[--Neutrals-NeutralSlate300] border-t-[--Brand-Orange]" />
)}
</div>
);
})}
</div>
</div>
</div>
{/* Main Content Area */}
<div className="flex-1 self-stretch inline-flex flex-col justify-start items-start">
{selectedReport ? (
selectedReport.type === 'company' ? (
<CompanyReportContent
report={selectedReport.report as CompanyReport}
onRegenerate={handleGenerateCompanyReport}
isGenerating={generatingCompanyReport}
org={org}
onChatWithAI={handleCompanyChatWithAI}
/>
) : (
(() => {
const employeeReport = selectedReport.report as EmployeeReport;
const employeeId = employeeReport.employeeId;
return (
<EmployeeReportContent
report={employeeReport}
employeeName={selectedReport.employeeName!}
employeeEmail={selectedReport.employeeEmail!}
onGenerateReport={() => {
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)}
/>
);
})()
)
) : (
<div className="flex-1 flex items-center justify-center">
<div className="text-center">
<h3 className="text-lg font-semibold text-[--Text-Gray-950] mb-2">
Select a Report
</h3>
<p className="text-[--Text-Gray-500]">
Choose a company or employee report from the list to view details.
</p>
</div>
</div>
)}
</div>
</div>
</>
);
};
// 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 */}
<div className="self-stretch px-5 py-3 inline-flex justify-start items-center gap-2.5">
<div className="flex-1 justify-start text-[--Text-Gray-800] text-base font-medium font-['Inter'] leading-normal">
Company Report
</div>
<div className="flex justify-start items-center gap-3">
<button
onClick={onRegenerate}
disabled={isGenerating}
className="px-3 py-2.5 bg-[--Neutrals-NeutralSlate100] rounded-[999px] flex justify-center items-center gap-1 overflow-hidden hover:bg-[--Neutrals-NeutralSlate200] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<div className="relative">
{isGenerating ? (
<div className="w-4 h-4 animate-spin rounded-full border-2 border-[--Neutrals-NeutralSlate300] border-t-[--Brand-Orange]" />
) : (
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.33337 8.00001C1.33337 8.00001 3.00004 4.66668 8.00004 4.66668C13 4.66668 14.6667 8.00001 14.6667 8.00001C14.6667 8.00001 13 11.3333 8.00004 11.3333C3.00004 11.3333 1.33337 8.00001 1.33337 8.00001Z" stroke="var(--Neutrals-NeutralSlate800)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<path d="M8 9.33334C8.73638 9.33334 9.33333 8.73639 9.33333 8.00001C9.33333 7.26363 8.73638 6.66668 8 6.66668C7.26362 6.66668 6.66667 7.26363 6.66667 8.00001C6.66667 8.73639 7.26362 9.33334 8 9.33334Z" stroke="var(--Neutrals-NeutralSlate800)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
)}
</div>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-[--Text-Gray-800] text-sm font-medium font-['Inter'] leading-tight">
{isGenerating ? 'Generating...' : 'Refresh Report'}
</div>
</div>
</button>
<button
onClick={onChatWithAI}
className="px-3 py-2.5 bg-[--Brand-Orange] rounded-[999px] flex justify-center items-center gap-1 overflow-hidden hover:bg-orange-600 transition-colors"
>
<div className="relative">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.6667 7.33333C14.6667 10.647 11.9804 13.3333 8.66667 13.3333C7.95 13.3333 7.27333 13.18 6.66667 12.9067L2 14L3.09333 9.33333C2.82 8.72667 2.66667 8.05 2.66667 7.33333C2.66667 4.01967 5.353 1.33333 8.66667 1.33333C11.9804 1.33333 14.6667 4.01967 14.6667 7.33333Z" stroke="white" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M6 6.66667H6.00667M8.66667 6.66667H8.67333M11.3333 6.66667H11.34" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</div>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">
Chat with AI
</div>
</div>
</button>
<FigmaPrimaryButton
onClick={() => downloadCompanyReportPDF(report, org?.companyName || 'Company')}
text="Download as PDF"
size="tiny"
iconLeft={<DownloadIcon />}
/>
</div>
</div>
{/* Content */}
<div className="self-stretch flex flex-col justify-start items-start gap-4 px-5 pb-6 overflow-y-auto">
{/* Company Weaknesses */}
<div className="w-full p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Gray-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Company Weaknesses</div>
</div>
<div className="self-stretch p-6 bg-[--Neutrals-NeutralSlate100] rounded-2xl outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] flex flex-col justify-start items-start gap-4">
{report?.weaknesses?.map((weakness, index) => (
<div key={index}>
<div className="self-stretch inline-flex justify-between items-start">
<div className="w-48 justify-start text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">{weakness.title}:</div>
<div className="flex-1 justify-start text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">{weakness.description}</div>
</div>
{index < (report?.weaknesses?.length || 0) - 1 && (
<div className="mt-4 self-stretch w-full flex">
<svg width="100%" height="2" viewBox="0 0 9999 2" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
<line x1="0" y1="1" x2="9999" y2="1" stroke="var(--Neutrals-NeutralSlate300)" stroke-width="2" />
</svg>
</div>
)}
</div>
)) || (
<div className="self-stretch inline-flex justify-between items-start">
<div className="w-48 justify-start text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">Lack of Structure:</div>
<div className="flex-1 justify-start text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">People are confused about their roles. No one knows who's responsible.</div>
</div>
)}
</div>
</div>
{/* Personnel Changes */}
{report?.personnelChanges && (
<div className="w-full p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Gray-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Personnel Changes</div>
</div>
<div className="self-stretch p-6 bg-[--Neutrals-NeutralSlate50] rounded-2xl outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] flex flex-col justify-start items-start gap-6">
{/* New Hires */}
{report.personnelChanges.newHires && report.personnelChanges.newHires.length > 0 && (
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">New Hires</div>
{report.personnelChanges.newHires.map((hire, index) => (
<div key={index} className="self-stretch p-3 bg-green-50 rounded-lg border border-green-200">
<div className="font-medium text-green-800">{hire.name} - {hire.role}</div>
<div className="text-sm text-green-600">Department: {hire.department}</div>
{hire.impact && <div className="text-sm text-green-600 mt-1">{hire.impact}</div>}
</div>
))}
</div>
)}
{/* Promotions */}
{report.personnelChanges.promotions && report.personnelChanges.promotions.length > 0 && (
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">Promotions</div>
{report.personnelChanges.promotions.map((promotion, index) => (
<div key={index} className="self-stretch p-3 bg-blue-50 rounded-lg border border-blue-200">
<div className="font-medium text-blue-800">{promotion.name}</div>
<div className="text-sm text-blue-600">{promotion.fromRole} → {promotion.toRole}</div>
{promotion.impact && <div className="text-sm text-blue-600 mt-1">{promotion.impact}</div>}
</div>
))}
</div>
)}
{/* Departures */}
{report.personnelChanges.departures && report.personnelChanges.departures.length > 0 && (
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">Departures</div>
{report.personnelChanges.departures.map((departure, index) => (
<div key={index} className="self-stretch p-3 bg-red-50 rounded-lg border border-red-200">
<div className="font-medium text-red-800">{departure.name}</div>
<div className="text-sm text-red-600">Department: {departure.department}</div>
<div className="text-sm text-red-600">Reason: {departure.reason}</div>
{departure.impact && <div className="text-sm text-red-600 mt-1">{departure.impact}</div>}
</div>
))}
</div>
)}
{/* 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) && (
<div className="self-stretch text-[--Text-Gray-500] text-base font-normal font-['Inter'] leading-normal">
No personnel changes to report.
</div>
)}
</div>
</div>
)}
{/* Hiring Needs */}
{report?.immediateHiringNeeds && report.immediateHiringNeeds.length > 0 && (
<div className="w-full p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Gray-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Immediate Hiring Needs</div>
</div>
<div className="self-stretch p-6 bg-[--Neutrals-NeutralSlate50] rounded-2xl outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] inline-flex flex-col justify-start items-start gap-4">
{report.immediateHiringNeeds.map((need, index) => (
<React.Fragment key={index}>
<div key={index} className="self-stretch content-end inline-flex justify-around items-center ">
<div className="flex-2 w-max p-3 justify-start text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">{need.role} - {need.department}</div>
<div className="flex-9 justify-start text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">{need.reasoning}</div>
</div>
{index !== report.immediateHiringNeeds.length - 1 && (
<div className="inline-flex self-stretch" data-svg-wrapper>
<svg width="100%" height="4" viewBox="0 0 9999 5" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M 0,0 H9999 M 0,1 H9999 M 0,2 H9999 M 0,3 H9999 M 0,4 H9999" stroke="var(--Neutrals-NeutralSlate900)" />
</svg>
</div>
)}
</React.Fragment>
))}
</div>
</div>
)}
{/* Forward Plan */}
{report?.forwardOperatingPlan && (
<div className="w-full self-stretch p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Gray-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Forward Plan</div>
</div>
<div className="self-stretch p-6 bg-[--Neutrals-NeutralSlate50] rounded-2xl outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] flex flex-col justify-start items-start gap-4">
{
report.forwardOperatingPlan.map((plan, index) => (
<div key={index} className="self-stretch flex flex-col justify-start items-start gap-4">
<div className="self-stretch flex flex-col justify-start items-start gap-4">
<div className="justify-start text-[--Text-Gray-800] text-base font-normal tracking-wide font-['Neue_Montreal'] leading-normal">{plan.title}</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<ul className="list-none space-y-1">
{plan.details.map((detail, idx) => (
<li key={idx} className="ps-2 flex items-center gap-3 font-['Neue_Montreal'] tracking-wide">
<span className="h-1 w-1 rounded-full bg-[--Neutrals-NeutralSlate800] flex-shrink-0"></span>
<span>{detail}</span>
</li>
))}
</ul>
</div>
</div>
{index !== report.forwardOperatingPlan.length - 1 && <div className="self-stretch h-0 outline outline-1 outline-offset-[-0.50px] outline-[--Neutrals-NeutralSlate200]" />}
</div>
))
}
</div>
</div>
)}
{/*
Strengths goes here
*/}
{report?.strengths && (
<div className="self-stretch p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] inline-flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Gray-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Strengths</div>
</div>
<div className="self-stretch p-6 bg-[--Neutrals-NeutralSlate50] rounded-2xl outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] flex flex-col justify-start items-start gap-4">
{report.strengths.map((strength, idx) => (
<div key={idx} className="self-stretch inline-flex justify-start items-start gap-4">
<div className="w-6 h-6 relative rounded-[999px] overflow-hidden">
<div className="w-6 h-6 left-0 top-0 absolute bg-[--Other-Green] rounded-full" />
<div data-svg-wrapper className="left-[5px] top-[5px] absolute">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.6666 3.5L5.24998 9.91667L2.33331 7" stroke="var(--Neutrals-NeutralSlate0)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</div>
</div>
<div className="flex-1 justify-start text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">{strength}</div>
</div>
))}
</div>
</div>
)}
{/*
Organizational Impact Summary
*/}
{/**
{report?.organizationalImpactSummary && (
<div className="w-full p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1 overflow-hidden">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Gray-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Organizational Impact Summary</div>
</div>
<div className="self-stretch p-6 bg-[--Neutrals-NeutralSlate50] rounded-2xl outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] flex flex-col justify-start items-start gap-6">
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="flex justify-start items-center gap-2">
<div className="w-3 h-3 bg-red-500 rounded-full"></div>
<div className="text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">Mission Critical</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
{report.organizationalImpactSummary.missionCritical.map((employee, index) => (
<div key={index} className="self-stretch flex justify-between items-start">
<div className="w-48 text-[--Text-Gray-800] text-sm font-medium font-['Inter'] leading-tight">{employee.employeeName}</div>
<div className="flex-1 text-[--Text-Gray-800] text-sm font-normal font-['Inter'] leading-tight">{employee.description}</div>
</div>
))}
</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="flex justify-start items-center gap-2">
<div className="w-3 h-3 bg-orange-500 rounded-full"></div>
<div className="text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">Highly Valuable</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
{report.organizationalImpactSummary.highlyValuable.map((employee, index) => (
<div key={index} className="self-stretch flex justify-between items-start">
<div className="w-48 text-[--Text-Gray-800] text-sm font-medium font-['Inter'] leading-tight">{employee.employeeName}</div>
<div className="flex-1 text-[--Text-Gray-800] text-sm font-normal font-['Inter'] leading-tight">{employee.description}</div>
</div>
))}
</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="flex justify-start items-center gap-2">
<div className="w-3 h-3 bg-yellow-500 rounded-full"></div>
<div className="text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">Core Support</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
{report.organizationalImpactSummary.coreSupport.map((employee, index) => (
<div key={index} className="self-stretch flex justify-between items-start">
<div className="w-48 text-[--Text-Gray-800] text-sm font-medium font-['Inter'] leading-tight">{employee.employeeName}</div>
<div className="flex-1 text-[--Text-Gray-800] text-sm font-normal font-['Inter'] leading-tight">{employee.description}</div>
</div>
))}
</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="flex justify-start items-center gap-2">
<div className="w-3 h-3 bg-green-500 rounded-full"></div>
<div className="text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">Low Criticality</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
{report.organizationalImpactSummary.lowCriticality.map((employee, index) => (
<div key={index} className="self-stretch flex justify-between items-start">
<div className="w-48 text-[--Text-Gray-800] text-sm font-medium font-['Inter'] leading-tight">{employee.employeeName}</div>
<div className="flex-1 text-[--Text-Gray-800] text-sm font-normal font-['Inter'] leading-tight">{employee.description}</div>
</div>
))}
</div>
</div>
</div>
</div>
)}
**/}
<div className="w-full p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Gray-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Organizational Impact Summary</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="p-1 bg-[--Neutrals-NeutralSlate200] rounded-full outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate50] inline-flex justify-start items-center gap-1">
{/* Department Tabs */}
{report.organizationalImpactSummary && report.organizationalImpactSummary.map((dept, index) => (
<div
key={dept.category}
className={`px-3 py-1.5 rounded-full flex justify-center items-center gap-1 overflow-hidden cursor-pointer ${activeImpactSummary === dept.category
? 'bg-[--Neutrals-NeutralSlate0]'
: 'bg-[--Neutrals-NeutralSlate100] shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)] shadow-[inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18)]'
}`}
onClick={() => setActiveImpactSummary(dept.category)}
>
<div className="px-0.5 flex justify-center items-center">
<div className={`justify-start text-xs flex items-center font-medium font-['Inter'] leading-none ${activeImpactSummary === dept.category ? 'text-[--Text-Gray-950]' : 'text-zinc-600'
}`}>
<span className={`flex-shrink-0 w-2 h-2 rounded-full mr-2
${dept?.employees.length === 0 ? 'blinkLightEmpty bg-[--Neutrals-NeutralSlate100]' : ''}
${dept.category === "Mission Critical" ?
'bg-green-400 blinkLightGreen' :
dept.category === "Highly Valuable" ?
'bg-yellow-400 blinkLightYellow' :
dept.category === "Core Support" ?
'bg-blue-800 blinkLightBlue' :
dept.category === "Low Criticality" ?
'bg-red-600 blinkLightRed' :
''}
`}></span>{dept.category}
</div>
</div>
</div>
))}
</div>
{/* Content for the currently selected department */}
{report.organizationalImpactSummary && (() => {
const currentImpact = report.organizationalImpactSummary.find(dept => dept.category === activeImpactSummary);
if (!currentImpact) return null;
return (
<div className="self-stretch p-6 bg-[--Neutrals-NeutralSlate100] rounded-2xl outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] flex flex-col justify-start items-start gap-4">
{/* Department Overview Section */}
{
currentImpact && currentImpact?.employees.map((item) => (
<div className="self-stretch flex flex-col justify-start items-start gap-4">
<div className="self-stretch flex flex-col justify-start items-start gap-4">
<div className="self-stretch inline-flex justify-start items-center">
<div className="w-48 justify-start text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal w-fit">{item.employeeName} - {item.impact}</div>
<div className="flex-1 text-right justify-start text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">{item.suggestedPay}</div>
</div>
<div className="self-stretch justify-start text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">{item.description}</div>
</div>
<div className="self-stretch h-0 outline outline-1 outline-offset-[-0.50px] outline-[--Neutrals-NeutralSlate200]" />
</div>
))
}
</div>
);
})()}
</div>
</div>
{/* Grading Overview */}
<div className="w-full p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Gray-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Grading Overview</div>
</div>
<div className="self-stretch flex flex-col justify-start items-start gap-3">
<div className="p-1 bg-[--Neutrals-NeutralSlate200] rounded-full outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate50] inline-flex justify-start items-center gap-1">
{/* Department Tabs */}
{report.gradingBreakdown && report?.gradingBreakdown?.map(dept => (
<div
key={dept.departmentNameShort}
className={`px-3 py-1.5 rounded-full flex justify-center items-center gap-1 overflow-hidden cursor-pointer ${activeDepartmentTab === dept.departmentNameShort
? 'bg-[--Neutrals-NeutralSlate0]'
: 'bg-[--Neutrals-NeutralSlate100] shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)] shadow-[inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18)]'
}`}
onClick={() => setActiveDepartmentTab(dept.departmentNameShort)}
>
<div className="px-0.5 flex justify-center items-center">
<div className={`justify-start text-xs font-medium font-['Inter'] leading-none ${activeDepartmentTab === dept.departmentNameShort ? 'text-[--Text-Gray-950]' : 'text-zinc-600'
}`}>
{dept.departmentNameShort}
</div>
</div>
</div>
))}
</div>
{/* Content for the currently selected department */}
{report.gradingBreakdown && (() => {
const currentDepartment = report?.gradingBreakdown?.find(dept => dept.departmentNameShort === activeDepartmentTab);
if (!currentDepartment) return null;
return (
<div className="self-stretch p-6 bg-[--Neutrals-NeutralSlate100] rounded-2xl outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] flex flex-col justify-start items-start gap-4">
{/* Department Overview Section */}
<div className="self-stretch p-5 bg-[--Neutrals-NeutralSlate100] rounded-2xl outline outline-1 outline-offset-[-1px] outline-[--Neutrals-NeutralSlate200] flex flex-col justify-start items-start gap-3 overflow-hidden">
<div className="self-stretch inline-flex justify-between items-center">
<div className="w-48 justify-start text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">Department Overview</div>
<div className="pl-3 pr-1 py-1 bg-green-500/10 rounded-2xl flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Gray-800] text-sm font-medium font-['Inter'] leading-tight">Overall Grade</div>
<div className="px-2 bg-green-500 rounded-2xl flex justify-start items-center">
<div className="text-center justify-start text-[--Text-Gray-0] text-sm font-medium font-['Inter'] leading-tight">A</div>
</div>
</div>
</div>
<div>
<svg width="752" height="2" viewBox="0 0 752 2" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 1H752" stroke="var(--Neutrals-NeutralSlate300)" />
</svg>
</div>
<div className="self-stretch justify-start text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">
Overall company performance shows strong collaboration and delivery with opportunities for process improvement.
</div>
</div>
{/* Employee Radar Charts Section */}
<div className="self-stretch flex flex-col justify-start items-start gap-4">
<div className="text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal">Team Performance Analysis</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 w-full">
{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 (
<div key={index} className="p-4 bg-[--Neutrals-NeutralSlate50] rounded-lg shadow-sm border border-[--Neutrals-NeutralSlate200] flex flex-col justify-start items-center gap-3">
<div className="flex flex-col items-center gap-1">
<h3 className="text-base font-semibold text-[--Text-Gray-800]">{teamScore.employeeName}</h3>
<div className={`px-2 py-1 rounded-full text-xs font-medium ${teamScore.grade.startsWith('A') ? 'bg-green-100 text-green-800' :
teamScore.grade.startsWith('B') ? 'bg-blue-100 text-blue-800' :
teamScore.grade.startsWith('C') ? 'bg-yellow-100 text-yellow-800' :
'bg-red-100 text-red-800'
}`}>
Grade: {teamScore.grade}
</div>
</div>
<div className="w-full h-64">
<RadarPerformanceChart
data={radarData}
height={240}
color={
teamScore.grade.startsWith('A') ? 'var(--Brand-Orange)' :
teamScore.grade.startsWith('B') ? 'var(--color-green)' :
teamScore.grade.startsWith('C') ? 'var(--color-yellow)' :
'var(--color-red)'
}
/>
</div>
</div>
);
})}
</div>
</div>
</div>
);
})()}
</div>
</div>
</div >
</>
);
};
// 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 */}
<div className="self-stretch px-5 py-3 inline-flex justify-start items-center gap-2.5">
<div className="flex-1 justify-start text-[--Text-Gray-800] text-base font-medium font-['Inter'] leading-normal">
{employeeName}'s Report
</div>
<div className="flex justify-start items-center gap-3">
{/* Generate Report Button - only show when needed */}
{showGenerateButton && hasSubmission && onGenerateReport && (
<button
onClick={onGenerateReport}
disabled={isGenerating}
className="px-3 py-2.5 bg-[--Brand-Orange] rounded-[999px] flex justify-center items-center gap-1 overflow-hidden hover:bg-orange-600 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<div className="relative">
{isGenerating ? (
<div className="w-4 h-4 animate-spin rounded-full border-2 border-white border-t-transparent" />
) : (
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 3V13M3 8H13" stroke="white" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
)}
</div>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">
{isGenerating ? 'Generating...' : 'Generate Report'}
</div>
</div>
</button>
)}
{/* Chat with AI Button - only show for actual reports */}
{!showGenerateButton && onChatWithAI && (
<button
onClick={onChatWithAI}
className="px-3 py-2.5 bg-[--Brand-Orange] rounded-[999px] flex justify-center items-center gap-1 overflow-hidden hover:bg-orange-600 transition-colors"
>
<div className="relative">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.6667 7.33333C14.6667 10.647 11.9804 13.3333 8.66667 13.3333C7.95 13.3333 7.27333 13.18 6.66667 12.9067L2 14L3.09333 9.33333C2.82 8.72667 2.66667 8.05 2.66667 7.33333C2.66667 4.01967 5.353 1.33333 8.66667 1.33333C11.9804 1.33333 14.6667 4.01967 14.6667 7.33333Z" stroke="white" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M6 6.66667H6.00667M8.66667 6.66667H8.67333M11.3333 6.66667H11.34" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</div>
<div className="px-1 flex justify-center items-center">
<div className="justify-center text-white text-sm font-medium font-['Inter'] leading-tight">
Chat with AI
</div>
</div>
</button>
)}
{/* Download PDF Button - only show for actual reports */}
{!showGenerateButton && (
<FigmaPrimaryButton
containerExtra='h-9.5'
text="Download as PDF"
onClick={() => {
const employee = employees.find(emp => emp.email === employeeName);
if (employee) {
downloadEmployeeReportPDF(employee, report, org?.companyName || 'Company');
}
}}
size="tiny"
iconLeft={<DownloadIcon />}
/>
)}
</div>
</div>
{/* Content */}
<div className="self-stretch flex flex-col justify-start items-start gap-4 px-5 pb-6 overflow-y-auto">
{/* Role & Responsibilities */}
<div className="w-full p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Dark-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Role & Responsibilities</div>
</div>
<div className="self-stretch p-6 bg-Light-Grays-l-gray08 rounded-2xl outline outline-1 outline-offset-[-1px] outline-Text-Gray-200 flex flex-col justify-start items-start gap-4">
<p className="text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">
{report.roleAndOutput?.responsibilities || 'No role information available.'}
</p>
</div>
</div>
{/* Self-Rated Output */}
{report.roleAndOutput && report.roleAndOutput?.selfRatedOutput && (
<div className="w-full p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Dark-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Self-Rated Output</div>
</div>
<div className="self-stretch p-6 bg-Light-Grays-l-gray08 rounded-2xl outline outline-1 outline-offset-[-1px] outline-Text-Gray-200 flex flex-col justify-start items-start gap-4">
<p className="text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">
{report.roleAndOutput.selfRatedOutput}
</p>
</div>
</div>
)}
{/* Insights */}
{report.insights && (
<div className="w-full p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Dark-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Insights & Traits</div>
</div>
<div className="self-stretch p-6 bg-Light-Grays-l-gray08 rounded-2xl outline outline-1 outline-offset-[-1px] outline-Text-Gray-200 flex flex-col justify-start items-start gap-4">
{report.insights.personalityTraits && (
<div className="self-stretch">
<div className="text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal mb-2">Personality Traits</div>
<p className="text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">
{report.insights.personalityTraits}
</p>
</div>
)}
{report.insights.selfAwareness && (
<div className="self-stretch">
<div className="text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal mb-2">Self Awareness</div>
<p className="text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">
{report.insights.selfAwareness}
</p>
</div>
)}
{report.insights.growthDesire && (
<div className="self-stretch">
<div className="text-[--Text-Gray-800] text-base font-semibold font-['Inter'] leading-normal mb-2">Growth Desire</div>
<p className="text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">
{report.insights.growthDesire}
</p>
</div>
)}
</div>
</div>
)}
{/* Strengths */}
{report.strengths && report.strengths.length > 0 && (
<div className="w-full p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Dark-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Strengths</div>
</div>
<div className="self-stretch p-6 bg-Light-Grays-l-gray08 rounded-2xl outline outline-1 outline-offset-[-1px] outline-Text-Gray-200 flex flex-col justify-start items-start gap-4">
{report.strengths.map((strength, index) => (
<div key={index} className="self-stretch flex justify-start items-start gap-3">
<div className="w-6 h-6 relative rounded-[999px] overflow-hidden">
<div className="w-6 h-6 left-0 top-0 absolute bg-Other-Green rounded-full" />
<div className="left-[5px] top-[5px] absolute">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.6666 3.5L5.24998 9.91667L2.33331 7" stroke="var(--Other-Green)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</div>
</div>
<div className="flex-1 justify-start text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">{strength}</div>
</div>
))}
</div>
</div>
)}
{/* Recommendations */}
{report.recommendations && report.recommendations.length > 0 && (
<div className="w-full p-3 bg-[--Neutrals-NeutralSlate100] rounded-[20px] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02)] flex flex-col justify-center items-start gap-1">
<div className="self-stretch px-3 py-2 inline-flex justify-start items-center gap-2">
<div className="justify-start text-[--Text-Dark-950] text-xl font-medium font-['Neue_Montreal'] leading-normal">Recommendations</div>
</div>
<div className="self-stretch p-6 bg-Light-Grays-l-gray08 rounded-2xl outline outline-1 outline-offset-[-1px] outline-Text-Gray-200 flex flex-col justify-start items-start gap-4">
{report.recommendations.map((recommendation, index) => (
<div key={index} className="self-stretch text-[--Text-Gray-800] text-base font-normal font-['Inter'] leading-normal">
<MarkdownRenderer content={recommendation} />
</div>
))}
</div>
</div>
)}
</div>
</>
);
};
export default Reports;