@burdenoff/microfe-crewfoundry 2026.704.5 → 2026.704.7

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 (155) hide show
  1. package/dist/crewfoundry/CrewFoundryRoutes.js +51 -43
  2. package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
  3. package/dist/crewfoundry/components/forms/formValues.js +5 -2
  4. package/dist/crewfoundry/components/forms/formValues.js.map +1 -1
  5. package/dist/crewfoundry/components/viz/AllocationBar.js +68 -0
  6. package/dist/crewfoundry/components/viz/AllocationBar.js.map +1 -0
  7. package/dist/crewfoundry/components/viz/AreaChart.js +102 -0
  8. package/dist/crewfoundry/components/viz/AreaChart.js.map +1 -0
  9. package/dist/crewfoundry/components/viz/AvatarStack.js +36 -0
  10. package/dist/crewfoundry/components/viz/AvatarStack.js.map +1 -0
  11. package/dist/crewfoundry/components/viz/BarChart.js +83 -0
  12. package/dist/crewfoundry/components/viz/BarChart.js.map +1 -0
  13. package/dist/crewfoundry/components/viz/CertificateCard.js +118 -0
  14. package/dist/crewfoundry/components/viz/CertificateCard.js.map +1 -0
  15. package/dist/crewfoundry/components/viz/DonutChart.js +109 -0
  16. package/dist/crewfoundry/components/viz/DonutChart.js.map +1 -0
  17. package/dist/crewfoundry/components/viz/HBarFunnel.js +54 -0
  18. package/dist/crewfoundry/components/viz/HBarFunnel.js.map +1 -0
  19. package/dist/crewfoundry/components/viz/Heatmap.js +91 -0
  20. package/dist/crewfoundry/components/viz/Heatmap.js.map +1 -0
  21. package/dist/crewfoundry/components/viz/KanbanBoard.js +50 -0
  22. package/dist/crewfoundry/components/viz/KanbanBoard.js.map +1 -0
  23. package/dist/crewfoundry/components/viz/LineChart.js +123 -0
  24. package/dist/crewfoundry/components/viz/LineChart.js.map +1 -0
  25. package/dist/crewfoundry/components/viz/OrgTree.js +83 -0
  26. package/dist/crewfoundry/components/viz/OrgTree.js.map +1 -0
  27. package/dist/crewfoundry/components/viz/PathSteps.js +68 -0
  28. package/dist/crewfoundry/components/viz/PathSteps.js.map +1 -0
  29. package/dist/crewfoundry/components/viz/ProgressRing.js +68 -0
  30. package/dist/crewfoundry/components/viz/ProgressRing.js.map +1 -0
  31. package/dist/crewfoundry/components/viz/RatingStars.js +51 -0
  32. package/dist/crewfoundry/components/viz/RatingStars.js.map +1 -0
  33. package/dist/crewfoundry/components/viz/SegmentedTabs.js +69 -0
  34. package/dist/crewfoundry/components/viz/SegmentedTabs.js.map +1 -0
  35. package/dist/crewfoundry/components/viz/SkillBar.js +3 -0
  36. package/dist/crewfoundry/components/viz/Sparkline.js +74 -0
  37. package/dist/crewfoundry/components/viz/Sparkline.js.map +1 -0
  38. package/dist/crewfoundry/components/viz/StatCard.js +60 -0
  39. package/dist/crewfoundry/components/viz/StatCard.js.map +1 -0
  40. package/dist/crewfoundry/components/viz/StepProgress.js +3 -0
  41. package/dist/crewfoundry/components/viz/Timeline.js +66 -0
  42. package/dist/crewfoundry/components/viz/Timeline.js.map +1 -0
  43. package/dist/crewfoundry/components/viz/index.js +23 -0
  44. package/dist/crewfoundry/components/viz/lib/Avatar.js +30 -0
  45. package/dist/crewfoundry/components/viz/lib/Avatar.js.map +1 -0
  46. package/dist/crewfoundry/components/viz/lib/CartesianFrame.js +119 -0
  47. package/dist/crewfoundry/components/viz/lib/CartesianFrame.js.map +1 -0
  48. package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js +35 -0
  49. package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js.map +1 -0
  50. package/dist/crewfoundry/components/viz/lib/format.js +21 -0
  51. package/dist/crewfoundry/components/viz/lib/format.js.map +1 -0
  52. package/dist/crewfoundry/components/viz/lib/geometry.js +69 -0
  53. package/dist/crewfoundry/components/viz/lib/geometry.js.map +1 -0
  54. package/dist/crewfoundry/components/viz/lib/hooks.js +39 -0
  55. package/dist/crewfoundry/components/viz/lib/hooks.js.map +1 -0
  56. package/dist/crewfoundry/components/viz/lib/palette.js +27 -0
  57. package/dist/crewfoundry/components/viz/lib/palette.js.map +1 -0
  58. package/dist/crewfoundry/lib/analytics.js +323 -0
  59. package/dist/crewfoundry/lib/analytics.js.map +1 -0
  60. package/dist/crewfoundry/lib/companyFinance.js +16 -0
  61. package/dist/crewfoundry/lib/companyFinance.js.map +1 -0
  62. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +226 -283
  63. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  64. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +107 -120
  65. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
  66. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +122 -162
  67. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
  68. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +121 -158
  69. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
  70. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +316 -211
  71. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
  72. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +75 -27
  73. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
  74. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +167 -165
  75. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
  76. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +168 -109
  77. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
  78. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +401 -290
  79. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
  80. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +84 -75
  81. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
  82. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +368 -174
  83. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
  84. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +236 -201
  85. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
  86. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +369 -196
  87. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
  88. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +252 -249
  89. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
  90. package/dist/crewfoundry/pages/HiringJobsPagePage.js +210 -110
  91. package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
  92. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +216 -178
  93. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
  94. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +385 -0
  95. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js.map +1 -0
  96. package/dist/crewfoundry/pages/HrEmployeesPagePage.js +189 -130
  97. package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
  98. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +397 -241
  99. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
  100. package/dist/crewfoundry/pages/HrPayrollPagePage.js +262 -147
  101. package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
  102. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +345 -167
  103. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
  104. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +98 -24
  105. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
  106. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +35 -31
  107. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
  108. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +289 -108
  109. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
  110. package/dist/crewfoundry/pages/LearningCoursesPagePage.js +221 -114
  111. package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
  112. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +136 -133
  113. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
  114. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +148 -97
  115. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
  116. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +264 -157
  117. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
  118. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
  119. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +85 -93
  120. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
  121. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
  122. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
  123. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
  124. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
  125. package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +28 -25
  126. package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
  127. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +290 -138
  128. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
  129. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
  130. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
  131. package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
  132. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +65 -61
  133. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
  134. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
  135. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
  136. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
  137. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
  138. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +142 -76
  139. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
  140. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
  141. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
  142. package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
  143. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
  144. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
  145. package/dist/crewfoundry/store/crewfoundryStore.js +1 -1
  146. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  147. package/dist/crewfoundry/utils/cn.js +10 -0
  148. package/dist/crewfoundry/utils/cn.js.map +1 -0
  149. package/dist/crewfoundry/utils/courseProgress.js +46 -0
  150. package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
  151. package/dist/node_modules/clsx/dist/clsx.js +18 -0
  152. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  153. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
  154. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  155. package/package.json +1 -1
@@ -1,29 +1,32 @@
1
1
  import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
2
2
  import { formatEnumLabel as t } from "../utils/formatEnumLabel.js";
3
- import { useMemo as n } from "react";
4
- import { Briefcase as r, Clock as i, Target as a, Users as o } from "lucide-react";
5
- import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
6
- import { Badge as u, Card as d, CardContent as f, CardDescription as p, CardHeader as m, CardTitle as h, GlassCard as g, GradientText as _, IllustratedEmptyState as v, PagePurpose as y, Pagination as b, ResponsiveTable as x } from "@burdenoff/fe-libs/ui";
7
- import { usePagination as S } from "@burdenoff/fe-libs/shared/hooks";
3
+ import { LineChart as n } from "../components/viz/LineChart.js";
4
+ import { BarChart as r } from "../components/viz/BarChart.js";
5
+ import "../components/viz/index.js";
6
+ import { useMemo as i } from "react";
7
+ import { Briefcase as a, Clock as o, Target as s, Users as c } from "lucide-react";
8
+ import { Fragment as l, jsx as u, jsxs as d } from "react/jsx-runtime";
9
+ import { Badge as f, Card as p, CardContent as m, CardDescription as h, CardHeader as g, CardTitle as _, GlassCard as v, GradientText as y, IllustratedEmptyState as b, PagePurpose as x, Pagination as S, ResponsiveTable as C } from "@burdenoff/fe-libs/ui";
10
+ import { usePagination as w } from "@burdenoff/fe-libs/shared/hooks";
8
11
  //#region src/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.tsx
9
- var C = (e) => {
12
+ var T = (e) => {
10
13
  let t = new Date(e);
11
14
  return `${t.getFullYear()}-${String(t.getMonth()).padStart(2, "0")}`;
12
- }, w = (/* @__PURE__ */ new Date("2026-03-01")).getTime();
13
- function T() {
14
- let { jobPostings: T, candidates: E, interviews: D } = e(), O = n(() => E.length === 0 && D.length === 0 ? [] : Array.from(new Set([...E.map((e) => C(e.appliedDate)), ...D.map((e) => C(e.date))])).sort().slice(-6).map((e) => {
15
+ }, E = (/* @__PURE__ */ new Date("2026-03-01")).getTime();
16
+ function D() {
17
+ let { jobPostings: D, candidates: O, interviews: k } = e(), A = i(() => O.length === 0 && k.length === 0 ? [] : Array.from(new Set([...O.map((e) => T(e.appliedDate)), ...k.map((e) => T(e.date))])).sort().slice(-6).map((e) => {
15
18
  let [t, n] = e.split("-").map(Number), r = new Date(t, n, 1).toLocaleString("en-US", {
16
19
  month: "short",
17
20
  year: "2-digit"
18
- }), i = E.filter((t) => C(t.appliedDate) === e);
21
+ }), i = O.filter((t) => T(t.appliedDate) === e);
19
22
  return {
20
23
  month: r,
21
24
  applications: i.length,
22
- interviews: D.filter((t) => C(t.date) === e).length,
25
+ interviews: k.filter((t) => T(t.date) === e).length,
23
26
  hires: i.filter((e) => e.status === "hired").length
24
27
  };
25
- }), [E, D]), k = n(() => {
26
- let e = E.reduce((e, t) => {
28
+ }), [O, k]), j = i(() => {
29
+ let e = O.reduce((e, t) => {
27
30
  let n = t.source || "Unknown", r = e[n] || {
28
31
  applications: 0,
29
32
  hires: 0
@@ -36,236 +39,196 @@ function T() {
36
39
  hires: t.hires,
37
40
  conversionRate: Number((t.hires / Math.max(t.applications, 1) * 100).toFixed(1))
38
41
  })).sort((e, t) => t.conversionRate - e.conversionRate);
39
- }, [E]), A = n(() => {
40
- let e = T.filter((e) => e.status === "active");
42
+ }, [O]), M = i(() => {
43
+ let e = D.filter((e) => e.status === "active");
41
44
  if (e.length === 0) return 0;
42
45
  let t = e.reduce((e, t) => {
43
46
  let n = new Date(t.postedDate).getTime();
44
- return Number.isNaN(n) ? e : e + Math.max(0, (w - n) / (1e3 * 60 * 60 * 24));
47
+ return Number.isNaN(n) ? e : e + Math.max(0, (E - n) / (1e3 * 60 * 60 * 24));
45
48
  }, 0);
46
49
  return Math.round(t / e.length);
47
- }, [T]), j = T.filter((e) => e.status === "active"), M = T.reduce((e, t) => e + t.applicants, 0), N = D.filter((e) => e.status === "scheduled").length, P = D.filter((e) => e.status === "completed").length, F = E.filter((e) => e.status === "offer").length, I = E.filter((e) => e.status === "hired").length, L = E.filter((e) => [
50
+ }, [D]), N = D.filter((e) => e.status === "active"), P = D.reduce((e, t) => e + t.applicants, 0), F = k.filter((e) => e.status === "scheduled").length, I = k.filter((e) => e.status === "completed").length, L = O.filter((e) => e.status === "offer").length, R = O.filter((e) => e.status === "hired").length, z = O.filter((e) => [
48
51
  "interview",
49
52
  "assessment",
50
53
  "offer",
51
54
  "hired"
52
- ].includes(e.status)).length, R = E.filter((e) => ["offer", "hired"].includes(e.status)).length, z = Math.round(R / Math.max(L, 1) * 100), B = Math.round(I / Math.max(F + I, 1) * 100), V = Math.max(1, ...O.map((e) => e.applications)), H = [
55
+ ].includes(e.status)).length, B = O.filter((e) => ["offer", "hired"].includes(e.status)).length, V = Math.round(B / Math.max(z, 1) * 100), H = Math.round(R / Math.max(L + R, 1) * 100), U = A.map((e) => ({
56
+ label: e.month,
57
+ value: e.applications
58
+ })), W = A.map((e) => e.hires), G = [
53
59
  {
54
60
  status: "New",
55
- count: E.filter((e) => e.status === "new").length,
61
+ count: O.filter((e) => e.status === "new").length,
56
62
  color: "bg-text-secondary"
57
63
  },
58
64
  {
59
65
  status: "Screening",
60
- count: E.filter((e) => e.status === "screening").length,
66
+ count: O.filter((e) => e.status === "screening").length,
61
67
  color: "bg-status-info-text"
62
68
  },
63
69
  {
64
70
  status: "Interview",
65
- count: E.filter((e) => e.status === "interview").length,
71
+ count: O.filter((e) => e.status === "interview").length,
66
72
  color: "bg-status-info-text"
67
73
  },
68
74
  {
69
75
  status: "Assessment",
70
- count: E.filter((e) => e.status === "assessment").length,
76
+ count: O.filter((e) => e.status === "assessment").length,
71
77
  color: "bg-action-primary-bg"
72
78
  },
73
79
  {
74
80
  status: "Offer",
75
- count: F,
81
+ count: L,
76
82
  color: "bg-status-warning-text"
77
83
  },
78
84
  {
79
85
  status: "Hired",
80
- count: I,
86
+ count: R,
81
87
  color: "bg-status-success-text"
82
88
  },
83
89
  {
84
90
  status: "Rejected",
85
- count: E.filter((e) => e.status === "rejected").length,
91
+ count: O.filter((e) => e.status === "rejected").length,
86
92
  color: "bg-status-error-text"
87
93
  }
88
- ], U = H.reduce((e, t) => e + t.count, 0), W = [...j].sort((e, t) => t.applicants - e.applicants), { page: G, pageSize: K, offset: q, setPage: J } = S({ initialPageSize: 8 }), Y = W.slice(q, q + K);
89
- return /* @__PURE__ */ l("div", {
94
+ ], K = G.reduce((e, t) => e + t.count, 0), q = G.map((e) => ({
95
+ label: e.status,
96
+ value: e.count
97
+ })), J = [...N].sort((e, t) => t.applicants - e.applicants), { page: Y, pageSize: X, offset: Z, setPage: Q } = w({ initialPageSize: 8 }), $ = J.slice(Z, Z + X);
98
+ return /* @__PURE__ */ d("div", {
90
99
  className: "space-y-6 p-6",
91
100
  children: [
92
- /* @__PURE__ */ c("div", {
101
+ /* @__PURE__ */ u("div", {
93
102
  className: "flex items-center justify-between",
94
- children: /* @__PURE__ */ l("div", { children: [
95
- /* @__PURE__ */ c("h1", {
103
+ children: /* @__PURE__ */ d("div", { children: [
104
+ /* @__PURE__ */ u("h1", {
96
105
  className: "text-2xl font-semibold",
97
- children: /* @__PURE__ */ c(_, { children: "Hiring Analytics" })
106
+ children: /* @__PURE__ */ u(y, { children: "Hiring Analytics" })
98
107
  }),
99
- /* @__PURE__ */ c("p", {
108
+ /* @__PURE__ */ u("p", {
100
109
  className: "text-sm text-text-secondary",
101
110
  children: "Recruitment performance and pipeline analysis"
102
111
  }),
103
- /* @__PURE__ */ c(y, {
112
+ /* @__PURE__ */ u(x, {
104
113
  className: "mt-1",
105
114
  children: "Measure how your hiring funnel performs — applications, time-to-hire, and source quality — to make recruiting faster and more effective."
106
115
  })
107
116
  ] })
108
117
  }),
109
- /* @__PURE__ */ l("div", {
118
+ /* @__PURE__ */ d("div", {
110
119
  className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4",
111
120
  children: [
112
- /* @__PURE__ */ l(g, {
121
+ /* @__PURE__ */ d(v, {
113
122
  treatment: "glass",
114
123
  glow: !0,
115
124
  className: "border-border-seam",
116
- children: [/* @__PURE__ */ l(m, {
125
+ children: [/* @__PURE__ */ d(g, {
117
126
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
118
- children: [/* @__PURE__ */ c(h, {
127
+ children: [/* @__PURE__ */ u(_, {
119
128
  className: "text-sm font-medium",
120
129
  children: "Active Postings"
121
- }), /* @__PURE__ */ c(r, { className: "h-4 w-4 text-text-secondary" })]
122
- }), /* @__PURE__ */ l(f, { children: [/* @__PURE__ */ c("div", {
130
+ }), /* @__PURE__ */ u(a, { className: "h-4 w-4 text-text-secondary" })]
131
+ }), /* @__PURE__ */ d(m, { children: [/* @__PURE__ */ u("div", {
123
132
  className: "text-2xl font-bold tabular-nums",
124
- children: j.length
125
- }), /* @__PURE__ */ l("p", {
133
+ children: N.length
134
+ }), /* @__PURE__ */ d("p", {
126
135
  className: "text-xs text-text-secondary",
127
- children: [M, " total applicants"]
136
+ children: [P, " total applicants"]
128
137
  })] })]
129
138
  }),
130
- /* @__PURE__ */ l(g, {
139
+ /* @__PURE__ */ d(v, {
131
140
  treatment: "metric",
132
141
  className: "border-border-seam",
133
- children: [/* @__PURE__ */ l(m, {
142
+ children: [/* @__PURE__ */ d(g, {
134
143
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
135
- children: [/* @__PURE__ */ c(h, {
144
+ children: [/* @__PURE__ */ u(_, {
136
145
  className: "text-sm font-medium",
137
146
  children: "Avg Days Open"
138
- }), /* @__PURE__ */ c(i, { className: "h-4 w-4 text-text-secondary" })]
139
- }), /* @__PURE__ */ l(f, { children: [/* @__PURE__ */ l("div", {
147
+ }), /* @__PURE__ */ u(o, { className: "h-4 w-4 text-text-secondary" })]
148
+ }), /* @__PURE__ */ d(m, { children: [/* @__PURE__ */ d("div", {
140
149
  className: "text-2xl font-bold tabular-nums",
141
- children: [A, " days"]
142
- }), /* @__PURE__ */ c("p", {
150
+ children: [M, " days"]
151
+ }), /* @__PURE__ */ u("p", {
143
152
  className: "text-xs text-text-secondary",
144
153
  children: "Across active postings"
145
154
  })] })]
146
155
  }),
147
- /* @__PURE__ */ l(g, {
156
+ /* @__PURE__ */ d(v, {
148
157
  treatment: "metric",
149
158
  className: "border-border-seam",
150
- children: [/* @__PURE__ */ l(m, {
159
+ children: [/* @__PURE__ */ d(g, {
151
160
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
152
- children: [/* @__PURE__ */ c(h, {
161
+ children: [/* @__PURE__ */ u(_, {
153
162
  className: "text-sm font-medium",
154
163
  children: "Interview to Offer"
155
- }), /* @__PURE__ */ c(a, { className: "h-4 w-4 text-text-secondary" })]
156
- }), /* @__PURE__ */ l(f, { children: [/* @__PURE__ */ l("div", {
164
+ }), /* @__PURE__ */ u(s, { className: "h-4 w-4 text-text-secondary" })]
165
+ }), /* @__PURE__ */ d(m, { children: [/* @__PURE__ */ d("div", {
157
166
  className: "text-2xl font-bold tabular-nums",
158
- children: [z, "%"]
159
- }), /* @__PURE__ */ l("p", {
167
+ children: [V, "%"]
168
+ }), /* @__PURE__ */ d("p", {
160
169
  className: "text-xs text-text-secondary",
161
170
  children: [
162
- N,
171
+ F,
163
172
  " scheduled, ",
164
- P,
173
+ I,
165
174
  " completed"
166
175
  ]
167
176
  })] })]
168
177
  }),
169
- /* @__PURE__ */ l(g, {
178
+ /* @__PURE__ */ d(v, {
170
179
  treatment: "metric",
171
180
  className: "border-border-seam",
172
- children: [/* @__PURE__ */ l(m, {
181
+ children: [/* @__PURE__ */ d(g, {
173
182
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
174
- children: [/* @__PURE__ */ c(h, {
183
+ children: [/* @__PURE__ */ u(_, {
175
184
  className: "text-sm font-medium",
176
185
  children: "Offer Acceptance"
177
- }), /* @__PURE__ */ c(o, { className: "h-4 w-4 text-text-secondary" })]
178
- }), /* @__PURE__ */ l(f, { children: [/* @__PURE__ */ l("div", {
186
+ }), /* @__PURE__ */ u(c, { className: "h-4 w-4 text-text-secondary" })]
187
+ }), /* @__PURE__ */ d(m, { children: [/* @__PURE__ */ d("div", {
179
188
  className: "text-2xl font-bold tabular-nums",
180
- children: [B, "%"]
181
- }), /* @__PURE__ */ l("p", {
189
+ children: [H, "%"]
190
+ }), /* @__PURE__ */ d("p", {
182
191
  className: "text-xs text-text-secondary",
183
- children: [I, " hired to date"]
192
+ children: [R, " hired to date"]
184
193
  })] })]
185
194
  })
186
195
  ]
187
196
  }),
188
- /* @__PURE__ */ l("div", {
197
+ /* @__PURE__ */ d("div", {
189
198
  className: "grid gap-4 md:grid-cols-7",
190
- children: [/* @__PURE__ */ l(d, {
199
+ children: [/* @__PURE__ */ d(p, {
191
200
  className: "col-span-4",
192
- children: [/* @__PURE__ */ l(m, { children: [/* @__PURE__ */ c(h, { children: "Monthly Hiring Activity" }), /* @__PURE__ */ c(p, { children: "Applications, interviews, and hires over time" })] }), /* @__PURE__ */ l(f, {
193
- className: "space-y-3",
194
- children: [O.length === 0 && /* @__PURE__ */ c("p", {
195
- className: "py-6 text-center text-sm text-text-secondary",
196
- children: "No hiring activity recorded yet."
197
- }), O.map((e) => /* @__PURE__ */ l("div", {
198
- className: "flex items-center gap-3",
199
- children: [
200
- /* @__PURE__ */ c("span", {
201
- className: "w-12 text-sm text-text-secondary",
202
- children: e.month
203
- }),
204
- /* @__PURE__ */ c("div", {
205
- className: "flex-1 h-5 bg-bg-sunken rounded overflow-hidden",
206
- children: /* @__PURE__ */ c("div", {
207
- className: "h-5 bg-action-primary-bg rounded",
208
- style: { width: `${Math.round(e.applications / V * 100)}%` }
209
- })
210
- }),
211
- /* @__PURE__ */ l("div", {
212
- className: "flex gap-1 w-48 justify-end",
213
- children: [
214
- /* @__PURE__ */ l(u, {
215
- variant: "outline",
216
- className: "text-[10px]",
217
- children: [e.applications, " apps"]
218
- }),
219
- /* @__PURE__ */ l(u, {
220
- variant: "secondary",
221
- className: "text-[10px]",
222
- children: [e.interviews, " int"]
223
- }),
224
- /* @__PURE__ */ l(u, {
225
- variant: "default",
226
- className: "text-[10px]",
227
- children: [e.hires, " hired"]
228
- })
229
- ]
230
- })
231
- ]
232
- }, e.month))]
233
- })]
234
- }), /* @__PURE__ */ l(d, {
201
+ children: [/* @__PURE__ */ d(g, { children: [/* @__PURE__ */ u(_, { children: "Monthly Hiring Activity" }), /* @__PURE__ */ u(h, { children: "Applications, interviews, and hires over time" })] }), /* @__PURE__ */ u(m, { children: U.length === 0 ? /* @__PURE__ */ u("p", {
202
+ className: "py-6 text-center text-sm text-text-secondary",
203
+ children: "No hiring activity recorded yet."
204
+ }) : /* @__PURE__ */ u(n, {
205
+ series: U,
206
+ compare: W,
207
+ seriesLabel: "Applications",
208
+ compareLabel: "Hires",
209
+ height: 220,
210
+ valueFormatter: (e) => `${e}`
211
+ }) })]
212
+ }), /* @__PURE__ */ d(p, {
235
213
  className: "col-span-3",
236
- children: [/* @__PURE__ */ l(m, { children: [/* @__PURE__ */ c(h, { children: "Pipeline Status" }), /* @__PURE__ */ c(p, { children: "Current candidate distribution" })] }), /* @__PURE__ */ c(f, {
237
- className: "space-y-3",
238
- children: H.map((e) => /* @__PURE__ */ l("div", {
239
- className: "flex items-center gap-3",
240
- children: [
241
- /* @__PURE__ */ c("div", { className: `h-3 w-3 rounded-full ${e.color}` }),
242
- /* @__PURE__ */ c("span", {
243
- className: "w-20 text-sm",
244
- children: t(e.status)
245
- }),
246
- /* @__PURE__ */ c("div", {
247
- className: "flex-1 h-3 bg-bg-sunken rounded overflow-hidden",
248
- children: /* @__PURE__ */ c("div", {
249
- className: `h-3 rounded ${e.color}`,
250
- style: { width: `${U > 0 ? Math.max(Math.round(e.count / U * 100), 3) : 3}%` }
251
- })
252
- }),
253
- /* @__PURE__ */ c("span", {
254
- className: "text-sm font-medium w-6 text-right",
255
- children: e.count
256
- })
257
- ]
258
- }, e.status))
259
- })]
214
+ children: [/* @__PURE__ */ d(g, { children: [/* @__PURE__ */ u(_, { children: "Pipeline Status" }), /* @__PURE__ */ u(h, { children: "Current candidate distribution" })] }), /* @__PURE__ */ u(m, { children: K > 0 ? /* @__PURE__ */ u(r, {
215
+ series: q,
216
+ colorful: !0,
217
+ height: 220,
218
+ title: "Candidate pipeline by stage"
219
+ }) : /* @__PURE__ */ u("p", {
220
+ className: "py-6 text-center text-sm text-text-secondary",
221
+ children: "No candidates in the pipeline yet."
222
+ }) })]
260
223
  })]
261
224
  }),
262
- /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ l(m, { children: [/* @__PURE__ */ c(h, { children: "Source Effectiveness" }), /* @__PURE__ */ c(p, { children: "Recruitment channel performance comparison" })] }), /* @__PURE__ */ c(f, { children: /* @__PURE__ */ c(x, {
225
+ /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ d(g, { children: [/* @__PURE__ */ u(_, { children: "Source Effectiveness" }), /* @__PURE__ */ u(h, { children: "Recruitment channel performance comparison" })] }), /* @__PURE__ */ u(m, { children: /* @__PURE__ */ u(C, {
263
226
  columns: [
264
227
  {
265
228
  key: "source",
266
229
  header: "Source",
267
230
  priority: "primary",
268
- cell: (e) => /* @__PURE__ */ c("span", {
231
+ cell: (e) => /* @__PURE__ */ u("span", {
269
232
  className: "font-medium",
270
233
  children: e.source
271
234
  })
@@ -274,7 +237,7 @@ function T() {
274
237
  key: "applications",
275
238
  header: "Applications",
276
239
  priority: "secondary",
277
- cell: (e) => /* @__PURE__ */ c("span", {
240
+ cell: (e) => /* @__PURE__ */ u("span", {
278
241
  className: "md:block md:text-right",
279
242
  children: e.applications
280
243
  })
@@ -283,7 +246,7 @@ function T() {
283
246
  key: "hires",
284
247
  header: "Hires",
285
248
  priority: "secondary",
286
- cell: (e) => /* @__PURE__ */ c("span", {
249
+ cell: (e) => /* @__PURE__ */ u("span", {
287
250
  className: "md:block md:text-right",
288
251
  children: e.hires
289
252
  })
@@ -292,9 +255,9 @@ function T() {
292
255
  key: "conversion",
293
256
  header: "Conversion",
294
257
  priority: "primary",
295
- cell: (e) => /* @__PURE__ */ c("span", {
258
+ cell: (e) => /* @__PURE__ */ u("span", {
296
259
  className: "md:block md:text-right",
297
- children: /* @__PURE__ */ l(u, {
260
+ children: /* @__PURE__ */ d(f, {
298
261
  variant: e.conversionRate >= 5 ? "default" : "secondary",
299
262
  className: "text-[10px]",
300
263
  children: [e.conversionRate, "%"]
@@ -302,24 +265,24 @@ function T() {
302
265
  })
303
266
  }
304
267
  ],
305
- data: k,
268
+ data: j,
306
269
  rowKey: (e) => e.source,
307
- emptyState: /* @__PURE__ */ c("p", {
270
+ emptyState: /* @__PURE__ */ u("p", {
308
271
  className: "py-6 text-center text-sm text-text-secondary",
309
272
  children: "No candidate source data yet."
310
273
  })
311
274
  }) })] }),
312
- /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ l(m, { children: [/* @__PURE__ */ c(h, { children: "Open Positions Detail" }), /* @__PURE__ */ c(p, { children: "Active job postings and applicant counts" })] }), /* @__PURE__ */ c(f, { children: W.length === 0 ? /* @__PURE__ */ c(v, {
275
+ /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ d(g, { children: [/* @__PURE__ */ u(_, { children: "Open Positions Detail" }), /* @__PURE__ */ u(h, { children: "Active job postings and applicant counts" })] }), /* @__PURE__ */ u(m, { children: J.length === 0 ? /* @__PURE__ */ u(b, {
313
276
  illustration: "empty-data",
314
277
  title: "No open positions",
315
278
  description: "Active job postings will appear here once you publish a role."
316
- }) : /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c(x, {
279
+ }) : /* @__PURE__ */ d(l, { children: [/* @__PURE__ */ u(C, {
317
280
  columns: [
318
281
  {
319
282
  key: "title",
320
283
  header: "Position",
321
284
  priority: "primary",
322
- cell: (e) => /* @__PURE__ */ c("span", {
285
+ cell: (e) => /* @__PURE__ */ u("span", {
323
286
  className: "font-medium",
324
287
  children: e.title
325
288
  })
@@ -328,7 +291,7 @@ function T() {
328
291
  key: "department",
329
292
  header: "Department",
330
293
  priority: "secondary",
331
- cell: (e) => /* @__PURE__ */ c("span", {
294
+ cell: (e) => /* @__PURE__ */ u("span", {
332
295
  className: "text-text-secondary",
333
296
  children: e.department
334
297
  })
@@ -337,7 +300,7 @@ function T() {
337
300
  key: "level",
338
301
  header: "Level",
339
302
  priority: "hidden-on-mobile",
340
- cell: (e) => /* @__PURE__ */ c(u, {
303
+ cell: (e) => /* @__PURE__ */ u(f, {
341
304
  variant: "outline",
342
305
  className: "w-fit text-[10px]",
343
306
  children: t(e.experienceLevel)
@@ -347,7 +310,7 @@ function T() {
347
310
  key: "applicants",
348
311
  header: "Applicants",
349
312
  priority: "secondary",
350
- cell: (e) => /* @__PURE__ */ c("span", {
313
+ cell: (e) => /* @__PURE__ */ u("span", {
351
314
  className: "md:block md:text-right",
352
315
  children: e.applicants
353
316
  })
@@ -356,7 +319,7 @@ function T() {
356
319
  key: "salary",
357
320
  header: "Salary Range",
358
321
  priority: "secondary",
359
- cell: (e) => /* @__PURE__ */ l("span", {
322
+ cell: (e) => /* @__PURE__ */ d("span", {
360
323
  className: "md:block md:text-right text-text-secondary",
361
324
  children: [
362
325
  "$",
@@ -371,26 +334,26 @@ function T() {
371
334
  key: "status",
372
335
  header: "Status",
373
336
  priority: "primary",
374
- cell: (e) => /* @__PURE__ */ c(u, {
337
+ cell: (e) => /* @__PURE__ */ u(f, {
375
338
  variant: "default",
376
339
  className: "text-[10px]",
377
340
  children: t(e.status)
378
341
  })
379
342
  }
380
343
  ],
381
- data: Y,
344
+ data: $,
382
345
  rowKey: (e) => e.id
383
- }), W.length > K && /* @__PURE__ */ c(b, {
384
- page: G,
385
- pageSize: K,
386
- totalItems: W.length,
387
- onPageChange: J,
346
+ }), J.length > X && /* @__PURE__ */ u(S, {
347
+ page: Y,
348
+ pageSize: X,
349
+ totalItems: J.length,
350
+ onPageChange: Q,
388
351
  className: "mt-3"
389
352
  })] }) })] })
390
353
  ]
391
354
  });
392
355
  }
393
356
  //#endregion
394
- export { T as AnalyticsHiringAnalyticsPagePage };
357
+ export { D as AnalyticsHiringAnalyticsPagePage };
395
358
 
396
359
  //# sourceMappingURL=AnalyticsHiringAnalyticsPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AnalyticsHiringAnalyticsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { Briefcase, Clock, Target, Users } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useCrewFoundryStore, type JobPosting } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\ntype SourceRow = {\n source: string;\n applications: number;\n hires: number;\n conversionRate: number;\n};\n\nconst monthKeyOf = (value: string) => {\n const date = new Date(value);\n return `${date.getFullYear()}-${String(date.getMonth()).padStart(2, '0')}`;\n};\n\n// Stable \"as of\" anchor for this dataset (avoids impure Date.now() in render).\nconst AS_OF = new Date('2026-03-01').getTime();\n\nexport function AnalyticsHiringAnalyticsPagePage() {\n const { jobPostings, candidates, interviews } = useCrewFoundryStore();\n\n // Real monthly activity derived from candidate/interview dates.\n const hiringMetrics = useMemo(() => {\n if (candidates.length === 0 && interviews.length === 0) {\n return [];\n }\n const keys = Array.from(\n new Set([\n ...candidates.map((candidate) => monthKeyOf(candidate.appliedDate)),\n ...interviews.map((interview) => monthKeyOf(interview.date)),\n ])\n )\n .sort()\n .slice(-6);\n return keys.map((key) => {\n const [year, month] = key.split('-').map(Number);\n const label = new Date(year, month, 1).toLocaleString('en-US', {\n month: 'short',\n year: '2-digit',\n });\n const monthCandidates = candidates.filter(\n (candidate) => monthKeyOf(candidate.appliedDate) === key\n );\n return {\n month: label,\n applications: monthCandidates.length,\n interviews: interviews.filter((interview) => monthKeyOf(interview.date) === key).length,\n hires: monthCandidates.filter((candidate) => candidate.status === 'hired').length,\n };\n });\n }, [candidates, interviews]);\n\n const sourceEffectiveness = useMemo<SourceRow[]>(() => {\n const grouped = candidates.reduce<Record<string, { applications: number; hires: number }>>(\n (acc, candidate) => {\n const source = candidate.source || 'Unknown';\n const value = acc[source] || { applications: 0, hires: 0 };\n value.applications += 1;\n if (candidate.status === 'hired') {\n value.hires += 1;\n }\n acc[source] = value;\n return acc;\n },\n {}\n );\n\n return Object.entries(grouped)\n .map(([source, value]) => ({\n source,\n applications: value.applications,\n hires: value.hires,\n conversionRate: Number(((value.hires / Math.max(value.applications, 1)) * 100).toFixed(1)),\n }))\n .sort((a, b) => b.conversionRate - a.conversionRate);\n }, [candidates]);\n\n // Real average number of days active postings have been open.\n const avgDaysOpen = useMemo(() => {\n const activePostings = jobPostings.filter((posting) => posting.status === 'active');\n if (activePostings.length === 0) {\n return 0;\n }\n const totalDays = activePostings.reduce((sum, posting) => {\n const posted = new Date(posting.postedDate).getTime();\n if (Number.isNaN(posted)) {\n return sum;\n }\n return sum + Math.max(0, (AS_OF - posted) / (1000 * 60 * 60 * 24));\n }, 0);\n return Math.round(totalDays / activePostings.length);\n }, [jobPostings]);\n\n const activeJobs = jobPostings.filter((j) => j.status === 'active');\n const totalApplicants = jobPostings.reduce((s, j) => s + j.applicants, 0);\n const scheduledInterviews = interviews.filter((i) => i.status === 'scheduled').length;\n const completedInterviews = interviews.filter((i) => i.status === 'completed').length;\n const offeredCandidates = candidates.filter((c) => c.status === 'offer').length;\n const hiredCandidates = candidates.filter((c) => c.status === 'hired').length;\n\n const interviewedOrBeyond = candidates.filter((c) =>\n ['interview', 'assessment', 'offer', 'hired'].includes(c.status)\n ).length;\n const offerOrBeyond = candidates.filter((c) => ['offer', 'hired'].includes(c.status)).length;\n const interviewToOffer = Math.round((offerOrBeyond / Math.max(interviewedOrBeyond, 1)) * 100);\n const offerAcceptance = Math.round(\n (hiredCandidates / Math.max(offeredCandidates + hiredCandidates, 1)) * 100\n );\n\n const maxApplications = Math.max(1, ...hiringMetrics.map((m) => m.applications));\n\n const statusPipeline = [\n {\n status: 'New',\n count: candidates.filter((c) => c.status === 'new').length,\n color: 'bg-text-secondary',\n },\n {\n status: 'Screening',\n count: candidates.filter((c) => c.status === 'screening').length,\n color: 'bg-status-info-text',\n },\n {\n status: 'Interview',\n count: candidates.filter((c) => c.status === 'interview').length,\n color: 'bg-status-info-text',\n },\n {\n status: 'Assessment',\n count: candidates.filter((c) => c.status === 'assessment').length,\n color: 'bg-action-primary-bg',\n },\n { status: 'Offer', count: offeredCandidates, color: 'bg-status-warning-text' },\n { status: 'Hired', count: hiredCandidates, color: 'bg-status-success-text' },\n {\n status: 'Rejected',\n count: candidates.filter((c) => c.status === 'rejected').length,\n color: 'bg-status-error-text',\n },\n ];\n const totalPipeline = statusPipeline.reduce((s, p) => s + p.count, 0);\n\n // Open Positions = active postings only, paginated to match the card title.\n const openPositions = [...activeJobs].sort((a, b) => b.applicants - a.applicants);\n const {\n page: jobPage,\n pageSize: jobPageSize,\n offset: jobOffset,\n setPage: setJobPage,\n } = usePagination({ initialPageSize: 8 });\n const jobPageItems = openPositions.slice(jobOffset, jobOffset + jobPageSize);\n\n const sourceColumns: ResponsiveTableColumn<SourceRow>[] = [\n {\n key: 'source',\n header: 'Source',\n priority: 'primary',\n cell: (src) => <span className=\"font-medium\">{src.source}</span>,\n },\n {\n key: 'applications',\n header: 'Applications',\n priority: 'secondary',\n cell: (src) => <span className=\"md:block md:text-right\">{src.applications}</span>,\n },\n {\n key: 'hires',\n header: 'Hires',\n priority: 'secondary',\n cell: (src) => <span className=\"md:block md:text-right\">{src.hires}</span>,\n },\n {\n key: 'conversion',\n header: 'Conversion',\n priority: 'primary',\n cell: (src) => (\n <span className=\"md:block md:text-right\">\n <Badge\n variant={src.conversionRate >= 5 ? 'default' : 'secondary'}\n className=\"text-[10px]\"\n >\n {src.conversionRate}%\n </Badge>\n </span>\n ),\n },\n ];\n\n const jobColumns: ResponsiveTableColumn<JobPosting>[] = [\n {\n key: 'title',\n header: 'Position',\n priority: 'primary',\n cell: (job) => <span className=\"font-medium\">{job.title}</span>,\n },\n {\n key: 'department',\n header: 'Department',\n priority: 'secondary',\n cell: (job) => <span className=\"text-text-secondary\">{job.department}</span>,\n },\n {\n key: 'level',\n header: 'Level',\n priority: 'hidden-on-mobile',\n cell: (job) => (\n <Badge variant=\"outline\" className=\"w-fit text-[10px]\">\n {formatEnumLabel(job.experienceLevel)}\n </Badge>\n ),\n },\n {\n key: 'applicants',\n header: 'Applicants',\n priority: 'secondary',\n cell: (job) => <span className=\"md:block md:text-right\">{job.applicants}</span>,\n },\n {\n key: 'salary',\n header: 'Salary Range',\n priority: 'secondary',\n cell: (job) => (\n <span className=\"md:block md:text-right text-text-secondary\">\n ${(job.salaryMin / 1000).toFixed(0)}K-${(job.salaryMax / 1000).toFixed(0)}K\n </span>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n priority: 'primary',\n cell: (job) => (\n <Badge variant=\"default\" className=\"text-[10px]\">\n {formatEnumLabel(job.status)}\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>Hiring Analytics</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Recruitment performance and pipeline analysis\n </p>\n <PagePurpose className=\"mt-1\">\n Measure how your hiring funnel performs — applications, time-to-hire, and source quality\n — to make recruiting faster and more effective.\n </PagePurpose>\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Active Postings</CardTitle>\n <Briefcase className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activeJobs.length}</div>\n <p className=\"text-xs text-text-secondary\">{totalApplicants} total applicants</p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Avg Days Open</CardTitle>\n <Clock className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgDaysOpen} days</div>\n <p className=\"text-xs text-text-secondary\">Across active postings</p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Interview to Offer</CardTitle>\n <Target className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{interviewToOffer}%</div>\n <p className=\"text-xs text-text-secondary\">\n {scheduledInterviews} scheduled, {completedInterviews} completed\n </p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Offer Acceptance</CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{offerAcceptance}%</div>\n <p className=\"text-xs text-text-secondary\">{hiredCandidates} hired to date</p>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-7\">\n <Card className=\"col-span-4\">\n <CardHeader>\n <CardTitle>Monthly Hiring Activity</CardTitle>\n <CardDescription>Applications, interviews, and hires over time</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {hiringMetrics.length === 0 && (\n <p className=\"py-6 text-center text-sm text-text-secondary\">\n No hiring activity recorded yet.\n </p>\n )}\n {hiringMetrics.map((m) => (\n <div key={m.month} className=\"flex items-center gap-3\">\n <span className=\"w-12 text-sm text-text-secondary\">{m.month}</span>\n <div className=\"flex-1 h-5 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-5 bg-action-primary-bg rounded\"\n style={{\n width: `${Math.round((m.applications / maxApplications) * 100)}%`,\n }}\n />\n </div>\n <div className=\"flex gap-1 w-48 justify-end\">\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {m.applications} apps\n </Badge>\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n {m.interviews} int\n </Badge>\n <Badge variant=\"default\" className=\"text-[10px]\">\n {m.hires} hired\n </Badge>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card className=\"col-span-3\">\n <CardHeader>\n <CardTitle>Pipeline Status</CardTitle>\n <CardDescription>Current candidate distribution</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {statusPipeline.map((stage) => (\n <div key={stage.status} className=\"flex items-center gap-3\">\n <div className={`h-3 w-3 rounded-full ${stage.color}`} />\n <span className=\"w-20 text-sm\">{formatEnumLabel(stage.status)}</span>\n <div className=\"flex-1 h-3 bg-bg-sunken rounded overflow-hidden\">\n <div\n className={`h-3 rounded ${stage.color}`}\n style={{\n width: `${totalPipeline > 0 ? Math.max(Math.round((stage.count / totalPipeline) * 100), 3) : 3}%`,\n }}\n />\n </div>\n <span className=\"text-sm font-medium w-6 text-right\">{stage.count}</span>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Source Effectiveness</CardTitle>\n <CardDescription>Recruitment channel performance comparison</CardDescription>\n </CardHeader>\n <CardContent>\n <ResponsiveTable\n columns={sourceColumns}\n data={sourceEffectiveness}\n rowKey={(src) => src.source}\n emptyState={\n <p className=\"py-6 text-center text-sm text-text-secondary\">\n No candidate source data yet.\n </p>\n }\n />\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Open Positions Detail</CardTitle>\n <CardDescription>Active job postings and applicant counts</CardDescription>\n </CardHeader>\n <CardContent>\n {openPositions.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No open positions\"\n description=\"Active job postings will appear here once you publish a role.\"\n />\n ) : (\n <>\n <ResponsiveTable columns={jobColumns} data={jobPageItems} rowKey={(job) => job.id} />\n {openPositions.length > jobPageSize && (\n <Pagination\n page={jobPage}\n pageSize={jobPageSize}\n totalItems={openPositions.length}\n onPageChange={setJobPage}\n className=\"mt-3\"\n />\n )}\n </>\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AnalyticsHiringAnalyticsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { Briefcase, Clock, Target, Users } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useCrewFoundryStore, type JobPosting } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\nimport { BarChart, LineChart } from '../components/viz';\nimport type { LabeledValue, Segment } from '../components/viz';\n\ntype SourceRow = {\n source: string;\n applications: number;\n hires: number;\n conversionRate: number;\n};\n\nconst monthKeyOf = (value: string) => {\n const date = new Date(value);\n return `${date.getFullYear()}-${String(date.getMonth()).padStart(2, '0')}`;\n};\n\n// Stable \"as of\" anchor for this dataset (avoids impure Date.now() in render).\nconst AS_OF = new Date('2026-03-01').getTime();\n\nexport function AnalyticsHiringAnalyticsPagePage() {\n const { jobPostings, candidates, interviews } = useCrewFoundryStore();\n\n // Real monthly activity derived from candidate/interview dates.\n const hiringMetrics = useMemo(() => {\n if (candidates.length === 0 && interviews.length === 0) {\n return [];\n }\n const keys = Array.from(\n new Set([\n ...candidates.map((candidate) => monthKeyOf(candidate.appliedDate)),\n ...interviews.map((interview) => monthKeyOf(interview.date)),\n ])\n )\n .sort()\n .slice(-6);\n return keys.map((key) => {\n const [year, month] = key.split('-').map(Number);\n const label = new Date(year, month, 1).toLocaleString('en-US', {\n month: 'short',\n year: '2-digit',\n });\n const monthCandidates = candidates.filter(\n (candidate) => monthKeyOf(candidate.appliedDate) === key\n );\n return {\n month: label,\n applications: monthCandidates.length,\n interviews: interviews.filter((interview) => monthKeyOf(interview.date) === key).length,\n hires: monthCandidates.filter((candidate) => candidate.status === 'hired').length,\n };\n });\n }, [candidates, interviews]);\n\n const sourceEffectiveness = useMemo<SourceRow[]>(() => {\n const grouped = candidates.reduce<Record<string, { applications: number; hires: number }>>(\n (acc, candidate) => {\n const source = candidate.source || 'Unknown';\n const value = acc[source] || { applications: 0, hires: 0 };\n value.applications += 1;\n if (candidate.status === 'hired') {\n value.hires += 1;\n }\n acc[source] = value;\n return acc;\n },\n {}\n );\n\n return Object.entries(grouped)\n .map(([source, value]) => ({\n source,\n applications: value.applications,\n hires: value.hires,\n conversionRate: Number(((value.hires / Math.max(value.applications, 1)) * 100).toFixed(1)),\n }))\n .sort((a, b) => b.conversionRate - a.conversionRate);\n }, [candidates]);\n\n // Real average number of days active postings have been open.\n const avgDaysOpen = useMemo(() => {\n const activePostings = jobPostings.filter((posting) => posting.status === 'active');\n if (activePostings.length === 0) {\n return 0;\n }\n const totalDays = activePostings.reduce((sum, posting) => {\n const posted = new Date(posting.postedDate).getTime();\n if (Number.isNaN(posted)) {\n return sum;\n }\n return sum + Math.max(0, (AS_OF - posted) / (1000 * 60 * 60 * 24));\n }, 0);\n return Math.round(totalDays / activePostings.length);\n }, [jobPostings]);\n\n const activeJobs = jobPostings.filter((j) => j.status === 'active');\n const totalApplicants = jobPostings.reduce((s, j) => s + j.applicants, 0);\n const scheduledInterviews = interviews.filter((i) => i.status === 'scheduled').length;\n const completedInterviews = interviews.filter((i) => i.status === 'completed').length;\n const offeredCandidates = candidates.filter((c) => c.status === 'offer').length;\n const hiredCandidates = candidates.filter((c) => c.status === 'hired').length;\n\n const interviewedOrBeyond = candidates.filter((c) =>\n ['interview', 'assessment', 'offer', 'hired'].includes(c.status)\n ).length;\n const offerOrBeyond = candidates.filter((c) => ['offer', 'hired'].includes(c.status)).length;\n const interviewToOffer = Math.round((offerOrBeyond / Math.max(interviewedOrBeyond, 1)) * 100);\n const offerAcceptance = Math.round(\n (hiredCandidates / Math.max(offeredCandidates + hiredCandidates, 1)) * 100\n );\n\n const applicationsSeries: LabeledValue[] = hiringMetrics.map((m) => ({\n label: m.month,\n value: m.applications,\n }));\n const hiresCompare = hiringMetrics.map((m) => m.hires);\n\n const statusPipeline = [\n {\n status: 'New',\n count: candidates.filter((c) => c.status === 'new').length,\n color: 'bg-text-secondary',\n },\n {\n status: 'Screening',\n count: candidates.filter((c) => c.status === 'screening').length,\n color: 'bg-status-info-text',\n },\n {\n status: 'Interview',\n count: candidates.filter((c) => c.status === 'interview').length,\n color: 'bg-status-info-text',\n },\n {\n status: 'Assessment',\n count: candidates.filter((c) => c.status === 'assessment').length,\n color: 'bg-action-primary-bg',\n },\n { status: 'Offer', count: offeredCandidates, color: 'bg-status-warning-text' },\n { status: 'Hired', count: hiredCandidates, color: 'bg-status-success-text' },\n {\n status: 'Rejected',\n count: candidates.filter((c) => c.status === 'rejected').length,\n color: 'bg-status-error-text',\n },\n ];\n const totalPipeline = statusPipeline.reduce((s, p) => s + p.count, 0);\n const pipelineSeries: Segment[] = statusPipeline.map((stage) => ({\n label: stage.status,\n value: stage.count,\n }));\n\n // Open Positions = active postings only, paginated to match the card title.\n const openPositions = [...activeJobs].sort((a, b) => b.applicants - a.applicants);\n const {\n page: jobPage,\n pageSize: jobPageSize,\n offset: jobOffset,\n setPage: setJobPage,\n } = usePagination({ initialPageSize: 8 });\n const jobPageItems = openPositions.slice(jobOffset, jobOffset + jobPageSize);\n\n const sourceColumns: ResponsiveTableColumn<SourceRow>[] = [\n {\n key: 'source',\n header: 'Source',\n priority: 'primary',\n cell: (src) => <span className=\"font-medium\">{src.source}</span>,\n },\n {\n key: 'applications',\n header: 'Applications',\n priority: 'secondary',\n cell: (src) => <span className=\"md:block md:text-right\">{src.applications}</span>,\n },\n {\n key: 'hires',\n header: 'Hires',\n priority: 'secondary',\n cell: (src) => <span className=\"md:block md:text-right\">{src.hires}</span>,\n },\n {\n key: 'conversion',\n header: 'Conversion',\n priority: 'primary',\n cell: (src) => (\n <span className=\"md:block md:text-right\">\n <Badge\n variant={src.conversionRate >= 5 ? 'default' : 'secondary'}\n className=\"text-[10px]\"\n >\n {src.conversionRate}%\n </Badge>\n </span>\n ),\n },\n ];\n\n const jobColumns: ResponsiveTableColumn<JobPosting>[] = [\n {\n key: 'title',\n header: 'Position',\n priority: 'primary',\n cell: (job) => <span className=\"font-medium\">{job.title}</span>,\n },\n {\n key: 'department',\n header: 'Department',\n priority: 'secondary',\n cell: (job) => <span className=\"text-text-secondary\">{job.department}</span>,\n },\n {\n key: 'level',\n header: 'Level',\n priority: 'hidden-on-mobile',\n cell: (job) => (\n <Badge variant=\"outline\" className=\"w-fit text-[10px]\">\n {formatEnumLabel(job.experienceLevel)}\n </Badge>\n ),\n },\n {\n key: 'applicants',\n header: 'Applicants',\n priority: 'secondary',\n cell: (job) => <span className=\"md:block md:text-right\">{job.applicants}</span>,\n },\n {\n key: 'salary',\n header: 'Salary Range',\n priority: 'secondary',\n cell: (job) => (\n <span className=\"md:block md:text-right text-text-secondary\">\n ${(job.salaryMin / 1000).toFixed(0)}K-${(job.salaryMax / 1000).toFixed(0)}K\n </span>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n priority: 'primary',\n cell: (job) => (\n <Badge variant=\"default\" className=\"text-[10px]\">\n {formatEnumLabel(job.status)}\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>Hiring Analytics</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Recruitment performance and pipeline analysis\n </p>\n <PagePurpose className=\"mt-1\">\n Measure how your hiring funnel performs — applications, time-to-hire, and source quality\n — to make recruiting faster and more effective.\n </PagePurpose>\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Active Postings</CardTitle>\n <Briefcase className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activeJobs.length}</div>\n <p className=\"text-xs text-text-secondary\">{totalApplicants} total applicants</p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Avg Days Open</CardTitle>\n <Clock className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgDaysOpen} days</div>\n <p className=\"text-xs text-text-secondary\">Across active postings</p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Interview to Offer</CardTitle>\n <Target className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{interviewToOffer}%</div>\n <p className=\"text-xs text-text-secondary\">\n {scheduledInterviews} scheduled, {completedInterviews} completed\n </p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Offer Acceptance</CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{offerAcceptance}%</div>\n <p className=\"text-xs text-text-secondary\">{hiredCandidates} hired to date</p>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-7\">\n <Card className=\"col-span-4\">\n <CardHeader>\n <CardTitle>Monthly Hiring Activity</CardTitle>\n <CardDescription>Applications, interviews, and hires over time</CardDescription>\n </CardHeader>\n <CardContent>\n {applicationsSeries.length === 0 ? (\n <p className=\"py-6 text-center text-sm text-text-secondary\">\n No hiring activity recorded yet.\n </p>\n ) : (\n <LineChart\n series={applicationsSeries}\n compare={hiresCompare}\n seriesLabel=\"Applications\"\n compareLabel=\"Hires\"\n height={220}\n valueFormatter={(value) => `${value}`}\n />\n )}\n </CardContent>\n </Card>\n\n <Card className=\"col-span-3\">\n <CardHeader>\n <CardTitle>Pipeline Status</CardTitle>\n <CardDescription>Current candidate distribution</CardDescription>\n </CardHeader>\n <CardContent>\n {totalPipeline > 0 ? (\n <BarChart series={pipelineSeries} colorful height={220} title=\"Candidate pipeline by stage\" />\n ) : (\n <p className=\"py-6 text-center text-sm text-text-secondary\">\n No candidates in the pipeline yet.\n </p>\n )}\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Source Effectiveness</CardTitle>\n <CardDescription>Recruitment channel performance comparison</CardDescription>\n </CardHeader>\n <CardContent>\n <ResponsiveTable\n columns={sourceColumns}\n data={sourceEffectiveness}\n rowKey={(src) => src.source}\n emptyState={\n <p className=\"py-6 text-center text-sm text-text-secondary\">\n No candidate source data yet.\n </p>\n }\n />\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Open Positions Detail</CardTitle>\n <CardDescription>Active job postings and applicant counts</CardDescription>\n </CardHeader>\n <CardContent>\n {openPositions.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No open positions\"\n description=\"Active job postings will appear here once you publish a role.\"\n />\n ) : (\n <>\n <ResponsiveTable columns={jobColumns} data={jobPageItems} rowKey={(job) => job.id} />\n {openPositions.length > jobPageSize && (\n <Pagination\n page={jobPage}\n pageSize={jobPageSize}\n totalItems={openPositions.length}\n onPageChange={setJobPage}\n className=\"mt-3\"\n />\n )}\n </>\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}