@burdenoff/microfe-crewfoundry 2026.1030.4 → 2026.1102.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/CrewFoundryRoot.d.ts.map +1 -1
- package/dist/crewfoundry/CrewFoundryRoot.js +14 -0
- package/dist/crewfoundry/CrewFoundryRoot.js.map +1 -1
- package/dist/crewfoundry/CrewFoundryRoutes.d.ts.map +1 -1
- package/dist/crewfoundry/CrewFoundryRoutes.js +27 -19
- package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
- package/dist/crewfoundry/components/field/DispatchBoardCard.d.ts +13 -0
- package/dist/crewfoundry/components/field/DispatchBoardCard.d.ts.map +1 -0
- package/dist/crewfoundry/components/field/DispatchBoardCard.js +124 -0
- package/dist/crewfoundry/components/field/DispatchBoardCard.js.map +1 -0
- package/dist/crewfoundry/components/field/FieldBadges.d.ts +12 -0
- package/dist/crewfoundry/components/field/FieldBadges.d.ts.map +1 -0
- package/dist/crewfoundry/components/field/FieldBadges.js +45 -0
- package/dist/crewfoundry/components/field/FieldBadges.js.map +1 -0
- package/dist/crewfoundry/components/field/MyDispatchItem.d.ts +12 -0
- package/dist/crewfoundry/components/field/MyDispatchItem.d.ts.map +1 -0
- package/dist/crewfoundry/components/field/MyDispatchItem.js +46 -0
- package/dist/crewfoundry/components/field/MyDispatchItem.js.map +1 -0
- package/dist/crewfoundry/components/field/MyShiftItem.d.ts +14 -0
- package/dist/crewfoundry/components/field/MyShiftItem.d.ts.map +1 -0
- package/dist/crewfoundry/components/field/MyShiftItem.js +84 -0
- package/dist/crewfoundry/components/field/MyShiftItem.js.map +1 -0
- package/dist/crewfoundry/components/field/ShiftsCard.d.ts +12 -0
- package/dist/crewfoundry/components/field/ShiftsCard.d.ts.map +1 -0
- package/dist/crewfoundry/components/field/ShiftsCard.js +84 -0
- package/dist/crewfoundry/components/field/ShiftsCard.js.map +1 -0
- package/dist/crewfoundry/components/field/fieldFormat.d.ts +8 -0
- package/dist/crewfoundry/components/field/fieldFormat.d.ts.map +1 -0
- package/dist/crewfoundry/components/field/fieldFormat.js +15 -0
- package/dist/crewfoundry/components/field/fieldFormat.js.map +1 -0
- package/dist/crewfoundry/components/field/fieldForms.d.ts +19 -0
- package/dist/crewfoundry/components/field/fieldForms.d.ts.map +1 -0
- package/dist/crewfoundry/components/field/fieldForms.js +223 -0
- package/dist/crewfoundry/components/field/fieldForms.js.map +1 -0
- package/dist/crewfoundry/components/forms/FormModal.d.ts +1 -1
- package/dist/crewfoundry/components/forms/FormModal.d.ts.map +1 -1
- package/dist/crewfoundry/components/forms/FormModal.js +1 -1
- package/dist/crewfoundry/components/forms/FormModal.js.map +1 -1
- package/dist/crewfoundry/lib/fieldOps.d.ts +105 -0
- package/dist/crewfoundry/lib/fieldOps.d.ts.map +1 -0
- package/dist/crewfoundry/lib/fieldOps.js +85 -0
- package/dist/crewfoundry/lib/fieldOps.js.map +1 -0
- package/dist/crewfoundry/lib/useFieldOpsData.d.ts +14 -0
- package/dist/crewfoundry/lib/useFieldOpsData.d.ts.map +1 -0
- package/dist/crewfoundry/lib/useFieldOpsData.js +31 -0
- package/dist/crewfoundry/lib/useFieldOpsData.js.map +1 -0
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.d.ts +8 -0
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js +468 -212
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js.map +1 -1
- package/dist/crewfoundry/pages/FieldMyWorkPagePage.d.ts +9 -0
- package/dist/crewfoundry/pages/FieldMyWorkPagePage.d.ts.map +1 -0
- package/dist/crewfoundry/pages/FieldMyWorkPagePage.js +141 -0
- package/dist/crewfoundry/pages/FieldMyWorkPagePage.js.map +1 -0
- package/dist/crewfoundry/pages/FieldOperationsPagePage.d.ts +9 -0
- package/dist/crewfoundry/pages/FieldOperationsPagePage.d.ts.map +1 -0
- package/dist/crewfoundry/pages/FieldOperationsPagePage.js +231 -0
- package/dist/crewfoundry/pages/FieldOperationsPagePage.js.map +1 -0
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +24 -24
- package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +4 -4
- package/dist/crewfoundry/store/crewfoundryStore.d.ts +47 -1
- package/dist/crewfoundry/store/crewfoundryStore.d.ts.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +93 -66
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/dist/crewfoundry/store/fieldOpsStore.d.ts +76 -0
- package/dist/crewfoundry/store/fieldOpsStore.d.ts.map +1 -0
- package/dist/crewfoundry/store/fieldOpsStore.js +188 -0
- package/dist/crewfoundry/store/fieldOpsStore.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,233 +1,489 @@
|
|
|
1
1
|
import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
2
|
-
import {
|
|
3
|
-
import { Building2 as
|
|
4
|
-
import { jsx as
|
|
5
|
-
import { Badge as
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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__ */
|
|
38
|
-
className: "flex items-
|
|
39
|
-
children: [/* @__PURE__ */
|
|
40
|
-
/* @__PURE__ */
|
|
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__ */
|
|
431
|
+
children: /* @__PURE__ */ d(x, { children: "Executive Dashboard" })
|
|
43
432
|
}),
|
|
44
|
-
/* @__PURE__ */
|
|
433
|
+
/* @__PURE__ */ d("p", {
|
|
45
434
|
className: "text-sm text-text-secondary",
|
|
46
435
|
children: "Strategic workforce insights for leadership"
|
|
47
436
|
}),
|
|
48
|
-
/* @__PURE__ */
|
|
437
|
+
/* @__PURE__ */ d(C, {
|
|
49
438
|
className: "mt-1",
|
|
50
|
-
children: "The executive snapshot —
|
|
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__ */
|
|
53
|
-
|
|
54
|
-
children:
|
|
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__ */
|
|
58
|
-
className: "
|
|
59
|
-
children:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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 {
|
|
487
|
+
export { U as DashboardExecutiveDashboardPage };
|
|
232
488
|
|
|
233
489
|
//# sourceMappingURL=DashboardExecutiveDashboardPage.js.map
|