@burdenoff/microfe-crewfoundry 2026.704.2 → 2026.704.4
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/pages/AdminAdminPagePage.js +76 -75
- package/dist/crewfoundry/pages/AdminAdminPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +118 -117
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +115 -114
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +105 -104
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js +52 -51
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +94 -93
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js +97 -96
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +68 -67
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js +96 -95
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +153 -152
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js +107 -106
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +77 -76
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +80 -79
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +102 -101
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +126 -125
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +64 -63
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +96 -95
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +127 -126
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js +118 -117
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +123 -122
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +77 -76
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +49 -48
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +62 -61
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.js +72 -71
- package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +70 -69
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +57 -56
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js +58 -57
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js +122 -121
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +70 -69
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +41 -40
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js +65 -64
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +75 -74
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +60 -59
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js +53 -52
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js +37 -36
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +126 -125
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +62 -61
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js +50 -49
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +72 -71
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +40 -39
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js +130 -129
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +60 -59
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +177 -146
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/dist/crewfoundry/utils/formatEnumLabel.js +8 -0
- package/dist/crewfoundry/utils/formatEnumLabel.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,166 +1,167 @@
|
|
|
1
1
|
import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { formatEnumLabel as t } from "../utils/formatEnumLabel.js";
|
|
3
|
+
import { useMemo as n } from "react";
|
|
4
|
+
import { BarChart3 as r, DollarSign as i, Target as a, TrendingDown as o, TrendingUp as s, Users as c } from "lucide-react";
|
|
5
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
6
|
+
import { Badge as d, Card as f, CardContent as p, CardDescription as m, CardHeader as h, CardTitle as g, GlassCard as _, GradientText as v, PagePurpose as y, ResponsiveTable as b } from "@burdenoff/fe-libs/ui";
|
|
6
7
|
//#region src/crewfoundry/pages/DashboardAnalyticsPagePage.tsx
|
|
7
|
-
function
|
|
8
|
-
let { employees:
|
|
9
|
-
if (
|
|
8
|
+
function x() {
|
|
9
|
+
let { employees: x, departments: S, jobPostings: C, payrollRecords: w, projects: T } = e(), E = n(() => {
|
|
10
|
+
if (x.length === 0) return [];
|
|
10
11
|
let e = (e) => {
|
|
11
12
|
let t = new Date(e);
|
|
12
13
|
return `${t.getFullYear()}-${String(t.getMonth()).padStart(2, "0")}`;
|
|
13
14
|
};
|
|
14
|
-
return Array.from(new Set(
|
|
15
|
+
return Array.from(new Set(x.map((t) => e(t.startDate)))).sort().slice(-6).map((t) => {
|
|
15
16
|
let [n, r] = t.split("-").map(Number), i = new Date(n, r + 1, 0).getTime(), a = new Date(n, r, 1).toLocaleString("en-US", {
|
|
16
17
|
month: "short",
|
|
17
18
|
year: "2-digit"
|
|
18
|
-
}), o =
|
|
19
|
+
}), o = x.filter((e) => new Date(e.startDate).getTime() <= i && e.status !== "terminated").length;
|
|
19
20
|
return {
|
|
20
21
|
month: a,
|
|
21
|
-
hires:
|
|
22
|
-
attrition:
|
|
22
|
+
hires: x.filter((n) => e(n.startDate) === t).length,
|
|
23
|
+
attrition: x.filter((n) => n.status === "terminated" && e(n.startDate) === t).length,
|
|
23
24
|
headcount: o
|
|
24
25
|
};
|
|
25
26
|
});
|
|
26
|
-
}, [
|
|
27
|
+
}, [x]), D = Math.max(1, ...E.map((e) => e.headcount)), O = w.reduce((e, t) => e + t.netPay, 0), k = Math.round(x.reduce((e, t) => e + t.salary, 0) / Math.max(x.length, 1)), A = C.filter((e) => e.status === "active").length, j = x.reduce((e, t) => {
|
|
27
28
|
let n = t.type.replace("_", " ");
|
|
28
29
|
return e[n] = (e[n] || 0) + 1, e;
|
|
29
|
-
}, {}),
|
|
30
|
+
}, {}), M = n(() => {
|
|
30
31
|
let e = [{
|
|
31
32
|
category: "Net Payroll",
|
|
32
|
-
amount:
|
|
33
|
+
amount: O
|
|
33
34
|
}, {
|
|
34
35
|
category: "Project Delivery",
|
|
35
|
-
amount:
|
|
36
|
+
amount: T.reduce((e, t) => e + t.spent, 0)
|
|
36
37
|
}], t = e.reduce((e, t) => e + t.amount, 0) || 1;
|
|
37
38
|
return e.map((e) => ({
|
|
38
39
|
...e,
|
|
39
40
|
percentage: Math.round(e.amount / t * 100)
|
|
40
41
|
}));
|
|
41
|
-
}, [
|
|
42
|
-
return /* @__PURE__ */
|
|
42
|
+
}, [T, O]);
|
|
43
|
+
return /* @__PURE__ */ u("div", {
|
|
43
44
|
className: "space-y-6 p-6",
|
|
44
45
|
children: [
|
|
45
|
-
/* @__PURE__ */
|
|
46
|
-
/* @__PURE__ */
|
|
46
|
+
/* @__PURE__ */ u("div", { children: [
|
|
47
|
+
/* @__PURE__ */ l("h1", {
|
|
47
48
|
className: "text-2xl font-semibold",
|
|
48
|
-
children: /* @__PURE__ */
|
|
49
|
+
children: /* @__PURE__ */ l(v, { children: "Dashboard Analytics" })
|
|
49
50
|
}),
|
|
50
|
-
/* @__PURE__ */
|
|
51
|
+
/* @__PURE__ */ l("p", {
|
|
51
52
|
className: "text-sm text-text-secondary",
|
|
52
53
|
children: "Workforce analytics and operational insights"
|
|
53
54
|
}),
|
|
54
|
-
/* @__PURE__ */
|
|
55
|
+
/* @__PURE__ */ l(y, {
|
|
55
56
|
className: "mt-1",
|
|
56
57
|
children: "A consolidated analytics view across your organization — use it to monitor the metrics that matter most without digging through separate reports."
|
|
57
58
|
})
|
|
58
59
|
] }),
|
|
59
|
-
/* @__PURE__ */
|
|
60
|
+
/* @__PURE__ */ u("div", {
|
|
60
61
|
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4",
|
|
61
62
|
children: [
|
|
62
|
-
/* @__PURE__ */
|
|
63
|
+
/* @__PURE__ */ u(_, {
|
|
63
64
|
treatment: "glass",
|
|
64
65
|
glow: !0,
|
|
65
66
|
className: "border-border-seam",
|
|
66
|
-
children: [/* @__PURE__ */
|
|
67
|
+
children: [/* @__PURE__ */ u(h, {
|
|
67
68
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
68
|
-
children: [/* @__PURE__ */
|
|
69
|
+
children: [/* @__PURE__ */ l(g, {
|
|
69
70
|
className: "text-sm font-medium",
|
|
70
71
|
children: "Total Headcount"
|
|
71
|
-
}), /* @__PURE__ */ c
|
|
72
|
-
}), /* @__PURE__ */
|
|
72
|
+
}), /* @__PURE__ */ l(c, { className: "h-4 w-4 text-text-secondary" })]
|
|
73
|
+
}), /* @__PURE__ */ u(p, { children: [/* @__PURE__ */ l("div", {
|
|
73
74
|
className: "text-2xl font-bold tabular-nums",
|
|
74
|
-
children:
|
|
75
|
-
}), /* @__PURE__ */
|
|
75
|
+
children: x.length
|
|
76
|
+
}), /* @__PURE__ */ u("div", {
|
|
76
77
|
className: "flex items-center text-xs text-status-success-text",
|
|
77
|
-
children: [/* @__PURE__ */
|
|
78
|
+
children: [/* @__PURE__ */ l(s, { className: "mr-1 h-3 w-3" }), "Live workforce count"]
|
|
78
79
|
})] })]
|
|
79
80
|
}),
|
|
80
|
-
/* @__PURE__ */
|
|
81
|
+
/* @__PURE__ */ u(_, {
|
|
81
82
|
treatment: "metric",
|
|
82
83
|
className: "border-border-seam",
|
|
83
|
-
children: [/* @__PURE__ */
|
|
84
|
+
children: [/* @__PURE__ */ u(h, {
|
|
84
85
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
85
|
-
children: [/* @__PURE__ */
|
|
86
|
+
children: [/* @__PURE__ */ l(g, {
|
|
86
87
|
className: "text-sm font-medium",
|
|
87
88
|
children: "Avg Salary"
|
|
88
|
-
}), /* @__PURE__ */
|
|
89
|
-
}), /* @__PURE__ */
|
|
89
|
+
}), /* @__PURE__ */ l(i, { className: "h-4 w-4 text-text-secondary" })]
|
|
90
|
+
}), /* @__PURE__ */ u(p, { children: [/* @__PURE__ */ u("div", {
|
|
90
91
|
className: "text-2xl font-bold tabular-nums",
|
|
91
|
-
children: ["$",
|
|
92
|
-
}), /* @__PURE__ */
|
|
92
|
+
children: ["$", k.toLocaleString()]
|
|
93
|
+
}), /* @__PURE__ */ u("div", {
|
|
93
94
|
className: "flex items-center text-xs text-status-success-text",
|
|
94
|
-
children: [/* @__PURE__ */
|
|
95
|
+
children: [/* @__PURE__ */ l(s, { className: "mr-1 h-3 w-3" }), "Updated from employee records"]
|
|
95
96
|
})] })]
|
|
96
97
|
}),
|
|
97
|
-
/* @__PURE__ */
|
|
98
|
+
/* @__PURE__ */ u(_, {
|
|
98
99
|
treatment: "metric",
|
|
99
100
|
className: "border-border-seam",
|
|
100
|
-
children: [/* @__PURE__ */
|
|
101
|
+
children: [/* @__PURE__ */ u(h, {
|
|
101
102
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
102
|
-
children: [/* @__PURE__ */
|
|
103
|
+
children: [/* @__PURE__ */ l(g, {
|
|
103
104
|
className: "text-sm font-medium",
|
|
104
105
|
children: "Attrition Rate"
|
|
105
|
-
}), /* @__PURE__ */
|
|
106
|
-
}), /* @__PURE__ */
|
|
106
|
+
}), /* @__PURE__ */ l(o, { className: "h-4 w-4 text-text-secondary" })]
|
|
107
|
+
}), /* @__PURE__ */ u(p, { children: [/* @__PURE__ */ u("div", {
|
|
107
108
|
className: "text-2xl font-bold tabular-nums",
|
|
108
|
-
children: [Math.round(
|
|
109
|
-
}), /* @__PURE__ */
|
|
109
|
+
children: [Math.round(x.filter((e) => e.status === "terminated").length / Math.max(x.length, 1) * 100), "%"]
|
|
110
|
+
}), /* @__PURE__ */ u("div", {
|
|
110
111
|
className: "flex items-center text-xs text-status-success-text",
|
|
111
|
-
children: [/* @__PURE__ */
|
|
112
|
+
children: [/* @__PURE__ */ l(o, { className: "mr-1 h-3 w-3" }), "Calculated from status mix"]
|
|
112
113
|
})] })]
|
|
113
114
|
}),
|
|
114
|
-
/* @__PURE__ */
|
|
115
|
+
/* @__PURE__ */ u(_, {
|
|
115
116
|
treatment: "metric",
|
|
116
117
|
className: "border-border-seam",
|
|
117
|
-
children: [/* @__PURE__ */
|
|
118
|
+
children: [/* @__PURE__ */ u(h, {
|
|
118
119
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
119
|
-
children: [/* @__PURE__ */
|
|
120
|
+
children: [/* @__PURE__ */ l(g, {
|
|
120
121
|
className: "text-sm font-medium",
|
|
121
122
|
children: "Open Roles"
|
|
122
|
-
}), /* @__PURE__ */
|
|
123
|
-
}), /* @__PURE__ */
|
|
123
|
+
}), /* @__PURE__ */ l(a, { className: "h-4 w-4 text-text-secondary" })]
|
|
124
|
+
}), /* @__PURE__ */ u(p, { children: [/* @__PURE__ */ l("div", {
|
|
124
125
|
className: "text-2xl font-bold tabular-nums",
|
|
125
|
-
children:
|
|
126
|
-
}), /* @__PURE__ */
|
|
126
|
+
children: A
|
|
127
|
+
}), /* @__PURE__ */ l("p", {
|
|
127
128
|
className: "text-xs text-text-secondary",
|
|
128
129
|
children: "Based on active job postings"
|
|
129
130
|
})] })]
|
|
130
131
|
})
|
|
131
132
|
]
|
|
132
133
|
}),
|
|
133
|
-
/* @__PURE__ */
|
|
134
|
+
/* @__PURE__ */ u("div", {
|
|
134
135
|
className: "grid gap-4 md:grid-cols-7",
|
|
135
|
-
children: [/* @__PURE__ */
|
|
136
|
+
children: [/* @__PURE__ */ u(f, {
|
|
136
137
|
className: "col-span-4",
|
|
137
|
-
children: [/* @__PURE__ */
|
|
138
|
+
children: [/* @__PURE__ */ u(h, { children: [/* @__PURE__ */ l(g, { children: "Headcount Trend" }), /* @__PURE__ */ l(m, { children: "Monthly headcount over recent months" })] }), /* @__PURE__ */ l(p, {
|
|
138
139
|
className: "space-y-3",
|
|
139
|
-
children:
|
|
140
|
+
children: E.map((e, t) => /* @__PURE__ */ u("div", {
|
|
140
141
|
className: "flex items-center gap-3",
|
|
141
142
|
children: [
|
|
142
|
-
/* @__PURE__ */
|
|
143
|
+
/* @__PURE__ */ l("span", {
|
|
143
144
|
className: "w-10 text-sm text-text-secondary",
|
|
144
145
|
children: e.month
|
|
145
146
|
}),
|
|
146
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ l("div", {
|
|
147
148
|
className: "h-4 flex-1 overflow-hidden rounded bg-bg-sunken",
|
|
148
|
-
children: /* @__PURE__ */
|
|
149
|
+
children: /* @__PURE__ */ l("div", {
|
|
149
150
|
className: "h-4 rounded bg-action-primary-bg",
|
|
150
|
-
style: { width: `${Math.round(e.headcount /
|
|
151
|
+
style: { width: `${Math.round(e.headcount / D * 100)}%` }
|
|
151
152
|
})
|
|
152
153
|
}),
|
|
153
|
-
/* @__PURE__ */
|
|
154
|
+
/* @__PURE__ */ l("span", {
|
|
154
155
|
className: "w-10 text-right text-sm font-medium",
|
|
155
156
|
children: e.headcount
|
|
156
157
|
}),
|
|
157
|
-
/* @__PURE__ */
|
|
158
|
+
/* @__PURE__ */ u("div", {
|
|
158
159
|
className: "flex w-24 gap-1",
|
|
159
|
-
children: [/* @__PURE__ */
|
|
160
|
+
children: [/* @__PURE__ */ u(d, {
|
|
160
161
|
variant: "default",
|
|
161
162
|
className: "text-[10px]",
|
|
162
163
|
children: ["+", e.hires]
|
|
163
|
-
}), /* @__PURE__ */
|
|
164
|
+
}), /* @__PURE__ */ u(d, {
|
|
164
165
|
variant: "destructive",
|
|
165
166
|
className: "text-[10px]",
|
|
166
167
|
children: ["-", e.attrition]
|
|
@@ -169,28 +170,28 @@ function b() {
|
|
|
169
170
|
]
|
|
170
171
|
}, `${e.month}-${t}`))
|
|
171
172
|
})]
|
|
172
|
-
}), /* @__PURE__ */
|
|
173
|
+
}), /* @__PURE__ */ u(f, {
|
|
173
174
|
className: "col-span-3",
|
|
174
|
-
children: [/* @__PURE__ */
|
|
175
|
+
children: [/* @__PURE__ */ u(h, { children: [/* @__PURE__ */ l(g, { children: "Employee Types" }), /* @__PURE__ */ l(m, { children: "Distribution by employment type" })] }), /* @__PURE__ */ l(p, {
|
|
175
176
|
className: "space-y-4",
|
|
176
|
-
children: Object.entries(
|
|
177
|
+
children: Object.entries(j).sort(([, e], [, t]) => t - e).map(([e, t]) => /* @__PURE__ */ u("div", {
|
|
177
178
|
className: "flex items-center justify-between",
|
|
178
|
-
children: [/* @__PURE__ */
|
|
179
|
+
children: [/* @__PURE__ */ u("div", {
|
|
179
180
|
className: "flex items-center gap-2",
|
|
180
|
-
children: [/* @__PURE__ */
|
|
181
|
+
children: [/* @__PURE__ */ l(r, { className: "h-4 w-4 text-text-secondary" }), /* @__PURE__ */ l("span", {
|
|
181
182
|
className: "text-sm capitalize",
|
|
182
183
|
children: e
|
|
183
184
|
})]
|
|
184
|
-
}), /* @__PURE__ */
|
|
185
|
+
}), /* @__PURE__ */ u("div", {
|
|
185
186
|
className: "flex items-center gap-2",
|
|
186
|
-
children: [/* @__PURE__ */
|
|
187
|
+
children: [/* @__PURE__ */ l("span", {
|
|
187
188
|
className: "text-sm font-medium",
|
|
188
189
|
children: t
|
|
189
|
-
}), /* @__PURE__ */
|
|
190
|
+
}), /* @__PURE__ */ u("span", {
|
|
190
191
|
className: "text-xs text-text-secondary",
|
|
191
192
|
children: [
|
|
192
193
|
"(",
|
|
193
|
-
Math.round(t / Math.max(
|
|
194
|
+
Math.round(t / Math.max(x.length, 1) * 100),
|
|
194
195
|
"%)"
|
|
195
196
|
]
|
|
196
197
|
})]
|
|
@@ -199,23 +200,23 @@ function b() {
|
|
|
199
200
|
})]
|
|
200
201
|
})]
|
|
201
202
|
}),
|
|
202
|
-
/* @__PURE__ */
|
|
203
|
+
/* @__PURE__ */ u(f, { children: [/* @__PURE__ */ u(h, { children: [/* @__PURE__ */ l(g, { children: "Workforce Cost Breakdown" }), /* @__PURE__ */ l(m, { children: "Operational costs by category" })] }), /* @__PURE__ */ u(p, { children: [/* @__PURE__ */ l("div", {
|
|
203
204
|
className: "space-y-3",
|
|
204
|
-
children:
|
|
205
|
+
children: M.map((e) => /* @__PURE__ */ u("div", {
|
|
205
206
|
className: "flex items-center gap-4",
|
|
206
207
|
children: [
|
|
207
|
-
/* @__PURE__ */
|
|
208
|
+
/* @__PURE__ */ l("span", {
|
|
208
209
|
className: "w-48 text-sm text-text-secondary",
|
|
209
210
|
children: e.category
|
|
210
211
|
}),
|
|
211
|
-
/* @__PURE__ */
|
|
212
|
+
/* @__PURE__ */ l("div", {
|
|
212
213
|
className: "h-3 flex-1 overflow-hidden rounded bg-bg-sunken",
|
|
213
|
-
children: /* @__PURE__ */
|
|
214
|
+
children: /* @__PURE__ */ l("div", {
|
|
214
215
|
className: "h-3 rounded bg-action-primary-bg/80",
|
|
215
216
|
style: { width: `${e.percentage}%` }
|
|
216
217
|
})
|
|
217
218
|
}),
|
|
218
|
-
/* @__PURE__ */
|
|
219
|
+
/* @__PURE__ */ u("span", {
|
|
219
220
|
className: "w-24 text-right text-sm font-medium",
|
|
220
221
|
children: [
|
|
221
222
|
"$",
|
|
@@ -223,33 +224,33 @@ function b() {
|
|
|
223
224
|
"K"
|
|
224
225
|
]
|
|
225
226
|
}),
|
|
226
|
-
/* @__PURE__ */
|
|
227
|
+
/* @__PURE__ */ u("span", {
|
|
227
228
|
className: "w-10 text-right text-xs text-text-secondary",
|
|
228
229
|
children: [e.percentage, "%"]
|
|
229
230
|
})
|
|
230
231
|
]
|
|
231
232
|
}, e.category))
|
|
232
|
-
}), /* @__PURE__ */
|
|
233
|
+
}), /* @__PURE__ */ u("div", {
|
|
233
234
|
className: "mt-4 flex justify-between border-t pt-4 text-sm",
|
|
234
|
-
children: [/* @__PURE__ */
|
|
235
|
+
children: [/* @__PURE__ */ l("span", {
|
|
235
236
|
className: "font-medium",
|
|
236
237
|
children: "Total Monthly Cost"
|
|
237
|
-
}), /* @__PURE__ */
|
|
238
|
+
}), /* @__PURE__ */ u("span", {
|
|
238
239
|
className: "font-bold",
|
|
239
240
|
children: [
|
|
240
241
|
"$",
|
|
241
|
-
(
|
|
242
|
+
(M.reduce((e, t) => e + t.amount, 0) / 1e3).toFixed(0),
|
|
242
243
|
"K"
|
|
243
244
|
]
|
|
244
245
|
})]
|
|
245
246
|
})] })] }),
|
|
246
|
-
/* @__PURE__ */
|
|
247
|
+
/* @__PURE__ */ u(f, { children: [/* @__PURE__ */ u(h, { children: [/* @__PURE__ */ l(g, { children: "Department Overview" }), /* @__PURE__ */ l(m, { children: "Key metrics by department" })] }), /* @__PURE__ */ l(p, { children: /* @__PURE__ */ l(b, {
|
|
247
248
|
columns: [
|
|
248
249
|
{
|
|
249
250
|
key: "name",
|
|
250
251
|
header: "Department",
|
|
251
252
|
priority: "primary",
|
|
252
|
-
cell: (e) => /* @__PURE__ */
|
|
253
|
+
cell: (e) => /* @__PURE__ */ l("span", {
|
|
253
254
|
className: "font-medium",
|
|
254
255
|
children: e.name
|
|
255
256
|
})
|
|
@@ -258,7 +259,7 @@ function b() {
|
|
|
258
259
|
key: "head",
|
|
259
260
|
header: "Head",
|
|
260
261
|
priority: "secondary",
|
|
261
|
-
cell: (e) => /* @__PURE__ */
|
|
262
|
+
cell: (e) => /* @__PURE__ */ l("span", {
|
|
262
263
|
className: "text-text-secondary",
|
|
263
264
|
children: e.headName
|
|
264
265
|
})
|
|
@@ -267,7 +268,7 @@ function b() {
|
|
|
267
268
|
key: "employees",
|
|
268
269
|
header: "Employees",
|
|
269
270
|
priority: "secondary",
|
|
270
|
-
cell: (e) => /* @__PURE__ */
|
|
271
|
+
cell: (e) => /* @__PURE__ */ l("span", {
|
|
271
272
|
className: "md:block md:text-right",
|
|
272
273
|
children: e.employeeCount
|
|
273
274
|
})
|
|
@@ -276,7 +277,7 @@ function b() {
|
|
|
276
277
|
key: "budget",
|
|
277
278
|
header: "Budget",
|
|
278
279
|
priority: "secondary",
|
|
279
|
-
cell: (e) => /* @__PURE__ */
|
|
280
|
+
cell: (e) => /* @__PURE__ */ u("span", {
|
|
280
281
|
className: "md:block md:text-right",
|
|
281
282
|
children: [
|
|
282
283
|
"$",
|
|
@@ -289,19 +290,19 @@ function b() {
|
|
|
289
290
|
key: "status",
|
|
290
291
|
header: "Status",
|
|
291
292
|
priority: "primary",
|
|
292
|
-
cell: (e) => /* @__PURE__ */
|
|
293
|
+
cell: (e) => /* @__PURE__ */ l(d, {
|
|
293
294
|
variant: e.status === "active" ? "default" : "secondary",
|
|
294
|
-
children: e.status
|
|
295
|
+
children: t(e.status)
|
|
295
296
|
})
|
|
296
297
|
}
|
|
297
298
|
],
|
|
298
|
-
data:
|
|
299
|
+
data: S,
|
|
299
300
|
rowKey: (e) => e.id
|
|
300
301
|
}) })] })
|
|
301
302
|
]
|
|
302
303
|
});
|
|
303
304
|
}
|
|
304
305
|
//#endregion
|
|
305
|
-
export {
|
|
306
|
+
export { x as DashboardAnalyticsPagePage };
|
|
306
307
|
|
|
307
308
|
//# sourceMappingURL=DashboardAnalyticsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardAnalyticsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/DashboardAnalyticsPagePage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { BarChart3, DollarSign, Target, TrendingDown, TrendingUp, Users } from 'lucide-react';\nimport {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n PagePurpose,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { useCrewFoundryStore, type Department } from '../store/crewfoundryStore';\n\ntype MonthlyTrend = {\n month: string;\n hires: number;\n attrition: number;\n headcount: number;\n};\n\ntype CostItem = {\n category: string;\n amount: number;\n percentage: number;\n};\n\nexport function DashboardAnalyticsPagePage() {\n const { employees, departments, jobPostings, payrollRecords, projects } = useCrewFoundryStore();\n\n const monthlyTrends = useMemo<MonthlyTrend[]>(() => {\n if (employees.length === 0) {\n return [];\n }\n const monthKey = (value: string) => {\n const date = new Date(value);\n return `${date.getFullYear()}-${String(date.getMonth()).padStart(2, '0')}`;\n };\n const distinctMonths = Array.from(new Set(employees.map((item) => monthKey(item.startDate))))\n .sort()\n .slice(-6);\n return distinctMonths.map((key) => {\n const [year, month] = key.split('-').map(Number);\n const monthEnd = new Date(year, month + 1, 0).getTime();\n const label = new Date(year, month, 1).toLocaleString('en-US', {\n month: 'short',\n year: '2-digit',\n });\n // Real cumulative headcount as of the end of this month (still employed).\n const headcount = employees.filter(\n (item) => new Date(item.startDate).getTime() <= monthEnd && item.status !== 'terminated'\n ).length;\n const hires = employees.filter((item) => monthKey(item.startDate) === key).length;\n const attrition = employees.filter(\n (item) => item.status === 'terminated' && monthKey(item.startDate) === key\n ).length;\n return { month: label, hires, attrition, headcount };\n });\n }, [employees]);\n\n const maxTrend = Math.max(1, ...monthlyTrends.map((trend) => trend.headcount));\n\n const totalPayroll = payrollRecords.reduce((sum, record) => sum + record.netPay, 0);\n const avgSalary = Math.round(\n employees.reduce((sum, employee) => sum + employee.salary, 0) / Math.max(employees.length, 1)\n );\n const activePostings = jobPostings.filter((posting) => posting.status === 'active').length;\n\n const typeDistribution = employees.reduce<Record<string, number>>((acc, employee) => {\n const key = employee.type.replace('_', ' ');\n acc[key] = (acc[key] || 0) + 1;\n return acc;\n }, {});\n\n // Only real, store-backed cost lines (no invented coefficients).\n const costBreakdown = useMemo<CostItem[]>(() => {\n const costs: Array<{ category: string; amount: number }> = [\n { category: 'Net Payroll', amount: totalPayroll },\n {\n category: 'Project Delivery',\n amount: projects.reduce((sum, project) => sum + project.spent, 0),\n },\n ];\n const total = costs.reduce((sum, item) => sum + item.amount, 0) || 1;\n return costs.map((item) => ({\n ...item,\n percentage: Math.round((item.amount / total) * 100),\n }));\n }, [projects, totalPayroll]);\n\n const departmentColumns: ResponsiveTableColumn<Department>[] = [\n {\n key: 'name',\n header: 'Department',\n priority: 'primary',\n cell: (department) => <span className=\"font-medium\">{department.name}</span>,\n },\n {\n key: 'head',\n header: 'Head',\n priority: 'secondary',\n cell: (department) => <span className=\"text-text-secondary\">{department.headName}</span>,\n },\n {\n key: 'employees',\n header: 'Employees',\n priority: 'secondary',\n cell: (department) => (\n <span className=\"md:block md:text-right\">{department.employeeCount}</span>\n ),\n },\n {\n key: 'budget',\n header: 'Budget',\n priority: 'secondary',\n cell: (department) => (\n <span className=\"md:block md:text-right\">${(department.budget / 1000000).toFixed(1)}M</span>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n priority: 'primary',\n cell: (department) => (\n <Badge variant={department.status === 'active' ? 'default' : 'secondary'}>\n {department.status}\n </Badge>\n ),\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Dashboard Analytics</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Workforce analytics and operational insights</p>\n <PagePurpose className=\"mt-1\">\n A consolidated analytics view across your organization — use it to monitor the metrics\n that matter most without digging through separate reports.\n </PagePurpose>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Total Headcount</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 <div className=\"flex items-center text-xs text-status-success-text\">\n <TrendingUp className=\"mr-1 h-3 w-3\" />\n Live workforce count\n </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 Salary</CardTitle>\n <DollarSign className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">${avgSalary.toLocaleString()}</div>\n <div className=\"flex items-center text-xs text-status-success-text\">\n <TrendingUp className=\"mr-1 h-3 w-3\" />\n Updated from employee records\n </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\">Attrition Rate</CardTitle>\n <TrendingDown className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n {Math.round(\n (employees.filter((employee) => employee.status === 'terminated').length /\n Math.max(employees.length, 1)) *\n 100\n )}\n %\n </div>\n <div className=\"flex items-center text-xs text-status-success-text\">\n <TrendingDown className=\"mr-1 h-3 w-3\" />\n Calculated from status mix\n </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\">Open Roles</CardTitle>\n <Target className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activePostings}</div>\n <p className=\"text-xs text-text-secondary\">Based on active job postings</p>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-7\">\n <Card className=\"col-span-4\">\n <CardHeader>\n <CardTitle>Headcount Trend</CardTitle>\n <CardDescription>Monthly headcount over recent months</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {monthlyTrends.map((trend, index) => (\n <div key={`${trend.month}-${index}`} className=\"flex items-center gap-3\">\n <span className=\"w-10 text-sm text-text-secondary\">{trend.month}</span>\n <div className=\"h-4 flex-1 overflow-hidden rounded bg-bg-sunken\">\n <div\n className=\"h-4 rounded bg-action-primary-bg\"\n style={{ width: `${Math.round((trend.headcount / maxTrend) * 100)}%` }}\n />\n </div>\n <span className=\"w-10 text-right text-sm font-medium\">{trend.headcount}</span>\n <div className=\"flex w-24 gap-1\">\n <Badge variant=\"default\" className=\"text-[10px]\">\n +{trend.hires}\n </Badge>\n <Badge variant=\"destructive\" className=\"text-[10px]\">\n -{trend.attrition}\n </Badge>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card className=\"col-span-3\">\n <CardHeader>\n <CardTitle>Employee Types</CardTitle>\n <CardDescription>Distribution by employment type</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {Object.entries(typeDistribution)\n .sort(([, a], [, b]) => b - a)\n .map(([type, count]) => (\n <div key={type} className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4 text-text-secondary\" />\n <span className=\"text-sm capitalize\">{type}</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{count}</span>\n <span className=\"text-xs text-text-secondary\">\n ({Math.round((count / Math.max(employees.length, 1)) * 100)}%)\n </span>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Workforce Cost Breakdown</CardTitle>\n <CardDescription>Operational costs by category</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {costBreakdown.map((item) => (\n <div key={item.category} className=\"flex items-center gap-4\">\n <span className=\"w-48 text-sm text-text-secondary\">{item.category}</span>\n <div className=\"h-3 flex-1 overflow-hidden rounded bg-bg-sunken\">\n <div\n className=\"h-3 rounded bg-action-primary-bg/80\"\n style={{ width: `${item.percentage}%` }}\n />\n </div>\n <span className=\"w-24 text-right text-sm font-medium\">\n ${(item.amount / 1000).toFixed(0)}K\n </span>\n <span className=\"w-10 text-right text-xs text-text-secondary\">\n {item.percentage}%\n </span>\n </div>\n ))}\n </div>\n <div className=\"mt-4 flex justify-between border-t pt-4 text-sm\">\n <span className=\"font-medium\">Total Monthly Cost</span>\n <span className=\"font-bold\">\n ${(costBreakdown.reduce((sum, item) => sum + item.amount, 0) / 1000).toFixed(0)}K\n </span>\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Department Overview</CardTitle>\n <CardDescription>Key metrics by department</CardDescription>\n </CardHeader>\n <CardContent>\n <ResponsiveTable\n columns={departmentColumns}\n data={departments}\n rowKey={(department) => department.id}\n />\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardAnalyticsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/DashboardAnalyticsPagePage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { BarChart3, DollarSign, Target, TrendingDown, TrendingUp, Users } from 'lucide-react';\nimport {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n PagePurpose,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { useCrewFoundryStore, type Department } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\ntype MonthlyTrend = {\n month: string;\n hires: number;\n attrition: number;\n headcount: number;\n};\n\ntype CostItem = {\n category: string;\n amount: number;\n percentage: number;\n};\n\nexport function DashboardAnalyticsPagePage() {\n const { employees, departments, jobPostings, payrollRecords, projects } = useCrewFoundryStore();\n\n const monthlyTrends = useMemo<MonthlyTrend[]>(() => {\n if (employees.length === 0) {\n return [];\n }\n const monthKey = (value: string) => {\n const date = new Date(value);\n return `${date.getFullYear()}-${String(date.getMonth()).padStart(2, '0')}`;\n };\n const distinctMonths = Array.from(new Set(employees.map((item) => monthKey(item.startDate))))\n .sort()\n .slice(-6);\n return distinctMonths.map((key) => {\n const [year, month] = key.split('-').map(Number);\n const monthEnd = new Date(year, month + 1, 0).getTime();\n const label = new Date(year, month, 1).toLocaleString('en-US', {\n month: 'short',\n year: '2-digit',\n });\n // Real cumulative headcount as of the end of this month (still employed).\n const headcount = employees.filter(\n (item) => new Date(item.startDate).getTime() <= monthEnd && item.status !== 'terminated'\n ).length;\n const hires = employees.filter((item) => monthKey(item.startDate) === key).length;\n const attrition = employees.filter(\n (item) => item.status === 'terminated' && monthKey(item.startDate) === key\n ).length;\n return { month: label, hires, attrition, headcount };\n });\n }, [employees]);\n\n const maxTrend = Math.max(1, ...monthlyTrends.map((trend) => trend.headcount));\n\n const totalPayroll = payrollRecords.reduce((sum, record) => sum + record.netPay, 0);\n const avgSalary = Math.round(\n employees.reduce((sum, employee) => sum + employee.salary, 0) / Math.max(employees.length, 1)\n );\n const activePostings = jobPostings.filter((posting) => posting.status === 'active').length;\n\n const typeDistribution = employees.reduce<Record<string, number>>((acc, employee) => {\n const key = employee.type.replace('_', ' ');\n acc[key] = (acc[key] || 0) + 1;\n return acc;\n }, {});\n\n // Only real, store-backed cost lines (no invented coefficients).\n const costBreakdown = useMemo<CostItem[]>(() => {\n const costs: Array<{ category: string; amount: number }> = [\n { category: 'Net Payroll', amount: totalPayroll },\n {\n category: 'Project Delivery',\n amount: projects.reduce((sum, project) => sum + project.spent, 0),\n },\n ];\n const total = costs.reduce((sum, item) => sum + item.amount, 0) || 1;\n return costs.map((item) => ({\n ...item,\n percentage: Math.round((item.amount / total) * 100),\n }));\n }, [projects, totalPayroll]);\n\n const departmentColumns: ResponsiveTableColumn<Department>[] = [\n {\n key: 'name',\n header: 'Department',\n priority: 'primary',\n cell: (department) => <span className=\"font-medium\">{department.name}</span>,\n },\n {\n key: 'head',\n header: 'Head',\n priority: 'secondary',\n cell: (department) => <span className=\"text-text-secondary\">{department.headName}</span>,\n },\n {\n key: 'employees',\n header: 'Employees',\n priority: 'secondary',\n cell: (department) => (\n <span className=\"md:block md:text-right\">{department.employeeCount}</span>\n ),\n },\n {\n key: 'budget',\n header: 'Budget',\n priority: 'secondary',\n cell: (department) => (\n <span className=\"md:block md:text-right\">${(department.budget / 1000000).toFixed(1)}M</span>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n priority: 'primary',\n cell: (department) => (\n <Badge variant={department.status === 'active' ? 'default' : 'secondary'}>\n {formatEnumLabel(department.status)}\n </Badge>\n ),\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Dashboard Analytics</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Workforce analytics and operational insights</p>\n <PagePurpose className=\"mt-1\">\n A consolidated analytics view across your organization — use it to monitor the metrics\n that matter most without digging through separate reports.\n </PagePurpose>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Total Headcount</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 <div className=\"flex items-center text-xs text-status-success-text\">\n <TrendingUp className=\"mr-1 h-3 w-3\" />\n Live workforce count\n </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 Salary</CardTitle>\n <DollarSign className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">${avgSalary.toLocaleString()}</div>\n <div className=\"flex items-center text-xs text-status-success-text\">\n <TrendingUp className=\"mr-1 h-3 w-3\" />\n Updated from employee records\n </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\">Attrition Rate</CardTitle>\n <TrendingDown className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n {Math.round(\n (employees.filter((employee) => employee.status === 'terminated').length /\n Math.max(employees.length, 1)) *\n 100\n )}\n %\n </div>\n <div className=\"flex items-center text-xs text-status-success-text\">\n <TrendingDown className=\"mr-1 h-3 w-3\" />\n Calculated from status mix\n </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\">Open Roles</CardTitle>\n <Target className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activePostings}</div>\n <p className=\"text-xs text-text-secondary\">Based on active job postings</p>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-7\">\n <Card className=\"col-span-4\">\n <CardHeader>\n <CardTitle>Headcount Trend</CardTitle>\n <CardDescription>Monthly headcount over recent months</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {monthlyTrends.map((trend, index) => (\n <div key={`${trend.month}-${index}`} className=\"flex items-center gap-3\">\n <span className=\"w-10 text-sm text-text-secondary\">{trend.month}</span>\n <div className=\"h-4 flex-1 overflow-hidden rounded bg-bg-sunken\">\n <div\n className=\"h-4 rounded bg-action-primary-bg\"\n style={{ width: `${Math.round((trend.headcount / maxTrend) * 100)}%` }}\n />\n </div>\n <span className=\"w-10 text-right text-sm font-medium\">{trend.headcount}</span>\n <div className=\"flex w-24 gap-1\">\n <Badge variant=\"default\" className=\"text-[10px]\">\n +{trend.hires}\n </Badge>\n <Badge variant=\"destructive\" className=\"text-[10px]\">\n -{trend.attrition}\n </Badge>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card className=\"col-span-3\">\n <CardHeader>\n <CardTitle>Employee Types</CardTitle>\n <CardDescription>Distribution by employment type</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {Object.entries(typeDistribution)\n .sort(([, a], [, b]) => b - a)\n .map(([type, count]) => (\n <div key={type} className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4 text-text-secondary\" />\n <span className=\"text-sm capitalize\">{type}</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{count}</span>\n <span className=\"text-xs text-text-secondary\">\n ({Math.round((count / Math.max(employees.length, 1)) * 100)}%)\n </span>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Workforce Cost Breakdown</CardTitle>\n <CardDescription>Operational costs by category</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {costBreakdown.map((item) => (\n <div key={item.category} className=\"flex items-center gap-4\">\n <span className=\"w-48 text-sm text-text-secondary\">{item.category}</span>\n <div className=\"h-3 flex-1 overflow-hidden rounded bg-bg-sunken\">\n <div\n className=\"h-3 rounded bg-action-primary-bg/80\"\n style={{ width: `${item.percentage}%` }}\n />\n </div>\n <span className=\"w-24 text-right text-sm font-medium\">\n ${(item.amount / 1000).toFixed(0)}K\n </span>\n <span className=\"w-10 text-right text-xs text-text-secondary\">\n {item.percentage}%\n </span>\n </div>\n ))}\n </div>\n <div className=\"mt-4 flex justify-between border-t pt-4 text-sm\">\n <span className=\"font-medium\">Total Monthly Cost</span>\n <span className=\"font-bold\">\n ${(costBreakdown.reduce((sum, item) => sum + item.amount, 0) / 1000).toFixed(0)}K\n </span>\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Department Overview</CardTitle>\n <CardDescription>Key metrics by department</CardDescription>\n </CardHeader>\n <CardContent>\n <ResponsiveTable\n columns={departmentColumns}\n data={departments}\n rowKey={(department) => department.id}\n />\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|