@burdenoff/microfe-crewfoundry 2026.625.2 → 2026.703.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/crewfoundry/components/forms/ConfirmDialog.js +43 -0
- package/dist/crewfoundry/components/forms/ConfirmDialog.js.map +1 -0
- package/dist/crewfoundry/components/forms/FormModal.js +220 -0
- package/dist/crewfoundry/components/forms/FormModal.js.map +1 -0
- package/dist/crewfoundry/components/forms/formValues.js +20 -0
- package/dist/crewfoundry/components/forms/formValues.js.map +1 -0
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +255 -65
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js +28 -17
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js +57 -53
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +32 -23
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js +44 -29
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +183 -57
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +214 -92
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +165 -131
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js +163 -133
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +269 -54
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +225 -78
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +213 -59
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +287 -90
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +49 -47
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +166 -59
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js +274 -83
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +198 -88
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js +216 -88
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +216 -66
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js +6 -7
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +83 -68
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +167 -46
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +75 -55
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +152 -79
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +75 -63
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js +3 -1
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js +235 -87
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +199 -86
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js +21 -40
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js +117 -45
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +249 -90
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +47 -45
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js +262 -133
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +144 -77
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +306 -51
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,197 +1,211 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { useCrewFoundry as e } from "../providers/CrewFoundryProvider.js";
|
|
2
|
+
import { useCrewFoundryStore as t } from "../store/crewfoundryStore.js";
|
|
3
|
+
import { useState as n } from "react";
|
|
4
|
+
import { Activity as r, Briefcase as i, Calendar as a, TrendingUp as o, Users as s } from "lucide-react";
|
|
5
|
+
import { useNavigate as c } from "react-router-dom";
|
|
6
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
7
|
+
import { AuroraBackground as d, Badge as f, Button as p, Card as m, CardContent as h, CardDescription as g, CardHeader as _, CardTitle as v, EmphasisPanel as y, GlassCard as b, GradientText as x, IllustratedEmptyState as S, NextSteps as C, PagePurpose as w } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
import { useGlobalUi as T } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
9
|
+
import { useI18n as E } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
8
10
|
//#region src/crewfoundry/pages/DashboardDashboardPagePage.tsx
|
|
9
|
-
function
|
|
10
|
-
let { t:
|
|
11
|
-
|
|
11
|
+
function D() {
|
|
12
|
+
let { t: D } = E(), O = c(), { showToast: k } = T(), { currentUser: A } = e(), { employees: j, jobPostings: M, leaveRequests: N, notifications: P, projects: F, updateLeaveRequest: I } = t(), [L, R] = n("month"), [z, B] = n(null), V = A?.name || [A?.firstName, A?.lastName].filter(Boolean).join(" ") || A?.email || "Manager", H = async (e, t) => {
|
|
13
|
+
B(e);
|
|
14
|
+
try {
|
|
15
|
+
await I(e, {
|
|
16
|
+
status: t,
|
|
17
|
+
approverName: V
|
|
18
|
+
}), k(t === "approved" ? "Leave approved" : "Leave rejected", "success");
|
|
19
|
+
} catch (e) {
|
|
20
|
+
k(e instanceof Error ? e.message : "Unable to update leave request", "error");
|
|
21
|
+
} finally {
|
|
22
|
+
B(null);
|
|
23
|
+
}
|
|
24
|
+
}, U = (e, t) => {
|
|
25
|
+
let n = D(e);
|
|
12
26
|
return n === e ? t : n;
|
|
13
|
-
},
|
|
14
|
-
return /* @__PURE__ */
|
|
27
|
+
}, W = j.filter((e) => e.status === "active").length, G = j.filter((e) => e.status === "on_leave").length, K = M.filter((e) => e.status === "active").length, q = M.reduce((e, t) => e + t.applicants, 0), J = N.filter((e) => e.status === "pending").length, Y = P.filter((e) => !e.read).length, X = F.filter((e) => e.status === "active").length, Z = (j.reduce((e, t) => e + t.performanceScore, 0) / j.length).toFixed(1), Q = j.reduce((e, t) => (e[t.department] = (e[t.department] || 0) + 1, e), {}), $ = Math.max(...Object.values(Q));
|
|
28
|
+
return /* @__PURE__ */ u("div", {
|
|
15
29
|
className: "space-y-6 p-6",
|
|
16
30
|
children: [
|
|
17
|
-
/* @__PURE__ */
|
|
31
|
+
/* @__PURE__ */ u("div", {
|
|
18
32
|
className: "relative overflow-hidden rounded-xl border border-border-seam bg-gloss-card p-6",
|
|
19
|
-
children: [/* @__PURE__ */
|
|
33
|
+
children: [/* @__PURE__ */ l(d, { intensity: "subtle" }), /* @__PURE__ */ u("div", {
|
|
20
34
|
className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
|
|
21
|
-
children: [/* @__PURE__ */
|
|
22
|
-
/* @__PURE__ */
|
|
35
|
+
children: [/* @__PURE__ */ u("div", { children: [
|
|
36
|
+
/* @__PURE__ */ l("h1", {
|
|
23
37
|
className: "text-2xl font-semibold",
|
|
24
|
-
children: /* @__PURE__ */
|
|
38
|
+
children: /* @__PURE__ */ l(x, { children: U("crewfoundry.dashboard.title", "Workforce Dashboard") })
|
|
25
39
|
}),
|
|
26
|
-
/* @__PURE__ */
|
|
40
|
+
/* @__PURE__ */ l("p", {
|
|
27
41
|
className: "text-sm text-text-secondary",
|
|
28
|
-
children:
|
|
42
|
+
children: U("crewfoundry.dashboard.subtitle", "Overview of your organization's workforce metrics")
|
|
29
43
|
}),
|
|
30
|
-
/* @__PURE__ */
|
|
44
|
+
/* @__PURE__ */ l(w, {
|
|
31
45
|
className: "mt-2",
|
|
32
|
-
children:
|
|
46
|
+
children: U("crewfoundry.dashboard.purpose", "Your workforce command center — see headcount, hiring, performance, and projects at a glance, then jump straight to the area that needs your attention.")
|
|
33
47
|
})
|
|
34
|
-
] }), /* @__PURE__ */
|
|
48
|
+
] }), /* @__PURE__ */ l("div", {
|
|
35
49
|
className: "flex gap-2",
|
|
36
50
|
children: [
|
|
37
51
|
"week",
|
|
38
52
|
"month",
|
|
39
53
|
"quarter"
|
|
40
|
-
].map((e) => /* @__PURE__ */
|
|
41
|
-
variant:
|
|
54
|
+
].map((e) => /* @__PURE__ */ l(p, {
|
|
55
|
+
variant: L === e ? "default" : "outline",
|
|
42
56
|
size: "sm",
|
|
43
|
-
onClick: () =>
|
|
44
|
-
children:
|
|
57
|
+
onClick: () => R(e),
|
|
58
|
+
children: U(`crewfoundry.dashboard.period.${e}`, e.charAt(0).toUpperCase() + e.slice(1))
|
|
45
59
|
}, e))
|
|
46
60
|
})]
|
|
47
61
|
})]
|
|
48
62
|
}),
|
|
49
|
-
/* @__PURE__ */
|
|
63
|
+
/* @__PURE__ */ l(C, {
|
|
50
64
|
storageKey: "crewfoundry-dashboard",
|
|
51
65
|
steps: [
|
|
52
66
|
{
|
|
53
67
|
id: "employees",
|
|
54
|
-
label:
|
|
55
|
-
description:
|
|
56
|
-
icon: /* @__PURE__ */
|
|
57
|
-
onClick: () =>
|
|
68
|
+
label: U("crewfoundry.dashboard.next.employees", "Review your team"),
|
|
69
|
+
description: U("crewfoundry.dashboard.next.employeesDesc", "Open the employee directory to see who is active and on leave."),
|
|
70
|
+
icon: /* @__PURE__ */ l(s, { className: "h-4 w-4" }),
|
|
71
|
+
onClick: () => O("../../hr/employees-page")
|
|
58
72
|
},
|
|
59
73
|
{
|
|
60
74
|
id: "hiring",
|
|
61
|
-
label:
|
|
62
|
-
description:
|
|
63
|
-
icon: /* @__PURE__ */
|
|
64
|
-
onClick: () =>
|
|
75
|
+
label: U("crewfoundry.dashboard.next.hiring", "Post a new job"),
|
|
76
|
+
description: U("crewfoundry.dashboard.next.hiringDesc", "Create an opening to start collecting applicants."),
|
|
77
|
+
icon: /* @__PURE__ */ l(i, { className: "h-4 w-4" }),
|
|
78
|
+
onClick: () => O("../../hiring/create-job-page")
|
|
65
79
|
},
|
|
66
80
|
{
|
|
67
81
|
id: "projects",
|
|
68
|
-
label:
|
|
69
|
-
description:
|
|
70
|
-
icon: /* @__PURE__ */
|
|
71
|
-
onClick: () =>
|
|
82
|
+
label: U("crewfoundry.dashboard.next.projects", "Check active projects"),
|
|
83
|
+
description: U("crewfoundry.dashboard.next.projectsDesc", "Track progress and budgets across in-flight work."),
|
|
84
|
+
icon: /* @__PURE__ */ l(r, { className: "h-4 w-4" }),
|
|
85
|
+
onClick: () => O("../../projects/projects-page")
|
|
72
86
|
}
|
|
73
87
|
]
|
|
74
88
|
}),
|
|
75
|
-
/* @__PURE__ */
|
|
89
|
+
/* @__PURE__ */ u("div", {
|
|
76
90
|
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4",
|
|
77
91
|
children: [
|
|
78
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ u(b, {
|
|
79
93
|
treatment: "glass",
|
|
80
94
|
glow: !0,
|
|
81
95
|
className: "border-border-seam",
|
|
82
|
-
children: [/* @__PURE__ */
|
|
96
|
+
children: [/* @__PURE__ */ u(_, {
|
|
83
97
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
84
|
-
children: [/* @__PURE__ */
|
|
98
|
+
children: [/* @__PURE__ */ l(v, {
|
|
85
99
|
className: "text-sm font-medium",
|
|
86
|
-
children:
|
|
87
|
-
}), /* @__PURE__ */
|
|
88
|
-
}), /* @__PURE__ */
|
|
100
|
+
children: U("crewfoundry.dashboard.stats.totalEmployees", "Total Employees")
|
|
101
|
+
}), /* @__PURE__ */ l(s, { className: "h-4 w-4 text-text-secondary" })]
|
|
102
|
+
}), /* @__PURE__ */ u(h, { children: [/* @__PURE__ */ l("div", {
|
|
89
103
|
className: "text-2xl font-bold tabular-nums",
|
|
90
|
-
children:
|
|
91
|
-
}), /* @__PURE__ */
|
|
104
|
+
children: j.length
|
|
105
|
+
}), /* @__PURE__ */ u("p", {
|
|
92
106
|
className: "text-xs text-text-secondary",
|
|
93
107
|
children: [
|
|
94
|
-
|
|
108
|
+
W,
|
|
95
109
|
" ",
|
|
96
|
-
|
|
110
|
+
U("crewfoundry.dashboard.stats.active", "active"),
|
|
97
111
|
", ",
|
|
98
|
-
|
|
112
|
+
G,
|
|
99
113
|
" ",
|
|
100
|
-
|
|
114
|
+
U("crewfoundry.dashboard.stats.onLeave", "on leave")
|
|
101
115
|
]
|
|
102
116
|
})] })]
|
|
103
117
|
}),
|
|
104
|
-
/* @__PURE__ */
|
|
118
|
+
/* @__PURE__ */ u(b, {
|
|
105
119
|
treatment: "metric",
|
|
106
120
|
className: "border-border-seam",
|
|
107
|
-
children: [/* @__PURE__ */
|
|
121
|
+
children: [/* @__PURE__ */ u(_, {
|
|
108
122
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
109
|
-
children: [/* @__PURE__ */
|
|
123
|
+
children: [/* @__PURE__ */ l(v, {
|
|
110
124
|
className: "text-sm font-medium",
|
|
111
|
-
children:
|
|
112
|
-
}), /* @__PURE__ */
|
|
113
|
-
}), /* @__PURE__ */
|
|
125
|
+
children: U("crewfoundry.dashboard.stats.openPositions", "Open Positions")
|
|
126
|
+
}), /* @__PURE__ */ l(i, { className: "h-4 w-4 text-text-secondary" })]
|
|
127
|
+
}), /* @__PURE__ */ u(h, { children: [/* @__PURE__ */ l("div", {
|
|
114
128
|
className: "text-2xl font-bold tabular-nums",
|
|
115
|
-
children:
|
|
116
|
-
}), /* @__PURE__ */
|
|
129
|
+
children: K
|
|
130
|
+
}), /* @__PURE__ */ u("p", {
|
|
117
131
|
className: "text-xs text-text-secondary",
|
|
118
132
|
children: [
|
|
119
|
-
|
|
133
|
+
q,
|
|
120
134
|
" ",
|
|
121
|
-
|
|
135
|
+
U("crewfoundry.dashboard.stats.totalApplicants", "total applicants")
|
|
122
136
|
]
|
|
123
137
|
})] })]
|
|
124
138
|
}),
|
|
125
|
-
/* @__PURE__ */
|
|
139
|
+
/* @__PURE__ */ u(b, {
|
|
126
140
|
treatment: "metric",
|
|
127
141
|
className: "border-border-seam",
|
|
128
|
-
children: [/* @__PURE__ */
|
|
142
|
+
children: [/* @__PURE__ */ u(_, {
|
|
129
143
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
130
|
-
children: [/* @__PURE__ */
|
|
144
|
+
children: [/* @__PURE__ */ l(v, {
|
|
131
145
|
className: "text-sm font-medium",
|
|
132
|
-
children:
|
|
133
|
-
}), /* @__PURE__ */
|
|
134
|
-
}), /* @__PURE__ */
|
|
146
|
+
children: U("crewfoundry.dashboard.stats.avgPerformance", "Avg Performance")
|
|
147
|
+
}), /* @__PURE__ */ l(o, { className: "h-4 w-4 text-text-secondary" })]
|
|
148
|
+
}), /* @__PURE__ */ u(h, { children: [/* @__PURE__ */ u("div", {
|
|
135
149
|
className: "text-2xl font-bold tabular-nums",
|
|
136
|
-
children: [
|
|
137
|
-
}), /* @__PURE__ */
|
|
150
|
+
children: [Z, "/5"]
|
|
151
|
+
}), /* @__PURE__ */ l("p", {
|
|
138
152
|
className: "text-xs text-text-secondary",
|
|
139
|
-
children:
|
|
153
|
+
children: U("crewfoundry.dashboard.stats.performanceTrend", "+0.2 from last quarter")
|
|
140
154
|
})] })]
|
|
141
155
|
}),
|
|
142
|
-
/* @__PURE__ */
|
|
156
|
+
/* @__PURE__ */ u(b, {
|
|
143
157
|
treatment: "metric",
|
|
144
158
|
className: "border-border-seam",
|
|
145
|
-
children: [/* @__PURE__ */
|
|
159
|
+
children: [/* @__PURE__ */ u(_, {
|
|
146
160
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
147
|
-
children: [/* @__PURE__ */
|
|
161
|
+
children: [/* @__PURE__ */ l(v, {
|
|
148
162
|
className: "text-sm font-medium",
|
|
149
|
-
children:
|
|
150
|
-
}), /* @__PURE__ */
|
|
151
|
-
}), /* @__PURE__ */
|
|
163
|
+
children: U("crewfoundry.dashboard.stats.activeProjects", "Active Projects")
|
|
164
|
+
}), /* @__PURE__ */ l(r, { className: "h-4 w-4 text-text-secondary" })]
|
|
165
|
+
}), /* @__PURE__ */ u(h, { children: [/* @__PURE__ */ l("div", {
|
|
152
166
|
className: "text-2xl font-bold tabular-nums",
|
|
153
|
-
children:
|
|
154
|
-
}), /* @__PURE__ */
|
|
167
|
+
children: X
|
|
168
|
+
}), /* @__PURE__ */ u("p", {
|
|
155
169
|
className: "text-xs text-text-secondary",
|
|
156
170
|
children: [
|
|
157
|
-
|
|
171
|
+
J,
|
|
158
172
|
" ",
|
|
159
|
-
|
|
173
|
+
U("crewfoundry.dashboard.stats.pendingLeaveRequests", "pending leave requests")
|
|
160
174
|
]
|
|
161
175
|
})] })]
|
|
162
176
|
})
|
|
163
177
|
]
|
|
164
178
|
}),
|
|
165
|
-
/* @__PURE__ */
|
|
179
|
+
/* @__PURE__ */ u("div", {
|
|
166
180
|
className: "grid gap-4 md:grid-cols-7",
|
|
167
|
-
children: [/* @__PURE__ */
|
|
181
|
+
children: [/* @__PURE__ */ u(y, {
|
|
168
182
|
className: "col-span-4",
|
|
169
183
|
children: [
|
|
170
|
-
/* @__PURE__ */
|
|
184
|
+
/* @__PURE__ */ l("div", {
|
|
171
185
|
className: "mb-1 text-lg font-semibold",
|
|
172
|
-
children:
|
|
186
|
+
children: U("crewfoundry.dashboard.departmentHeadcount.title", "Department Headcount")
|
|
173
187
|
}),
|
|
174
|
-
/* @__PURE__ */
|
|
188
|
+
/* @__PURE__ */ l("p", {
|
|
175
189
|
className: "mb-4 text-sm text-text-secondary",
|
|
176
|
-
children:
|
|
190
|
+
children: U("crewfoundry.dashboard.departmentHeadcount.description", "Employee distribution across departments")
|
|
177
191
|
}),
|
|
178
|
-
/* @__PURE__ */
|
|
192
|
+
/* @__PURE__ */ l("div", {
|
|
179
193
|
className: "space-y-3",
|
|
180
|
-
children: Object.entries(
|
|
194
|
+
children: Object.entries(Q).sort(([, e], [, t]) => t - e).map(([e, t]) => /* @__PURE__ */ u("div", {
|
|
181
195
|
className: "flex items-center gap-3",
|
|
182
196
|
children: [
|
|
183
|
-
/* @__PURE__ */
|
|
197
|
+
/* @__PURE__ */ l("span", {
|
|
184
198
|
className: "w-24 text-sm text-text-secondary truncate",
|
|
185
199
|
children: e
|
|
186
200
|
}),
|
|
187
|
-
/* @__PURE__ */
|
|
201
|
+
/* @__PURE__ */ l("div", {
|
|
188
202
|
className: "flex-1 h-4 bg-bg-sunken rounded overflow-hidden",
|
|
189
|
-
children: /* @__PURE__ */
|
|
203
|
+
children: /* @__PURE__ */ l("div", {
|
|
190
204
|
className: "h-4 bg-action-primary-bg rounded",
|
|
191
|
-
style: { width: `${Math.round(t /
|
|
205
|
+
style: { width: `${Math.round(t / $ * 100)}%` }
|
|
192
206
|
})
|
|
193
207
|
}),
|
|
194
|
-
/* @__PURE__ */
|
|
208
|
+
/* @__PURE__ */ l("span", {
|
|
195
209
|
className: "text-sm font-medium w-8 text-right tabular-nums",
|
|
196
210
|
children: t
|
|
197
211
|
})
|
|
@@ -199,28 +213,28 @@ function T() {
|
|
|
199
213
|
}, e))
|
|
200
214
|
})
|
|
201
215
|
]
|
|
202
|
-
}), /* @__PURE__ */
|
|
216
|
+
}), /* @__PURE__ */ u(m, {
|
|
203
217
|
className: "col-span-3",
|
|
204
|
-
children: [/* @__PURE__ */
|
|
218
|
+
children: [/* @__PURE__ */ u(_, {
|
|
205
219
|
className: "flex flex-row items-center justify-between",
|
|
206
|
-
children: [/* @__PURE__ */
|
|
220
|
+
children: [/* @__PURE__ */ l(v, { children: U("crewfoundry.dashboard.notifications.title", "Recent Notifications") }), /* @__PURE__ */ u(f, {
|
|
207
221
|
variant: "secondary",
|
|
208
222
|
children: [
|
|
209
|
-
|
|
223
|
+
Y,
|
|
210
224
|
" ",
|
|
211
|
-
|
|
225
|
+
U("crewfoundry.dashboard.notifications.unread", "unread")
|
|
212
226
|
]
|
|
213
227
|
})]
|
|
214
|
-
}), /* @__PURE__ */
|
|
228
|
+
}), /* @__PURE__ */ l(h, {
|
|
215
229
|
className: "space-y-4",
|
|
216
|
-
children:
|
|
230
|
+
children: P.slice(0, 5).map((e) => /* @__PURE__ */ u("div", {
|
|
217
231
|
className: "flex items-start gap-3",
|
|
218
|
-
children: [/* @__PURE__ */
|
|
232
|
+
children: [/* @__PURE__ */ l("div", { className: `mt-1 h-2 w-2 rounded-full flex-shrink-0 motion-safe:animate-vc-glow-pulse ${e.type === "success" ? "bg-status-success-text" : e.type === "warning" ? "bg-status-warning-text" : e.type === "error" ? "bg-status-error-text" : "bg-status-info-text"}` }), /* @__PURE__ */ u("div", {
|
|
219
233
|
className: "flex-1 min-w-0",
|
|
220
|
-
children: [/* @__PURE__ */
|
|
234
|
+
children: [/* @__PURE__ */ l("p", {
|
|
221
235
|
className: `text-sm ${e.read ? "text-text-secondary" : "font-medium"}`,
|
|
222
236
|
children: e.title
|
|
223
|
-
}), /* @__PURE__ */
|
|
237
|
+
}), /* @__PURE__ */ l("p", {
|
|
224
238
|
className: "text-xs text-text-secondary truncate",
|
|
225
239
|
children: e.message
|
|
226
240
|
})]
|
|
@@ -229,62 +243,82 @@ function T() {
|
|
|
229
243
|
})]
|
|
230
244
|
})]
|
|
231
245
|
}),
|
|
232
|
-
/* @__PURE__ */
|
|
246
|
+
/* @__PURE__ */ u("div", {
|
|
233
247
|
className: "grid gap-4 md:grid-cols-2",
|
|
234
|
-
children: [/* @__PURE__ */
|
|
248
|
+
children: [/* @__PURE__ */ u(m, { children: [/* @__PURE__ */ u(_, { children: [/* @__PURE__ */ l(v, { children: U("crewfoundry.dashboard.upcomingInterviews.title", "Upcoming Interviews") }), /* @__PURE__ */ l(g, { children: U("crewfoundry.dashboard.upcomingInterviews.description", "Scheduled for this week") })] }), /* @__PURE__ */ l(h, {
|
|
235
249
|
className: "space-y-3",
|
|
236
|
-
children:
|
|
250
|
+
children: F.filter((e) => e.status === "active").slice(0, 4).map((e) => /* @__PURE__ */ u("div", {
|
|
237
251
|
className: "flex items-center justify-between rounded border p-3",
|
|
238
|
-
children: [/* @__PURE__ */
|
|
252
|
+
children: [/* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("p", {
|
|
239
253
|
className: "text-sm font-medium",
|
|
240
254
|
children: e.name
|
|
241
|
-
}), /* @__PURE__ */
|
|
255
|
+
}), /* @__PURE__ */ l("p", {
|
|
242
256
|
className: "text-xs text-text-secondary",
|
|
243
257
|
children: e.teamName
|
|
244
|
-
})] }), /* @__PURE__ */
|
|
258
|
+
})] }), /* @__PURE__ */ u("div", {
|
|
245
259
|
className: "flex items-center gap-2",
|
|
246
|
-
children: [/* @__PURE__ */
|
|
260
|
+
children: [/* @__PURE__ */ l("div", {
|
|
247
261
|
className: "w-24 h-2 bg-bg-sunken rounded overflow-hidden",
|
|
248
|
-
children: /* @__PURE__ */
|
|
262
|
+
children: /* @__PURE__ */ l("div", {
|
|
249
263
|
className: "h-2 bg-action-primary-bg rounded",
|
|
250
264
|
style: { width: `${e.progress}%` }
|
|
251
265
|
})
|
|
252
|
-
}), /* @__PURE__ */
|
|
266
|
+
}), /* @__PURE__ */ u("span", {
|
|
253
267
|
className: "text-xs text-text-secondary",
|
|
254
268
|
children: [e.progress, "%"]
|
|
255
269
|
})]
|
|
256
270
|
})]
|
|
257
271
|
}, e.id))
|
|
258
|
-
})] }), /* @__PURE__ */
|
|
272
|
+
})] }), /* @__PURE__ */ u(m, { children: [/* @__PURE__ */ u(_, { children: [/* @__PURE__ */ l(v, { children: U("crewfoundry.dashboard.leaveRequests.title", "Recent Leave Requests") }), /* @__PURE__ */ l(g, { children: U("crewfoundry.dashboard.leaveRequests.description", "Pending approval") })] }), /* @__PURE__ */ u(h, {
|
|
259
273
|
className: "space-y-3",
|
|
260
|
-
children: [
|
|
274
|
+
children: [N.length === 0 && /* @__PURE__ */ l(S, {
|
|
261
275
|
illustration: "empty-data",
|
|
262
|
-
title:
|
|
263
|
-
description:
|
|
264
|
-
}),
|
|
276
|
+
title: U("crewfoundry.dashboard.leaveRequests.emptyTitle", "No leave requests"),
|
|
277
|
+
description: U("crewfoundry.dashboard.leaveRequests.emptyDescription", "Pending leave requests will appear here.")
|
|
278
|
+
}), N.map((e) => /* @__PURE__ */ u("div", {
|
|
265
279
|
className: "flex items-center justify-between rounded border p-3",
|
|
266
|
-
children: [/* @__PURE__ */
|
|
280
|
+
children: [/* @__PURE__ */ l("div", {
|
|
267
281
|
className: "flex items-center gap-3",
|
|
268
|
-
children: /* @__PURE__ */
|
|
282
|
+
children: /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("p", {
|
|
269
283
|
className: "text-sm font-medium",
|
|
270
284
|
children: e.employeeName
|
|
271
|
-
}), /* @__PURE__ */
|
|
285
|
+
}), /* @__PURE__ */ u("div", {
|
|
272
286
|
className: "flex items-center gap-2 text-xs text-text-secondary",
|
|
273
|
-
children: [/* @__PURE__ */
|
|
287
|
+
children: [/* @__PURE__ */ l(a, { className: "h-3 w-3" }), /* @__PURE__ */ u("span", { children: [
|
|
274
288
|
e.startDate,
|
|
275
289
|
" - ",
|
|
276
290
|
e.endDate
|
|
277
291
|
] })]
|
|
278
292
|
})] })
|
|
279
|
-
}), /* @__PURE__ */
|
|
293
|
+
}), /* @__PURE__ */ u("div", {
|
|
280
294
|
className: "flex items-center gap-2",
|
|
281
|
-
children: [
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
295
|
+
children: [
|
|
296
|
+
e.status === "pending" && /* @__PURE__ */ u("div", {
|
|
297
|
+
className: "flex gap-1",
|
|
298
|
+
children: [/* @__PURE__ */ l(p, {
|
|
299
|
+
size: "sm",
|
|
300
|
+
variant: "outline",
|
|
301
|
+
className: "h-7 text-xs",
|
|
302
|
+
disabled: z === e.id,
|
|
303
|
+
onClick: () => void H(e.id, "rejected"),
|
|
304
|
+
children: U("crewfoundry.dashboard.leaveRequests.reject", "Reject")
|
|
305
|
+
}), /* @__PURE__ */ l(p, {
|
|
306
|
+
size: "sm",
|
|
307
|
+
className: "h-7 text-xs",
|
|
308
|
+
disabled: z === e.id,
|
|
309
|
+
onClick: () => void H(e.id, "approved"),
|
|
310
|
+
children: U("crewfoundry.dashboard.leaveRequests.approve", "Approve")
|
|
311
|
+
})]
|
|
312
|
+
}),
|
|
313
|
+
/* @__PURE__ */ l(f, {
|
|
314
|
+
variant: e.status === "approved" ? "default" : e.status === "pending" ? "secondary" : "destructive",
|
|
315
|
+
children: e.status
|
|
316
|
+
}),
|
|
317
|
+
/* @__PURE__ */ l(f, {
|
|
318
|
+
variant: "outline",
|
|
319
|
+
children: e.type
|
|
320
|
+
})
|
|
321
|
+
]
|
|
288
322
|
})]
|
|
289
323
|
}, e.id))]
|
|
290
324
|
})] })]
|
|
@@ -293,6 +327,6 @@ function T() {
|
|
|
293
327
|
});
|
|
294
328
|
}
|
|
295
329
|
//#endregion
|
|
296
|
-
export {
|
|
330
|
+
export { D as DashboardDashboardPagePage };
|
|
297
331
|
|
|
298
332
|
//# sourceMappingURL=DashboardDashboardPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardDashboardPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/DashboardDashboardPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n AuroraBackground,\n EmphasisPanel,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Activity,\n ArrowUpRight,\n Briefcase,\n Calendar,\n Clock,\n TrendingUp,\n Users,\n UserCheck,\n} from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function DashboardDashboardPagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { employees, jobPostings, leaveRequests, notifications, projects } = useCrewFoundryStore();\n const [selectedPeriod, setSelectedPeriod] = useState<'week' | 'month' | 'quarter'>('month');\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n\n const activeEmployees = employees.filter((e) => e.status === 'active').length;\n const onLeave = employees.filter((e) => e.status === 'on_leave').length;\n const openPositions = jobPostings.filter((j) => j.status === 'active').length;\n const totalApplicants = jobPostings.reduce((sum, j) => sum + j.applicants, 0);\n const pendingLeaves = leaveRequests.filter((l) => l.status === 'pending').length;\n const unreadNotifications = notifications.filter((n) => !n.read).length;\n const activeProjects = projects.filter((p) => p.status === 'active').length;\n const avgPerformance = (\n employees.reduce((sum, e) => sum + e.performanceScore, 0) / employees.length\n ).toFixed(1);\n\n const departmentHeadcount = employees.reduce<Record<string, number>>((acc, e) => {\n acc[e.department] = (acc[e.department] || 0) + 1;\n return acc;\n }, {});\n\n const maxHeadcount = Math.max(...Object.values(departmentHeadcount));\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"relative overflow-hidden rounded-xl border border-border-seam bg-gloss-card p-6\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{t('crewfoundry.dashboard.title', 'Workforce Dashboard')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'crewfoundry.dashboard.subtitle',\n \"Overview of your organization's workforce metrics\"\n )}\n </p>\n <PagePurpose className=\"mt-2\">\n {t(\n 'crewfoundry.dashboard.purpose',\n 'Your workforce command center — see headcount, hiring, performance, and projects at a glance, then jump straight to the area that needs your attention.'\n )}\n </PagePurpose>\n </div>\n <div className=\"flex gap-2\">\n {(['week', 'month', 'quarter'] as const).map((period) => (\n <Button\n key={period}\n variant={selectedPeriod === period ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setSelectedPeriod(period)}\n >\n {t(\n `crewfoundry.dashboard.period.${period}`,\n period.charAt(0).toUpperCase() + period.slice(1)\n )}\n </Button>\n ))}\n </div>\n </div>\n </div>\n\n <NextSteps\n storageKey=\"crewfoundry-dashboard\"\n steps={[\n {\n id: 'employees',\n label: t('crewfoundry.dashboard.next.employees', 'Review your team'),\n description: t(\n 'crewfoundry.dashboard.next.employeesDesc',\n 'Open the employee directory to see who is active and on leave.'\n ),\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hr/employees-page'),\n },\n {\n id: 'hiring',\n label: t('crewfoundry.dashboard.next.hiring', 'Post a new job'),\n description: t(\n 'crewfoundry.dashboard.next.hiringDesc',\n 'Create an opening to start collecting applicants.'\n ),\n icon: <Briefcase className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hiring/create-job-page'),\n },\n {\n id: 'projects',\n label: t('crewfoundry.dashboard.next.projects', 'Check active projects'),\n description: t(\n 'crewfoundry.dashboard.next.projectsDesc',\n 'Track progress and budgets across in-flight work.'\n ),\n icon: <Activity className=\"h-4 w-4\" />,\n onClick: () => navigate('../../projects/projects-page'),\n },\n ]}\n />\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\">\n {t('crewfoundry.dashboard.stats.totalEmployees', 'Total Employees')}\n </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 <p className=\"text-xs text-text-secondary\">\n {activeEmployees} {t('crewfoundry.dashboard.stats.active', 'active')}, {onLeave}{' '}\n {t('crewfoundry.dashboard.stats.onLeave', 'on leave')}\n </p>\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\">\n {t('crewfoundry.dashboard.stats.openPositions', 'Open Positions')}\n </CardTitle>\n <Briefcase className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{openPositions}</div>\n <p className=\"text-xs text-text-secondary\">\n {totalApplicants}{' '}\n {t('crewfoundry.dashboard.stats.totalApplicants', 'total applicants')}\n </p>\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\">\n {t('crewfoundry.dashboard.stats.avgPerformance', 'Avg Performance')}\n </CardTitle>\n <TrendingUp className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgPerformance}/5</div>\n <p className=\"text-xs text-text-secondary\">\n {t('crewfoundry.dashboard.stats.performanceTrend', '+0.2 from last quarter')}\n </p>\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\">\n {t('crewfoundry.dashboard.stats.activeProjects', 'Active Projects')}\n </CardTitle>\n <Activity className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activeProjects}</div>\n <p className=\"text-xs text-text-secondary\">\n {pendingLeaves}{' '}\n {t('crewfoundry.dashboard.stats.pendingLeaveRequests', 'pending leave requests')}\n </p>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-7\">\n <EmphasisPanel className=\"col-span-4\">\n <div className=\"mb-1 text-lg font-semibold\">\n {t('crewfoundry.dashboard.departmentHeadcount.title', 'Department Headcount')}\n </div>\n <p className=\"mb-4 text-sm text-text-secondary\">\n {t(\n 'crewfoundry.dashboard.departmentHeadcount.description',\n 'Employee distribution across departments'\n )}\n </p>\n <div className=\"space-y-3\">\n {Object.entries(departmentHeadcount)\n .sort(([, a], [, b]) => b - a)\n .map(([dept, count]) => (\n <div key={dept} className=\"flex items-center gap-3\">\n <span className=\"w-24 text-sm text-text-secondary truncate\">{dept}</span>\n <div className=\"flex-1 h-4 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-4 bg-action-primary-bg rounded\"\n style={{ width: `${Math.round((count / maxHeadcount) * 100)}%` }}\n />\n </div>\n <span className=\"text-sm font-medium w-8 text-right tabular-nums\">{count}</span>\n </div>\n ))}\n </div>\n </EmphasisPanel>\n\n <Card className=\"col-span-3\">\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <CardTitle>\n {t('crewfoundry.dashboard.notifications.title', 'Recent Notifications')}\n </CardTitle>\n <Badge variant=\"secondary\">\n {unreadNotifications} {t('crewfoundry.dashboard.notifications.unread', 'unread')}\n </Badge>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {notifications.slice(0, 5).map((notif) => (\n <div key={notif.id} className=\"flex items-start gap-3\">\n <div\n className={`mt-1 h-2 w-2 rounded-full flex-shrink-0 motion-safe:animate-vc-glow-pulse ${\n notif.type === 'success'\n ? 'bg-status-success-text'\n : notif.type === 'warning'\n ? 'bg-status-warning-text'\n : notif.type === 'error'\n ? 'bg-status-error-text'\n : 'bg-status-info-text'\n }`}\n />\n <div className=\"flex-1 min-w-0\">\n <p className={`text-sm ${notif.read ? 'text-text-secondary' : 'font-medium'}`}>\n {notif.title}\n </p>\n <p className=\"text-xs text-text-secondary truncate\">{notif.message}</p>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>\n {t('crewfoundry.dashboard.upcomingInterviews.title', 'Upcoming Interviews')}\n </CardTitle>\n <CardDescription>\n {t('crewfoundry.dashboard.upcomingInterviews.description', 'Scheduled for this week')}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {projects\n .filter((p) => p.status === 'active')\n .slice(0, 4)\n .map((project) => (\n <div\n key={project.id}\n className=\"flex items-center justify-between rounded border p-3\"\n >\n <div>\n <p className=\"text-sm font-medium\">{project.name}</p>\n <p className=\"text-xs text-text-secondary\">{project.teamName}</p>\n </div>\n <div className=\"flex items-center gap-2\">\n <div className=\"w-24 h-2 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-2 bg-action-primary-bg rounded\"\n style={{ width: `${project.progress}%` }}\n />\n </div>\n <span className=\"text-xs text-text-secondary\">{project.progress}%</span>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>\n {t('crewfoundry.dashboard.leaveRequests.title', 'Recent Leave Requests')}\n </CardTitle>\n <CardDescription>\n {t('crewfoundry.dashboard.leaveRequests.description', 'Pending approval')}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {leaveRequests.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('crewfoundry.dashboard.leaveRequests.emptyTitle', 'No leave requests')}\n description={t(\n 'crewfoundry.dashboard.leaveRequests.emptyDescription',\n 'Pending leave requests will appear here.'\n )}\n />\n )}\n {leaveRequests.map((leave) => (\n <div key={leave.id} className=\"flex items-center justify-between rounded border p-3\">\n <div className=\"flex items-center gap-3\">\n <div>\n <p className=\"text-sm font-medium\">{leave.employeeName}</p>\n <div className=\"flex items-center gap-2 text-xs text-text-secondary\">\n <Calendar className=\"h-3 w-3\" />\n <span>\n {leave.startDate} - {leave.endDate}\n </span>\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Badge\n variant={\n leave.status === 'approved'\n ? 'default'\n : leave.status === 'pending'\n ? 'secondary'\n : 'destructive'\n }\n >\n {leave.status}\n </Badge>\n <Badge variant=\"outline\">{leave.type}</Badge>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardDashboardPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/DashboardDashboardPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n AuroraBackground,\n EmphasisPanel,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Activity, Briefcase, Calendar, TrendingUp, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport { useCrewFoundry } from '../providers/CrewFoundryProvider';\n\nexport function DashboardDashboardPagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { showToast } = useGlobalUi();\n const { currentUser } = useCrewFoundry();\n const { employees, jobPostings, leaveRequests, notifications, projects, updateLeaveRequest } =\n useCrewFoundryStore();\n const [selectedPeriod, setSelectedPeriod] = useState<'week' | 'month' | 'quarter'>('month');\n const [processingLeaveId, setProcessingLeaveId] = useState<string | null>(null);\n\n const approverName =\n currentUser?.name ||\n [currentUser?.firstName, currentUser?.lastName].filter(Boolean).join(' ') ||\n currentUser?.email ||\n 'Manager';\n\n const decideLeave = async (id: string, status: 'approved' | 'rejected') => {\n setProcessingLeaveId(id);\n try {\n await updateLeaveRequest(id, { status, approverName });\n showToast(status === 'approved' ? 'Leave approved' : 'Leave rejected', 'success');\n } catch (error) {\n showToast(\n error instanceof Error ? error.message : 'Unable to update leave request',\n 'error'\n );\n } finally {\n setProcessingLeaveId(null);\n }\n };\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n\n const activeEmployees = employees.filter((e) => e.status === 'active').length;\n const onLeave = employees.filter((e) => e.status === 'on_leave').length;\n const openPositions = jobPostings.filter((j) => j.status === 'active').length;\n const totalApplicants = jobPostings.reduce((sum, j) => sum + j.applicants, 0);\n const pendingLeaves = leaveRequests.filter((l) => l.status === 'pending').length;\n const unreadNotifications = notifications.filter((n) => !n.read).length;\n const activeProjects = projects.filter((p) => p.status === 'active').length;\n const avgPerformance = (\n employees.reduce((sum, e) => sum + e.performanceScore, 0) / employees.length\n ).toFixed(1);\n\n const departmentHeadcount = employees.reduce<Record<string, number>>((acc, e) => {\n acc[e.department] = (acc[e.department] || 0) + 1;\n return acc;\n }, {});\n\n const maxHeadcount = Math.max(...Object.values(departmentHeadcount));\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"relative overflow-hidden rounded-xl border border-border-seam bg-gloss-card p-6\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{t('crewfoundry.dashboard.title', 'Workforce Dashboard')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'crewfoundry.dashboard.subtitle',\n \"Overview of your organization's workforce metrics\"\n )}\n </p>\n <PagePurpose className=\"mt-2\">\n {t(\n 'crewfoundry.dashboard.purpose',\n 'Your workforce command center — see headcount, hiring, performance, and projects at a glance, then jump straight to the area that needs your attention.'\n )}\n </PagePurpose>\n </div>\n <div className=\"flex gap-2\">\n {(['week', 'month', 'quarter'] as const).map((period) => (\n <Button\n key={period}\n variant={selectedPeriod === period ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setSelectedPeriod(period)}\n >\n {t(\n `crewfoundry.dashboard.period.${period}`,\n period.charAt(0).toUpperCase() + period.slice(1)\n )}\n </Button>\n ))}\n </div>\n </div>\n </div>\n\n <NextSteps\n storageKey=\"crewfoundry-dashboard\"\n steps={[\n {\n id: 'employees',\n label: t('crewfoundry.dashboard.next.employees', 'Review your team'),\n description: t(\n 'crewfoundry.dashboard.next.employeesDesc',\n 'Open the employee directory to see who is active and on leave.'\n ),\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hr/employees-page'),\n },\n {\n id: 'hiring',\n label: t('crewfoundry.dashboard.next.hiring', 'Post a new job'),\n description: t(\n 'crewfoundry.dashboard.next.hiringDesc',\n 'Create an opening to start collecting applicants.'\n ),\n icon: <Briefcase className=\"h-4 w-4\" />,\n onClick: () => navigate('../../hiring/create-job-page'),\n },\n {\n id: 'projects',\n label: t('crewfoundry.dashboard.next.projects', 'Check active projects'),\n description: t(\n 'crewfoundry.dashboard.next.projectsDesc',\n 'Track progress and budgets across in-flight work.'\n ),\n icon: <Activity className=\"h-4 w-4\" />,\n onClick: () => navigate('../../projects/projects-page'),\n },\n ]}\n />\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\">\n {t('crewfoundry.dashboard.stats.totalEmployees', 'Total Employees')}\n </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 <p className=\"text-xs text-text-secondary\">\n {activeEmployees} {t('crewfoundry.dashboard.stats.active', 'active')}, {onLeave}{' '}\n {t('crewfoundry.dashboard.stats.onLeave', 'on leave')}\n </p>\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\">\n {t('crewfoundry.dashboard.stats.openPositions', 'Open Positions')}\n </CardTitle>\n <Briefcase className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{openPositions}</div>\n <p className=\"text-xs text-text-secondary\">\n {totalApplicants}{' '}\n {t('crewfoundry.dashboard.stats.totalApplicants', 'total applicants')}\n </p>\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\">\n {t('crewfoundry.dashboard.stats.avgPerformance', 'Avg Performance')}\n </CardTitle>\n <TrendingUp className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgPerformance}/5</div>\n <p className=\"text-xs text-text-secondary\">\n {t('crewfoundry.dashboard.stats.performanceTrend', '+0.2 from last quarter')}\n </p>\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\">\n {t('crewfoundry.dashboard.stats.activeProjects', 'Active Projects')}\n </CardTitle>\n <Activity className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activeProjects}</div>\n <p className=\"text-xs text-text-secondary\">\n {pendingLeaves}{' '}\n {t('crewfoundry.dashboard.stats.pendingLeaveRequests', 'pending leave requests')}\n </p>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-7\">\n <EmphasisPanel className=\"col-span-4\">\n <div className=\"mb-1 text-lg font-semibold\">\n {t('crewfoundry.dashboard.departmentHeadcount.title', 'Department Headcount')}\n </div>\n <p className=\"mb-4 text-sm text-text-secondary\">\n {t(\n 'crewfoundry.dashboard.departmentHeadcount.description',\n 'Employee distribution across departments'\n )}\n </p>\n <div className=\"space-y-3\">\n {Object.entries(departmentHeadcount)\n .sort(([, a], [, b]) => b - a)\n .map(([dept, count]) => (\n <div key={dept} className=\"flex items-center gap-3\">\n <span className=\"w-24 text-sm text-text-secondary truncate\">{dept}</span>\n <div className=\"flex-1 h-4 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-4 bg-action-primary-bg rounded\"\n style={{ width: `${Math.round((count / maxHeadcount) * 100)}%` }}\n />\n </div>\n <span className=\"text-sm font-medium w-8 text-right tabular-nums\">{count}</span>\n </div>\n ))}\n </div>\n </EmphasisPanel>\n\n <Card className=\"col-span-3\">\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <CardTitle>\n {t('crewfoundry.dashboard.notifications.title', 'Recent Notifications')}\n </CardTitle>\n <Badge variant=\"secondary\">\n {unreadNotifications} {t('crewfoundry.dashboard.notifications.unread', 'unread')}\n </Badge>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {notifications.slice(0, 5).map((notif) => (\n <div key={notif.id} className=\"flex items-start gap-3\">\n <div\n className={`mt-1 h-2 w-2 rounded-full flex-shrink-0 motion-safe:animate-vc-glow-pulse ${\n notif.type === 'success'\n ? 'bg-status-success-text'\n : notif.type === 'warning'\n ? 'bg-status-warning-text'\n : notif.type === 'error'\n ? 'bg-status-error-text'\n : 'bg-status-info-text'\n }`}\n />\n <div className=\"flex-1 min-w-0\">\n <p className={`text-sm ${notif.read ? 'text-text-secondary' : 'font-medium'}`}>\n {notif.title}\n </p>\n <p className=\"text-xs text-text-secondary truncate\">{notif.message}</p>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>\n {t('crewfoundry.dashboard.upcomingInterviews.title', 'Upcoming Interviews')}\n </CardTitle>\n <CardDescription>\n {t('crewfoundry.dashboard.upcomingInterviews.description', 'Scheduled for this week')}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {projects\n .filter((p) => p.status === 'active')\n .slice(0, 4)\n .map((project) => (\n <div\n key={project.id}\n className=\"flex items-center justify-between rounded border p-3\"\n >\n <div>\n <p className=\"text-sm font-medium\">{project.name}</p>\n <p className=\"text-xs text-text-secondary\">{project.teamName}</p>\n </div>\n <div className=\"flex items-center gap-2\">\n <div className=\"w-24 h-2 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-2 bg-action-primary-bg rounded\"\n style={{ width: `${project.progress}%` }}\n />\n </div>\n <span className=\"text-xs text-text-secondary\">{project.progress}%</span>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>\n {t('crewfoundry.dashboard.leaveRequests.title', 'Recent Leave Requests')}\n </CardTitle>\n <CardDescription>\n {t('crewfoundry.dashboard.leaveRequests.description', 'Pending approval')}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {leaveRequests.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('crewfoundry.dashboard.leaveRequests.emptyTitle', 'No leave requests')}\n description={t(\n 'crewfoundry.dashboard.leaveRequests.emptyDescription',\n 'Pending leave requests will appear here.'\n )}\n />\n )}\n {leaveRequests.map((leave) => (\n <div key={leave.id} className=\"flex items-center justify-between rounded border p-3\">\n <div className=\"flex items-center gap-3\">\n <div>\n <p className=\"text-sm font-medium\">{leave.employeeName}</p>\n <div className=\"flex items-center gap-2 text-xs text-text-secondary\">\n <Calendar className=\"h-3 w-3\" />\n <span>\n {leave.startDate} - {leave.endDate}\n </span>\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n {leave.status === 'pending' && (\n <div className=\"flex gap-1\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"h-7 text-xs\"\n disabled={processingLeaveId === leave.id}\n onClick={() => void decideLeave(leave.id, 'rejected')}\n >\n {t('crewfoundry.dashboard.leaveRequests.reject', 'Reject')}\n </Button>\n <Button\n size=\"sm\"\n className=\"h-7 text-xs\"\n disabled={processingLeaveId === leave.id}\n onClick={() => void decideLeave(leave.id, 'approved')}\n >\n {t('crewfoundry.dashboard.leaveRequests.approve', 'Approve')}\n </Button>\n </div>\n )}\n <Badge\n variant={\n leave.status === 'approved'\n ? 'default'\n : leave.status === 'pending'\n ? 'secondary'\n : 'destructive'\n }\n >\n {leave.status}\n </Badge>\n <Badge variant=\"outline\">{leave.type}</Badge>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|