@burdenoff/microfe-crewfoundry 2026.703.2 → 2026.704.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/components/forms/FormModal.js.map +1 -1
- package/dist/crewfoundry/pages/AdminAdminPagePage.js +117 -164
- package/dist/crewfoundry/pages/AdminAdminPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +99 -82
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +160 -192
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +238 -231
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +196 -166
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js +45 -147
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsDirectoryPagePage.js +20 -11
- package/dist/crewfoundry/pages/CommunicationsDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js +45 -152
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +50 -138
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js +149 -67
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js +50 -201
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +205 -136
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js +25 -31
- package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js +118 -104
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +117 -58
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js +90 -94
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +210 -191
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js +213 -180
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js +133 -264
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js.map +1 -1
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js +279 -212
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +131 -105
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +167 -148
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +3 -3
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +13 -5
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +151 -152
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +38 -21
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +3 -3
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js +134 -127
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +163 -132
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js +202 -160
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +104 -91
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js +29 -147
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +22 -106
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +74 -74
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +101 -97
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +64 -47
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js +111 -121
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.js +131 -110
- package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +65 -64
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +58 -43
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +66 -82
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js +38 -88
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js +59 -65
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js +209 -323
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +175 -220
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +74 -59
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +96 -80
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js +28 -100
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js +27 -20
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +73 -73
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +62 -56
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js +40 -138
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +126 -93
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js +99 -77
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js +73 -74
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js +1 -1
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +122 -122
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +130 -113
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js +68 -59
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +73 -62
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +82 -58
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js +153 -153
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +63 -48
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardEnhancedDashboardPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/DashboardEnhancedDashboardPagePage.tsx"],"sourcesContent":["import { useMemo, useState } 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 { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport { useCrewFoundry } from '../providers/CrewFoundryProvider';\n\nexport function DashboardEnhancedDashboardPagePage() {\n const navigate = useNavigate();\n const { showToast } = useGlobalUi();\n const { currentUser } = useCrewFoundry();\n const {\n employees,\n jobPostings,\n candidates,\n interviews,\n leaveRequests,\n notifications,\n projects,\n announcements,\n updateLeaveRequest,\n } = useCrewFoundryStore();\n const [processingLeaveId, setProcessingLeaveId] = useState<string | null>(null);\n\n const approverName =\n currentUser?.name ||\n [currentUser?.firstName, currentUser?.lastName].filter(Boolean).join(' ') ||\n currentUser?.email ||\n 'Manager';\n\n const decideLeave = async (id: string, status: 'approved' | 'rejected') => {\n setProcessingLeaveId(id);\n try {\n await updateLeaveRequest(id, { status, approverName });\n showToast(status === 'approved' ? 'Leave approved' : 'Leave rejected', 'success');\n } catch (error) {\n showToast(\n error instanceof Error ? error.message : 'Unable to update leave request',\n 'error'\n );\n } finally {\n setProcessingLeaveId(null);\n }\n };\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 to: '../../hiring/create-job-page',\n },\n {\n label: `Review Candidates (${candidates.filter((candidate) => candidate.status === 'new').length})`,\n icon: Users,\n color: 'text-action-primary-bg',\n to: '../../hiring/candidates-page',\n },\n {\n label: `Approve Leaves (${leaveRequests.filter((leave) => leave.status === 'pending').length})`,\n icon: CheckCircle,\n color: 'text-status-success-text',\n to: '../../hr/leave-management-page',\n },\n {\n label: `Run Payroll (${projects.filter((project) => project.status === 'active').length} projects)`,\n icon: Zap,\n color: 'text-status-warning-text',\n to: '../../hr/payroll-page',\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\" onClick={() => navigate('../../hr/leave-management-page')}>\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\n key={action.label}\n role=\"button\"\n tabIndex={0}\n aria-label={action.label}\n className=\"cursor-pointer hover:shadow-md transition-shadow\"\n onClick={() => navigate(action.to)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n navigate(action.to);\n }\n }}\n >\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\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs\"\n disabled={processingLeaveId === leave.id}\n onClick={() => void decideLeave(leave.id, 'rejected')}\n >\n Deny\n </Button>\n <Button\n size=\"sm\"\n className=\"h-7 text-xs\"\n disabled={processingLeaveId === leave.id}\n onClick={() => void decideLeave(leave.id, 'approved')}\n >\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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"}
|
|
1
|
+
{"version":3,"file":"DashboardEnhancedDashboardPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/DashboardEnhancedDashboardPagePage.tsx"],"sourcesContent":["import { useMemo, useState } 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 ResponsiveTable,\n type ResponsiveTableColumn,\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 { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useCrewFoundryStore, type Employee } from '../store/crewfoundryStore';\nimport { useCrewFoundry } from '../providers/CrewFoundryProvider';\n\nexport function DashboardEnhancedDashboardPagePage() {\n const navigate = useNavigate();\n const { showToast } = useGlobalUi();\n const { currentUser } = useCrewFoundry();\n const {\n employees,\n jobPostings,\n candidates,\n interviews,\n leaveRequests,\n notifications,\n projects,\n announcements,\n updateLeaveRequest,\n markAllNotificationsRead,\n } = useCrewFoundryStore();\n const [processingLeaveId, setProcessingLeaveId] = useState<string | null>(null);\n const [markingRead, setMarkingRead] = useState(false);\n\n const handleMarkAllRead = async () => {\n setMarkingRead(true);\n try {\n await markAllNotificationsRead();\n showToast('All notifications marked as read', 'success');\n } catch (error) {\n showToast(error instanceof Error ? error.message : 'Unable to update notifications', 'error');\n } finally {\n setMarkingRead(false);\n }\n };\n\n const approverName =\n currentUser?.name ||\n [currentUser?.firstName, currentUser?.lastName].filter(Boolean).join(' ') ||\n currentUser?.email ||\n 'Manager';\n\n const decideLeave = async (id: string, status: 'approved' | 'rejected') => {\n setProcessingLeaveId(id);\n try {\n await updateLeaveRequest(id, { status, approverName });\n showToast(status === 'approved' ? 'Leave approved' : 'Leave rejected', 'success');\n } catch (error) {\n showToast(error instanceof Error ? error.message : 'Unable to update leave request', 'error');\n } finally {\n setProcessingLeaveId(null);\n }\n };\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 to: '../../hiring/create-job-page',\n },\n {\n label: `Review Candidates (${candidates.filter((candidate) => candidate.status === 'new').length})`,\n icon: Users,\n color: 'text-action-primary-bg',\n to: '../../hiring/candidates-page',\n },\n {\n label: `Approve Leaves (${leaveRequests.filter((leave) => leave.status === 'pending').length})`,\n icon: CheckCircle,\n color: 'text-status-success-text',\n to: '../../hr/leave-management-page',\n },\n {\n label: `Run Payroll (${projects.filter((project) => project.status === 'active').length} projects)`,\n icon: Zap,\n color: 'text-status-warning-text',\n to: '../../hr/payroll-page',\n },\n ],\n [candidates, jobPostings, leaveRequests, projects]\n );\n\n // Only goals whose current value is derived from real store data.\n const companyGoals = useMemo(() => {\n const hired = candidates.filter((candidate) => candidate.status === 'hired').length;\n const avgPerformance =\n employees.reduce((sum, employee) => sum + employee.performanceScore, 0) /\n Math.max(employees.length, 1);\n const activeShare = Math.round(\n (employees.filter((employee) => employee.status === 'active').length /\n Math.max(employees.length, 1)) *\n 100\n );\n return [\n {\n goal: 'Fill 30 open positions',\n current: hired,\n target: 30,\n unit: 'positions',\n },\n {\n goal: 'Reach 90% average performance',\n current: Math.round(avgPerformance * 20),\n target: 90,\n unit: '%',\n },\n {\n goal: 'Keep 95% of workforce active',\n current: activeShare,\n target: 95,\n unit: '%',\n },\n ];\n }, [candidates, employees]);\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 const recentHireColumns: ResponsiveTableColumn<Employee>[] = [\n {\n key: 'name',\n header: 'Name',\n priority: 'primary',\n cell: (emp) => (\n <span className=\"font-medium\">\n {emp.firstName} {emp.lastName}\n </span>\n ),\n },\n {\n key: 'position',\n header: 'Position',\n priority: 'secondary',\n cell: (emp) => <span className=\"text-text-secondary\">{emp.position}</span>,\n },\n {\n key: 'department',\n header: 'Department',\n priority: 'secondary',\n cell: (emp) => <span>{emp.department}</span>,\n },\n {\n key: 'location',\n header: 'Location',\n priority: 'hidden-on-mobile',\n cell: (emp) => <span className=\"text-text-secondary\">{emp.location}</span>,\n },\n {\n key: 'startDate',\n header: 'Start Date',\n priority: 'secondary',\n cell: (emp) => <span>{emp.startDate}</span>,\n },\n {\n key: 'type',\n header: 'Type',\n priority: 'primary',\n cell: (emp) => (\n <Badge variant=\"outline\" className=\"w-fit text-[10px]\">\n {emp.type.replace('_', ' ')}\n </Badge>\n ),\n },\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\">\n A richer, customizable command center for your workforce — see live metrics, activity,\n and trends tailored to how you run your organization.\n </PagePurpose>\n </div>\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"relative\"\n disabled={unreadNotifs.length === 0 || markingRead}\n aria-label={\n unreadNotifs.length > 0\n ? `${unreadNotifs.length} unread notifications, mark all as read`\n : 'No unread notifications'\n }\n title={\n unreadNotifs.length > 0 ? 'Mark all notifications as read' : 'No unread notifications'\n }\n onClick={() => void handleMarkAllRead()}\n >\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-text-inverse flex items-center justify-center\">\n {unreadNotifs.length}\n </span>\n )}\n </Button>\n <Button size=\"sm\" onClick={() => navigate('../../hr/leave-management-page')}>\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\n key={action.label}\n role=\"button\"\n tabIndex={0}\n aria-label={action.label}\n className=\"cursor-pointer hover:shadow-md transition-shadow\"\n onClick={() => navigate(action.to)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n navigate(action.to);\n }\n }}\n >\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\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs\"\n disabled={processingLeaveId === leave.id}\n onClick={() => void decideLeave(leave.id, 'rejected')}\n >\n Deny\n </Button>\n <Button\n size=\"sm\"\n className=\"h-7 text-xs\"\n disabled={processingLeaveId === leave.id}\n onClick={() => void decideLeave(leave.id, 'approved')}\n >\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 / Math.max(employees.length, 1)) * 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 <ResponsiveTable\n columns={recentHireColumns}\n data={recentHires}\n rowKey={(emp) => emp.id}\n />\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,357 +1,226 @@
|
|
|
1
1
|
import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
2
2
|
import { useMemo as t } from "react";
|
|
3
|
-
import {
|
|
4
|
-
import { jsx as
|
|
5
|
-
import { Badge as
|
|
3
|
+
import { Building2 as n, Percent as r, Target as i } from "lucide-react";
|
|
4
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
5
|
+
import { Badge as s, Card as c, CardContent as l, CardDescription as u, CardHeader as d, CardTitle as f, GlassCard as p, GradientText as m, PagePurpose as h, ResponsiveTable as g, Separator as _ } from "@burdenoff/fe-libs/ui";
|
|
6
6
|
//#region src/crewfoundry/pages/DashboardExecutiveDashboardPage.tsx
|
|
7
|
-
function
|
|
8
|
-
let { employees:
|
|
9
|
-
let e = [
|
|
10
|
-
"Q1 2025",
|
|
11
|
-
"Q2 2025",
|
|
12
|
-
"Q3 2025",
|
|
13
|
-
"Q4 2025"
|
|
14
|
-
], t = x.reduce((e, t) => e + t.budget, 0) || 1e6;
|
|
15
|
-
return e.map((e, n) => {
|
|
16
|
-
let r = Math.round(t * (.55 + n * .08)), i = Math.max(1, y.length - (3 - n) * 4);
|
|
17
|
-
return {
|
|
18
|
-
quarter: e,
|
|
19
|
-
revenue: r,
|
|
20
|
-
headcount: i,
|
|
21
|
-
revenuePerHead: Math.round(r / i)
|
|
22
|
-
};
|
|
23
|
-
});
|
|
24
|
-
}, [y.length, x]), w = t(() => [
|
|
7
|
+
function v() {
|
|
8
|
+
let { employees: v, departments: y, projects: b, jobPostings: x } = e(), S = t(() => [
|
|
25
9
|
{
|
|
26
10
|
metric: "Flight Risk Employees",
|
|
27
|
-
value:
|
|
11
|
+
value: v.filter((e) => e.performanceScore < 3.6).length,
|
|
28
12
|
severity: "warning",
|
|
29
|
-
detail: `${Math.round(
|
|
13
|
+
detail: `${Math.round(v.filter((e) => e.performanceScore < 3.6).length / Math.max(v.length, 1) * 100)}% of workforce`
|
|
30
14
|
},
|
|
31
15
|
{
|
|
32
|
-
metric: "
|
|
33
|
-
value:
|
|
16
|
+
metric: "Employees On Leave",
|
|
17
|
+
value: v.filter((e) => e.status === "on_leave").length,
|
|
34
18
|
severity: "error",
|
|
35
|
-
detail: "
|
|
19
|
+
detail: "Coverage follow-ups required"
|
|
36
20
|
},
|
|
37
21
|
{
|
|
38
|
-
metric: "Unfilled
|
|
39
|
-
value:
|
|
22
|
+
metric: "Unfilled Lead Roles",
|
|
23
|
+
value: x.filter((e) => e.status === "active" && e.experienceLevel === "lead").length,
|
|
40
24
|
severity: "warning",
|
|
41
25
|
detail: "Open lead-level positions"
|
|
42
26
|
},
|
|
43
27
|
{
|
|
44
|
-
metric: "
|
|
45
|
-
value:
|
|
28
|
+
metric: "Contract Employees",
|
|
29
|
+
value: v.filter((e) => e.type === "contract").length,
|
|
46
30
|
severity: "info",
|
|
47
31
|
detail: "Contract renewals in focus"
|
|
48
32
|
}
|
|
49
|
-
], [
|
|
50
|
-
|
|
51
|
-
male: 52,
|
|
52
|
-
female: 43,
|
|
53
|
-
other: 5
|
|
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
|
-
return {
|
|
57
|
-
category: e.name,
|
|
58
|
-
male: n,
|
|
59
|
-
female: r,
|
|
60
|
-
other: i
|
|
61
|
-
};
|
|
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
|
-
return /* @__PURE__ */ c("div", {
|
|
33
|
+
], [v, x]), C = v.reduce((e, t) => e + t.salary, 0), w = y.reduce((e, t) => e + t.budget, 0), T = b.reduce((e, t) => e + t.budget, 0), E = b.reduce((e, t) => e + t.spent, 0), D = T > 0 ? Math.round(E / T * 100) : 0, O = v.filter((e) => e.status === "terminated").length, k = v.length > 0 ? Math.round((1 - O / v.length) * 100) : 0, A = y.reduce((e, t) => e + t.employeeCount, 0), j = A > 0 ? w / A : 0;
|
|
34
|
+
return /* @__PURE__ */ o("div", {
|
|
64
35
|
className: "space-y-6 p-6",
|
|
65
36
|
children: [
|
|
66
|
-
/* @__PURE__ */
|
|
37
|
+
/* @__PURE__ */ o("div", {
|
|
67
38
|
className: "flex items-center justify-between",
|
|
68
|
-
children: [/* @__PURE__ */
|
|
69
|
-
/* @__PURE__ */
|
|
39
|
+
children: [/* @__PURE__ */ o("div", { children: [
|
|
40
|
+
/* @__PURE__ */ a("h1", {
|
|
70
41
|
className: "text-2xl font-semibold",
|
|
71
|
-
children: /* @__PURE__ */
|
|
42
|
+
children: /* @__PURE__ */ a(m, { children: "Executive Dashboard" })
|
|
72
43
|
}),
|
|
73
|
-
/* @__PURE__ */
|
|
44
|
+
/* @__PURE__ */ a("p", {
|
|
74
45
|
className: "text-sm text-text-secondary",
|
|
75
46
|
children: "Strategic workforce insights for leadership"
|
|
76
47
|
}),
|
|
77
|
-
/* @__PURE__ */
|
|
48
|
+
/* @__PURE__ */ a(h, {
|
|
78
49
|
className: "mt-1",
|
|
79
50
|
children: "The executive snapshot — top-line workforce, financial, and hiring KPIs in one view so leaders can make decisions fast."
|
|
80
51
|
})
|
|
81
|
-
] }), /* @__PURE__ */ s
|
|
52
|
+
] }), /* @__PURE__ */ a(s, {
|
|
82
53
|
variant: "outline",
|
|
83
54
|
children: "Q1 2026"
|
|
84
55
|
})]
|
|
85
56
|
}),
|
|
86
|
-
/* @__PURE__ */
|
|
87
|
-
className: "grid gap-4 md:grid-cols-
|
|
57
|
+
/* @__PURE__ */ o("div", {
|
|
58
|
+
className: "grid gap-4 md:grid-cols-3",
|
|
88
59
|
children: [
|
|
89
|
-
/* @__PURE__ */
|
|
60
|
+
/* @__PURE__ */ o(p, {
|
|
90
61
|
treatment: "glass",
|
|
91
62
|
glow: !0,
|
|
92
63
|
className: "border-border-seam",
|
|
93
|
-
children: [/* @__PURE__ */
|
|
64
|
+
children: [/* @__PURE__ */ o(d, {
|
|
94
65
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
95
|
-
children: [/* @__PURE__ */
|
|
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, {
|
|
66
|
+
children: [/* @__PURE__ */ a(f, {
|
|
113
67
|
className: "text-sm font-medium",
|
|
114
68
|
children: "Total Workforce Cost"
|
|
115
|
-
}), /* @__PURE__ */
|
|
116
|
-
}), /* @__PURE__ */
|
|
69
|
+
}), /* @__PURE__ */ a(n, { className: "h-4 w-4 text-text-secondary" })]
|
|
70
|
+
}), /* @__PURE__ */ o(l, { children: [/* @__PURE__ */ o("div", {
|
|
117
71
|
className: "text-2xl font-bold tabular-nums",
|
|
118
72
|
children: [
|
|
119
73
|
"$",
|
|
120
|
-
(
|
|
74
|
+
(C / 1e6).toFixed(1),
|
|
121
75
|
"M"
|
|
122
76
|
]
|
|
123
|
-
}), /* @__PURE__ */
|
|
77
|
+
}), /* @__PURE__ */ a("p", {
|
|
124
78
|
className: "text-xs text-text-secondary",
|
|
125
79
|
children: "Annual salary expenditure"
|
|
126
80
|
})] })]
|
|
127
81
|
}),
|
|
128
|
-
/* @__PURE__ */
|
|
82
|
+
/* @__PURE__ */ o(p, {
|
|
129
83
|
treatment: "metric",
|
|
130
84
|
className: "border-border-seam",
|
|
131
|
-
children: [/* @__PURE__ */
|
|
85
|
+
children: [/* @__PURE__ */ o(d, {
|
|
132
86
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
133
|
-
children: [/* @__PURE__ */
|
|
87
|
+
children: [/* @__PURE__ */ a(f, {
|
|
134
88
|
className: "text-sm font-medium",
|
|
135
89
|
children: "Budget Utilization"
|
|
136
|
-
}), /* @__PURE__ */
|
|
137
|
-
}), /* @__PURE__ */
|
|
90
|
+
}), /* @__PURE__ */ a(r, { className: "h-4 w-4 text-text-secondary" })]
|
|
91
|
+
}), /* @__PURE__ */ o(l, { children: [/* @__PURE__ */ o("div", {
|
|
138
92
|
className: "text-2xl font-bold tabular-nums",
|
|
139
|
-
children: [
|
|
140
|
-
}), /* @__PURE__ */
|
|
93
|
+
children: [D, "%"]
|
|
94
|
+
}), /* @__PURE__ */ o("p", {
|
|
141
95
|
className: "text-xs text-text-secondary",
|
|
142
96
|
children: [
|
|
143
97
|
"$",
|
|
144
|
-
(
|
|
98
|
+
(E / 1e6).toFixed(1),
|
|
145
99
|
"M of $",
|
|
146
|
-
(
|
|
147
|
-
"M"
|
|
100
|
+
(T / 1e6).toFixed(1),
|
|
101
|
+
"M project budget"
|
|
148
102
|
]
|
|
149
103
|
})] })]
|
|
150
104
|
}),
|
|
151
|
-
/* @__PURE__ */
|
|
105
|
+
/* @__PURE__ */ o(p, {
|
|
152
106
|
treatment: "metric",
|
|
153
107
|
className: "border-border-seam",
|
|
154
|
-
children: [/* @__PURE__ */
|
|
108
|
+
children: [/* @__PURE__ */ o(d, {
|
|
155
109
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
156
|
-
children: [/* @__PURE__ */
|
|
110
|
+
children: [/* @__PURE__ */ a(f, {
|
|
157
111
|
className: "text-sm font-medium",
|
|
158
112
|
children: "Retention Rate"
|
|
159
|
-
}), /* @__PURE__ */
|
|
160
|
-
}), /* @__PURE__ */
|
|
113
|
+
}), /* @__PURE__ */ a(i, { className: "h-4 w-4 text-text-secondary" })]
|
|
114
|
+
}), /* @__PURE__ */ o(l, { children: [/* @__PURE__ */ o("div", {
|
|
161
115
|
className: "text-2xl font-bold tabular-nums",
|
|
162
|
-
children: "
|
|
163
|
-
}), /* @__PURE__ */
|
|
164
|
-
className: "
|
|
165
|
-
children: [
|
|
116
|
+
children: [k, "%"]
|
|
117
|
+
}), /* @__PURE__ */ o("p", {
|
|
118
|
+
className: "text-xs text-text-secondary",
|
|
119
|
+
children: [
|
|
120
|
+
O,
|
|
121
|
+
" of ",
|
|
122
|
+
v.length,
|
|
123
|
+
" employees no longer active"
|
|
124
|
+
]
|
|
166
125
|
})] })]
|
|
167
126
|
})
|
|
168
127
|
]
|
|
169
128
|
}),
|
|
170
|
-
/* @__PURE__ */ c("
|
|
171
|
-
className: "grid gap-
|
|
172
|
-
children:
|
|
173
|
-
className: "
|
|
174
|
-
children: [
|
|
175
|
-
|
|
176
|
-
/* @__PURE__ */
|
|
177
|
-
className: "text-
|
|
178
|
-
children:
|
|
179
|
-
}),
|
|
180
|
-
/* @__PURE__ */ s("span", {
|
|
181
|
-
className: "text-right",
|
|
182
|
-
children: "Headcount"
|
|
183
|
-
}),
|
|
184
|
-
/* @__PURE__ */ s("span", {
|
|
185
|
-
className: "text-right",
|
|
186
|
-
children: "Rev/Head"
|
|
187
|
-
})
|
|
188
|
-
]
|
|
189
|
-
}), C.map((e) => /* @__PURE__ */ c("div", {
|
|
190
|
-
className: "grid grid-cols-4 gap-2 py-2 border-b last:border-0 text-sm",
|
|
191
|
-
children: [
|
|
192
|
-
/* @__PURE__ */ s("span", {
|
|
193
|
-
className: "font-medium",
|
|
194
|
-
children: e.quarter
|
|
195
|
-
}),
|
|
196
|
-
/* @__PURE__ */ c("span", {
|
|
197
|
-
className: "text-right",
|
|
198
|
-
children: [
|
|
199
|
-
"$",
|
|
200
|
-
(e.revenue / 1e6).toFixed(1),
|
|
201
|
-
"M"
|
|
202
|
-
]
|
|
203
|
-
}),
|
|
204
|
-
/* @__PURE__ */ s("span", {
|
|
205
|
-
className: "text-right",
|
|
206
|
-
children: e.headcount
|
|
207
|
-
}),
|
|
208
|
-
/* @__PURE__ */ c("span", {
|
|
209
|
-
className: "text-right font-medium",
|
|
210
|
-
children: ["$", e.revenuePerHead.toLocaleString()]
|
|
211
|
-
})
|
|
212
|
-
]
|
|
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, {
|
|
214
|
-
className: "space-y-3",
|
|
215
|
-
children: w.map((e) => /* @__PURE__ */ c("div", {
|
|
216
|
-
className: "flex items-center justify-between rounded border p-3",
|
|
217
|
-
children: [/* @__PURE__ */ c("div", {
|
|
218
|
-
className: "flex items-center gap-3",
|
|
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", {
|
|
220
|
-
className: "text-sm font-medium",
|
|
221
|
-
children: e.metric
|
|
222
|
-
}), /* @__PURE__ */ s("p", {
|
|
223
|
-
className: "text-xs text-text-secondary",
|
|
224
|
-
children: e.detail
|
|
225
|
-
})] })]
|
|
226
|
-
}), /* @__PURE__ */ s("span", {
|
|
227
|
-
className: "text-lg font-bold",
|
|
228
|
-
children: e.value
|
|
229
|
-
})]
|
|
230
|
-
}, e.metric))
|
|
231
|
-
})] })]
|
|
232
|
-
}),
|
|
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", {
|
|
234
|
-
className: "space-y-4",
|
|
235
|
-
children: T.map((e) => /* @__PURE__ */ c("div", {
|
|
236
|
-
className: "space-y-1",
|
|
237
|
-
children: [/* @__PURE__ */ c("div", {
|
|
238
|
-
className: "flex justify-between text-sm",
|
|
239
|
-
children: [/* @__PURE__ */ s("span", {
|
|
240
|
-
className: "font-medium",
|
|
241
|
-
children: e.category
|
|
242
|
-
}), /* @__PURE__ */ c("span", {
|
|
129
|
+
/* @__PURE__ */ o(c, { children: [/* @__PURE__ */ o(d, { children: [/* @__PURE__ */ a(f, { children: "Risk Indicators" }), /* @__PURE__ */ a(u, { children: "Items requiring executive attention" })] }), /* @__PURE__ */ a(l, {
|
|
130
|
+
className: "grid gap-3 md:grid-cols-2",
|
|
131
|
+
children: S.map((e) => /* @__PURE__ */ o("div", {
|
|
132
|
+
className: "flex items-center justify-between rounded border p-3",
|
|
133
|
+
children: [/* @__PURE__ */ o("div", {
|
|
134
|
+
className: "flex items-center gap-3",
|
|
135
|
+
children: [/* @__PURE__ */ a("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__ */ o("div", { children: [/* @__PURE__ */ a("p", {
|
|
136
|
+
className: "text-sm font-medium",
|
|
137
|
+
children: e.metric
|
|
138
|
+
}), /* @__PURE__ */ a("p", {
|
|
243
139
|
className: "text-xs text-text-secondary",
|
|
244
|
-
children:
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
"% · Other: ",
|
|
250
|
-
e.other,
|
|
251
|
-
"%"
|
|
252
|
-
]
|
|
253
|
-
})]
|
|
254
|
-
}), /* @__PURE__ */ c("div", {
|
|
255
|
-
className: "flex h-3 rounded overflow-hidden",
|
|
256
|
-
children: [
|
|
257
|
-
/* @__PURE__ */ s("div", {
|
|
258
|
-
className: "bg-status-info-text",
|
|
259
|
-
style: { width: `${e.male}%` }
|
|
260
|
-
}),
|
|
261
|
-
/* @__PURE__ */ s("div", {
|
|
262
|
-
className: "bg-action-primary-bg",
|
|
263
|
-
style: { width: `${e.female}%` }
|
|
264
|
-
}),
|
|
265
|
-
/* @__PURE__ */ s("div", {
|
|
266
|
-
className: "bg-status-success-text",
|
|
267
|
-
style: { width: `${e.other}%` }
|
|
268
|
-
})
|
|
269
|
-
]
|
|
140
|
+
children: e.detail
|
|
141
|
+
})] })]
|
|
142
|
+
}), /* @__PURE__ */ a("span", {
|
|
143
|
+
className: "text-lg font-bold",
|
|
144
|
+
children: e.value
|
|
270
145
|
})]
|
|
271
|
-
}, e.
|
|
272
|
-
})
|
|
273
|
-
/* @__PURE__ */ c
|
|
274
|
-
/* @__PURE__ */
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
children: "Headcount"
|
|
282
|
-
}),
|
|
283
|
-
/* @__PURE__ */ s("span", {
|
|
284
|
-
className: "text-right",
|
|
285
|
-
children: "Budget"
|
|
286
|
-
}),
|
|
287
|
-
/* @__PURE__ */ s("span", {
|
|
288
|
-
className: "text-right",
|
|
289
|
-
children: "Cost/Employee"
|
|
290
|
-
})
|
|
291
|
-
]
|
|
292
|
-
}),
|
|
293
|
-
b.map((e) => {
|
|
294
|
-
let t = e.employeeCount > 0 ? Math.round(e.budget / e.employeeCount) : 0;
|
|
295
|
-
return /* @__PURE__ */ c("div", {
|
|
296
|
-
className: "grid grid-cols-5 gap-2 py-2 border-b last:border-0 text-sm",
|
|
297
|
-
children: [
|
|
298
|
-
/* @__PURE__ */ s("span", {
|
|
146
|
+
}, e.metric))
|
|
147
|
+
})] }),
|
|
148
|
+
/* @__PURE__ */ o(c, { children: [/* @__PURE__ */ o(d, { children: [/* @__PURE__ */ a(f, { children: "Department Budget Status" }), /* @__PURE__ */ a(u, { children: "Annual budget allocation and headcount" })] }), /* @__PURE__ */ o(l, { children: [
|
|
149
|
+
/* @__PURE__ */ a(g, {
|
|
150
|
+
columns: [
|
|
151
|
+
{
|
|
152
|
+
key: "name",
|
|
153
|
+
header: "Department",
|
|
154
|
+
priority: "primary",
|
|
155
|
+
cell: (e) => /* @__PURE__ */ a("span", {
|
|
299
156
|
className: "font-medium",
|
|
300
157
|
children: e.name
|
|
301
|
-
})
|
|
302
|
-
|
|
158
|
+
})
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
key: "head",
|
|
162
|
+
header: "Head",
|
|
163
|
+
priority: "secondary",
|
|
164
|
+
cell: (e) => /* @__PURE__ */ a("span", {
|
|
303
165
|
className: "text-text-secondary",
|
|
304
166
|
children: e.headName
|
|
305
|
-
})
|
|
306
|
-
|
|
307
|
-
|
|
167
|
+
})
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
key: "headcount",
|
|
171
|
+
header: "Headcount",
|
|
172
|
+
priority: "secondary",
|
|
173
|
+
cell: (e) => /* @__PURE__ */ a("span", {
|
|
174
|
+
className: "md:block md:text-right",
|
|
308
175
|
children: e.employeeCount
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
|
|
176
|
+
})
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
key: "budget",
|
|
180
|
+
header: "Budget",
|
|
181
|
+
priority: "secondary",
|
|
182
|
+
cell: (e) => /* @__PURE__ */ o("span", {
|
|
183
|
+
className: "md:block md:text-right",
|
|
312
184
|
children: [
|
|
313
185
|
"$",
|
|
314
186
|
(e.budget / 1e6).toFixed(1),
|
|
315
187
|
"M"
|
|
316
188
|
]
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
|
|
189
|
+
})
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
key: "costPerEmployee",
|
|
193
|
+
header: "Cost/Employee",
|
|
194
|
+
priority: "primary",
|
|
195
|
+
cell: (e) => /* @__PURE__ */ o("span", {
|
|
196
|
+
className: "md:block md:text-right",
|
|
320
197
|
children: [
|
|
321
198
|
"$",
|
|
322
|
-
(
|
|
199
|
+
((e.employeeCount > 0 ? Math.round(e.budget / e.employeeCount) : 0) / 1e3).toFixed(0),
|
|
323
200
|
"K"
|
|
324
201
|
]
|
|
325
202
|
})
|
|
326
|
-
|
|
327
|
-
|
|
203
|
+
}
|
|
204
|
+
],
|
|
205
|
+
data: y,
|
|
206
|
+
rowKey: (e) => e.id
|
|
328
207
|
}),
|
|
329
|
-
/* @__PURE__ */
|
|
330
|
-
/* @__PURE__ */
|
|
331
|
-
className: "
|
|
208
|
+
/* @__PURE__ */ a(_, { className: "my-3" }),
|
|
209
|
+
/* @__PURE__ */ o("div", {
|
|
210
|
+
className: "flex flex-wrap items-center justify-between gap-2 text-sm font-bold",
|
|
332
211
|
children: [
|
|
333
|
-
/* @__PURE__ */
|
|
334
|
-
/* @__PURE__ */
|
|
335
|
-
/* @__PURE__ */
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
]
|
|
346
|
-
}),
|
|
347
|
-
/* @__PURE__ */ c("span", {
|
|
348
|
-
className: "text-right",
|
|
349
|
-
children: [
|
|
350
|
-
"$",
|
|
351
|
-
(D / b.reduce((e, t) => e + t.employeeCount, 0) / 1e3).toFixed(0),
|
|
352
|
-
"K"
|
|
353
|
-
]
|
|
354
|
-
})
|
|
212
|
+
/* @__PURE__ */ a("span", { children: "Total" }),
|
|
213
|
+
/* @__PURE__ */ o("span", { children: [A, " employees"] }),
|
|
214
|
+
/* @__PURE__ */ o("span", { children: [
|
|
215
|
+
"$",
|
|
216
|
+
(w / 1e6).toFixed(1),
|
|
217
|
+
"M budget"
|
|
218
|
+
] }),
|
|
219
|
+
/* @__PURE__ */ o("span", { children: [
|
|
220
|
+
"$",
|
|
221
|
+
(j / 1e3).toFixed(0),
|
|
222
|
+
"K / employee"
|
|
223
|
+
] })
|
|
355
224
|
]
|
|
356
225
|
})
|
|
357
226
|
] })] })
|
|
@@ -359,6 +228,6 @@ function y() {
|
|
|
359
228
|
});
|
|
360
229
|
}
|
|
361
230
|
//#endregion
|
|
362
|
-
export {
|
|
231
|
+
export { v as DashboardExecutiveDashboardPage };
|
|
363
232
|
|
|
364
233
|
//# sourceMappingURL=DashboardExecutiveDashboardPage.js.map
|