@burdenoff/microfe-crewfoundry 2026.1030.3 → 2026.1102.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/crewfoundry/CrewFoundryRoutes.d.ts.map +1 -1
  2. package/dist/crewfoundry/CrewFoundryRoutes.js +18 -14
  3. package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
  4. package/dist/crewfoundry/components/EmployeeSkillsPanel.d.ts +9 -0
  5. package/dist/crewfoundry/components/EmployeeSkillsPanel.d.ts.map +1 -1
  6. package/dist/crewfoundry/components/EmployeeSkillsPanel.js +111 -77
  7. package/dist/crewfoundry/components/EmployeeSkillsPanel.js.map +1 -1
  8. package/dist/crewfoundry/components/skills/FindPeopleBySkillCard.d.ts +13 -0
  9. package/dist/crewfoundry/components/skills/FindPeopleBySkillCard.d.ts.map +1 -0
  10. package/dist/crewfoundry/components/skills/FindPeopleBySkillCard.js +128 -0
  11. package/dist/crewfoundry/components/skills/FindPeopleBySkillCard.js.map +1 -0
  12. package/dist/crewfoundry/components/skills/MergeSkillDialog.d.ts +15 -0
  13. package/dist/crewfoundry/components/skills/MergeSkillDialog.d.ts.map +1 -0
  14. package/dist/crewfoundry/components/skills/MergeSkillDialog.js +58 -0
  15. package/dist/crewfoundry/components/skills/MergeSkillDialog.js.map +1 -0
  16. package/dist/crewfoundry/components/skills/RoleSkillMatchPanel.d.ts +15 -0
  17. package/dist/crewfoundry/components/skills/RoleSkillMatchPanel.d.ts.map +1 -0
  18. package/dist/crewfoundry/components/skills/RoleSkillMatchPanel.js +163 -0
  19. package/dist/crewfoundry/components/skills/RoleSkillMatchPanel.js.map +1 -0
  20. package/dist/crewfoundry/components/skills/SkillPicker.d.ts +20 -0
  21. package/dist/crewfoundry/components/skills/SkillPicker.d.ts.map +1 -0
  22. package/dist/crewfoundry/components/skills/SkillPicker.js +73 -0
  23. package/dist/crewfoundry/components/skills/SkillPicker.js.map +1 -0
  24. package/dist/crewfoundry/components/skills/SkillRelationsDialog.d.ts +13 -0
  25. package/dist/crewfoundry/components/skills/SkillRelationsDialog.d.ts.map +1 -0
  26. package/dist/crewfoundry/components/skills/SkillRelationsDialog.js +156 -0
  27. package/dist/crewfoundry/components/skills/SkillRelationsDialog.js.map +1 -0
  28. package/dist/crewfoundry/lib/analytics.d.ts +1 -29
  29. package/dist/crewfoundry/lib/analytics.d.ts.map +1 -1
  30. package/dist/crewfoundry/lib/analytics.js +3 -48
  31. package/dist/crewfoundry/lib/analytics.js.map +1 -1
  32. package/dist/crewfoundry/lib/skillMatching.d.ts +70 -0
  33. package/dist/crewfoundry/lib/skillMatching.d.ts.map +1 -0
  34. package/dist/crewfoundry/lib/skillMatching.js +73 -0
  35. package/dist/crewfoundry/lib/skillMatching.js.map +1 -0
  36. package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.d.ts +8 -0
  37. package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.d.ts.map +1 -1
  38. package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js +468 -212
  39. package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js.map +1 -1
  40. package/dist/crewfoundry/pages/HiringCandidatesPagePage.d.ts.map +1 -1
  41. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +210 -177
  42. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
  43. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +6 -6
  44. package/dist/crewfoundry/pages/HrSkillsTaxonomyPagePage.d.ts +9 -0
  45. package/dist/crewfoundry/pages/HrSkillsTaxonomyPagePage.d.ts.map +1 -0
  46. package/dist/crewfoundry/pages/HrSkillsTaxonomyPagePage.js +456 -0
  47. package/dist/crewfoundry/pages/HrSkillsTaxonomyPagePage.js.map +1 -0
  48. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.d.ts.map +1 -1
  49. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +50 -102
  50. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -1
  51. package/dist/crewfoundry/store/crewfoundryStore.d.ts +145 -0
  52. package/dist/crewfoundry/store/crewfoundryStore.d.ts.map +1 -1
  53. package/dist/crewfoundry/store/crewfoundryStore.js +188 -57
  54. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  55. package/package.json +1 -1
@@ -1,233 +1,489 @@
1
1
  import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
2
- import { useMemo as t } from "react";
3
- import { Building2 as n, Percent as r, Target as i } from "lucide-react";
4
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
5
- import { Badge as s, Card as c, CardContent as l, CardDescription as u, CardHeader as d, CardTitle as f, GlassCard as p, GradientText as m, PagePurpose as h, ResponsiveTable as g, Separator as _ } from "@burdenoff/fe-libs/ui";
2
+ import { useCallback as t, useEffect as n, useMemo as r } from "react";
3
+ import { Building2 as i, Percent as a, RefreshCw as o, Target as s, UserPlus as c, Users as l } from "lucide-react";
4
+ import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
5
+ import { Badge as p, Button as m, Card as h, CardContent as g, CardDescription as _, CardHeader as v, CardTitle as y, GlassCard as b, GradientText as x, IllustratedEmptyState as S, PagePurpose as C, ResponsiveTable as w, Separator as T, Spinner as E } from "@burdenoff/fe-libs/ui";
6
6
  //#region src/crewfoundry/pages/DashboardExecutiveDashboardPage.tsx
7
- function v() {
8
- let { employees: v, departments: y, projects: b, jobPostings: x } = e(), S = t(() => [
9
- {
10
- metric: "Flight Risk Employees",
11
- value: v.filter((e) => e.performanceScore < 3.6).length,
12
- severity: "warning",
13
- detail: `${Math.round(v.filter((e) => e.performanceScore < 3.6).length / Math.max(v.length, 1) * 100)}% of workforce`
14
- },
15
- {
16
- metric: "Employees On Leave",
17
- value: v.filter((e) => e.status === "on_leave").length,
18
- severity: "error",
19
- detail: "Coverage follow-ups required"
20
- },
21
- {
22
- metric: "Unfilled Lead Roles",
23
- value: x.filter((e) => e.status === "active" && e.experienceLevel === "lead").length,
24
- severity: "warning",
25
- detail: "Open lead-level positions"
26
- },
27
- {
28
- metric: "Contract Employees",
29
- value: v.filter((e) => e.type === "contract").length,
30
- severity: "info",
31
- detail: "Contract renewals in focus"
32
- }
33
- ], [v, x]), C = v.reduce((e, t) => e + t.salary, 0), w = y.reduce((e, t) => e + t.budget, 0), T = b.reduce((e, t) => e + t.budget, 0), E = b.reduce((e, t) => e + t.spent, 0), D = T > 0 ? Math.round(E / T * 100) : 0, O = v.filter((e) => e.status === "terminated").length, k = v.length > 0 ? Math.round((1 - O / v.length) * 100) : 0, A = y.reduce((e, t) => e + t.employeeCount, 0), j = A > 0 ? w / A : 0;
34
- return /* @__PURE__ */ o("div", {
7
+ var D = 8, O = {
8
+ HIGH: "destructive",
9
+ MEDIUM: "warning",
10
+ LOW: "secondary"
11
+ };
12
+ function k(e) {
13
+ return Math.abs(e) >= 1e6 ? `$${(e / 1e6).toFixed(1)}M` : Math.abs(e) >= 1e3 ? `$${(e / 1e3).toFixed(0)}K` : `$${Math.round(e)}`;
14
+ }
15
+ function A(e) {
16
+ let t = new Date(e);
17
+ return Number.isNaN(t.getTime()) ? "" : t.toLocaleString(void 0, {
18
+ dateStyle: "medium",
19
+ timeStyle: "short"
20
+ });
21
+ }
22
+ var j = [
23
+ {
24
+ key: "employee",
25
+ header: "Employee",
26
+ priority: "primary",
27
+ cell: (e) => /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("p", {
28
+ className: "font-medium",
29
+ children: e.employeeName
30
+ }), /* @__PURE__ */ d("p", {
31
+ className: "text-xs text-text-secondary",
32
+ children: e.department
33
+ })] })
34
+ },
35
+ {
36
+ key: "level",
37
+ header: "Risk",
38
+ priority: "primary",
39
+ cell: (e) => /* @__PURE__ */ f(p, {
40
+ variant: O[e.riskLevel],
41
+ children: [
42
+ e.riskLevel.charAt(0),
43
+ e.riskLevel.slice(1).toLowerCase(),
44
+ " · ",
45
+ e.riskScore.toFixed(2)
46
+ ]
47
+ })
48
+ },
49
+ {
50
+ key: "drivers",
51
+ header: "Drivers",
52
+ priority: "secondary",
53
+ cell: (e) => /* @__PURE__ */ d("span", {
54
+ className: "text-sm text-text-secondary",
55
+ children: e.drivers.length > 0 ? e.drivers.join(", ") : "No risk signals"
56
+ })
57
+ }
58
+ ], M = [
59
+ {
60
+ key: "department",
61
+ header: "Department",
62
+ priority: "primary",
63
+ cell: (e) => /* @__PURE__ */ d("span", {
64
+ className: "font-medium",
65
+ children: e.department
66
+ })
67
+ },
68
+ {
69
+ key: "current",
70
+ header: "Active",
71
+ priority: "secondary",
72
+ cell: (e) => /* @__PURE__ */ d("span", {
73
+ className: "tabular-nums md:block md:text-right",
74
+ children: e.current
75
+ })
76
+ },
77
+ {
78
+ key: "open",
79
+ header: "Open roles",
80
+ priority: "primary",
81
+ cell: (e) => /* @__PURE__ */ d("span", {
82
+ className: "tabular-nums md:block md:text-right",
83
+ children: e.openPostings
84
+ })
85
+ },
86
+ {
87
+ key: "projected",
88
+ header: "Projected",
89
+ priority: "secondary",
90
+ cell: (e) => /* @__PURE__ */ d("span", {
91
+ className: "tabular-nums md:block md:text-right",
92
+ children: e.projectedHeadcount
93
+ })
94
+ }
95
+ ], N = [
96
+ {
97
+ key: "skill",
98
+ header: "Skill",
99
+ priority: "primary",
100
+ cell: (e) => /* @__PURE__ */ d("span", {
101
+ className: "font-medium",
102
+ children: e.skill
103
+ })
104
+ },
105
+ {
106
+ key: "supply",
107
+ header: "People",
108
+ priority: "secondary",
109
+ cell: (e) => /* @__PURE__ */ d("span", {
110
+ className: "tabular-nums md:block md:text-right",
111
+ children: e.employeesWithSkill
112
+ })
113
+ },
114
+ {
115
+ key: "demand",
116
+ header: "Open roles",
117
+ priority: "secondary",
118
+ cell: (e) => /* @__PURE__ */ d("span", {
119
+ className: "tabular-nums md:block md:text-right",
120
+ children: e.openJobsRequiringSkill
121
+ })
122
+ },
123
+ {
124
+ key: "shortage",
125
+ header: "Shortage",
126
+ priority: "primary",
127
+ cell: (e) => /* @__PURE__ */ d("span", {
128
+ className: "font-semibold tabular-nums text-status-warning-text md:block md:text-right",
129
+ children: e.shortage
130
+ })
131
+ }
132
+ ], P = [
133
+ {
134
+ key: "department",
135
+ header: "Department",
136
+ priority: "primary",
137
+ cell: (e) => /* @__PURE__ */ d("span", {
138
+ className: "font-medium",
139
+ children: e.department
140
+ })
141
+ },
142
+ {
143
+ key: "headcount",
144
+ header: "Active",
145
+ priority: "secondary",
146
+ cell: (e) => /* @__PURE__ */ d("span", {
147
+ className: "tabular-nums md:block md:text-right",
148
+ children: e.headcount
149
+ })
150
+ },
151
+ {
152
+ key: "monthly",
153
+ header: "Monthly",
154
+ priority: "secondary",
155
+ cell: (e) => /* @__PURE__ */ d("span", {
156
+ className: "tabular-nums md:block md:text-right",
157
+ children: k(e.monthly)
158
+ })
159
+ },
160
+ {
161
+ key: "annual",
162
+ header: "Annual",
163
+ priority: "primary",
164
+ cell: (e) => /* @__PURE__ */ d("span", {
165
+ className: "tabular-nums md:block md:text-right",
166
+ children: k(e.annual)
167
+ })
168
+ }
169
+ ], F = [
170
+ {
171
+ key: "name",
172
+ header: "Department",
173
+ priority: "primary",
174
+ cell: (e) => /* @__PURE__ */ d("span", {
175
+ className: "font-medium",
176
+ children: e.name
177
+ })
178
+ },
179
+ {
180
+ key: "head",
181
+ header: "Head",
182
+ priority: "secondary",
183
+ cell: (e) => /* @__PURE__ */ d("span", {
184
+ className: "text-text-secondary",
185
+ children: e.headName
186
+ })
187
+ },
188
+ {
189
+ key: "headcount",
190
+ header: "Headcount",
191
+ priority: "secondary",
192
+ cell: (e) => /* @__PURE__ */ d("span", {
193
+ className: "md:block md:text-right",
194
+ children: e.employeeCount
195
+ })
196
+ },
197
+ {
198
+ key: "budget",
199
+ header: "Budget",
200
+ priority: "secondary",
201
+ cell: (e) => /* @__PURE__ */ d("span", {
202
+ className: "md:block md:text-right",
203
+ children: k(e.budget)
204
+ })
205
+ },
206
+ {
207
+ key: "costPerEmployee",
208
+ header: "Cost/Employee",
209
+ priority: "primary",
210
+ cell: (e) => /* @__PURE__ */ d("span", {
211
+ className: "md:block md:text-right",
212
+ children: k(e.employeeCount > 0 ? Math.round(e.budget / e.employeeCount) : 0)
213
+ })
214
+ }
215
+ ];
216
+ function I({ label: e, value: t, caption: n, icon: r, testId: i }) {
217
+ return /* @__PURE__ */ f(b, {
218
+ treatment: "metric",
219
+ className: "border-border-seam",
220
+ "data-testid": i,
221
+ children: [/* @__PURE__ */ f(v, {
222
+ className: "flex flex-row items-center justify-between space-y-0 pb-2",
223
+ children: [/* @__PURE__ */ d(y, {
224
+ className: "text-sm font-medium",
225
+ children: e
226
+ }), r]
227
+ }), /* @__PURE__ */ f(g, { children: [/* @__PURE__ */ d("div", {
228
+ className: "text-2xl font-bold tabular-nums",
229
+ children: t
230
+ }), /* @__PURE__ */ d("p", {
231
+ className: "text-xs text-text-secondary",
232
+ children: n
233
+ })] })]
234
+ });
235
+ }
236
+ function L({ analytics: e, budget: t, retention: n }) {
237
+ let r = e.costProjection.reduce((e, t) => e + t.annual, 0), o = e.headcountGap.reduce((e, t) => e + t.openPostings, 0), u = t.total > 0 ? Math.round(t.spent / t.total * 100) : 0, p = n.total > 0 ? `${Math.round(n.retained / n.total * 100)}%` : "—", m = "h-4 w-4 text-text-secondary";
238
+ return /* @__PURE__ */ f("div", {
239
+ className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4",
240
+ children: [
241
+ /* @__PURE__ */ d(I, {
242
+ label: "Active headcount",
243
+ value: e.activeHeadcount,
244
+ caption: `${e.totalHeadcount} people on record`,
245
+ icon: /* @__PURE__ */ d(l, { className: m }),
246
+ testId: "kpi-active-headcount"
247
+ }),
248
+ /* @__PURE__ */ d(I, {
249
+ label: "Hires and exits (90 days)",
250
+ value: `${e.newHiresLast90Days} / ${e.exitsLast90Days}`,
251
+ caption: `${e.newHiresLast90Days} joined, ${e.exitsLast90Days} left`,
252
+ icon: /* @__PURE__ */ d(c, { className: m })
253
+ }),
254
+ /* @__PURE__ */ d(I, {
255
+ label: "Average tenure",
256
+ value: `${e.averageTenureMonths.toFixed(1)} mo`,
257
+ caption: `Average performance ${e.averagePerformanceScore.toFixed(2)} of 5`,
258
+ icon: /* @__PURE__ */ d(s, { className: m })
259
+ }),
260
+ /* @__PURE__ */ d(I, {
261
+ label: "Retention rate",
262
+ value: p,
263
+ caption: `${n.total - n.retained} of ${n.total} people on record have left`,
264
+ icon: /* @__PURE__ */ d(s, { className: m })
265
+ }),
266
+ /* @__PURE__ */ d(I, {
267
+ label: "Payroll run-rate",
268
+ value: k(r),
269
+ caption: `Annual salary of active employees; ${o} open role${o === 1 ? "" : "s"} not included`,
270
+ icon: /* @__PURE__ */ d(i, { className: m }),
271
+ testId: "kpi-payroll-run-rate"
272
+ }),
273
+ /* @__PURE__ */ d(I, {
274
+ label: "Budget utilization",
275
+ value: `${u}%`,
276
+ caption: `${k(t.spent)} of ${k(t.total)} project budget`,
277
+ icon: /* @__PURE__ */ d(a, { className: m })
278
+ })
279
+ ]
280
+ });
281
+ }
282
+ var R = [
283
+ {
284
+ key: "high",
285
+ label: "High",
286
+ dot: "bg-status-error-text"
287
+ },
288
+ {
289
+ key: "medium",
290
+ label: "Medium",
291
+ dot: "bg-status-warning-text"
292
+ },
293
+ {
294
+ key: "low",
295
+ label: "Low",
296
+ dot: "bg-status-success-text"
297
+ }
298
+ ];
299
+ function z({ risk: e }) {
300
+ let t = {
301
+ high: e.highCount,
302
+ medium: e.mediumCount,
303
+ low: e.lowCount
304
+ };
305
+ return /* @__PURE__ */ f(h, { children: [/* @__PURE__ */ f(v, { children: [/* @__PURE__ */ d(y, { children: "Attrition risk" }), /* @__PURE__ */ d(_, { children: "Heuristic risk bands from performance, tenure, contract type and recent leave. A signal to start a conversation, not a prediction." })] }), /* @__PURE__ */ f(g, {
306
+ className: "space-y-4",
307
+ children: [/* @__PURE__ */ d("div", {
308
+ className: "grid gap-3 sm:grid-cols-3",
309
+ children: R.map((e) => /* @__PURE__ */ f("div", {
310
+ className: "flex items-center justify-between rounded border p-3",
311
+ "data-testid": `attrition-${e.key}`,
312
+ children: [/* @__PURE__ */ f("div", {
313
+ className: "flex items-center gap-3",
314
+ children: [/* @__PURE__ */ d("div", { className: `h-3 w-3 rounded-full ${e.dot}` }), /* @__PURE__ */ f("p", {
315
+ className: "text-sm font-medium",
316
+ children: [e.label, " risk"]
317
+ })]
318
+ }), /* @__PURE__ */ d("span", {
319
+ className: "text-lg font-bold tabular-nums",
320
+ children: t[e.key]
321
+ })]
322
+ }, e.key))
323
+ }), e.totalAssessed === 0 ? /* @__PURE__ */ d(S, {
324
+ illustration: "empty-data",
325
+ title: "No active employees to assess",
326
+ description: "Add employees to see where retention attention is needed."
327
+ }) : /* @__PURE__ */ d(w, {
328
+ columns: j,
329
+ data: e.topRisks,
330
+ rowKey: (e) => e.employeeId
331
+ })]
332
+ })] });
333
+ }
334
+ function B({ title: e, description: t, columns: n, rows: r, rowKey: i, emptyTitle: a, emptyDescription: o }) {
335
+ return /* @__PURE__ */ f(h, { children: [/* @__PURE__ */ f(v, { children: [/* @__PURE__ */ d(y, { children: e }), /* @__PURE__ */ d(_, { children: t })] }), /* @__PURE__ */ d(g, { children: r.length > 0 ? /* @__PURE__ */ d(w, {
336
+ columns: n,
337
+ data: r,
338
+ rowKey: i
339
+ }) : /* @__PURE__ */ d(S, {
340
+ illustration: "empty-data",
341
+ title: a,
342
+ description: o
343
+ }) })] });
344
+ }
345
+ function V({ analytics: e, budget: t, retention: n }) {
346
+ let r = e.skillsGap.filter((e) => e.shortage > 0).slice(0, D);
347
+ return /* @__PURE__ */ f(u, { children: [
348
+ /* @__PURE__ */ d(L, {
349
+ analytics: e,
350
+ budget: t,
351
+ retention: n
352
+ }),
353
+ /* @__PURE__ */ d(z, { risk: e.attritionRisk }),
354
+ /* @__PURE__ */ f("div", {
355
+ className: "grid gap-4 lg:grid-cols-2",
356
+ children: [/* @__PURE__ */ d(B, {
357
+ title: "Headcount plan",
358
+ description: "Active people per department plus open (active or paused) roles.",
359
+ columns: M,
360
+ rows: e.headcountGap,
361
+ rowKey: (e) => e.department,
362
+ emptyTitle: "No headcount yet",
363
+ emptyDescription: "Departments appear here once they have active people or open roles."
364
+ }), /* @__PURE__ */ d(B, {
365
+ title: "Skills shortages",
366
+ description: "Skills open roles ask for that more roles need than people have.",
367
+ columns: N,
368
+ rows: r,
369
+ rowKey: (e) => e.skill,
370
+ emptyTitle: "No skills shortages",
371
+ emptyDescription: "Every skill listed on an open role is covered by at least as many active employees."
372
+ })]
373
+ }),
374
+ /* @__PURE__ */ d(B, {
375
+ title: "Payroll run-rate by department",
376
+ description: "Annualised salary of active employees",
377
+ columns: P,
378
+ rows: e.costProjection,
379
+ rowKey: (e) => e.department,
380
+ emptyTitle: "No salaried employees yet",
381
+ emptyDescription: "Record salaries on active employees to see the run-rate."
382
+ })
383
+ ] });
384
+ }
385
+ function H({ departments: e }) {
386
+ let t = e.reduce((e, t) => e + t.budget, 0), n = e.reduce((e, t) => e + t.employeeCount, 0), r = n > 0 ? t / n : 0;
387
+ return /* @__PURE__ */ f(h, { children: [/* @__PURE__ */ f(v, { children: [/* @__PURE__ */ d(y, { children: "Department Budget Status" }), /* @__PURE__ */ d(_, { children: "Annual budget allocation and headcount" })] }), /* @__PURE__ */ f(g, { children: [
388
+ /* @__PURE__ */ d(w, {
389
+ columns: F,
390
+ data: e,
391
+ rowKey: (e) => e.id
392
+ }),
393
+ /* @__PURE__ */ d(T, { className: "my-3" }),
394
+ /* @__PURE__ */ f("div", {
395
+ className: "flex flex-wrap items-center justify-between gap-2 text-sm font-bold",
396
+ children: [
397
+ /* @__PURE__ */ d("span", { children: "Total" }),
398
+ /* @__PURE__ */ f("span", { children: [n, " employees"] }),
399
+ /* @__PURE__ */ f("span", { children: [k(t), " budget"] }),
400
+ /* @__PURE__ */ f("span", { children: [k(r), " / employee"] })
401
+ ]
402
+ })
403
+ ] })] });
404
+ }
405
+ function U() {
406
+ let i = e((e) => e.initialized), a = e((e) => e.initParams.workspaceId), s = e((e) => e.departments), c = e((e) => e.projects), l = e((e) => e.employees), u = e((e) => e.executiveDashboard), _ = e((e) => e.executiveDashboardLoading), v = e((e) => e.executiveDashboardError), y = e((e) => e.fetchExecutiveDashboard), b = t(() => {
407
+ y();
408
+ }, [y]);
409
+ n(() => {
410
+ !i || !a || b();
411
+ }, [
412
+ i,
413
+ a,
414
+ b
415
+ ]);
416
+ let S = r(() => ({
417
+ spent: c.reduce((e, t) => e + t.spent, 0),
418
+ total: c.reduce((e, t) => e + t.budget, 0)
419
+ }), [c]), w = r(() => ({
420
+ retained: l.filter((e) => e.status !== "terminated").length,
421
+ total: l.length
422
+ }), [l]);
423
+ return i ? /* @__PURE__ */ f("div", {
35
424
  className: "space-y-6 p-6",
36
425
  children: [
37
- /* @__PURE__ */ o("div", {
38
- className: "flex items-center justify-between",
39
- children: [/* @__PURE__ */ o("div", { children: [
40
- /* @__PURE__ */ a("h1", {
426
+ /* @__PURE__ */ f("div", {
427
+ className: "flex flex-wrap items-start justify-between gap-3",
428
+ children: [/* @__PURE__ */ f("div", { children: [
429
+ /* @__PURE__ */ d("h1", {
41
430
  className: "text-2xl font-semibold",
42
- children: /* @__PURE__ */ a(m, { children: "Executive Dashboard" })
431
+ children: /* @__PURE__ */ d(x, { children: "Executive Dashboard" })
43
432
  }),
44
- /* @__PURE__ */ a("p", {
433
+ /* @__PURE__ */ d("p", {
45
434
  className: "text-sm text-text-secondary",
46
435
  children: "Strategic workforce insights for leadership"
47
436
  }),
48
- /* @__PURE__ */ a(h, {
437
+ /* @__PURE__ */ d(C, {
49
438
  className: "mt-1",
50
- children: "The executive snapshot — top-line workforce, financial, and hiring KPIs in one view so leaders can make decisions fast."
439
+ children: "The executive snapshot — headcount, attrition risk, hiring plan, skills shortages and payroll run-rate in one view, computed from your workspace's own records."
51
440
  })
52
- ] }), /* @__PURE__ */ a(s, {
53
- variant: "outline",
54
- children: "Q1 2026"
441
+ ] }), /* @__PURE__ */ f("div", {
442
+ className: "flex items-center gap-2",
443
+ children: [u ? /* @__PURE__ */ f(p, {
444
+ variant: "outline",
445
+ children: ["Updated ", A(u.generatedAt)]
446
+ }) : null, /* @__PURE__ */ f(m, {
447
+ variant: "outline",
448
+ size: "sm",
449
+ onClick: b,
450
+ disabled: _,
451
+ "aria-label": "Refresh workforce analytics",
452
+ children: [/* @__PURE__ */ d(o, { className: `mr-2 h-4 w-4 ${_ ? "animate-spin" : ""}` }), "Refresh"]
453
+ })]
55
454
  })]
56
455
  }),
57
- /* @__PURE__ */ o("div", {
58
- className: "grid gap-4 md:grid-cols-3",
59
- children: [
60
- /* @__PURE__ */ o(p, {
61
- treatment: "glass",
62
- glow: !0,
63
- className: "border-border-seam",
64
- children: [/* @__PURE__ */ o(d, {
65
- className: "flex flex-row items-center justify-between space-y-0 pb-2",
66
- children: [/* @__PURE__ */ a(f, {
67
- className: "text-sm font-medium",
68
- children: "Total Workforce Cost"
69
- }), /* @__PURE__ */ a(n, { className: "h-4 w-4 text-text-secondary" })]
70
- }), /* @__PURE__ */ o(l, { children: [/* @__PURE__ */ o("div", {
71
- className: "text-2xl font-bold tabular-nums",
72
- children: [
73
- "$",
74
- (C / 1e6).toFixed(1),
75
- "M"
76
- ]
77
- }), /* @__PURE__ */ a("p", {
78
- className: "text-xs text-text-secondary",
79
- children: "Annual salary expenditure"
80
- })] })]
81
- }),
82
- /* @__PURE__ */ o(p, {
83
- treatment: "metric",
84
- className: "border-border-seam",
85
- children: [/* @__PURE__ */ o(d, {
86
- className: "flex flex-row items-center justify-between space-y-0 pb-2",
87
- children: [/* @__PURE__ */ a(f, {
88
- className: "text-sm font-medium",
89
- children: "Budget Utilization"
90
- }), /* @__PURE__ */ a(r, { className: "h-4 w-4 text-text-secondary" })]
91
- }), /* @__PURE__ */ o(l, { children: [/* @__PURE__ */ o("div", {
92
- className: "text-2xl font-bold tabular-nums",
93
- children: [D, "%"]
94
- }), /* @__PURE__ */ o("p", {
95
- className: "text-xs text-text-secondary",
96
- children: [
97
- "$",
98
- (E / 1e6).toFixed(1),
99
- "M of $",
100
- (T / 1e6).toFixed(1),
101
- "M project budget"
102
- ]
103
- })] })]
104
- }),
105
- /* @__PURE__ */ o(p, {
106
- treatment: "metric",
107
- className: "border-border-seam",
108
- children: [/* @__PURE__ */ o(d, {
109
- className: "flex flex-row items-center justify-between space-y-0 pb-2",
110
- children: [/* @__PURE__ */ a(f, {
111
- className: "text-sm font-medium",
112
- children: "Retention Rate"
113
- }), /* @__PURE__ */ a(i, { className: "h-4 w-4 text-text-secondary" })]
114
- }), /* @__PURE__ */ o(l, { children: [/* @__PURE__ */ o("div", {
115
- className: "text-2xl font-bold tabular-nums",
116
- children: [k, "%"]
117
- }), /* @__PURE__ */ o("p", {
118
- className: "text-xs text-text-secondary",
119
- children: [
120
- O,
121
- " of ",
122
- v.length,
123
- " employees no longer active"
124
- ]
125
- })] })]
126
- })
127
- ]
128
- }),
129
- /* @__PURE__ */ o(c, { children: [/* @__PURE__ */ o(d, { children: [/* @__PURE__ */ a(f, { children: "Risk Indicators" }), /* @__PURE__ */ a(u, { children: "Items requiring executive attention" })] }), /* @__PURE__ */ a(l, {
130
- className: "grid gap-3 md:grid-cols-2",
131
- children: S.map((e) => /* @__PURE__ */ o("div", {
132
- className: "flex items-center justify-between rounded border p-3",
133
- children: [/* @__PURE__ */ o("div", {
134
- className: "flex items-center gap-3",
135
- children: [/* @__PURE__ */ a("div", { className: `h-3 w-3 rounded-full ${e.severity === "error" ? "bg-status-error-text" : e.severity === "warning" ? "bg-status-warning-text" : "bg-status-info-text"}` }), /* @__PURE__ */ o("div", { children: [/* @__PURE__ */ a("p", {
136
- className: "text-sm font-medium",
137
- children: e.metric
138
- }), /* @__PURE__ */ a("p", {
139
- className: "text-xs text-text-secondary",
140
- children: e.detail
141
- })] })]
142
- }), /* @__PURE__ */ a("span", {
143
- className: "text-lg font-bold",
144
- children: e.value
456
+ v ? /* @__PURE__ */ d(h, {
457
+ className: "border-status-error-border",
458
+ children: /* @__PURE__ */ f(g, {
459
+ className: "flex flex-wrap items-center justify-between gap-3 py-4",
460
+ children: [/* @__PURE__ */ d("p", {
461
+ className: "text-sm text-status-error-text",
462
+ children: v
463
+ }), /* @__PURE__ */ d(m, {
464
+ variant: "outline",
465
+ size: "sm",
466
+ onClick: b,
467
+ children: "Try again"
145
468
  })]
146
- }, e.metric))
147
- })] }),
148
- /* @__PURE__ */ o(c, { children: [/* @__PURE__ */ o(d, { children: [/* @__PURE__ */ a(f, { children: "Department Budget Status" }), /* @__PURE__ */ a(u, { children: "Annual budget allocation and headcount" })] }), /* @__PURE__ */ o(l, { children: [
149
- /* @__PURE__ */ a(g, {
150
- columns: [
151
- {
152
- key: "name",
153
- header: "Department",
154
- priority: "primary",
155
- cell: (e) => /* @__PURE__ */ a("span", {
156
- className: "font-medium",
157
- children: e.name
158
- })
159
- },
160
- {
161
- key: "head",
162
- header: "Head",
163
- priority: "secondary",
164
- cell: (e) => /* @__PURE__ */ a("span", {
165
- className: "text-text-secondary",
166
- children: e.headName
167
- })
168
- },
169
- {
170
- key: "headcount",
171
- header: "Headcount",
172
- priority: "secondary",
173
- cell: (e) => /* @__PURE__ */ a("span", {
174
- className: "md:block md:text-right",
175
- children: e.employeeCount
176
- })
177
- },
178
- {
179
- key: "budget",
180
- header: "Budget",
181
- priority: "secondary",
182
- cell: (e) => /* @__PURE__ */ o("span", {
183
- className: "md:block md:text-right",
184
- children: [
185
- "$",
186
- (e.budget / 1e6).toFixed(1),
187
- "M"
188
- ]
189
- })
190
- },
191
- {
192
- key: "costPerEmployee",
193
- header: "Cost/Employee",
194
- priority: "primary",
195
- cell: (e) => /* @__PURE__ */ o("span", {
196
- className: "md:block md:text-right",
197
- children: [
198
- "$",
199
- ((e.employeeCount > 0 ? Math.round(e.budget / e.employeeCount) : 0) / 1e3).toFixed(0),
200
- "K"
201
- ]
202
- })
203
- }
204
- ],
205
- data: y,
206
- rowKey: (e) => e.id
207
- }),
208
- /* @__PURE__ */ a(_, { className: "my-3" }),
209
- /* @__PURE__ */ o("div", {
210
- className: "flex flex-wrap items-center justify-between gap-2 text-sm font-bold",
211
- children: [
212
- /* @__PURE__ */ a("span", { children: "Total" }),
213
- /* @__PURE__ */ o("span", { children: [A, " employees"] }),
214
- /* @__PURE__ */ o("span", { children: [
215
- "$",
216
- (w / 1e6).toFixed(1),
217
- "M budget"
218
- ] }),
219
- /* @__PURE__ */ o("span", { children: [
220
- "$",
221
- (j / 1e3).toFixed(0),
222
- "K / employee"
223
- ] })
224
- ]
225
469
  })
226
- ] })] })
470
+ }) : null,
471
+ u ? /* @__PURE__ */ d(V, {
472
+ analytics: u,
473
+ budget: S,
474
+ retention: w
475
+ }) : _ ? /* @__PURE__ */ d("div", {
476
+ className: "flex min-h-[12rem] items-center justify-center",
477
+ children: /* @__PURE__ */ d(E, { size: "md" })
478
+ }) : null,
479
+ /* @__PURE__ */ d(H, { departments: s })
227
480
  ]
481
+ }) : /* @__PURE__ */ d("div", {
482
+ className: "flex min-h-[60vh] items-center justify-center p-6",
483
+ children: /* @__PURE__ */ d(E, { size: "lg" })
228
484
  });
229
485
  }
230
486
  //#endregion
231
- export { v as DashboardExecutiveDashboardPage };
487
+ export { U as DashboardExecutiveDashboardPage };
232
488
 
233
489
  //# sourceMappingURL=DashboardExecutiveDashboardPage.js.map