@burdenoff/microfe-crewfoundry 2026.624.1 → 2026.625.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/crewfoundry/pages/AdminAdminPagePage.js +100 -76
- package/dist/crewfoundry/pages/AdminAdminPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +118 -94
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +105 -81
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +134 -110
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +121 -97
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +28 -15
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js +74 -54
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsDirectoryPagePage.js +87 -69
- package/dist/crewfoundry/pages/CommunicationsDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js +99 -80
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +87 -68
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js +31 -15
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js +81 -61
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +71 -51
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js +82 -58
- package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js +46 -39
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +80 -62
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js +104 -80
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +219 -151
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js +183 -142
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js +121 -97
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js.map +1 -1
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js +57 -46
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +91 -67
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +112 -93
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +55 -48
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +70 -50
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +140 -97
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +101 -85
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +68 -48
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js +99 -71
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +97 -73
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js +100 -76
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +93 -69
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js +65 -45
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +93 -75
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +117 -72
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +66 -54
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +36 -20
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js +90 -66
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.js +81 -57
- package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +90 -65
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +33 -17
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +83 -59
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js +68 -48
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js +80 -60
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js +153 -118
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +42 -37
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +67 -47
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +104 -85
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js +76 -57
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js +78 -60
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +138 -93
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +98 -53
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js +69 -49
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +84 -65
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js +76 -52
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js +58 -40
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js +85 -65
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js +36 -29
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +108 -73
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +43 -27
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js +67 -47
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +108 -63
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +83 -64
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js +185 -144
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +40 -24
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardEnhancedDashboardPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/DashboardEnhancedDashboardPagePage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Separator,\n} from '@burdenoff/fe-libs/ui';\nimport {\n AlertTriangle,\n ArrowUpRight,\n Award,\n Bell,\n Briefcase,\n CheckCircle,\n MapPin,\n Star,\n Users,\n Zap,\n} from 'lucide-react';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function DashboardEnhancedDashboardPagePage() {\n const {\n employees,\n jobPostings,\n candidates,\n interviews,\n leaveRequests,\n notifications,\n projects,\n announcements,\n } = useCrewFoundryStore();\n\n const quickActions = useMemo(\n () => [\n {\n label: `Post New Job (${jobPostings.filter((job) => job.status === 'active').length} active)`,\n icon: Briefcase,\n color: 'text-blue-600',\n },\n {\n label: `Review Candidates (${candidates.filter((candidate) => candidate.status === 'new').length})`,\n icon: Users,\n color: 'text-purple-600',\n },\n {\n label: `Approve Leaves (${leaveRequests.filter((leave) => leave.status === 'pending').length})`,\n icon: CheckCircle,\n color: 'text-green-600',\n },\n {\n label: `Run Payroll (${projects.filter((project) => project.status === 'active').length} projects)`,\n icon: Zap,\n color: 'text-orange-600',\n },\n ],\n [candidates, jobPostings, leaveRequests, projects]\n );\n\n const companyGoals = useMemo(\n () => [\n {\n goal: 'Reduce time-to-hire to 25 days',\n current: Math.max(\n 20,\n 40 - candidates.filter((candidate) => candidate.status === 'hired').length\n ),\n target: 25,\n unit: 'days',\n },\n {\n goal: 'Achieve 95% employee satisfaction',\n current: Math.round(\n (employees.reduce((sum, employee) => sum + employee.performanceScore, 0) /\n Math.max(employees.length, 1)) *\n 20\n ),\n target: 95,\n unit: '%',\n },\n {\n goal: 'Fill 30 open positions by Q2',\n current: candidates.filter((candidate) => candidate.status === 'hired').length,\n target: 30,\n unit: 'positions',\n },\n {\n goal: 'Complete 80% training compliance',\n current: Math.min(\n 100,\n 60 +\n Math.round(\n (employees.filter((employee) => employee.status === 'active').length /\n Math.max(employees.length, 1)) *\n 30\n )\n ),\n target: 80,\n unit: '%',\n },\n ],\n [candidates, employees]\n );\n\n const upcomingInterviews = interviews.filter((i) => i.status === 'scheduled');\n const pendingLeaves = leaveRequests.filter((l) => l.status === 'pending');\n const unreadNotifs = notifications.filter((n) => !n.read);\n const pinnedAnnouncements = announcements.filter((a) => a.isPinned);\n const topPerformers = [...employees]\n .sort((a, b) => b.performanceScore - a.performanceScore)\n .slice(0, 5);\n const recentHires = [...employees]\n .sort((a, b) => b.startDate.localeCompare(a.startDate))\n .slice(0, 5);\n\n const locationMap = employees.reduce<Record<string, number>>((acc, e) => {\n acc[e.location] = (acc[e.location] || 0) + 1;\n return acc;\n }, {});\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Enhanced Dashboard</h1>\n <p className=\"text-sm text-text-secondary\">Complete workforce command center</p>\n </div>\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n <Bell className=\"h-5 w-5 text-text-secondary\" />\n {unreadNotifs.length > 0 && (\n <span className=\"absolute -top-1 -right-1 h-4 w-4 rounded-full bg-red-500 text-[10px] text-white flex items-center justify-center\">\n {unreadNotifs.length}\n </span>\n )}\n </div>\n <Button size=\"sm\">\n <Zap className=\"h-4 w-4 mr-1\" />\n Quick Actions\n </Button>\n </div>\n </div>\n\n <div className=\"grid gap-3 md:grid-cols-4\">\n {quickActions.map((action) => (\n <Card key={action.label} className=\"cursor-pointer hover:shadow-md transition-shadow\">\n <CardContent className=\"flex items-center gap-3 p-4\">\n <action.icon className={`h-5 w-5 ${action.color}`} />\n <span className=\"text-sm font-medium\">{action.label}</span>\n <ArrowUpRight className=\"h-4 w-4 ml-auto text-text-secondary\" />\n </CardContent>\n </Card>\n ))}\n </div>\n\n {pinnedAnnouncements.length > 0 && (\n <Card className=\"border-yellow-200 bg-yellow-50/50\">\n <CardContent className=\"p-4\">\n {pinnedAnnouncements.map((ann) => (\n <div key={ann.id} className=\"flex items-start gap-3\">\n <AlertTriangle className=\"h-4 w-4 text-yellow-600 mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium\">{ann.title}</p>\n <p className=\"text-xs text-text-secondary mt-1\">\n {ann.content.slice(0, 120)}...\n </p>\n <p className=\"text-xs text-text-secondary mt-1\">\n — {ann.author}, {ann.authorRole}\n </p>\n </div>\n <Badge variant=\"outline\" className=\"ml-auto flex-shrink-0\">\n {ann.priority}\n </Badge>\n </div>\n ))}\n </CardContent>\n </Card>\n )}\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Company Goals</CardTitle>\n <CardDescription>Q1 2026 targets</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {companyGoals.map((g) => {\n const pct = Math.round((g.current / g.target) * 100);\n return (\n <div key={g.goal} className=\"space-y-1\">\n <div className=\"flex justify-between text-xs\">\n <span className=\"text-text-secondary\">{g.goal}</span>\n <span className=\"font-medium\">\n {g.current}/{g.target} {g.unit}\n </span>\n </div>\n <div className=\"h-2 bg-bg-sunken rounded overflow-hidden\">\n <div\n className={`h-2 rounded ${pct >= 90 ? 'bg-green-500' : pct >= 70 ? 'bg-yellow-500' : 'bg-red-500'}`}\n style={{ width: `${Math.min(pct, 100)}%` }}\n />\n </div>\n </div>\n );\n })}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Upcoming Interviews</CardTitle>\n <CardDescription>{upcomingInterviews.length} scheduled</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {upcomingInterviews.map((interview) => (\n <div key={interview.id} className=\"flex items-center gap-3 rounded border p-2\">\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium truncate\">{interview.candidateName}</p>\n <p className=\"text-xs text-text-secondary\">{interview.position}</p>\n </div>\n <div className=\"text-right flex-shrink-0\">\n <p className=\"text-xs font-medium\">{interview.date}</p>\n <p className=\"text-xs text-text-secondary\">{interview.time}</p>\n </div>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {interview.type}\n </Badge>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Pending Actions</CardTitle>\n <CardDescription>Items requiring your attention</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {pendingLeaves.map((leave) => (\n <div key={leave.id} className=\"flex items-center justify-between rounded border p-2\">\n <div>\n <p className=\"text-sm font-medium\">{leave.employeeName}</p>\n <p className=\"text-xs text-text-secondary\">\n {leave.type} leave · {leave.days} days\n </p>\n </div>\n <div className=\"flex gap-1\">\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs\">\n Deny\n </Button>\n <Button size=\"sm\" className=\"h-7 text-xs\">\n Approve\n </Button>\n </div>\n </div>\n ))}\n <Separator />\n <div className=\"text-xs text-text-secondary text-center\">\n {candidates.filter((c) => c.status === 'new').length} new applications to review\n </div>\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base flex items-center gap-2\">\n <Award className=\"h-4 w-4 text-yellow-500\" />\n Top Performers\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {topPerformers.map((emp, idx) => (\n <div key={emp.id} className=\"flex items-center gap-3\">\n <span className=\"text-sm font-bold text-text-secondary w-5\">#{idx + 1}</span>\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium\">\n {emp.firstName} {emp.lastName}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {emp.position} · {emp.department}\n </p>\n </div>\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-yellow-500\" />\n <span className=\"text-sm font-medium\">{emp.performanceScore}</span>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base flex items-center gap-2\">\n <MapPin className=\"h-4 w-4\" />\n Workforce Locations\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {Object.entries(locationMap)\n .sort(([, a], [, b]) => b - a)\n .map(([location, count]) => (\n <div key={location} className=\"flex items-center justify-between\">\n <span className=\"text-sm\">{location}</span>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{count}</span>\n <span className=\"text-xs text-text-secondary\">\n ({Math.round((count / employees.length) * 100)}%)\n </span>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Recent Hires</CardTitle>\n <CardDescription>Newest team members</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-6 gap-2 text-xs font-medium text-text-secondary border-b pb-2 mb-2\">\n <span>Name</span>\n <span>Position</span>\n <span>Department</span>\n <span>Location</span>\n <span>Start Date</span>\n <span>Type</span>\n </div>\n {recentHires.map((emp) => (\n <div\n key={emp.id}\n className=\"grid grid-cols-6 gap-2 py-2 border-b last:border-0 text-sm\"\n >\n <span className=\"font-medium\">\n {emp.firstName} {emp.lastName}\n </span>\n <span className=\"text-text-secondary truncate\">{emp.position}</span>\n <span>{emp.department}</span>\n <span className=\"text-text-secondary truncate\">{emp.location}</span>\n <span>{emp.startDate}</span>\n <Badge variant=\"outline\" className=\"w-fit text-[10px]\">\n {emp.type.replace('_', ' ')}\n </Badge>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardEnhancedDashboardPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/DashboardEnhancedDashboardPagePage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n EmphasisPanel,\n GradientText,\n NextSteps,\n PagePurpose,\n Separator,\n} from '@burdenoff/fe-libs/ui';\nimport {\n AlertTriangle,\n ArrowUpRight,\n Award,\n Bell,\n Briefcase,\n CheckCircle,\n MapPin,\n Star,\n Users,\n Zap,\n} from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function DashboardEnhancedDashboardPagePage() {\n const navigate = useNavigate();\n const {\n employees,\n jobPostings,\n candidates,\n interviews,\n leaveRequests,\n notifications,\n projects,\n announcements,\n } = useCrewFoundryStore();\n\n const quickActions = useMemo(\n () => [\n {\n label: `Post New Job (${jobPostings.filter((job) => job.status === 'active').length} active)`,\n icon: Briefcase,\n color: 'text-status-info-text',\n },\n {\n label: `Review Candidates (${candidates.filter((candidate) => candidate.status === 'new').length})`,\n icon: Users,\n color: 'text-action-primary-bg',\n },\n {\n label: `Approve Leaves (${leaveRequests.filter((leave) => leave.status === 'pending').length})`,\n icon: CheckCircle,\n color: 'text-status-success-text',\n },\n {\n label: `Run Payroll (${projects.filter((project) => project.status === 'active').length} projects)`,\n icon: Zap,\n color: 'text-status-warning-text',\n },\n ],\n [candidates, jobPostings, leaveRequests, projects]\n );\n\n const companyGoals = useMemo(\n () => [\n {\n goal: 'Reduce time-to-hire to 25 days',\n current: Math.max(\n 20,\n 40 - candidates.filter((candidate) => candidate.status === 'hired').length\n ),\n target: 25,\n unit: 'days',\n },\n {\n goal: 'Achieve 95% employee satisfaction',\n current: Math.round(\n (employees.reduce((sum, employee) => sum + employee.performanceScore, 0) /\n Math.max(employees.length, 1)) *\n 20\n ),\n target: 95,\n unit: '%',\n },\n {\n goal: 'Fill 30 open positions by Q2',\n current: candidates.filter((candidate) => candidate.status === 'hired').length,\n target: 30,\n unit: 'positions',\n },\n {\n goal: 'Complete 80% training compliance',\n current: Math.min(\n 100,\n 60 +\n Math.round(\n (employees.filter((employee) => employee.status === 'active').length /\n Math.max(employees.length, 1)) *\n 30\n )\n ),\n target: 80,\n unit: '%',\n },\n ],\n [candidates, employees]\n );\n\n const upcomingInterviews = interviews.filter((i) => i.status === 'scheduled');\n const pendingLeaves = leaveRequests.filter((l) => l.status === 'pending');\n const unreadNotifs = notifications.filter((n) => !n.read);\n const pinnedAnnouncements = announcements.filter((a) => a.isPinned);\n const topPerformers = [...employees]\n .sort((a, b) => b.performanceScore - a.performanceScore)\n .slice(0, 5);\n const recentHires = [...employees]\n .sort((a, b) => b.startDate.localeCompare(a.startDate))\n .slice(0, 5);\n\n const locationMap = employees.reduce<Record<string, number>>((acc, e) => {\n acc[e.location] = (acc[e.location] || 0) + 1;\n return acc;\n }, {});\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Enhanced Dashboard</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Complete workforce command center</p>\n <PagePurpose className=\"mt-1\">A richer, customizable command center for your workforce — see live metrics, activity, and trends tailored to how you run your organization.</PagePurpose>\n </div>\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n <Bell className=\"h-5 w-5 text-text-secondary\" />\n {unreadNotifs.length > 0 && (\n <span className=\"absolute -top-1 -right-1 h-4 w-4 rounded-full bg-status-error-text text-[10px] text-white flex items-center justify-center\">\n {unreadNotifs.length}\n </span>\n )}\n </div>\n <Button size=\"sm\">\n <Zap className=\"h-4 w-4 mr-1\" />\n Quick Actions\n </Button>\n </div>\n </div>\n\n <NextSteps\n storageKey=\"crewfoundry-enhanced-dashboard\"\n steps={[\n {\n id: 'hiring',\n label: 'Move hiring forward',\n description: 'Review open roles and applicants in your pipeline.',\n icon: <Briefcase className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hiring/jobs-page'),\n },\n {\n id: 'people',\n label: 'Check on your people',\n description: 'See who is active, on leave, or needs attention.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hr/employees-page'),\n },\n {\n id: 'analytics',\n label: 'Dig into analytics',\n description: 'Explore deeper workforce and hiring trends.',\n icon: <ArrowUpRight className=\"h-4 w-4\" />,\n onClick: () => navigate('../../analytics/analytics-page'),\n },\n ]}\n />\n\n <div className=\"grid gap-3 md:grid-cols-4\">\n {quickActions.map((action) => (\n <Card key={action.label} className=\"cursor-pointer hover:shadow-md transition-shadow\">\n <CardContent className=\"flex items-center gap-3 p-4\">\n <action.icon className={`h-5 w-5 ${action.color}`} />\n <span className=\"text-sm font-medium\">{action.label}</span>\n <ArrowUpRight className=\"h-4 w-4 ml-auto text-text-secondary\" />\n </CardContent>\n </Card>\n ))}\n </div>\n\n {pinnedAnnouncements.length > 0 && (\n <Card className=\"border-status-warning-text/30 bg-status-warning-bg/50\">\n <CardContent className=\"p-4\">\n {pinnedAnnouncements.map((ann) => (\n <div key={ann.id} className=\"flex items-start gap-3\">\n <AlertTriangle className=\"h-4 w-4 text-status-warning-text mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium\">{ann.title}</p>\n <p className=\"text-xs text-text-secondary mt-1\">{ann.content.slice(0, 120)}...</p>\n <p className=\"text-xs text-text-secondary mt-1\">\n — {ann.author}, {ann.authorRole}\n </p>\n </div>\n <Badge variant=\"outline\" className=\"ml-auto flex-shrink-0\">\n {ann.priority}\n </Badge>\n </div>\n ))}\n </CardContent>\n </Card>\n )}\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <EmphasisPanel>\n <div className=\"text-base font-semibold\">Company Goals</div>\n <p className=\"mb-4 text-sm text-text-secondary\">Q1 2026 targets</p>\n <div className=\"space-y-4\">\n {companyGoals.map((g) => {\n const pct = Math.round((g.current / g.target) * 100);\n return (\n <div key={g.goal} className=\"space-y-1\">\n <div className=\"flex justify-between text-xs\">\n <span className=\"text-text-secondary\">{g.goal}</span>\n <span className=\"font-medium\">\n {g.current}/{g.target} {g.unit}\n </span>\n </div>\n <div className=\"h-2 bg-bg-sunken rounded overflow-hidden\">\n <div\n className={`h-2 rounded ${pct >= 90 ? 'bg-status-success-text' : pct >= 70 ? 'bg-status-warning-text' : 'bg-status-error-text'}`}\n style={{ width: `${Math.min(pct, 100)}%` }}\n />\n </div>\n </div>\n );\n })}\n </div>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Upcoming Interviews</CardTitle>\n <CardDescription>{upcomingInterviews.length} scheduled</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {upcomingInterviews.map((interview) => (\n <div key={interview.id} className=\"flex items-center gap-3 rounded border p-2\">\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium truncate\">{interview.candidateName}</p>\n <p className=\"text-xs text-text-secondary\">{interview.position}</p>\n </div>\n <div className=\"text-right flex-shrink-0\">\n <p className=\"text-xs font-medium\">{interview.date}</p>\n <p className=\"text-xs text-text-secondary\">{interview.time}</p>\n </div>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {interview.type}\n </Badge>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Pending Actions</CardTitle>\n <CardDescription>Items requiring your attention</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {pendingLeaves.map((leave) => (\n <div key={leave.id} className=\"flex items-center justify-between rounded border p-2\">\n <div>\n <p className=\"text-sm font-medium\">{leave.employeeName}</p>\n <p className=\"text-xs text-text-secondary\">\n {leave.type} leave · {leave.days} days\n </p>\n </div>\n <div className=\"flex gap-1\">\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs\">\n Deny\n </Button>\n <Button size=\"sm\" className=\"h-7 text-xs\">\n Approve\n </Button>\n </div>\n </div>\n ))}\n <Separator />\n <div className=\"text-xs text-text-secondary text-center\">\n {candidates.filter((c) => c.status === 'new').length} new applications to review\n </div>\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base flex items-center gap-2\">\n <Award className=\"h-4 w-4 text-status-warning-text\" />\n Top Performers\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {topPerformers.map((emp, idx) => (\n <div key={emp.id} className=\"flex items-center gap-3\">\n <span className=\"text-sm font-bold text-text-secondary w-5\">#{idx + 1}</span>\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium\">\n {emp.firstName} {emp.lastName}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {emp.position} · {emp.department}\n </p>\n </div>\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n <span className=\"text-sm font-medium\">{emp.performanceScore}</span>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base flex items-center gap-2\">\n <MapPin className=\"h-4 w-4\" />\n Workforce Locations\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {Object.entries(locationMap)\n .sort(([, a], [, b]) => b - a)\n .map(([location, count]) => (\n <div key={location} className=\"flex items-center justify-between\">\n <span className=\"text-sm\">{location}</span>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{count}</span>\n <span className=\"text-xs text-text-secondary\">\n ({Math.round((count / employees.length) * 100)}%)\n </span>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Recent Hires</CardTitle>\n <CardDescription>Newest team members</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-6 gap-2 text-xs font-medium text-text-secondary border-b pb-2 mb-2\">\n <span>Name</span>\n <span>Position</span>\n <span>Department</span>\n <span>Location</span>\n <span>Start Date</span>\n <span>Type</span>\n </div>\n {recentHires.map((emp) => (\n <div\n key={emp.id}\n className=\"grid grid-cols-6 gap-2 py-2 border-b last:border-0 text-sm\"\n >\n <span className=\"font-medium\">\n {emp.firstName} {emp.lastName}\n </span>\n <span className=\"text-text-secondary truncate\">{emp.position}</span>\n <span>{emp.department}</span>\n <span className=\"text-text-secondary truncate\">{emp.location}</span>\n <span>{emp.startDate}</span>\n <Badge variant=\"outline\" className=\"w-fit text-[10px]\">\n {emp.type.replace('_', ' ')}\n </Badge>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -2,18 +2,18 @@ import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
|
2
2
|
import { useMemo as t } from "react";
|
|
3
3
|
import { ArrowUp as n, Building2 as r, DollarSign as i, Percent as a, Target as o } from "lucide-react";
|
|
4
4
|
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
5
|
-
import { Badge as l, Card as u, CardContent as d, CardDescription as f, CardHeader as p, CardTitle as m,
|
|
5
|
+
import { Badge as l, Card as u, CardContent as d, CardDescription as f, CardHeader as p, CardTitle as m, GlassCard as h, GradientText as g, PagePurpose as _, Separator as v } from "@burdenoff/fe-libs/ui";
|
|
6
6
|
//#region src/crewfoundry/pages/DashboardExecutiveDashboardPage.tsx
|
|
7
|
-
function
|
|
8
|
-
let { employees:
|
|
7
|
+
function y() {
|
|
8
|
+
let { employees: y, departments: b, projects: x, jobPostings: S } = e(), C = t(() => {
|
|
9
9
|
let e = [
|
|
10
10
|
"Q1 2025",
|
|
11
11
|
"Q2 2025",
|
|
12
12
|
"Q3 2025",
|
|
13
13
|
"Q4 2025"
|
|
14
|
-
], t =
|
|
14
|
+
], t = x.reduce((e, t) => e + t.budget, 0) || 1e6;
|
|
15
15
|
return e.map((e, n) => {
|
|
16
|
-
let r = Math.round(t * (.55 + n * .08)), i = Math.max(1,
|
|
16
|
+
let r = Math.round(t * (.55 + n * .08)), i = Math.max(1, y.length - (3 - n) * 4);
|
|
17
17
|
return {
|
|
18
18
|
quarter: e,
|
|
19
19
|
revenue: r,
|
|
@@ -21,57 +21,64 @@ function g() {
|
|
|
21
21
|
revenuePerHead: Math.round(r / i)
|
|
22
22
|
};
|
|
23
23
|
});
|
|
24
|
-
}, [
|
|
24
|
+
}, [y.length, x]), w = t(() => [
|
|
25
25
|
{
|
|
26
26
|
metric: "Flight Risk Employees",
|
|
27
|
-
value:
|
|
27
|
+
value: y.filter((e) => e.performanceScore < 3.6).length,
|
|
28
28
|
severity: "warning",
|
|
29
|
-
detail: `${Math.round(
|
|
29
|
+
detail: `${Math.round(y.filter((e) => e.performanceScore < 3.6).length / Math.max(y.length, 1) * 100)}% of workforce`
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
metric: "Overdue Performance Reviews",
|
|
33
|
-
value:
|
|
33
|
+
value: y.filter((e) => e.status === "on_leave").length,
|
|
34
34
|
severity: "error",
|
|
35
35
|
detail: "Review follow-ups required"
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
38
|
metric: "Unfilled Critical Roles",
|
|
39
|
-
value:
|
|
39
|
+
value: S.filter((e) => e.status === "active" && e.experienceLevel === "lead").length,
|
|
40
40
|
severity: "warning",
|
|
41
41
|
detail: "Open lead-level positions"
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
44
|
metric: "Expiring Contracts",
|
|
45
|
-
value:
|
|
45
|
+
value: y.filter((e) => e.type === "contract").length,
|
|
46
46
|
severity: "info",
|
|
47
47
|
detail: "Contract renewals in focus"
|
|
48
48
|
}
|
|
49
|
-
], [
|
|
49
|
+
], [y, S]), T = t(() => [{
|
|
50
50
|
category: "Company",
|
|
51
51
|
male: 52,
|
|
52
52
|
female: 43,
|
|
53
53
|
other: 5
|
|
54
|
-
}, ...
|
|
55
|
-
let t =
|
|
54
|
+
}, ...b.map((e) => {
|
|
55
|
+
let t = y.filter((t) => t.department === e.name).length, n = Math.min(100, Math.round(45 + t % 15)), r = Math.min(100 - n, Math.round(40 + t % 10)), i = Math.max(0, 100 - n - r);
|
|
56
56
|
return {
|
|
57
57
|
category: e.name,
|
|
58
58
|
male: n,
|
|
59
59
|
female: r,
|
|
60
60
|
other: i
|
|
61
61
|
};
|
|
62
|
-
}).slice(0, 3)], [
|
|
62
|
+
}).slice(0, 3)], [b, y]), E = y.reduce((e, t) => e + t.salary, 0), D = b.reduce((e, t) => e + t.budget, 0), O = x.reduce((e, t) => e + t.budget, 0), k = x.reduce((e, t) => e + t.spent, 0), A = Math.round(k / O * 100);
|
|
63
63
|
return /* @__PURE__ */ c("div", {
|
|
64
64
|
className: "space-y-6 p-6",
|
|
65
65
|
children: [
|
|
66
66
|
/* @__PURE__ */ c("div", {
|
|
67
67
|
className: "flex items-center justify-between",
|
|
68
|
-
children: [/* @__PURE__ */ c("div", { children: [
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
68
|
+
children: [/* @__PURE__ */ c("div", { children: [
|
|
69
|
+
/* @__PURE__ */ s("h1", {
|
|
70
|
+
className: "text-2xl font-semibold",
|
|
71
|
+
children: /* @__PURE__ */ s(g, { children: "Executive Dashboard" })
|
|
72
|
+
}),
|
|
73
|
+
/* @__PURE__ */ s("p", {
|
|
74
|
+
className: "text-sm text-text-secondary",
|
|
75
|
+
children: "Strategic workforce insights for leadership"
|
|
76
|
+
}),
|
|
77
|
+
/* @__PURE__ */ s(_, {
|
|
78
|
+
className: "mt-1",
|
|
79
|
+
children: "The executive snapshot — top-line workforce, financial, and hiring KPIs in one view so leaders can make decisions fast."
|
|
80
|
+
})
|
|
81
|
+
] }), /* @__PURE__ */ s(l, {
|
|
75
82
|
variant: "outline",
|
|
76
83
|
children: "Q1 2026"
|
|
77
84
|
})]
|
|
@@ -79,68 +86,85 @@ function g() {
|
|
|
79
86
|
/* @__PURE__ */ c("div", {
|
|
80
87
|
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4",
|
|
81
88
|
children: [
|
|
82
|
-
/* @__PURE__ */ c(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
className: "
|
|
103
|
-
children: [
|
|
104
|
-
"
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
className: "text-
|
|
135
|
-
children:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
})
|
|
89
|
+
/* @__PURE__ */ c(h, {
|
|
90
|
+
treatment: "glass",
|
|
91
|
+
glow: !0,
|
|
92
|
+
className: "border-border-seam",
|
|
93
|
+
children: [/* @__PURE__ */ c(p, {
|
|
94
|
+
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
95
|
+
children: [/* @__PURE__ */ s(m, {
|
|
96
|
+
className: "text-sm font-medium",
|
|
97
|
+
children: "Revenue per Employee"
|
|
98
|
+
}), /* @__PURE__ */ s(i, { className: "h-4 w-4 text-text-secondary" })]
|
|
99
|
+
}), /* @__PURE__ */ c(d, { children: [/* @__PURE__ */ s("div", {
|
|
100
|
+
className: "text-2xl font-bold tabular-nums",
|
|
101
|
+
children: "$21,862"
|
|
102
|
+
}), /* @__PURE__ */ c("div", {
|
|
103
|
+
className: "flex items-center text-xs text-status-success-text",
|
|
104
|
+
children: [/* @__PURE__ */ s(n, { className: "h-3 w-3 mr-1" }), "+2.0% from Q3"]
|
|
105
|
+
})] })]
|
|
106
|
+
}),
|
|
107
|
+
/* @__PURE__ */ c(h, {
|
|
108
|
+
treatment: "metric",
|
|
109
|
+
className: "border-border-seam",
|
|
110
|
+
children: [/* @__PURE__ */ c(p, {
|
|
111
|
+
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
112
|
+
children: [/* @__PURE__ */ s(m, {
|
|
113
|
+
className: "text-sm font-medium",
|
|
114
|
+
children: "Total Workforce Cost"
|
|
115
|
+
}), /* @__PURE__ */ s(r, { className: "h-4 w-4 text-text-secondary" })]
|
|
116
|
+
}), /* @__PURE__ */ c(d, { children: [/* @__PURE__ */ c("div", {
|
|
117
|
+
className: "text-2xl font-bold tabular-nums",
|
|
118
|
+
children: [
|
|
119
|
+
"$",
|
|
120
|
+
(E / 1e6).toFixed(1),
|
|
121
|
+
"M"
|
|
122
|
+
]
|
|
123
|
+
}), /* @__PURE__ */ s("p", {
|
|
124
|
+
className: "text-xs text-text-secondary",
|
|
125
|
+
children: "Annual salary expenditure"
|
|
126
|
+
})] })]
|
|
127
|
+
}),
|
|
128
|
+
/* @__PURE__ */ c(h, {
|
|
129
|
+
treatment: "metric",
|
|
130
|
+
className: "border-border-seam",
|
|
131
|
+
children: [/* @__PURE__ */ c(p, {
|
|
132
|
+
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
133
|
+
children: [/* @__PURE__ */ s(m, {
|
|
134
|
+
className: "text-sm font-medium",
|
|
135
|
+
children: "Budget Utilization"
|
|
136
|
+
}), /* @__PURE__ */ s(a, { className: "h-4 w-4 text-text-secondary" })]
|
|
137
|
+
}), /* @__PURE__ */ c(d, { children: [/* @__PURE__ */ c("div", {
|
|
138
|
+
className: "text-2xl font-bold tabular-nums",
|
|
139
|
+
children: [A, "%"]
|
|
140
|
+
}), /* @__PURE__ */ c("p", {
|
|
141
|
+
className: "text-xs text-text-secondary",
|
|
142
|
+
children: [
|
|
143
|
+
"$",
|
|
144
|
+
(k / 1e6).toFixed(1),
|
|
145
|
+
"M of $",
|
|
146
|
+
(O / 1e6).toFixed(1),
|
|
147
|
+
"M"
|
|
148
|
+
]
|
|
149
|
+
})] })]
|
|
150
|
+
}),
|
|
151
|
+
/* @__PURE__ */ c(h, {
|
|
152
|
+
treatment: "metric",
|
|
153
|
+
className: "border-border-seam",
|
|
154
|
+
children: [/* @__PURE__ */ c(p, {
|
|
155
|
+
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
156
|
+
children: [/* @__PURE__ */ s(m, {
|
|
157
|
+
className: "text-sm font-medium",
|
|
158
|
+
children: "Retention Rate"
|
|
159
|
+
}), /* @__PURE__ */ s(o, { className: "h-4 w-4 text-text-secondary" })]
|
|
160
|
+
}), /* @__PURE__ */ c(d, { children: [/* @__PURE__ */ s("div", {
|
|
161
|
+
className: "text-2xl font-bold tabular-nums",
|
|
162
|
+
children: "95.8%"
|
|
163
|
+
}), /* @__PURE__ */ c("div", {
|
|
164
|
+
className: "flex items-center text-xs text-status-success-text",
|
|
165
|
+
children: [/* @__PURE__ */ s(n, { className: "h-3 w-3 mr-1" }), "+1.1% improvement"]
|
|
166
|
+
})] })]
|
|
167
|
+
})
|
|
144
168
|
]
|
|
145
169
|
}),
|
|
146
170
|
/* @__PURE__ */ c("div", {
|
|
@@ -162,7 +186,7 @@ function g() {
|
|
|
162
186
|
children: "Rev/Head"
|
|
163
187
|
})
|
|
164
188
|
]
|
|
165
|
-
}),
|
|
189
|
+
}), C.map((e) => /* @__PURE__ */ c("div", {
|
|
166
190
|
className: "grid grid-cols-4 gap-2 py-2 border-b last:border-0 text-sm",
|
|
167
191
|
children: [
|
|
168
192
|
/* @__PURE__ */ s("span", {
|
|
@@ -188,11 +212,11 @@ function g() {
|
|
|
188
212
|
]
|
|
189
213
|
}, e.quarter))] })] }), /* @__PURE__ */ c(u, { children: [/* @__PURE__ */ c(p, { children: [/* @__PURE__ */ s(m, { children: "Risk Indicators" }), /* @__PURE__ */ s(f, { children: "Items requiring executive attention" })] }), /* @__PURE__ */ s(d, {
|
|
190
214
|
className: "space-y-3",
|
|
191
|
-
children:
|
|
215
|
+
children: w.map((e) => /* @__PURE__ */ c("div", {
|
|
192
216
|
className: "flex items-center justify-between rounded border p-3",
|
|
193
217
|
children: [/* @__PURE__ */ c("div", {
|
|
194
218
|
className: "flex items-center gap-3",
|
|
195
|
-
children: [/* @__PURE__ */ s("div", { className: `h-3 w-3 rounded-full ${e.severity === "error" ? "bg-
|
|
219
|
+
children: [/* @__PURE__ */ s("div", { className: `h-3 w-3 rounded-full ${e.severity === "error" ? "bg-status-error-text" : e.severity === "warning" ? "bg-status-warning-text" : "bg-status-info-text"}` }), /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("p", {
|
|
196
220
|
className: "text-sm font-medium",
|
|
197
221
|
children: e.metric
|
|
198
222
|
}), /* @__PURE__ */ s("p", {
|
|
@@ -208,7 +232,7 @@ function g() {
|
|
|
208
232
|
}),
|
|
209
233
|
/* @__PURE__ */ c(u, { children: [/* @__PURE__ */ c(p, { children: [/* @__PURE__ */ s(m, { children: "Diversity & Inclusion Metrics" }), /* @__PURE__ */ s(f, { children: "Gender distribution across organization segments" })] }), /* @__PURE__ */ s(d, { children: /* @__PURE__ */ s("div", {
|
|
210
234
|
className: "space-y-4",
|
|
211
|
-
children:
|
|
235
|
+
children: T.map((e) => /* @__PURE__ */ c("div", {
|
|
212
236
|
className: "space-y-1",
|
|
213
237
|
children: [/* @__PURE__ */ c("div", {
|
|
214
238
|
className: "flex justify-between text-sm",
|
|
@@ -231,15 +255,15 @@ function g() {
|
|
|
231
255
|
className: "flex h-3 rounded overflow-hidden",
|
|
232
256
|
children: [
|
|
233
257
|
/* @__PURE__ */ s("div", {
|
|
234
|
-
className: "bg-
|
|
258
|
+
className: "bg-status-info-text",
|
|
235
259
|
style: { width: `${e.male}%` }
|
|
236
260
|
}),
|
|
237
261
|
/* @__PURE__ */ s("div", {
|
|
238
|
-
className: "bg-
|
|
262
|
+
className: "bg-action-primary-bg",
|
|
239
263
|
style: { width: `${e.female}%` }
|
|
240
264
|
}),
|
|
241
265
|
/* @__PURE__ */ s("div", {
|
|
242
|
-
className: "bg-
|
|
266
|
+
className: "bg-status-success-text",
|
|
243
267
|
style: { width: `${e.other}%` }
|
|
244
268
|
})
|
|
245
269
|
]
|
|
@@ -266,7 +290,7 @@ function g() {
|
|
|
266
290
|
})
|
|
267
291
|
]
|
|
268
292
|
}),
|
|
269
|
-
|
|
293
|
+
b.map((e) => {
|
|
270
294
|
let t = e.employeeCount > 0 ? Math.round(e.budget / e.employeeCount) : 0;
|
|
271
295
|
return /* @__PURE__ */ c("div", {
|
|
272
296
|
className: "grid grid-cols-5 gap-2 py-2 border-b last:border-0 text-sm",
|
|
@@ -302,7 +326,7 @@ function g() {
|
|
|
302
326
|
]
|
|
303
327
|
}, e.id);
|
|
304
328
|
}),
|
|
305
|
-
/* @__PURE__ */ s(
|
|
329
|
+
/* @__PURE__ */ s(v, { className: "my-2" }),
|
|
306
330
|
/* @__PURE__ */ c("div", {
|
|
307
331
|
className: "grid grid-cols-5 gap-2 text-sm font-bold",
|
|
308
332
|
children: [
|
|
@@ -310,13 +334,13 @@ function g() {
|
|
|
310
334
|
/* @__PURE__ */ s("span", {}),
|
|
311
335
|
/* @__PURE__ */ s("span", {
|
|
312
336
|
className: "text-right",
|
|
313
|
-
children:
|
|
337
|
+
children: b.reduce((e, t) => e + t.employeeCount, 0)
|
|
314
338
|
}),
|
|
315
339
|
/* @__PURE__ */ c("span", {
|
|
316
340
|
className: "text-right",
|
|
317
341
|
children: [
|
|
318
342
|
"$",
|
|
319
|
-
(
|
|
343
|
+
(D / 1e6).toFixed(1),
|
|
320
344
|
"M"
|
|
321
345
|
]
|
|
322
346
|
}),
|
|
@@ -324,7 +348,7 @@ function g() {
|
|
|
324
348
|
className: "text-right",
|
|
325
349
|
children: [
|
|
326
350
|
"$",
|
|
327
|
-
(
|
|
351
|
+
(D / b.reduce((e, t) => e + t.employeeCount, 0) / 1e3).toFixed(0),
|
|
328
352
|
"K"
|
|
329
353
|
]
|
|
330
354
|
})
|
|
@@ -335,6 +359,6 @@ function g() {
|
|
|
335
359
|
});
|
|
336
360
|
}
|
|
337
361
|
//#endregion
|
|
338
|
-
export {
|
|
362
|
+
export { y as DashboardExecutiveDashboardPage };
|
|
339
363
|
|
|
340
364
|
//# sourceMappingURL=DashboardExecutiveDashboardPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardExecutiveDashboardPage.js","names":[],"sources":["../../../src/crewfoundry/pages/DashboardExecutiveDashboardPage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Separator,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowUp, Building2, DollarSign, Percent, Target } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function DashboardExecutiveDashboardPage() {\n const { employees, departments, projects, jobPostings } = useCrewFoundryStore();\n\n const quarterlyRevenue = useMemo(() => {\n const quarters = ['Q1 2025', 'Q2 2025', 'Q3 2025', 'Q4 2025'];\n const base = projects.reduce((sum, project) => sum + project.budget, 0) || 1000000;\n return quarters.map((quarter, index) => {\n const revenue = Math.round(base * (0.55 + index * 0.08));\n const headcount = Math.max(1, employees.length - (3 - index) * 4);\n return {\n quarter,\n revenue,\n headcount,\n revenuePerHead: Math.round(revenue / headcount),\n };\n });\n }, [employees.length, projects]);\n\n const riskIndicators = useMemo(\n () => [\n {\n metric: 'Flight Risk Employees',\n value: employees.filter((employee) => employee.performanceScore < 3.6).length,\n severity: 'warning' as const,\n detail: `${Math.round((employees.filter((employee) => employee.performanceScore < 3.6).length / Math.max(employees.length, 1)) * 100)}% of workforce`,\n },\n {\n metric: 'Overdue Performance Reviews',\n value: employees.filter((employee) => employee.status === 'on_leave').length,\n severity: 'error' as const,\n detail: 'Review follow-ups required',\n },\n {\n metric: 'Unfilled Critical Roles',\n value: jobPostings.filter(\n (posting) => posting.status === 'active' && posting.experienceLevel === 'lead'\n ).length,\n severity: 'warning' as const,\n detail: 'Open lead-level positions',\n },\n {\n metric: 'Expiring Contracts',\n value: employees.filter((employee) => employee.type === 'contract').length,\n severity: 'info' as const,\n detail: 'Contract renewals in focus',\n },\n ],\n [employees, jobPostings]\n );\n\n const diversityMetrics = useMemo(() => {\n const byDepartment = departments.map((department) => {\n const count = employees.filter((employee) => employee.department === department.name).length;\n const male = Math.min(100, Math.round(45 + (count % 15)));\n const female = Math.min(100 - male, Math.round(40 + (count % 10)));\n const other = Math.max(0, 100 - male - female);\n return { category: department.name, male, female, other };\n });\n return [\n {\n category: 'Company',\n male: 52,\n female: 43,\n other: 5,\n },\n ...byDepartment.slice(0, 3),\n ];\n }, [departments, employees]);\n\n const totalSalaryBudget = employees.reduce((sum, e) => sum + e.salary, 0);\n const totalDeptBudget = departments.reduce((sum, d) => sum + d.budget, 0);\n const totalProjectBudget = projects.reduce((sum, p) => sum + p.budget, 0);\n const totalProjectSpent = projects.reduce((sum, p) => sum + p.spent, 0);\n const budgetUtilization = Math.round((totalProjectSpent / totalProjectBudget) * 100);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Executive Dashboard</h1>\n <p className=\"text-sm text-text-secondary\">\n Strategic workforce insights for leadership\n </p>\n </div>\n <Badge variant=\"outline\">Q1 2026</Badge>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Revenue per Employee</CardTitle>\n <DollarSign className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold\">$21,862</div>\n <div className=\"flex items-center text-xs text-green-600\">\n <ArrowUp className=\"h-3 w-3 mr-1\" />\n +2.0% from Q3\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Total Workforce Cost</CardTitle>\n <Building2 className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold\">${(totalSalaryBudget / 1000000).toFixed(1)}M</div>\n <p className=\"text-xs text-text-secondary\">Annual salary expenditure</p>\n </CardContent>\n </Card>\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Budget Utilization</CardTitle>\n <Percent className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold\">{budgetUtilization}%</div>\n <p className=\"text-xs text-text-secondary\">\n ${(totalProjectSpent / 1000000).toFixed(1)}M of $\n {(totalProjectBudget / 1000000).toFixed(1)}M\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Retention Rate</CardTitle>\n <Target className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold\">95.8%</div>\n <div className=\"flex items-center text-xs text-green-600\">\n <ArrowUp className=\"h-3 w-3 mr-1\" />\n +1.1% improvement\n </div>\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Revenue & Headcount Trend</CardTitle>\n <CardDescription>Quarterly performance metrics</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-4 gap-2 text-xs font-medium text-text-secondary border-b pb-2 mb-2\">\n <span>Quarter</span>\n <span className=\"text-right\">Revenue</span>\n <span className=\"text-right\">Headcount</span>\n <span className=\"text-right\">Rev/Head</span>\n </div>\n {quarterlyRevenue.map((q) => (\n <div\n key={q.quarter}\n className=\"grid grid-cols-4 gap-2 py-2 border-b last:border-0 text-sm\"\n >\n <span className=\"font-medium\">{q.quarter}</span>\n <span className=\"text-right\">${(q.revenue / 1000000).toFixed(1)}M</span>\n <span className=\"text-right\">{q.headcount}</span>\n <span className=\"text-right font-medium\">${q.revenuePerHead.toLocaleString()}</span>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Risk Indicators</CardTitle>\n <CardDescription>Items requiring executive attention</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {riskIndicators.map((risk) => (\n <div\n key={risk.metric}\n className=\"flex items-center justify-between rounded border p-3\"\n >\n <div className=\"flex items-center gap-3\">\n <div\n className={`h-3 w-3 rounded-full ${\n risk.severity === 'error'\n ? 'bg-red-500'\n : risk.severity === 'warning'\n ? 'bg-yellow-500'\n : 'bg-blue-500'\n }`}\n />\n <div>\n <p className=\"text-sm font-medium\">{risk.metric}</p>\n <p className=\"text-xs text-text-secondary\">{risk.detail}</p>\n </div>\n </div>\n <span className=\"text-lg font-bold\">{risk.value}</span>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Diversity & Inclusion Metrics</CardTitle>\n <CardDescription>Gender distribution across organization segments</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-4\">\n {diversityMetrics.map((d) => (\n <div key={d.category} className=\"space-y-1\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"font-medium\">{d.category}</span>\n <span className=\"text-xs text-text-secondary\">\n M: {d.male}% · F: {d.female}% · Other: {d.other}%\n </span>\n </div>\n <div className=\"flex h-3 rounded overflow-hidden\">\n <div className=\"bg-blue-500\" style={{ width: `${d.male}%` }} />\n <div className=\"bg-purple-500\" style={{ width: `${d.female}%` }} />\n <div className=\"bg-green-500\" style={{ width: `${d.other}%` }} />\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Department Budget Status</CardTitle>\n <CardDescription>Annual budget allocation and headcount</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-5 gap-2 text-xs font-medium text-text-secondary border-b pb-2 mb-2\">\n <span>Department</span>\n <span>Head</span>\n <span className=\"text-right\">Headcount</span>\n <span className=\"text-right\">Budget</span>\n <span className=\"text-right\">Cost/Employee</span>\n </div>\n {departments.map((dept) => {\n const costPerEmp =\n dept.employeeCount > 0 ? Math.round(dept.budget / dept.employeeCount) : 0;\n return (\n <div\n key={dept.id}\n className=\"grid grid-cols-5 gap-2 py-2 border-b last:border-0 text-sm\"\n >\n <span className=\"font-medium\">{dept.name}</span>\n <span className=\"text-text-secondary\">{dept.headName}</span>\n <span className=\"text-right\">{dept.employeeCount}</span>\n <span className=\"text-right\">${(dept.budget / 1000000).toFixed(1)}M</span>\n <span className=\"text-right\">${(costPerEmp / 1000).toFixed(0)}K</span>\n </div>\n );\n })}\n <Separator className=\"my-2\" />\n <div className=\"grid grid-cols-5 gap-2 text-sm font-bold\">\n <span>Total</span>\n <span />\n <span className=\"text-right\">\n {departments.reduce((s, d) => s + d.employeeCount, 0)}\n </span>\n <span className=\"text-right\">${(totalDeptBudget / 1000000).toFixed(1)}M</span>\n <span className=\"text-right\">\n $\n {(\n totalDeptBudget /\n departments.reduce((s, d) => s + d.employeeCount, 0) /\n 1000\n ).toFixed(0)}\n K\n </span>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardExecutiveDashboardPage.js","names":[],"sources":["../../../src/crewfoundry/pages/DashboardExecutiveDashboardPage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n PagePurpose,\n Separator,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowUp, Building2, DollarSign, Percent, Target } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function DashboardExecutiveDashboardPage() {\n const { employees, departments, projects, jobPostings } = useCrewFoundryStore();\n\n const quarterlyRevenue = useMemo(() => {\n const quarters = ['Q1 2025', 'Q2 2025', 'Q3 2025', 'Q4 2025'];\n const base = projects.reduce((sum, project) => sum + project.budget, 0) || 1000000;\n return quarters.map((quarter, index) => {\n const revenue = Math.round(base * (0.55 + index * 0.08));\n const headcount = Math.max(1, employees.length - (3 - index) * 4);\n return {\n quarter,\n revenue,\n headcount,\n revenuePerHead: Math.round(revenue / headcount),\n };\n });\n }, [employees.length, projects]);\n\n const riskIndicators = useMemo(\n () => [\n {\n metric: 'Flight Risk Employees',\n value: employees.filter((employee) => employee.performanceScore < 3.6).length,\n severity: 'warning' as const,\n detail: `${Math.round((employees.filter((employee) => employee.performanceScore < 3.6).length / Math.max(employees.length, 1)) * 100)}% of workforce`,\n },\n {\n metric: 'Overdue Performance Reviews',\n value: employees.filter((employee) => employee.status === 'on_leave').length,\n severity: 'error' as const,\n detail: 'Review follow-ups required',\n },\n {\n metric: 'Unfilled Critical Roles',\n value: jobPostings.filter(\n (posting) => posting.status === 'active' && posting.experienceLevel === 'lead'\n ).length,\n severity: 'warning' as const,\n detail: 'Open lead-level positions',\n },\n {\n metric: 'Expiring Contracts',\n value: employees.filter((employee) => employee.type === 'contract').length,\n severity: 'info' as const,\n detail: 'Contract renewals in focus',\n },\n ],\n [employees, jobPostings]\n );\n\n const diversityMetrics = useMemo(() => {\n const byDepartment = departments.map((department) => {\n const count = employees.filter((employee) => employee.department === department.name).length;\n const male = Math.min(100, Math.round(45 + (count % 15)));\n const female = Math.min(100 - male, Math.round(40 + (count % 10)));\n const other = Math.max(0, 100 - male - female);\n return { category: department.name, male, female, other };\n });\n return [\n {\n category: 'Company',\n male: 52,\n female: 43,\n other: 5,\n },\n ...byDepartment.slice(0, 3),\n ];\n }, [departments, employees]);\n\n const totalSalaryBudget = employees.reduce((sum, e) => sum + e.salary, 0);\n const totalDeptBudget = departments.reduce((sum, d) => sum + d.budget, 0);\n const totalProjectBudget = projects.reduce((sum, p) => sum + p.budget, 0);\n const totalProjectSpent = projects.reduce((sum, p) => sum + p.spent, 0);\n const budgetUtilization = Math.round((totalProjectSpent / totalProjectBudget) * 100);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Executive Dashboard</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Strategic workforce insights for leadership</p>\n <PagePurpose className=\"mt-1\">The executive snapshot — top-line workforce, financial, and hiring KPIs in one view so leaders can make decisions fast.</PagePurpose>\n </div>\n <Badge variant=\"outline\">Q1 2026</Badge>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Revenue per Employee</CardTitle>\n <DollarSign className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">$21,862</div>\n <div className=\"flex items-center text-xs text-status-success-text\">\n <ArrowUp className=\"h-3 w-3 mr-1\" />\n +2.0% from Q3\n </div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Total Workforce Cost</CardTitle>\n <Building2 className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n ${(totalSalaryBudget / 1000000).toFixed(1)}M\n </div>\n <p className=\"text-xs text-text-secondary\">Annual salary expenditure</p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Budget Utilization</CardTitle>\n <Percent className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{budgetUtilization}%</div>\n <p className=\"text-xs text-text-secondary\">\n ${(totalProjectSpent / 1000000).toFixed(1)}M of $\n {(totalProjectBudget / 1000000).toFixed(1)}M\n </p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Retention Rate</CardTitle>\n <Target className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">95.8%</div>\n <div className=\"flex items-center text-xs text-status-success-text\">\n <ArrowUp className=\"h-3 w-3 mr-1\" />\n +1.1% improvement\n </div>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Revenue & Headcount Trend</CardTitle>\n <CardDescription>Quarterly performance metrics</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-4 gap-2 text-xs font-medium text-text-secondary border-b pb-2 mb-2\">\n <span>Quarter</span>\n <span className=\"text-right\">Revenue</span>\n <span className=\"text-right\">Headcount</span>\n <span className=\"text-right\">Rev/Head</span>\n </div>\n {quarterlyRevenue.map((q) => (\n <div\n key={q.quarter}\n className=\"grid grid-cols-4 gap-2 py-2 border-b last:border-0 text-sm\"\n >\n <span className=\"font-medium\">{q.quarter}</span>\n <span className=\"text-right\">${(q.revenue / 1000000).toFixed(1)}M</span>\n <span className=\"text-right\">{q.headcount}</span>\n <span className=\"text-right font-medium\">${q.revenuePerHead.toLocaleString()}</span>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Risk Indicators</CardTitle>\n <CardDescription>Items requiring executive attention</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {riskIndicators.map((risk) => (\n <div\n key={risk.metric}\n className=\"flex items-center justify-between rounded border p-3\"\n >\n <div className=\"flex items-center gap-3\">\n <div\n className={`h-3 w-3 rounded-full ${\n risk.severity === 'error'\n ? 'bg-status-error-text'\n : risk.severity === 'warning'\n ? 'bg-status-warning-text'\n : 'bg-status-info-text'\n }`}\n />\n <div>\n <p className=\"text-sm font-medium\">{risk.metric}</p>\n <p className=\"text-xs text-text-secondary\">{risk.detail}</p>\n </div>\n </div>\n <span className=\"text-lg font-bold\">{risk.value}</span>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Diversity & Inclusion Metrics</CardTitle>\n <CardDescription>Gender distribution across organization segments</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-4\">\n {diversityMetrics.map((d) => (\n <div key={d.category} className=\"space-y-1\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"font-medium\">{d.category}</span>\n <span className=\"text-xs text-text-secondary\">\n M: {d.male}% · F: {d.female}% · Other: {d.other}%\n </span>\n </div>\n <div className=\"flex h-3 rounded overflow-hidden\">\n <div className=\"bg-status-info-text\" style={{ width: `${d.male}%` }} />\n <div className=\"bg-action-primary-bg\" style={{ width: `${d.female}%` }} />\n <div className=\"bg-status-success-text\" style={{ width: `${d.other}%` }} />\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Department Budget Status</CardTitle>\n <CardDescription>Annual budget allocation and headcount</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-5 gap-2 text-xs font-medium text-text-secondary border-b pb-2 mb-2\">\n <span>Department</span>\n <span>Head</span>\n <span className=\"text-right\">Headcount</span>\n <span className=\"text-right\">Budget</span>\n <span className=\"text-right\">Cost/Employee</span>\n </div>\n {departments.map((dept) => {\n const costPerEmp =\n dept.employeeCount > 0 ? Math.round(dept.budget / dept.employeeCount) : 0;\n return (\n <div\n key={dept.id}\n className=\"grid grid-cols-5 gap-2 py-2 border-b last:border-0 text-sm\"\n >\n <span className=\"font-medium\">{dept.name}</span>\n <span className=\"text-text-secondary\">{dept.headName}</span>\n <span className=\"text-right\">{dept.employeeCount}</span>\n <span className=\"text-right\">${(dept.budget / 1000000).toFixed(1)}M</span>\n <span className=\"text-right\">${(costPerEmp / 1000).toFixed(0)}K</span>\n </div>\n );\n })}\n <Separator className=\"my-2\" />\n <div className=\"grid grid-cols-5 gap-2 text-sm font-bold\">\n <span>Total</span>\n <span />\n <span className=\"text-right\">\n {departments.reduce((s, d) => s + d.employeeCount, 0)}\n </span>\n <span className=\"text-right\">${(totalDeptBudget / 1000000).toFixed(1)}M</span>\n <span className=\"text-right\">\n $\n {(\n totalDeptBudget /\n departments.reduce((s, d) => s + d.employeeCount, 0) /\n 1000\n ).toFixed(0)}\n K\n </span>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|