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