@burdenoff/microfe-crewfoundry 2026.704.6 → 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 (148) 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 +269 -270
  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 +1 -1
  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 +134 -135
  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/MarketplaceFreelancerProfilePagePage.js +85 -93
  119. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
  120. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
  121. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
  122. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
  123. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
  124. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +289 -140
  125. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
  126. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
  127. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
  128. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
  129. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
  130. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
  131. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
  132. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +140 -78
  133. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
  134. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
  135. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
  136. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
  137. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
  138. package/dist/crewfoundry/store/crewfoundryStore.js +1 -1
  139. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  140. package/dist/crewfoundry/utils/cn.js +10 -0
  141. package/dist/crewfoundry/utils/cn.js.map +1 -0
  142. package/dist/crewfoundry/utils/courseProgress.js +46 -0
  143. package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
  144. package/dist/node_modules/clsx/dist/clsx.js +18 -0
  145. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  146. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
  147. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  148. package/package.json +1 -1
@@ -1,14 +1,18 @@
1
1
  import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
2
- import { FormModal as t, useFormModal as n } from "../components/forms/FormModal.js";
3
- import { ConfirmDialog as r } from "../components/forms/ConfirmDialog.js";
4
- import { getNumber as i, getText as a, newClientId as o } from "../components/forms/formValues.js";
5
- import { useState as s } from "react";
6
- import { MapPin as c, Pencil as l, Plus as u, Search as d, Star as f, Trash2 as ee, UserCheck as p, Users as m } from "lucide-react";
2
+ import { AvatarStack as t } from "../components/viz/AvatarStack.js";
3
+ import { SegmentedTabs as n } from "../components/viz/SegmentedTabs.js";
4
+ import "../components/viz/index.js";
5
+ import { FormModal as r, useFormModal as i } from "../components/forms/FormModal.js";
6
+ import { ConfirmDialog as a } from "../components/forms/ConfirmDialog.js";
7
+ import { getNumber as o, getTags as ee, getText as s, newClientId as c } from "../components/forms/formValues.js";
8
+ import { useState as l } from "react";
9
+ import { MapPin as te, Pencil as ne, Plus as re, Search as ie, Star as u, Trash2 as d, UserCheck as f, Users as p } from "lucide-react";
10
+ import { useNavigate as m } from "react-router-dom";
7
11
  import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
8
- import { Badge as v, Button as y, Card as b, CardContent as x, CardHeader as S, CardTitle as C, GlassCard as w, GradientText as T, IllustratedEmptyState as te, Input as ne, PagePurpose as E, Pagination as D, ResponsiveTable as O, Select as k, SelectContent as A, SelectItem as j, SelectTrigger as M, SelectValue as N } from "@burdenoff/fe-libs/ui";
9
- import { usePagination as P } from "@burdenoff/fe-libs/shared/hooks";
12
+ import { Badge as ae, Button as v, Card as oe, CardContent as y, CardHeader as b, CardTitle as x, GlassCard as S, GradientText as se, IllustratedEmptyState as ce, Input as le, PagePurpose as ue, Pagination as C, ResponsiveTable as w, Select as T, SelectContent as E, SelectItem as D, SelectTrigger as O, SelectValue as k } from "@burdenoff/fe-libs/ui";
13
+ import { usePagination as A } from "@burdenoff/fe-libs/shared/hooks";
10
14
  //#region src/crewfoundry/pages/HrEmployeesPagePage.tsx
11
- var F = [
15
+ var j = [
12
16
  {
13
17
  name: "firstName",
14
18
  label: "First name",
@@ -116,8 +120,15 @@ var F = [
116
120
  name: "performanceScore",
117
121
  label: "Performance score (0-5)",
118
122
  type: "number"
123
+ },
124
+ {
125
+ name: "skills",
126
+ label: "Skills",
127
+ type: "tags",
128
+ colSpan: 2,
129
+ placeholder: "Add a skill and press Enter"
119
130
  }
120
- ], I = (e) => ({
131
+ ], M = (e) => ({
121
132
  firstName: e.firstName,
122
133
  lastName: e.lastName,
123
134
  email: e.email,
@@ -129,17 +140,20 @@ var F = [
129
140
  status: e.status,
130
141
  salary: e.salary,
131
142
  startDate: e.startDate.slice(0, 10),
132
- performanceScore: e.performanceScore
143
+ performanceScore: e.performanceScore,
144
+ skills: e.skills
133
145
  });
134
- function L() {
135
- let { employees: L, addEmployee: R, updateEmployee: z, removeEmployee: B } = e(), [V, re] = s(""), [H, U] = s("all"), W = n(), [G, K] = s(null), { page: q, pageSize: J, offset: Y, setPage: X } = P({ initialPageSize: 25 }), Z = [...new Set(L.map((e) => e.department))], Q = L.filter((e) => {
136
- let t = `${e.firstName} ${e.lastName} ${e.email} ${e.position}`.toLowerCase().includes(V.toLowerCase()), n = H === "all" || e.department === H;
137
- return t && n;
138
- }), ie = Q.slice(Y, Y + J), ae = (e) => {
139
- re(e), X(1);
140
- }, oe = (e) => {
141
- U(e), X(1);
142
- }, se = L.filter((e) => e.status === "active").length, ce = L.filter((e) => e.status === "on_leave").length, le = L.length > 0 ? (L.reduce((e, t) => e + t.performanceScore, 0) / L.length).toFixed(1) : "0.0", $ = W.context;
146
+ function N() {
147
+ let N = m(), { employees: P, addEmployee: F, updateEmployee: I, removeEmployee: L } = e(), [R, de] = l(""), [z, B] = l("all"), [V, H] = l("all"), U = i(), [W, G] = l(null), { page: fe, pageSize: K, offset: q, setPage: J } = A({ initialPageSize: 25 }), Y = [...new Set(P.map((e) => e.department))], X = P.filter((e) => e.status === "active").length, Z = P.filter((e) => e.status === "on_leave").length, Q = P.filter((e) => {
148
+ let t = `${e.firstName} ${e.lastName} ${e.email} ${e.position}`.toLowerCase().includes(R.toLowerCase()), n = z === "all" || e.department === z, r = V === "all" || e.status === V;
149
+ return t && n && r;
150
+ }), pe = Q.slice(q, q + K), me = (e) => {
151
+ de(e), J(1);
152
+ }, he = (e) => {
153
+ B(e), J(1);
154
+ }, ge = (e) => {
155
+ H(e), J(1);
156
+ }, _e = P.length > 0 ? (P.reduce((e, t) => e + t.performanceScore, 0) / P.length).toFixed(1) : "0.0", $ = U.context, ve = (e) => N(`../hr/employee-profile-page?id=${encodeURIComponent(e.id)}`);
143
157
  return /* @__PURE__ */ _("div", {
144
158
  className: "space-y-6 p-6",
145
159
  children: [
@@ -148,136 +162,172 @@ function L() {
148
162
  children: [/* @__PURE__ */ _("div", { children: [
149
163
  /* @__PURE__ */ g("h1", {
150
164
  className: "text-2xl font-semibold",
151
- children: /* @__PURE__ */ g(T, { children: "Employee Directory" })
165
+ children: /* @__PURE__ */ g(se, { children: "Employee Directory" })
152
166
  }),
153
167
  /* @__PURE__ */ _("p", {
154
168
  className: "text-sm text-text-secondary",
155
169
  children: [
156
- L.length,
170
+ P.length,
157
171
  " employees across ",
158
- Z.length,
172
+ Y.length,
159
173
  " departments"
160
174
  ]
161
175
  }),
162
- /* @__PURE__ */ g(E, {
176
+ /* @__PURE__ */ g(ue, {
163
177
  className: "mt-1",
164
178
  children: "Your complete employee directory — search, filter, and review everyone on the team along with their role, department, and status."
165
179
  })
166
- ] }), /* @__PURE__ */ _(y, {
180
+ ] }), /* @__PURE__ */ _(v, {
167
181
  size: "sm",
168
- onClick: () => W.openModal(),
169
- children: [/* @__PURE__ */ g(u, { className: "h-4 w-4 mr-1" }), "Add Employee"]
182
+ onClick: () => U.openModal(),
183
+ children: [/* @__PURE__ */ g(re, { className: "h-4 w-4 mr-1" }), "Add Employee"]
170
184
  })]
171
185
  }),
172
186
  /* @__PURE__ */ _("div", {
173
187
  className: "grid gap-4 md:grid-cols-4",
174
188
  children: [
175
- /* @__PURE__ */ _(w, {
189
+ /* @__PURE__ */ _(S, {
176
190
  treatment: "glass",
177
191
  glow: !0,
178
192
  className: "border-border-seam",
179
- children: [/* @__PURE__ */ _(S, {
193
+ children: [/* @__PURE__ */ _(b, {
180
194
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
181
- children: [/* @__PURE__ */ g(C, {
195
+ children: [/* @__PURE__ */ g(x, {
182
196
  className: "text-sm font-medium",
183
197
  children: "Total"
184
- }), /* @__PURE__ */ g(m, { className: "h-4 w-4 text-text-secondary" })]
185
- }), /* @__PURE__ */ g(x, { children: /* @__PURE__ */ g("div", {
198
+ }), /* @__PURE__ */ g(p, { className: "h-4 w-4 text-text-secondary" })]
199
+ }), /* @__PURE__ */ g(y, { children: /* @__PURE__ */ g("div", {
186
200
  className: "text-2xl font-bold tabular-nums",
187
- children: L.length
201
+ children: P.length
188
202
  }) })]
189
203
  }),
190
- /* @__PURE__ */ _(w, {
204
+ /* @__PURE__ */ _(S, {
191
205
  treatment: "metric",
192
206
  className: "border-border-seam",
193
- children: [/* @__PURE__ */ _(S, {
207
+ children: [/* @__PURE__ */ _(b, {
194
208
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
195
- children: [/* @__PURE__ */ g(C, {
209
+ children: [/* @__PURE__ */ g(x, {
196
210
  className: "text-sm font-medium",
197
211
  children: "Active"
198
- }), /* @__PURE__ */ g(p, { className: "h-4 w-4 text-status-success-text" })]
199
- }), /* @__PURE__ */ g(x, { children: /* @__PURE__ */ g("div", {
212
+ }), /* @__PURE__ */ g(f, { className: "h-4 w-4 text-status-success-text" })]
213
+ }), /* @__PURE__ */ g(y, { children: /* @__PURE__ */ g("div", {
200
214
  className: "text-2xl font-bold tabular-nums",
201
- children: se
215
+ children: X
202
216
  }) })]
203
217
  }),
204
- /* @__PURE__ */ _(w, {
218
+ /* @__PURE__ */ _(S, {
205
219
  treatment: "metric",
206
220
  className: "border-border-seam",
207
- children: [/* @__PURE__ */ _(S, {
221
+ children: [/* @__PURE__ */ _(b, {
208
222
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
209
- children: [/* @__PURE__ */ g(C, {
223
+ children: [/* @__PURE__ */ g(x, {
210
224
  className: "text-sm font-medium",
211
225
  children: "On Leave"
212
- }), /* @__PURE__ */ g(m, { className: "h-4 w-4 text-status-warning-text" })]
213
- }), /* @__PURE__ */ g(x, { children: /* @__PURE__ */ g("div", {
226
+ }), /* @__PURE__ */ g(p, { className: "h-4 w-4 text-status-warning-text" })]
227
+ }), /* @__PURE__ */ g(y, { children: /* @__PURE__ */ g("div", {
214
228
  className: "text-2xl font-bold tabular-nums",
215
- children: ce
229
+ children: Z
216
230
  }) })]
217
231
  }),
218
- /* @__PURE__ */ _(w, {
232
+ /* @__PURE__ */ _(S, {
219
233
  treatment: "metric",
220
234
  className: "border-border-seam",
221
- children: [/* @__PURE__ */ _(S, {
235
+ children: [/* @__PURE__ */ _(b, {
222
236
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
223
- children: [/* @__PURE__ */ g(C, {
237
+ children: [/* @__PURE__ */ g(x, {
224
238
  className: "text-sm font-medium",
225
239
  children: "Avg Rating"
226
- }), /* @__PURE__ */ g(f, { className: "h-4 w-4 text-status-warning-text" })]
227
- }), /* @__PURE__ */ g(x, { children: /* @__PURE__ */ g("div", {
240
+ }), /* @__PURE__ */ g(u, { className: "h-4 w-4 text-status-warning-text" })]
241
+ }), /* @__PURE__ */ g(y, { children: /* @__PURE__ */ g("div", {
228
242
  className: "text-2xl font-bold tabular-nums",
229
- children: le
243
+ children: _e
230
244
  }) })]
231
245
  })
232
246
  ]
233
247
  }),
234
248
  /* @__PURE__ */ _("div", {
235
- className: "flex flex-col gap-3 sm:flex-row",
236
- children: [/* @__PURE__ */ _("div", {
237
- className: "relative flex-1 sm:max-w-sm",
238
- children: [/* @__PURE__ */ g(d, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ g(ne, {
239
- placeholder: "Search employees...",
240
- className: "pl-9",
241
- value: V,
242
- onChange: (e) => ae(e.target.value)
249
+ className: "flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between",
250
+ children: [/* @__PURE__ */ g(n, {
251
+ "aria-label": "Filter by status",
252
+ value: V,
253
+ onChange: ge,
254
+ tabs: [
255
+ {
256
+ id: "all",
257
+ label: "All",
258
+ count: P.length
259
+ },
260
+ {
261
+ id: "active",
262
+ label: "Active",
263
+ count: X
264
+ },
265
+ {
266
+ id: "on_leave",
267
+ label: "On Leave",
268
+ count: Z
269
+ }
270
+ ]
271
+ }), /* @__PURE__ */ _("div", {
272
+ className: "flex flex-col gap-3 sm:flex-row",
273
+ children: [/* @__PURE__ */ _("div", {
274
+ className: "relative flex-1 sm:max-w-sm",
275
+ children: [/* @__PURE__ */ g(ie, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ g(le, {
276
+ placeholder: "Search employees...",
277
+ className: "pl-9",
278
+ value: R,
279
+ onChange: (e) => me(e.target.value)
280
+ })]
281
+ }), /* @__PURE__ */ _(T, {
282
+ value: z,
283
+ onValueChange: he,
284
+ children: [/* @__PURE__ */ g(O, {
285
+ className: "w-full sm:w-56",
286
+ "aria-label": "Filter by department",
287
+ children: /* @__PURE__ */ g(k, { placeholder: "All departments" })
288
+ }), /* @__PURE__ */ _(E, { children: [/* @__PURE__ */ g(D, {
289
+ value: "all",
290
+ children: "All departments"
291
+ }), Y.map((e) => /* @__PURE__ */ g(D, {
292
+ value: e,
293
+ children: e
294
+ }, e))] })]
243
295
  })]
244
- }), /* @__PURE__ */ _(k, {
245
- value: H,
246
- onValueChange: oe,
247
- children: [/* @__PURE__ */ g(M, {
248
- className: "w-full sm:w-56",
249
- "aria-label": "Filter by department",
250
- children: /* @__PURE__ */ g(N, { placeholder: "All departments" })
251
- }), /* @__PURE__ */ _(A, { children: [/* @__PURE__ */ g(j, {
252
- value: "all",
253
- children: "All departments"
254
- }), Z.map((e) => /* @__PURE__ */ g(j, {
255
- value: e,
256
- children: e
257
- }, e))] })]
258
296
  })]
259
297
  }),
260
- /* @__PURE__ */ g(b, { children: /* @__PURE__ */ _(x, {
298
+ /* @__PURE__ */ g(oe, { children: /* @__PURE__ */ _(y, {
261
299
  className: "space-y-4 p-4",
262
- children: [/* @__PURE__ */ g(O, {
263
- data: ie,
300
+ children: [/* @__PURE__ */ g(w, {
301
+ data: pe,
264
302
  rowKey: (e) => e.id,
265
303
  columns: [
266
304
  {
267
305
  key: "name",
268
- header: "Name",
306
+ header: "Employee",
269
307
  priority: "primary",
270
- cell: (e) => /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ _("p", {
271
- className: "font-medium",
272
- children: [
273
- e.firstName,
274
- " ",
275
- e.lastName
276
- ]
277
- }), /* @__PURE__ */ g("p", {
278
- className: "text-xs text-text-secondary",
279
- children: e.email
280
- })] })
308
+ cell: (e) => /* @__PURE__ */ _("div", {
309
+ className: "flex items-center gap-3",
310
+ children: [/* @__PURE__ */ g(t, {
311
+ people: [{
312
+ name: `${e.firstName} ${e.lastName}`,
313
+ avatarUrl: e.avatar
314
+ }],
315
+ size: 36
316
+ }), /* @__PURE__ */ _("div", {
317
+ className: "min-w-0",
318
+ children: [/* @__PURE__ */ _("p", {
319
+ className: "truncate font-medium",
320
+ children: [
321
+ e.firstName,
322
+ " ",
323
+ e.lastName
324
+ ]
325
+ }), /* @__PURE__ */ g("p", {
326
+ className: "truncate text-xs text-text-secondary",
327
+ children: e.email
328
+ })]
329
+ })]
330
+ })
281
331
  },
282
332
  {
283
333
  key: "position",
@@ -297,7 +347,7 @@ function L() {
297
347
  header: "Location",
298
348
  cell: (e) => /* @__PURE__ */ _("div", {
299
349
  className: "flex items-center gap-1 text-text-secondary",
300
- children: [/* @__PURE__ */ g(c, { className: "h-3 w-3" }), /* @__PURE__ */ g("span", {
350
+ children: [/* @__PURE__ */ g(te, { className: "h-3 w-3" }), /* @__PURE__ */ g("span", {
301
351
  className: "truncate text-xs",
302
352
  children: e.location
303
353
  })]
@@ -312,98 +362,107 @@ function L() {
312
362
  },
313
363
  {
314
364
  key: "rating",
315
- header: "Rating",
316
- cell: (e) => /* @__PURE__ */ _("div", {
317
- className: "flex items-center gap-1",
318
- children: [/* @__PURE__ */ g(f, { className: "h-3 w-3 text-status-warning-text" }), /* @__PURE__ */ g("span", { children: e.performanceScore })]
319
- })
365
+ header: "Performance",
366
+ cell: (e) => {
367
+ let t = e.performanceScore >= 4 ? "text-status-success-text" : e.performanceScore >= 3 ? "text-status-warning-text" : "text-status-error-text";
368
+ return /* @__PURE__ */ _("div", {
369
+ className: "flex items-center gap-1.5",
370
+ children: [/* @__PURE__ */ g("span", {
371
+ className: `font-semibold tabular-nums ${t}`,
372
+ children: e.performanceScore.toFixed(1)
373
+ }), /* @__PURE__ */ g(u, { className: `h-3.5 w-3.5 fill-current ${t}` })]
374
+ });
375
+ }
320
376
  },
321
377
  {
322
378
  key: "status",
323
379
  header: "Status",
324
- cell: (e) => /* @__PURE__ */ g(v, {
380
+ cell: (e) => /* @__PURE__ */ g(ae, {
325
381
  variant: e.status === "active" ? "default" : e.status === "on_leave" ? "secondary" : "destructive",
326
382
  className: "text-[10px]",
327
383
  children: e.status.replace("_", " ")
328
384
  })
329
385
  }
330
386
  ],
331
- rowActions: (e) => /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(y, {
387
+ onRowClick: (e) => ve(e),
388
+ rowActions: (e) => /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(v, {
332
389
  variant: "ghost",
333
390
  size: "sm",
334
391
  className: "h-8 w-8 p-0",
335
392
  "aria-label": `Edit ${e.firstName} ${e.lastName}`,
336
- onClick: () => W.openModal(e),
337
- children: /* @__PURE__ */ g(l, { className: "h-4 w-4" })
338
- }), /* @__PURE__ */ g(y, {
393
+ onClick: () => U.openModal(e),
394
+ children: /* @__PURE__ */ g(ne, { className: "h-4 w-4" })
395
+ }), /* @__PURE__ */ g(v, {
339
396
  variant: "ghost",
340
397
  size: "sm",
341
398
  className: "h-8 w-8 p-0",
342
399
  "aria-label": `Delete ${e.firstName} ${e.lastName}`,
343
- onClick: () => K(e),
344
- children: /* @__PURE__ */ g(ee, { className: "h-4 w-4 text-status-error-text" })
400
+ onClick: () => G(e),
401
+ children: /* @__PURE__ */ g(d, { className: "h-4 w-4 text-status-error-text" })
345
402
  })] }),
346
403
  emptyState: /* @__PURE__ */ g("div", {
347
404
  className: "p-6",
348
- children: /* @__PURE__ */ g(te, {
405
+ children: /* @__PURE__ */ g(ce, {
349
406
  illustration: "empty-people",
350
407
  title: "No employees match",
351
408
  description: "Try a different search term or department filter."
352
409
  })
353
410
  })
354
- }), Q.length > J && /* @__PURE__ */ g(D, {
355
- page: q,
356
- pageSize: J,
411
+ }), Q.length > K && /* @__PURE__ */ g(C, {
412
+ page: fe,
413
+ pageSize: K,
357
414
  totalItems: Q.length,
358
- onPageChange: X
415
+ onPageChange: J
359
416
  })]
360
417
  }) }),
361
- /* @__PURE__ */ g(t, {
362
- open: W.open,
363
- onOpenChange: W.onOpenChange,
418
+ /* @__PURE__ */ g(r, {
419
+ open: U.open,
420
+ onOpenChange: U.onOpenChange,
364
421
  title: $ ? "Edit employee" : "Add employee",
365
422
  description: $ ? "Update this team member’s profile details." : "Add a new team member to your directory.",
366
- fields: F,
367
- initialValues: $ ? I($) : void 0,
423
+ fields: j,
424
+ initialValues: $ ? M($) : void 0,
368
425
  submitLabel: $ ? "Save changes" : "Add employee",
369
426
  onSubmit: async (e) => {
370
427
  let t = {
371
- id: $?.id ?? o(),
372
- firstName: a(e, "firstName"),
373
- lastName: a(e, "lastName"),
374
- email: a(e, "email"),
375
- department: a(e, "department"),
376
- position: a(e, "position"),
377
- status: a(e, "status"),
378
- type: a(e, "type"),
379
- salary: i(e, "salary"),
380
- startDate: a(e, "startDate"),
381
- location: a(e, "location"),
382
- phone: a(e, "phone"),
383
- performanceScore: i(e, "performanceScore"),
428
+ id: $?.id ?? c(),
429
+ firstName: s(e, "firstName"),
430
+ lastName: s(e, "lastName"),
431
+ email: s(e, "email"),
432
+ department: s(e, "department"),
433
+ position: s(e, "position"),
434
+ status: s(e, "status"),
435
+ type: s(e, "type"),
436
+ salary: o(e, "salary"),
437
+ startDate: s(e, "startDate"),
438
+ location: s(e, "location"),
439
+ phone: s(e, "phone"),
440
+ performanceScore: o(e, "performanceScore"),
441
+ skills: ee(e, "skills"),
442
+ terminationDate: $?.terminationDate,
384
443
  managerId: $?.managerId,
385
444
  avatar: $?.avatar
386
445
  };
387
- $ ? await z($.id, t) : await R(t);
446
+ $ ? await I($.id, t) : await F(t);
388
447
  }
389
448
  }),
390
- /* @__PURE__ */ g(r, {
391
- open: G !== null,
449
+ /* @__PURE__ */ g(a, {
450
+ open: W !== null,
392
451
  onOpenChange: (e) => {
393
- e || K(null);
452
+ e || G(null);
394
453
  },
395
454
  title: "Delete employee?",
396
- description: G ? `${G.firstName} ${G.lastName} will be removed from the directory. This cannot be undone.` : void 0,
455
+ description: W ? `${W.firstName} ${W.lastName} will be removed from the directory. This cannot be undone.` : void 0,
397
456
  confirmLabel: "Delete",
398
457
  destructive: !0,
399
458
  onConfirm: async () => {
400
- G && (await B(G.id), K(null));
459
+ W && (await L(W.id), G(null));
401
460
  }
402
461
  })
403
462
  ]
404
463
  });
405
464
  }
406
465
  //#endregion
407
- export { L as HrEmployeesPagePage };
466
+ export { N as HrEmployeesPagePage };
408
467
 
409
468
  //# sourceMappingURL=HrEmployeesPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HrEmployeesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HrEmployeesPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { MapPin, Pencil, Plus, Search, Star, Trash2, UserCheck, Users } from 'lucide-react';\nimport { useCrewFoundryStore, type Employee } from '../store/crewfoundryStore';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { ConfirmDialog } from '../components/forms/ConfirmDialog';\nimport { getNumber, getText, newClientId } from '../components/forms/formValues';\n\nconst EMPLOYEE_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, colSpan: 2 },\n { name: 'position', label: 'Position', type: 'text', required: true },\n { name: 'department', label: 'Department', type: 'text', required: true },\n { name: 'location', label: 'Location', type: 'text', required: true },\n { name: 'phone', label: 'Phone', type: 'text', required: true },\n {\n name: 'type',\n label: 'Employment type',\n type: 'select',\n required: true,\n options: [\n { label: 'Full time', value: 'full_time' },\n { label: 'Part time', value: 'part_time' },\n { label: 'Contract', value: 'contract' },\n { label: 'Intern', value: 'intern' },\n ],\n },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n required: true,\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Inactive', value: 'inactive' },\n { label: 'On leave', value: 'on_leave' },\n { label: 'Terminated', value: 'terminated' },\n ],\n },\n { name: 'salary', label: 'Annual salary', type: 'number', required: true },\n { name: 'startDate', label: 'Start date', type: 'date', required: true },\n { name: 'performanceScore', label: 'Performance score (0-5)', type: 'number' },\n];\n\nconst toFormValues = (employee: Employee): FormValues => ({\n firstName: employee.firstName,\n lastName: employee.lastName,\n email: employee.email,\n position: employee.position,\n department: employee.department,\n location: employee.location,\n phone: employee.phone,\n type: employee.type,\n status: employee.status,\n salary: employee.salary,\n startDate: employee.startDate.slice(0, 10),\n performanceScore: employee.performanceScore,\n});\n\nexport function HrEmployeesPagePage() {\n const { employees, addEmployee, updateEmployee, removeEmployee } = useCrewFoundryStore();\n const [search, setSearch] = useState('');\n const [filterDept, setFilterDept] = useState<string>('all');\n const form = useFormModal<Employee>();\n const [deleting, setDeleting] = useState<Employee | null>(null);\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 25 });\n\n const departments = [...new Set(employees.map((e) => e.department))];\n const filtered = employees.filter((e) => {\n const matchSearch = `${e.firstName} ${e.lastName} ${e.email} ${e.position}`\n .toLowerCase()\n .includes(search.toLowerCase());\n const matchDept = filterDept === 'all' || e.department === filterDept;\n return matchSearch && matchDept;\n });\n const pageItems = filtered.slice(offset, offset + pageSize);\n\n const handleSearchChange = (value: string) => {\n setSearch(value);\n setPage(1);\n };\n const handleDeptChange = (value: string) => {\n setFilterDept(value);\n setPage(1);\n };\n\n const activeCount = employees.filter((e) => e.status === 'active').length;\n const onLeaveCount = employees.filter((e) => e.status === 'on_leave').length;\n const avgRating =\n employees.length > 0\n ? (employees.reduce((s, e) => s + e.performanceScore, 0) / employees.length).toFixed(1)\n : '0.0';\n\n const editing = form.context;\n\n const handleSubmit = async (values: FormValues) => {\n const payload: Employee = {\n id: editing?.id ?? newClientId(),\n firstName: getText(values, 'firstName'),\n lastName: getText(values, 'lastName'),\n email: getText(values, 'email'),\n department: getText(values, 'department'),\n position: getText(values, 'position'),\n status: getText(values, 'status') as Employee['status'],\n type: getText(values, 'type') as Employee['type'],\n salary: getNumber(values, 'salary'),\n startDate: getText(values, 'startDate'),\n location: getText(values, 'location'),\n phone: getText(values, 'phone'),\n performanceScore: getNumber(values, 'performanceScore'),\n managerId: editing?.managerId,\n avatar: editing?.avatar,\n };\n if (editing) {\n await updateEmployee(editing.id, payload);\n } else {\n await addEmployee(payload);\n }\n };\n\n const columns: ResponsiveTableColumn<Employee>[] = [\n {\n key: 'name',\n header: 'Name',\n priority: 'primary',\n cell: (emp) => (\n <div>\n <p className=\"font-medium\">\n {emp.firstName} {emp.lastName}\n </p>\n <p className=\"text-xs text-text-secondary\">{emp.email}</p>\n </div>\n ),\n },\n {\n key: 'position',\n header: 'Position',\n cell: (emp) => <span className=\"text-text-secondary\">{emp.position}</span>,\n },\n {\n key: 'department',\n header: 'Department',\n cell: (emp) => <span>{emp.department}</span>,\n },\n {\n key: 'location',\n header: 'Location',\n cell: (emp) => (\n <div className=\"flex items-center gap-1 text-text-secondary\">\n <MapPin className=\"h-3 w-3\" />\n <span className=\"truncate text-xs\">{emp.location}</span>\n </div>\n ),\n },\n {\n key: 'salary',\n header: 'Salary',\n headerClassName: 'text-right',\n cellClassName: 'md:text-right',\n cell: (emp) => <span>${emp.salary.toLocaleString()}</span>,\n },\n {\n key: 'rating',\n header: 'Rating',\n cell: (emp) => (\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n <span>{emp.performanceScore}</span>\n </div>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n cell: (emp) => (\n <Badge\n variant={\n emp.status === 'active'\n ? 'default'\n : emp.status === 'on_leave'\n ? 'secondary'\n : 'destructive'\n }\n className=\"text-[10px]\"\n >\n {emp.status.replace('_', ' ')}\n </Badge>\n ),\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Employee Directory</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {employees.length} employees across {departments.length} departments\n </p>\n <PagePurpose className=\"mt-1\">\n Your complete employee directory — search, filter, and review everyone on the team along\n with their role, department, and status.\n </PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => form.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add Employee\n </Button>\n </div>\n\n <div className=\"grid gap-4 md: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\">Total</CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{employees.length}</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Active</CardTitle>\n <UserCheck className=\"h-4 w-4 text-status-success-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activeCount}</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">On Leave</CardTitle>\n <Users className=\"h-4 w-4 text-status-warning-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{onLeaveCount}</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Avg Rating</CardTitle>\n <Star className=\"h-4 w-4 text-status-warning-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgRating}</div>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n <div className=\"relative flex-1 sm: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 employees...\"\n className=\"pl-9\"\n value={search}\n onChange={(e) => handleSearchChange(e.target.value)}\n />\n </div>\n <Select value={filterDept} onValueChange={handleDeptChange}>\n <SelectTrigger className=\"w-full sm:w-56\" aria-label=\"Filter by department\">\n <SelectValue placeholder=\"All departments\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All departments</SelectItem>\n {departments.map((dept) => (\n <SelectItem key={dept} value={dept}>\n {dept}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <Card>\n <CardContent className=\"space-y-4 p-4\">\n <ResponsiveTable<Employee>\n data={pageItems}\n rowKey={(emp) => emp.id}\n columns={columns}\n rowActions={(emp) => (\n <>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Edit ${emp.firstName} ${emp.lastName}`}\n onClick={() => form.openModal(emp)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Delete ${emp.firstName} ${emp.lastName}`}\n onClick={() => setDeleting(emp)}\n >\n <Trash2 className=\"h-4 w-4 text-status-error-text\" />\n </Button>\n </>\n )}\n emptyState={\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title=\"No employees match\"\n description=\"Try a different search term or department filter.\"\n />\n </div>\n }\n />\n {filtered.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={filtered.length}\n onPageChange={setPage}\n />\n )}\n </CardContent>\n </Card>\n\n <FormModal\n open={form.open}\n onOpenChange={form.onOpenChange}\n title={editing ? 'Edit employee' : 'Add employee'}\n description={\n editing\n ? 'Update this team member’s profile details.'\n : 'Add a new team member to your directory.'\n }\n fields={EMPLOYEE_FIELDS}\n initialValues={editing ? toFormValues(editing) : undefined}\n submitLabel={editing ? 'Save changes' : 'Add employee'}\n onSubmit={handleSubmit}\n />\n\n <ConfirmDialog\n open={deleting !== null}\n onOpenChange={(open) => {\n if (!open) {\n setDeleting(null);\n }\n }}\n title=\"Delete employee?\"\n description={\n deleting\n ? `${deleting.firstName} ${deleting.lastName} will be removed from the directory. This cannot be undone.`\n : undefined\n }\n confirmLabel=\"Delete\"\n destructive\n onConfirm={async () => {\n if (deleting) {\n await removeEmployee(deleting.id);\n setDeleting(null);\n }\n }}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"HrEmployeesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HrEmployeesPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { MapPin, Pencil, Plus, Search, Star, Trash2, UserCheck, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore, type Employee } from '../store/crewfoundryStore';\nimport { AvatarStack, SegmentedTabs } from '../components/viz';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { ConfirmDialog } from '../components/forms/ConfirmDialog';\nimport { getNumber, getTags, getText, newClientId } from '../components/forms/formValues';\n\nconst EMPLOYEE_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, colSpan: 2 },\n { name: 'position', label: 'Position', type: 'text', required: true },\n { name: 'department', label: 'Department', type: 'text', required: true },\n { name: 'location', label: 'Location', type: 'text', required: true },\n { name: 'phone', label: 'Phone', type: 'text', required: true },\n {\n name: 'type',\n label: 'Employment type',\n type: 'select',\n required: true,\n options: [\n { label: 'Full time', value: 'full_time' },\n { label: 'Part time', value: 'part_time' },\n { label: 'Contract', value: 'contract' },\n { label: 'Intern', value: 'intern' },\n ],\n },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n required: true,\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Inactive', value: 'inactive' },\n { label: 'On leave', value: 'on_leave' },\n { label: 'Terminated', value: 'terminated' },\n ],\n },\n { name: 'salary', label: 'Annual salary', type: 'number', required: true },\n { name: 'startDate', label: 'Start date', type: 'date', required: true },\n { name: 'performanceScore', label: 'Performance score (0-5)', type: 'number' },\n {\n name: 'skills',\n label: 'Skills',\n type: 'tags',\n colSpan: 2,\n placeholder: 'Add a skill and press Enter',\n },\n];\n\nconst toFormValues = (employee: Employee): FormValues => ({\n firstName: employee.firstName,\n lastName: employee.lastName,\n email: employee.email,\n position: employee.position,\n department: employee.department,\n location: employee.location,\n phone: employee.phone,\n type: employee.type,\n status: employee.status,\n salary: employee.salary,\n startDate: employee.startDate.slice(0, 10),\n performanceScore: employee.performanceScore,\n skills: employee.skills,\n});\n\nexport function HrEmployeesPagePage() {\n const navigate = useNavigate();\n const { employees, addEmployee, updateEmployee, removeEmployee } = useCrewFoundryStore();\n const [search, setSearch] = useState('');\n const [filterDept, setFilterDept] = useState<string>('all');\n const [filterStatus, setFilterStatus] = useState<'all' | 'active' | 'on_leave'>('all');\n const form = useFormModal<Employee>();\n const [deleting, setDeleting] = useState<Employee | null>(null);\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 25 });\n\n const departments = [...new Set(employees.map((e) => e.department))];\n const activeCount = employees.filter((e) => e.status === 'active').length;\n const onLeaveCount = employees.filter((e) => e.status === 'on_leave').length;\n\n const filtered = employees.filter((e) => {\n const matchSearch = `${e.firstName} ${e.lastName} ${e.email} ${e.position}`\n .toLowerCase()\n .includes(search.toLowerCase());\n const matchDept = filterDept === 'all' || e.department === filterDept;\n const matchStatus = filterStatus === 'all' || e.status === filterStatus;\n return matchSearch && matchDept && matchStatus;\n });\n const pageItems = filtered.slice(offset, offset + pageSize);\n\n const handleSearchChange = (value: string) => {\n setSearch(value);\n setPage(1);\n };\n const handleDeptChange = (value: string) => {\n setFilterDept(value);\n setPage(1);\n };\n const handleStatusChange = (value: string) => {\n setFilterStatus(value as 'all' | 'active' | 'on_leave');\n setPage(1);\n };\n const avgRating =\n employees.length > 0\n ? (employees.reduce((s, e) => s + e.performanceScore, 0) / employees.length).toFixed(1)\n : '0.0';\n\n const editing = form.context;\n\n const openProfile = (employee: Employee) =>\n navigate(`../hr/employee-profile-page?id=${encodeURIComponent(employee.id)}`);\n\n const handleSubmit = async (values: FormValues) => {\n const payload: Employee = {\n id: editing?.id ?? newClientId(),\n firstName: getText(values, 'firstName'),\n lastName: getText(values, 'lastName'),\n email: getText(values, 'email'),\n department: getText(values, 'department'),\n position: getText(values, 'position'),\n status: getText(values, 'status') as Employee['status'],\n type: getText(values, 'type') as Employee['type'],\n salary: getNumber(values, 'salary'),\n startDate: getText(values, 'startDate'),\n location: getText(values, 'location'),\n phone: getText(values, 'phone'),\n performanceScore: getNumber(values, 'performanceScore'),\n skills: getTags(values, 'skills'),\n // Preserve the exit date on edit (there is no exit-date input here); new\n // employees have none. The store mapper passes it through when present.\n terminationDate: editing?.terminationDate,\n managerId: editing?.managerId,\n avatar: editing?.avatar,\n };\n if (editing) {\n await updateEmployee(editing.id, payload);\n } else {\n await addEmployee(payload);\n }\n };\n\n const columns: ResponsiveTableColumn<Employee>[] = [\n {\n key: 'name',\n header: 'Employee',\n priority: 'primary',\n cell: (emp) => (\n <div className=\"flex items-center gap-3\">\n <AvatarStack\n people={[{ name: `${emp.firstName} ${emp.lastName}`, avatarUrl: emp.avatar }]}\n size={36}\n />\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium\">\n {emp.firstName} {emp.lastName}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">{emp.email}</p>\n </div>\n </div>\n ),\n },\n {\n key: 'position',\n header: 'Position',\n cell: (emp) => <span className=\"text-text-secondary\">{emp.position}</span>,\n },\n {\n key: 'department',\n header: 'Department',\n cell: (emp) => <span>{emp.department}</span>,\n },\n {\n key: 'location',\n header: 'Location',\n cell: (emp) => (\n <div className=\"flex items-center gap-1 text-text-secondary\">\n <MapPin className=\"h-3 w-3\" />\n <span className=\"truncate text-xs\">{emp.location}</span>\n </div>\n ),\n },\n {\n key: 'salary',\n header: 'Salary',\n headerClassName: 'text-right',\n cellClassName: 'md:text-right',\n cell: (emp) => <span>${emp.salary.toLocaleString()}</span>,\n },\n {\n key: 'rating',\n header: 'Performance',\n cell: (emp) => {\n const tone =\n emp.performanceScore >= 4\n ? 'text-status-success-text'\n : emp.performanceScore >= 3\n ? 'text-status-warning-text'\n : 'text-status-error-text';\n return (\n <div className=\"flex items-center gap-1.5\">\n <span className={`font-semibold tabular-nums ${tone}`}>\n {emp.performanceScore.toFixed(1)}\n </span>\n <Star className={`h-3.5 w-3.5 fill-current ${tone}`} />\n </div>\n );\n },\n },\n {\n key: 'status',\n header: 'Status',\n cell: (emp) => (\n <Badge\n variant={\n emp.status === 'active'\n ? 'default'\n : emp.status === 'on_leave'\n ? 'secondary'\n : 'destructive'\n }\n className=\"text-[10px]\"\n >\n {emp.status.replace('_', ' ')}\n </Badge>\n ),\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Employee Directory</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {employees.length} employees across {departments.length} departments\n </p>\n <PagePurpose className=\"mt-1\">\n Your complete employee directory — search, filter, and review everyone on the team along\n with their role, department, and status.\n </PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => form.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add Employee\n </Button>\n </div>\n\n <div className=\"grid gap-4 md: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\">Total</CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{employees.length}</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Active</CardTitle>\n <UserCheck className=\"h-4 w-4 text-status-success-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activeCount}</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">On Leave</CardTitle>\n <Users className=\"h-4 w-4 text-status-warning-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{onLeaveCount}</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Avg Rating</CardTitle>\n <Star className=\"h-4 w-4 text-status-warning-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgRating}</div>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <SegmentedTabs\n aria-label=\"Filter by status\"\n value={filterStatus}\n onChange={handleStatusChange}\n tabs={[\n { id: 'all', label: 'All', count: employees.length },\n { id: 'active', label: 'Active', count: activeCount },\n { id: 'on_leave', label: 'On Leave', count: onLeaveCount },\n ]}\n />\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n <div className=\"relative flex-1 sm: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 employees...\"\n className=\"pl-9\"\n value={search}\n onChange={(e) => handleSearchChange(e.target.value)}\n />\n </div>\n <Select value={filterDept} onValueChange={handleDeptChange}>\n <SelectTrigger className=\"w-full sm:w-56\" aria-label=\"Filter by department\">\n <SelectValue placeholder=\"All departments\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All departments</SelectItem>\n {departments.map((dept) => (\n <SelectItem key={dept} value={dept}>\n {dept}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <Card>\n <CardContent className=\"space-y-4 p-4\">\n <ResponsiveTable<Employee>\n data={pageItems}\n rowKey={(emp) => emp.id}\n columns={columns}\n onRowClick={(emp) => openProfile(emp)}\n rowActions={(emp) => (\n <>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Edit ${emp.firstName} ${emp.lastName}`}\n onClick={() => form.openModal(emp)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Delete ${emp.firstName} ${emp.lastName}`}\n onClick={() => setDeleting(emp)}\n >\n <Trash2 className=\"h-4 w-4 text-status-error-text\" />\n </Button>\n </>\n )}\n emptyState={\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title=\"No employees match\"\n description=\"Try a different search term or department filter.\"\n />\n </div>\n }\n />\n {filtered.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={filtered.length}\n onPageChange={setPage}\n />\n )}\n </CardContent>\n </Card>\n\n <FormModal\n open={form.open}\n onOpenChange={form.onOpenChange}\n title={editing ? 'Edit employee' : 'Add employee'}\n description={\n editing\n ? 'Update this team member’s profile details.'\n : 'Add a new team member to your directory.'\n }\n fields={EMPLOYEE_FIELDS}\n initialValues={editing ? toFormValues(editing) : undefined}\n submitLabel={editing ? 'Save changes' : 'Add employee'}\n onSubmit={handleSubmit}\n />\n\n <ConfirmDialog\n open={deleting !== null}\n onOpenChange={(open) => {\n if (!open) {\n setDeleting(null);\n }\n }}\n title=\"Delete employee?\"\n description={\n deleting\n ? `${deleting.firstName} ${deleting.lastName} will be removed from the directory. This cannot be undone.`\n : undefined\n }\n confirmLabel=\"Delete\"\n destructive\n onConfirm={async () => {\n if (deleting) {\n await removeEmployee(deleting.id);\n setDeleting(null);\n }\n }}\n />\n </div>\n );\n}\n"],"mappings":"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"}