update 9/23
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useOrg } from '../contexts/OrgContext';
|
||||
import { secureApi } from '../services/secureApi';
|
||||
import { CompanyReport, Employee, EmployeeReport } from '../types';
|
||||
@@ -8,12 +8,153 @@ 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 } | 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);
|
||||
@@ -23,6 +164,16 @@ const Reports: React.FC = () => {
|
||||
// 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
|
||||
|
||||
@@ -49,29 +200,39 @@ const Reports: React.FC = () => {
|
||||
// Load company report on component mount
|
||||
useEffect(() => {
|
||||
const loadCompanyReport = async () => {
|
||||
if (currentUserIsOwner) {
|
||||
try {
|
||||
const history = await getFullCompanyReportHistory();
|
||||
if (history.length > 0) {
|
||||
setCompanyReport(history[0]);
|
||||
// Auto-select company report by default
|
||||
setSelectedReport({ report: history[0], type: 'company' });
|
||||
} else {
|
||||
// FIXED: No automatic generation - only load existing reports
|
||||
// Use sample data when no real reports exist
|
||||
console.log('No company reports found, using sample data. Click "Refresh Report" to generate a new one.');
|
||||
setCompanyReport(SAMPLE_COMPANY_REPORT);
|
||||
setSelectedReport({ report: SAMPLE_COMPANY_REPORT, type: 'company' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load company report:', error);
|
||||
setCompanyReport(SAMPLE_COMPANY_REPORT);
|
||||
setSelectedReport({ report: SAMPLE_COMPANY_REPORT, type: 'company' });
|
||||
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]); // FIXED: Removed generateCompanyReport and submissions dependencies
|
||||
}, [currentUserIsOwner, getFullCompanyReportHistory, employees, user?.uid]);
|
||||
|
||||
const handleEmployeeSelect = useCallback(async (employee: Employee) => {
|
||||
const employeeReport = reports[employee.id];
|
||||
@@ -79,7 +240,8 @@ const Reports: React.FC = () => {
|
||||
setSelectedReport({
|
||||
report: employeeReport,
|
||||
type: 'employee',
|
||||
employeeName: employee.name
|
||||
employeeName: employee.name,
|
||||
employeeEmail: employee.email
|
||||
});
|
||||
} else {
|
||||
// FIXED: Only check if employee has submission - do NOT auto-generate
|
||||
@@ -102,7 +264,8 @@ const Reports: React.FC = () => {
|
||||
recommendations: ['Generate the report to view detailed analysis and recommendations']
|
||||
} as EmployeeReport,
|
||||
type: 'employee',
|
||||
employeeName: employee.name
|
||||
employeeName: employee.name,
|
||||
employeeEmail: employee.email
|
||||
});
|
||||
} else {
|
||||
// No submission available - show message
|
||||
@@ -122,7 +285,8 @@ const Reports: React.FC = () => {
|
||||
recommendations: ['Employee should complete the questionnaire first']
|
||||
} as EmployeeReport,
|
||||
type: 'employee',
|
||||
employeeName: employee.name
|
||||
employeeName: employee.name,
|
||||
employeeEmail: employee.email
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -139,11 +303,11 @@ const Reports: React.FC = () => {
|
||||
}, [selectedEmployeeId, employees, handleEmployeeSelect]);
|
||||
|
||||
// Filter and sort employees
|
||||
const visibleEmployees = currentUserIsOwner
|
||||
? employees.filter(emp =>
|
||||
emp.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
).sort((a, b) => a.name.localeCompare(b.name))
|
||||
: employees.filter(emp => emp.id === user?.uid);
|
||||
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) {
|
||||
@@ -171,7 +335,7 @@ const Reports: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
{/* Middle Section - Employee List */}
|
||||
<div className="h-100vh flex-1 self-stretch bg-[--Neutrals-NeutralSlate0] flex justify-start items-center">
|
||||
<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>
|
||||
@@ -199,8 +363,8 @@ const Reports: React.FC = () => {
|
||||
|
||||
{/* Employee List */}
|
||||
<div className="self-stretch px-3 flex flex-col justify-start items-start">
|
||||
{/* Company Report Item */}
|
||||
{currentUserIsOwner && (
|
||||
{/* 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]' : ''
|
||||
}`}
|
||||
@@ -208,10 +372,18 @@ const Reports: React.FC = () => {
|
||||
>
|
||||
<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">
|
||||
C
|
||||
{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">Company Report</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>
|
||||
)}
|
||||
|
||||
@@ -224,12 +396,12 @@ const Reports: React.FC = () => {
|
||||
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?.employeeName === employee.name ? 'bg-[--Neutrals-NeutralSlate100]' : ''
|
||||
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 bg-[--Neutrals-NeutralSlate100] rounded-[666.67px] flex justify-center items-center relative">
|
||||
<div className="text-center justify-start text-[--Text-Gray-500] text-xs font-medium font-['Inter'] leading-none">
|
||||
<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 */}
|
||||
@@ -265,6 +437,7 @@ const Reports: React.FC = () => {
|
||||
onRegenerate={handleGenerateCompanyReport}
|
||||
isGenerating={generatingCompanyReport}
|
||||
org={org}
|
||||
onChatWithAI={handleCompanyChatWithAI}
|
||||
/>
|
||||
) : (
|
||||
(() => {
|
||||
@@ -274,8 +447,9 @@ const Reports: React.FC = () => {
|
||||
<EmployeeReportContent
|
||||
report={employeeReport}
|
||||
employeeName={selectedReport.employeeName!}
|
||||
employeeEmail={selectedReport.employeeEmail!}
|
||||
onGenerateReport={() => {
|
||||
const employee = employees.find(emp => emp.name === selectedReport.employeeName);
|
||||
const employee = employees.find(emp => emp.email === selectedReport.employeeEmail);
|
||||
if (employee) handleGenerateEmployeeReport(employee);
|
||||
}}
|
||||
isGenerating={generatingEmployeeReport === employeeId}
|
||||
@@ -283,6 +457,7 @@ const Reports: React.FC = () => {
|
||||
showGenerateButton={!reports[employeeId] && !!submissions[employeeId]}
|
||||
employees={employees}
|
||||
org={org}
|
||||
onChatWithAI={() => handleEmployeeChatWithAI(selectedReport.employeeName!, employeeReport)}
|
||||
/>
|
||||
);
|
||||
})()
|
||||
@@ -311,7 +486,8 @@ const CompanyReportContent: React.FC<{
|
||||
onRegenerate: () => void;
|
||||
isGenerating: boolean;
|
||||
org?: any;
|
||||
}> = ({ report, onRegenerate, isGenerating, org }) => {
|
||||
onChatWithAI?: () => void;
|
||||
}> = ({ report, onRegenerate, isGenerating, org, onChatWithAI }) => {
|
||||
// Default to the first department in the array
|
||||
const [activeDepartmentTab, setActiveDepartmentTab] = useState(() =>
|
||||
report?.gradingBreakdown?.[0]?.departmentNameShort || 'Campaigns'
|
||||
@@ -349,6 +525,22 @@ const CompanyReportContent: React.FC<{
|
||||
</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"
|
||||
@@ -361,7 +553,7 @@ const CompanyReportContent: React.FC<{
|
||||
{/* 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 overflow-hidden">
|
||||
<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>
|
||||
@@ -391,7 +583,7 @@ const CompanyReportContent: React.FC<{
|
||||
|
||||
{/* 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 overflow-hidden">
|
||||
<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>
|
||||
@@ -453,7 +645,7 @@ const CompanyReportContent: React.FC<{
|
||||
|
||||
{/* 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 overflow-hidden">
|
||||
<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>
|
||||
@@ -479,7 +671,7 @@ const CompanyReportContent: React.FC<{
|
||||
|
||||
{/* 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 overflow-hidden">
|
||||
<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>
|
||||
@@ -512,7 +704,7 @@ const CompanyReportContent: React.FC<{
|
||||
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 overflow-hidden">
|
||||
<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>
|
||||
@@ -609,7 +801,7 @@ const CompanyReportContent: React.FC<{
|
||||
)}
|
||||
**/}
|
||||
|
||||
<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="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>
|
||||
@@ -675,7 +867,7 @@ const CompanyReportContent: React.FC<{
|
||||
|
||||
|
||||
{/* 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 overflow-hidden">
|
||||
<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>
|
||||
@@ -784,13 +976,15 @@ const CompanyReportContent: React.FC<{
|
||||
const EmployeeReportContent: React.FC<{
|
||||
report: EmployeeReport;
|
||||
employeeName: string;
|
||||
employeeEmail: string;
|
||||
onGenerateReport?: () => void;
|
||||
isGenerating?: boolean;
|
||||
hasSubmission?: boolean;
|
||||
showGenerateButton?: boolean;
|
||||
employees?: Employee[];
|
||||
org?: any;
|
||||
}> = ({ report, employeeName, onGenerateReport, isGenerating = false, hasSubmission = false, showGenerateButton = false, employees, org }) => {
|
||||
onChatWithAI?: () => void;
|
||||
}> = ({ report, employeeName, onGenerateReport, isGenerating = false, hasSubmission = false, showGenerateButton = false, employees, org, onChatWithAI }) => {
|
||||
return (
|
||||
<>
|
||||
{/* Header */}
|
||||
@@ -823,13 +1017,33 @@ const EmployeeReportContent: React.FC<{
|
||||
</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.name === employeeName);
|
||||
const employee = employees.find(emp => emp.email === employeeName);
|
||||
if (employee) {
|
||||
downloadEmployeeReportPDF(employee, report, org?.companyName || 'Company');
|
||||
}
|
||||
@@ -844,7 +1058,7 @@ const EmployeeReportContent: React.FC<{
|
||||
{/* 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 overflow-hidden">
|
||||
<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>
|
||||
@@ -857,7 +1071,7 @@ const EmployeeReportContent: React.FC<{
|
||||
|
||||
{/* 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 overflow-hidden">
|
||||
<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>
|
||||
@@ -871,7 +1085,7 @@ const EmployeeReportContent: React.FC<{
|
||||
|
||||
{/* 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 overflow-hidden">
|
||||
<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>
|
||||
@@ -906,7 +1120,7 @@ const EmployeeReportContent: React.FC<{
|
||||
|
||||
{/* 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 overflow-hidden">
|
||||
<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>
|
||||
@@ -930,14 +1144,14 @@ const EmployeeReportContent: React.FC<{
|
||||
|
||||
{/* 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 overflow-hidden">
|
||||
<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">
|
||||
• {recommendation}
|
||||
<MarkdownRenderer content={recommendation} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user