@burdenoff/microfe-crewfoundry 2026.625.2 → 2026.703.1

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.
Files changed (82) hide show
  1. package/dist/crewfoundry/components/forms/ConfirmDialog.js +43 -0
  2. package/dist/crewfoundry/components/forms/ConfirmDialog.js.map +1 -0
  3. package/dist/crewfoundry/components/forms/FormModal.js +220 -0
  4. package/dist/crewfoundry/components/forms/FormModal.js.map +1 -0
  5. package/dist/crewfoundry/components/forms/formValues.js +20 -0
  6. package/dist/crewfoundry/components/forms/formValues.js.map +1 -0
  7. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +255 -65
  8. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
  9. package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js +28 -17
  10. package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js.map +1 -1
  11. package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js +57 -53
  12. package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js.map +1 -1
  13. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +32 -23
  14. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
  15. package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js +44 -29
  16. package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js.map +1 -1
  17. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +183 -57
  18. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
  19. package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js.map +1 -1
  20. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +214 -92
  21. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
  22. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +165 -131
  23. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
  24. package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js +163 -133
  25. package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js.map +1 -1
  26. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +269 -54
  27. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
  28. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +225 -78
  29. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
  30. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +213 -59
  31. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
  32. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +287 -90
  33. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
  34. package/dist/crewfoundry/pages/HiringJobsPagePage.js +49 -47
  35. package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
  36. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +166 -59
  37. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
  38. package/dist/crewfoundry/pages/HrEmployeesPagePage.js +274 -83
  39. package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
  40. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +198 -88
  41. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
  42. package/dist/crewfoundry/pages/HrPayrollPagePage.js +216 -88
  43. package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
  44. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +216 -66
  45. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
  46. package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js +6 -7
  47. package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js.map +1 -1
  48. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +83 -68
  49. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
  50. package/dist/crewfoundry/pages/LearningCoursesPagePage.js +167 -46
  51. package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
  52. package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +1 -1
  53. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +75 -55
  54. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
  55. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +152 -79
  56. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
  57. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +75 -63
  58. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
  59. package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js +3 -1
  60. package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js.map +1 -1
  61. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
  62. package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js +235 -87
  63. package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
  64. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +199 -86
  65. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
  66. package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
  67. package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js +21 -40
  68. package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js.map +1 -1
  69. package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js +117 -45
  70. package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js.map +1 -1
  71. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +249 -90
  72. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
  73. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +47 -45
  74. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
  75. package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js.map +1 -1
  76. package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js +262 -133
  77. package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
  78. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +144 -77
  79. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
  80. package/dist/crewfoundry/store/crewfoundryStore.js +306 -51
  81. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  82. package/package.json +1 -1
@@ -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 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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"}
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,143 +1,358 @@
1
1
  import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
2
- import { useState as t } from "react";
3
- import { Search as n, Star as r } from "lucide-react";
4
- import { Fragment as i, jsx as a, jsxs as o } from "react/jsx-runtime";
5
- import { Badge as s, Button as c, CardContent as l, GlassCard as u, GradientText as d, IllustratedEmptyState as f, Input as p, PagePurpose as m } from "@burdenoff/fe-libs/ui";
2
+ import { FormModal as t } from "../components/forms/FormModal.js";
3
+ import { ConfirmDialog as n } from "../components/forms/ConfirmDialog.js";
4
+ import { getNumber as r, getTags as i, getText as a, newClientId as o } from "../components/forms/formValues.js";
5
+ import { useState as s } from "react";
6
+ import { Pencil as c, Plus as l, Search as u, Star as d, Trash2 as f } from "lucide-react";
7
+ import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
8
+ import { Badge as g, Button as _, CardContent as v, GlassCard as y, GradientText as b, IllustratedEmptyState as x, Input as S, PagePurpose as C } from "@burdenoff/fe-libs/ui";
9
+ import { useGlobalUi as w } from "@burdenoff/fe-libs/shared/providers/shell";
6
10
  //#region src/crewfoundry/pages/HiringCandidatesPagePage.tsx
7
- function h() {
8
- let { candidates: h } = e(), [g, _] = t(""), [v, y] = t("all"), b = [...new Set(h.map((e) => e.status))], x = h.filter((e) => {
9
- let t = `${e.firstName} ${e.lastName} ${e.position} ${e.email}`.toLowerCase().includes(g.toLowerCase()), n = v === "all" || e.status === v;
11
+ var T = [
12
+ {
13
+ name: "firstName",
14
+ label: "First Name",
15
+ type: "text",
16
+ required: !0
17
+ },
18
+ {
19
+ name: "lastName",
20
+ label: "Last Name",
21
+ type: "text",
22
+ required: !0
23
+ },
24
+ {
25
+ name: "email",
26
+ label: "Email",
27
+ type: "email",
28
+ required: !0
29
+ },
30
+ {
31
+ name: "phone",
32
+ label: "Phone",
33
+ type: "text",
34
+ required: !0
35
+ },
36
+ {
37
+ name: "position",
38
+ label: "Position",
39
+ type: "text",
40
+ required: !0
41
+ },
42
+ {
43
+ name: "status",
44
+ label: "Status",
45
+ type: "select",
46
+ required: !0,
47
+ options: [
48
+ {
49
+ label: "New",
50
+ value: "new"
51
+ },
52
+ {
53
+ label: "Screening",
54
+ value: "screening"
55
+ },
56
+ {
57
+ label: "Interview",
58
+ value: "interview"
59
+ },
60
+ {
61
+ label: "Assessment",
62
+ value: "assessment"
63
+ },
64
+ {
65
+ label: "Offer",
66
+ value: "offer"
67
+ },
68
+ {
69
+ label: "Hired",
70
+ value: "hired"
71
+ },
72
+ {
73
+ label: "Rejected",
74
+ value: "rejected"
75
+ }
76
+ ]
77
+ },
78
+ {
79
+ name: "source",
80
+ label: "Source",
81
+ type: "text",
82
+ required: !0,
83
+ placeholder: "e.g. LinkedIn"
84
+ },
85
+ {
86
+ name: "experience",
87
+ label: "Experience (years)",
88
+ type: "number",
89
+ required: !0
90
+ },
91
+ {
92
+ name: "currentCompany",
93
+ label: "Current Company",
94
+ type: "text"
95
+ },
96
+ {
97
+ name: "rating",
98
+ label: "Rating (out of 5)",
99
+ type: "number"
100
+ },
101
+ {
102
+ name: "appliedDate",
103
+ label: "Applied Date",
104
+ type: "date"
105
+ },
106
+ {
107
+ name: "resumeUrl",
108
+ label: "Resume URL",
109
+ type: "text"
110
+ },
111
+ {
112
+ name: "skills",
113
+ label: "Skills",
114
+ type: "tags",
115
+ colSpan: 2
116
+ },
117
+ {
118
+ name: "notes",
119
+ label: "Notes",
120
+ type: "textarea",
121
+ colSpan: 2
122
+ }
123
+ ], E = (e) => ({
124
+ firstName: e.firstName,
125
+ lastName: e.lastName,
126
+ email: e.email,
127
+ phone: e.phone,
128
+ position: e.position,
129
+ status: e.status,
130
+ source: e.source,
131
+ experience: e.experience,
132
+ currentCompany: e.currentCompany,
133
+ rating: e.rating,
134
+ appliedDate: e.appliedDate,
135
+ resumeUrl: e.resumeUrl ?? "",
136
+ skills: e.skills,
137
+ notes: e.notes
138
+ }), D = (e) => {
139
+ let t = a(e, "appliedDate");
140
+ return {
141
+ firstName: a(e, "firstName"),
142
+ lastName: a(e, "lastName"),
143
+ email: a(e, "email"),
144
+ phone: a(e, "phone"),
145
+ position: a(e, "position"),
146
+ status: e.status,
147
+ source: a(e, "source"),
148
+ experience: r(e, "experience"),
149
+ currentCompany: a(e, "currentCompany"),
150
+ rating: r(e, "rating"),
151
+ appliedDate: t.trim() === "" ? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10) : t,
152
+ resumeUrl: a(e, "resumeUrl"),
153
+ skills: i(e, "skills"),
154
+ notes: a(e, "notes")
155
+ };
156
+ };
157
+ function O() {
158
+ let { showToast: r } = w(), { candidates: i, addCandidate: a, updateCandidate: O, removeCandidate: k } = e(), [A, j] = s(""), [M, N] = s("all"), [P, F] = s(!1), [I, L] = s(null), [R, z] = s(null), B = async (e) => {
159
+ await a({
160
+ id: o(),
161
+ ...D(e)
162
+ }), r("Candidate added", "success");
163
+ }, V = async (e) => {
164
+ I && (await O(I.id, D(e)), r("Candidate updated", "success"));
165
+ }, H = async () => {
166
+ R && (await k(R.id), r("Candidate removed", "success"));
167
+ }, U = [...new Set(i.map((e) => e.status))], W = i.filter((e) => {
168
+ let t = `${e.firstName} ${e.lastName} ${e.position} ${e.email}`.toLowerCase().includes(A.toLowerCase()), n = M === "all" || e.status === M;
10
169
  return t && n;
11
170
  });
12
- return /* @__PURE__ */ o("div", {
171
+ return /* @__PURE__ */ h("div", {
13
172
  className: "space-y-6 p-6",
14
173
  children: [
15
- /* @__PURE__ */ a("div", {
174
+ /* @__PURE__ */ h("div", {
16
175
  className: "flex items-center justify-between",
17
- children: /* @__PURE__ */ o("div", { children: [
18
- /* @__PURE__ */ a("h1", {
176
+ children: [/* @__PURE__ */ h("div", { children: [
177
+ /* @__PURE__ */ m("h1", {
19
178
  className: "text-2xl font-semibold",
20
- children: /* @__PURE__ */ a(d, { children: "Candidates" })
179
+ children: /* @__PURE__ */ m(b, { children: "Candidates" })
21
180
  }),
22
- /* @__PURE__ */ o("p", {
181
+ /* @__PURE__ */ h("p", {
23
182
  className: "text-sm text-text-secondary",
24
- children: [h.length, " candidates in pipeline"]
183
+ children: [i.length, " candidates in pipeline"]
25
184
  }),
26
- /* @__PURE__ */ a(m, {
185
+ /* @__PURE__ */ m(C, {
27
186
  className: "mt-1",
28
187
  children: "Your candidate pool — search, filter, and evaluate the people you're considering so you can fill open roles with the right talent."
29
188
  })
30
- ] })
189
+ ] }), /* @__PURE__ */ h(_, {
190
+ size: "sm",
191
+ onClick: () => F(!0),
192
+ children: [/* @__PURE__ */ m(l, { className: "h-4 w-4 mr-1" }), "Add Candidate"]
193
+ })]
31
194
  }),
32
- /* @__PURE__ */ o("div", {
195
+ /* @__PURE__ */ h("div", {
33
196
  className: "flex gap-3 flex-wrap",
34
- children: [/* @__PURE__ */ o("div", {
197
+ children: [/* @__PURE__ */ h("div", {
35
198
  className: "relative flex-1 max-w-sm",
36
- children: [/* @__PURE__ */ a(n, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ a(p, {
199
+ children: [/* @__PURE__ */ m(u, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ m(S, {
37
200
  placeholder: "Search candidates...",
38
201
  className: "pl-9",
39
- value: g,
40
- onChange: (e) => _(e.target.value)
202
+ value: A,
203
+ onChange: (e) => j(e.target.value)
41
204
  })]
42
- }), /* @__PURE__ */ o("div", {
205
+ }), /* @__PURE__ */ h("div", {
43
206
  className: "flex gap-1",
44
- children: [/* @__PURE__ */ a(c, {
45
- variant: v === "all" ? "default" : "outline",
207
+ children: [/* @__PURE__ */ m(_, {
208
+ variant: M === "all" ? "default" : "outline",
46
209
  size: "sm",
47
- onClick: () => y("all"),
210
+ onClick: () => N("all"),
48
211
  children: "All"
49
- }), b.map((e) => /* @__PURE__ */ a(c, {
50
- variant: v === e ? "default" : "outline",
212
+ }), U.map((e) => /* @__PURE__ */ m(_, {
213
+ variant: M === e ? "default" : "outline",
51
214
  size: "sm",
52
- onClick: () => y(e),
215
+ onClick: () => N(e),
53
216
  children: e
54
217
  }, e))]
55
218
  })]
56
219
  }),
57
- /* @__PURE__ */ a(u, {
220
+ /* @__PURE__ */ m(y, {
58
221
  treatment: "glass",
59
222
  glow: !0,
60
223
  className: "border-border-seam",
61
- children: /* @__PURE__ */ a(l, {
224
+ children: /* @__PURE__ */ m(v, {
62
225
  className: "p-0",
63
- children: x.length === 0 ? /* @__PURE__ */ a("div", {
226
+ children: W.length === 0 ? /* @__PURE__ */ m("div", {
64
227
  className: "p-6",
65
- children: /* @__PURE__ */ a(f, {
228
+ children: /* @__PURE__ */ m(x, {
66
229
  illustration: "empty-search",
67
230
  title: "No candidates match",
68
231
  description: "Try a different search term or status filter."
69
232
  })
70
- }) : /* @__PURE__ */ o(i, { children: [/* @__PURE__ */ o("div", {
71
- className: "grid grid-cols-7 gap-2 text-xs font-medium text-text-secondary p-4 border-b",
233
+ }) : /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ h("div", {
234
+ className: "grid grid-cols-8 gap-2 text-xs font-medium text-text-secondary p-4 border-b",
72
235
  children: [
73
- /* @__PURE__ */ a("span", { children: "Name" }),
74
- /* @__PURE__ */ a("span", { children: "Position" }),
75
- /* @__PURE__ */ a("span", { children: "Source" }),
76
- /* @__PURE__ */ a("span", {
236
+ /* @__PURE__ */ m("span", { children: "Name" }),
237
+ /* @__PURE__ */ m("span", { children: "Position" }),
238
+ /* @__PURE__ */ m("span", { children: "Source" }),
239
+ /* @__PURE__ */ m("span", {
77
240
  className: "text-right",
78
241
  children: "Experience"
79
242
  }),
80
- /* @__PURE__ */ a("span", {
243
+ /* @__PURE__ */ m("span", {
81
244
  className: "text-center",
82
245
  children: "Rating"
83
246
  }),
84
- /* @__PURE__ */ a("span", { children: "Applied" }),
85
- /* @__PURE__ */ a("span", {
247
+ /* @__PURE__ */ m("span", { children: "Applied" }),
248
+ /* @__PURE__ */ m("span", {
86
249
  className: "text-center",
87
250
  children: "Status"
251
+ }),
252
+ /* @__PURE__ */ m("span", {
253
+ className: "text-right",
254
+ children: "Actions"
88
255
  })
89
256
  ]
90
- }), x.map((e) => /* @__PURE__ */ o("div", {
91
- className: "grid grid-cols-7 gap-2 py-3 px-4 border-b last:border-0 text-sm hover:bg-bg-sunken/50",
257
+ }), W.map((e) => /* @__PURE__ */ h("div", {
258
+ className: "grid grid-cols-8 gap-2 py-3 px-4 border-b last:border-0 text-sm hover:bg-bg-sunken/50",
92
259
  children: [
93
- /* @__PURE__ */ o("div", { children: [/* @__PURE__ */ o("p", {
260
+ /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ h("p", {
94
261
  className: "font-medium",
95
262
  children: [
96
263
  e.firstName,
97
264
  " ",
98
265
  e.lastName
99
266
  ]
100
- }), /* @__PURE__ */ a("p", {
267
+ }), /* @__PURE__ */ m("p", {
101
268
  className: "text-xs text-text-secondary",
102
269
  children: e.email
103
270
  })] }),
104
- /* @__PURE__ */ a("span", {
271
+ /* @__PURE__ */ m("span", {
105
272
  className: "text-text-secondary",
106
273
  children: e.position
107
274
  }),
108
- /* @__PURE__ */ a(s, {
275
+ /* @__PURE__ */ m(g, {
109
276
  variant: "outline",
110
277
  className: "w-fit h-fit text-[10px]",
111
278
  children: e.source
112
279
  }),
113
- /* @__PURE__ */ o("span", {
280
+ /* @__PURE__ */ h("span", {
114
281
  className: "text-right",
115
282
  children: [e.experience, " yrs"]
116
283
  }),
117
- /* @__PURE__ */ o("div", {
284
+ /* @__PURE__ */ h("div", {
118
285
  className: "flex items-center justify-center gap-1",
119
- children: [/* @__PURE__ */ a(r, { className: "h-3 w-3 text-status-warning-text" }), /* @__PURE__ */ a("span", { children: e.rating })]
286
+ children: [/* @__PURE__ */ m(d, { className: "h-3 w-3 text-status-warning-text" }), /* @__PURE__ */ m("span", { children: e.rating })]
120
287
  }),
121
- /* @__PURE__ */ a("span", {
288
+ /* @__PURE__ */ m("span", {
122
289
  className: "text-text-secondary text-xs",
123
290
  children: e.appliedDate
124
291
  }),
125
- /* @__PURE__ */ a("div", {
292
+ /* @__PURE__ */ m("div", {
126
293
  className: "text-center",
127
- children: /* @__PURE__ */ a(s, {
294
+ children: /* @__PURE__ */ m(g, {
128
295
  variant: e.status === "hired" || e.status === "offer" ? "default" : e.status === "rejected" ? "destructive" : "secondary",
129
296
  className: "text-[10px]",
130
297
  children: e.status
131
298
  })
299
+ }),
300
+ /* @__PURE__ */ h("div", {
301
+ className: "flex items-center justify-end gap-1",
302
+ children: [/* @__PURE__ */ m(_, {
303
+ variant: "ghost",
304
+ size: "sm",
305
+ "aria-label": `Edit ${e.firstName} ${e.lastName}`,
306
+ onClick: () => L(e),
307
+ children: /* @__PURE__ */ m(c, { className: "h-3.5 w-3.5" })
308
+ }), /* @__PURE__ */ m(_, {
309
+ variant: "ghost",
310
+ size: "sm",
311
+ "aria-label": `Delete ${e.firstName} ${e.lastName}`,
312
+ onClick: () => z(e),
313
+ children: /* @__PURE__ */ m(f, { className: "h-3.5 w-3.5 text-status-error-fg" })
314
+ })]
132
315
  })
133
316
  ]
134
317
  }, e.id))] })
135
318
  })
319
+ }),
320
+ /* @__PURE__ */ m(t, {
321
+ open: P,
322
+ onOpenChange: F,
323
+ title: "Add Candidate",
324
+ description: "Add someone to your hiring pipeline.",
325
+ fields: T,
326
+ submitLabel: "Add candidate",
327
+ onSubmit: B
328
+ }),
329
+ /* @__PURE__ */ m(t, {
330
+ open: I !== null,
331
+ onOpenChange: (e) => {
332
+ e || L(null);
333
+ },
334
+ title: "Edit Candidate",
335
+ description: I ? `${I.firstName} ${I.lastName}` : void 0,
336
+ fields: T,
337
+ initialValues: I ? E(I) : void 0,
338
+ submitLabel: "Save changes",
339
+ onSubmit: V
340
+ }),
341
+ /* @__PURE__ */ m(n, {
342
+ open: R !== null,
343
+ onOpenChange: (e) => {
344
+ e || z(null);
345
+ },
346
+ title: "Remove candidate",
347
+ description: R ? `Remove ${R.firstName} ${R.lastName} from the pipeline?` : void 0,
348
+ confirmLabel: "Remove",
349
+ destructive: !0,
350
+ onConfirm: H
136
351
  })
137
352
  ]
138
353
  });
139
354
  }
140
355
  //#endregion
141
- export { h as HiringCandidatesPagePage };
356
+ export { O as HiringCandidatesPagePage };
142
357
 
143
358
  //# sourceMappingURL=HiringCandidatesPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HiringCandidatesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HiringCandidatesPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Badge,\n Button,\n CardContent,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Search, Star } from 'lucide-react';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function HiringCandidatesPagePage() {\n const { candidates } = useCrewFoundryStore();\n const [search, setSearch] = useState('');\n const [filterStatus, setFilterStatus] = useState<string>('all');\n\n const statuses = [...new Set(candidates.map((c) => c.status))];\n const filtered = candidates.filter((c) => {\n const matchSearch = `${c.firstName} ${c.lastName} ${c.position} ${c.email}`\n .toLowerCase()\n .includes(search.toLowerCase());\n const matchStatus = filterStatus === 'all' || c.status === filterStatus;\n return matchSearch && matchStatus;\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>Candidates</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{candidates.length} candidates in pipeline</p>\n <PagePurpose className=\"mt-1\">Your candidate pool — search, filter, and evaluate the people you&apos;re considering so you can fill open roles with the right talent.</PagePurpose>\n </div>\n </div>\n\n <div className=\"flex gap-3 flex-wrap\">\n <div className=\"relative flex-1 max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder=\"Search candidates...\"\n className=\"pl-9\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n <div className=\"flex gap-1\">\n <Button\n variant={filterStatus === 'all' ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setFilterStatus('all')}\n >\n All\n </Button>\n {statuses.map((status) => (\n <Button\n key={status}\n variant={filterStatus === status ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setFilterStatus(status)}\n >\n {status}\n </Button>\n ))}\n </div>\n </div>\n\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"p-0\">\n {filtered.length === 0 ? (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No candidates match\"\n description=\"Try a different search term or status filter.\"\n />\n </div>\n ) : (\n <>\n <div className=\"grid grid-cols-7 gap-2 text-xs font-medium text-text-secondary p-4 border-b\">\n <span>Name</span>\n <span>Position</span>\n <span>Source</span>\n <span className=\"text-right\">Experience</span>\n <span className=\"text-center\">Rating</span>\n <span>Applied</span>\n <span className=\"text-center\">Status</span>\n </div>\n {filtered.map((candidate) => (\n <div\n key={candidate.id}\n className=\"grid grid-cols-7 gap-2 py-3 px-4 border-b last:border-0 text-sm hover:bg-bg-sunken/50\"\n >\n <div>\n <p className=\"font-medium\">\n {candidate.firstName} {candidate.lastName}\n </p>\n <p className=\"text-xs text-text-secondary\">{candidate.email}</p>\n </div>\n <span className=\"text-text-secondary\">{candidate.position}</span>\n <Badge variant=\"outline\" className=\"w-fit h-fit text-[10px]\">\n {candidate.source}\n </Badge>\n <span className=\"text-right\">{candidate.experience} yrs</span>\n <div className=\"flex items-center justify-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n <span>{candidate.rating}</span>\n </div>\n <span className=\"text-text-secondary text-xs\">{candidate.appliedDate}</span>\n <div className=\"text-center\">\n <Badge\n variant={\n candidate.status === 'hired'\n ? 'default'\n : candidate.status === 'offer'\n ? 'default'\n : candidate.status === 'rejected'\n ? 'destructive'\n : 'secondary'\n }\n className=\"text-[10px]\"\n >\n {candidate.status}\n </Badge>\n </div>\n </div>\n ))}\n </>\n )}\n </CardContent>\n </GlassCard>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"HiringCandidatesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HiringCandidatesPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Badge,\n Button,\n CardContent,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { Pencil, Plus, Search, Star, Trash2 } from 'lucide-react';\nimport { useCrewFoundryStore, type Candidate } from '../store/crewfoundryStore';\nimport { FormModal, type FieldConfig, type FormValues } from '../components/forms/FormModal';\nimport { ConfirmDialog } from '../components/forms/ConfirmDialog';\nimport { getNumber, getTags, getText, newClientId } from '../components/forms/formValues';\n\nconst CANDIDATE_STATUS_OPTIONS: FieldConfig['options'] = [\n { label: 'New', value: 'new' },\n { label: 'Screening', value: 'screening' },\n { label: 'Interview', value: 'interview' },\n { label: 'Assessment', value: 'assessment' },\n { label: 'Offer', value: 'offer' },\n { label: 'Hired', value: 'hired' },\n { label: 'Rejected', value: 'rejected' },\n];\n\nconst CANDIDATE_FIELDS: FieldConfig[] = [\n { name: 'firstName', label: 'First Name', type: 'text', required: true },\n { name: 'lastName', label: 'Last Name', type: 'text', required: true },\n { name: 'email', label: 'Email', type: 'email', required: true },\n { name: 'phone', label: 'Phone', type: 'text', required: true },\n { name: 'position', label: 'Position', type: 'text', required: true },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n required: true,\n options: CANDIDATE_STATUS_OPTIONS,\n },\n { name: 'source', label: 'Source', type: 'text', required: true, placeholder: 'e.g. LinkedIn' },\n { name: 'experience', label: 'Experience (years)', type: 'number', required: true },\n { name: 'currentCompany', label: 'Current Company', type: 'text' },\n { name: 'rating', label: 'Rating (out of 5)', type: 'number' },\n { name: 'appliedDate', label: 'Applied Date', type: 'date' },\n { name: 'resumeUrl', label: 'Resume URL', type: 'text' },\n { name: 'skills', label: 'Skills', type: 'tags', colSpan: 2 },\n { name: 'notes', label: 'Notes', type: 'textarea', colSpan: 2 },\n];\n\nconst candidateToValues = (candidate: Candidate): FormValues => ({\n firstName: candidate.firstName,\n lastName: candidate.lastName,\n email: candidate.email,\n phone: candidate.phone,\n position: candidate.position,\n status: candidate.status,\n source: candidate.source,\n experience: candidate.experience,\n currentCompany: candidate.currentCompany,\n rating: candidate.rating,\n appliedDate: candidate.appliedDate,\n resumeUrl: candidate.resumeUrl ?? '',\n skills: candidate.skills,\n notes: candidate.notes,\n});\n\nconst valuesToCandidateFields = (values: FormValues): Omit<Candidate, 'id'> => {\n const appliedDate = getText(values, 'appliedDate');\n return {\n firstName: getText(values, 'firstName'),\n lastName: getText(values, 'lastName'),\n email: getText(values, 'email'),\n phone: getText(values, 'phone'),\n position: getText(values, 'position'),\n status: values.status as Candidate['status'],\n source: getText(values, 'source'),\n experience: getNumber(values, 'experience'),\n currentCompany: getText(values, 'currentCompany'),\n rating: getNumber(values, 'rating'),\n appliedDate: appliedDate.trim() !== '' ? appliedDate : new Date().toISOString().slice(0, 10),\n resumeUrl: getText(values, 'resumeUrl'),\n skills: getTags(values, 'skills'),\n notes: getText(values, 'notes'),\n };\n};\n\nexport function HiringCandidatesPagePage() {\n const { showToast } = useGlobalUi();\n const { candidates, addCandidate, updateCandidate, removeCandidate } = useCrewFoundryStore();\n const [search, setSearch] = useState('');\n const [filterStatus, setFilterStatus] = useState<string>('all');\n const [createOpen, setCreateOpen] = useState(false);\n const [editTarget, setEditTarget] = useState<Candidate | null>(null);\n const [deleteTarget, setDeleteTarget] = useState<Candidate | null>(null);\n\n const handleCreate = async (values: FormValues) => {\n await addCandidate({ id: newClientId(), ...valuesToCandidateFields(values) });\n showToast('Candidate added', 'success');\n };\n\n const handleEdit = async (values: FormValues) => {\n if (!editTarget) {\n return;\n }\n await updateCandidate(editTarget.id, valuesToCandidateFields(values));\n showToast('Candidate updated', 'success');\n };\n\n const handleDelete = async () => {\n if (!deleteTarget) {\n return;\n }\n await removeCandidate(deleteTarget.id);\n showToast('Candidate removed', 'success');\n };\n\n const statuses = [...new Set(candidates.map((c) => c.status))];\n const filtered = candidates.filter((c) => {\n const matchSearch = `${c.firstName} ${c.lastName} ${c.position} ${c.email}`\n .toLowerCase()\n .includes(search.toLowerCase());\n const matchStatus = filterStatus === 'all' || c.status === filterStatus;\n return matchSearch && matchStatus;\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>Candidates</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{candidates.length} candidates in pipeline</p>\n <PagePurpose className=\"mt-1\">Your candidate pool — search, filter, and evaluate the people you&apos;re considering so you can fill open roles with the right talent.</PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => setCreateOpen(true)}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add Candidate\n </Button>\n </div>\n\n <div className=\"flex gap-3 flex-wrap\">\n <div className=\"relative flex-1 max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder=\"Search candidates...\"\n className=\"pl-9\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n <div className=\"flex gap-1\">\n <Button\n variant={filterStatus === 'all' ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setFilterStatus('all')}\n >\n All\n </Button>\n {statuses.map((status) => (\n <Button\n key={status}\n variant={filterStatus === status ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setFilterStatus(status)}\n >\n {status}\n </Button>\n ))}\n </div>\n </div>\n\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"p-0\">\n {filtered.length === 0 ? (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No candidates match\"\n description=\"Try a different search term or status filter.\"\n />\n </div>\n ) : (\n <>\n <div className=\"grid grid-cols-8 gap-2 text-xs font-medium text-text-secondary p-4 border-b\">\n <span>Name</span>\n <span>Position</span>\n <span>Source</span>\n <span className=\"text-right\">Experience</span>\n <span className=\"text-center\">Rating</span>\n <span>Applied</span>\n <span className=\"text-center\">Status</span>\n <span className=\"text-right\">Actions</span>\n </div>\n {filtered.map((candidate) => (\n <div\n key={candidate.id}\n className=\"grid grid-cols-8 gap-2 py-3 px-4 border-b last:border-0 text-sm hover:bg-bg-sunken/50\"\n >\n <div>\n <p className=\"font-medium\">\n {candidate.firstName} {candidate.lastName}\n </p>\n <p className=\"text-xs text-text-secondary\">{candidate.email}</p>\n </div>\n <span className=\"text-text-secondary\">{candidate.position}</span>\n <Badge variant=\"outline\" className=\"w-fit h-fit text-[10px]\">\n {candidate.source}\n </Badge>\n <span className=\"text-right\">{candidate.experience} yrs</span>\n <div className=\"flex items-center justify-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n <span>{candidate.rating}</span>\n </div>\n <span className=\"text-text-secondary text-xs\">{candidate.appliedDate}</span>\n <div className=\"text-center\">\n <Badge\n variant={\n candidate.status === 'hired'\n ? 'default'\n : candidate.status === 'offer'\n ? 'default'\n : candidate.status === 'rejected'\n ? 'destructive'\n : 'secondary'\n }\n className=\"text-[10px]\"\n >\n {candidate.status}\n </Badge>\n </div>\n <div className=\"flex items-center justify-end gap-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Edit ${candidate.firstName} ${candidate.lastName}`}\n onClick={() => setEditTarget(candidate)}\n >\n <Pencil className=\"h-3.5 w-3.5\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Delete ${candidate.firstName} ${candidate.lastName}`}\n onClick={() => setDeleteTarget(candidate)}\n >\n <Trash2 className=\"h-3.5 w-3.5 text-status-error-fg\" />\n </Button>\n </div>\n </div>\n ))}\n </>\n )}\n </CardContent>\n </GlassCard>\n\n <FormModal\n open={createOpen}\n onOpenChange={setCreateOpen}\n title=\"Add Candidate\"\n description=\"Add someone to your hiring pipeline.\"\n fields={CANDIDATE_FIELDS}\n submitLabel=\"Add candidate\"\n onSubmit={handleCreate}\n />\n <FormModal\n open={editTarget !== null}\n onOpenChange={(open) => {\n if (!open) {\n setEditTarget(null);\n }\n }}\n title=\"Edit Candidate\"\n description={editTarget ? `${editTarget.firstName} ${editTarget.lastName}` : undefined}\n fields={CANDIDATE_FIELDS}\n initialValues={editTarget ? candidateToValues(editTarget) : undefined}\n submitLabel=\"Save changes\"\n onSubmit={handleEdit}\n />\n <ConfirmDialog\n open={deleteTarget !== null}\n onOpenChange={(open) => {\n if (!open) {\n setDeleteTarget(null);\n }\n }}\n title=\"Remove candidate\"\n description={\n deleteTarget\n ? `Remove ${deleteTarget.firstName} ${deleteTarget.lastName} from the pipeline?`\n : undefined\n }\n confirmLabel=\"Remove\"\n destructive\n onConfirm={handleDelete}\n />\n </div>\n );\n}\n"],"mappings":"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"}