@burdenoff/microfe-crewfoundry 2026.704.5 → 2026.704.7
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/CrewFoundryRoutes.js +51 -43
- package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
- package/dist/crewfoundry/components/forms/formValues.js +5 -2
- package/dist/crewfoundry/components/forms/formValues.js.map +1 -1
- package/dist/crewfoundry/components/viz/AllocationBar.js +68 -0
- package/dist/crewfoundry/components/viz/AllocationBar.js.map +1 -0
- package/dist/crewfoundry/components/viz/AreaChart.js +102 -0
- package/dist/crewfoundry/components/viz/AreaChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/AvatarStack.js +36 -0
- package/dist/crewfoundry/components/viz/AvatarStack.js.map +1 -0
- package/dist/crewfoundry/components/viz/BarChart.js +83 -0
- package/dist/crewfoundry/components/viz/BarChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/CertificateCard.js +118 -0
- package/dist/crewfoundry/components/viz/CertificateCard.js.map +1 -0
- package/dist/crewfoundry/components/viz/DonutChart.js +109 -0
- package/dist/crewfoundry/components/viz/DonutChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/HBarFunnel.js +54 -0
- package/dist/crewfoundry/components/viz/HBarFunnel.js.map +1 -0
- package/dist/crewfoundry/components/viz/Heatmap.js +91 -0
- package/dist/crewfoundry/components/viz/Heatmap.js.map +1 -0
- package/dist/crewfoundry/components/viz/KanbanBoard.js +50 -0
- package/dist/crewfoundry/components/viz/KanbanBoard.js.map +1 -0
- package/dist/crewfoundry/components/viz/LineChart.js +123 -0
- package/dist/crewfoundry/components/viz/LineChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/OrgTree.js +83 -0
- package/dist/crewfoundry/components/viz/OrgTree.js.map +1 -0
- package/dist/crewfoundry/components/viz/PathSteps.js +68 -0
- package/dist/crewfoundry/components/viz/PathSteps.js.map +1 -0
- package/dist/crewfoundry/components/viz/ProgressRing.js +68 -0
- package/dist/crewfoundry/components/viz/ProgressRing.js.map +1 -0
- package/dist/crewfoundry/components/viz/RatingStars.js +51 -0
- package/dist/crewfoundry/components/viz/RatingStars.js.map +1 -0
- package/dist/crewfoundry/components/viz/SegmentedTabs.js +69 -0
- package/dist/crewfoundry/components/viz/SegmentedTabs.js.map +1 -0
- package/dist/crewfoundry/components/viz/SkillBar.js +3 -0
- package/dist/crewfoundry/components/viz/Sparkline.js +74 -0
- package/dist/crewfoundry/components/viz/Sparkline.js.map +1 -0
- package/dist/crewfoundry/components/viz/StatCard.js +60 -0
- package/dist/crewfoundry/components/viz/StatCard.js.map +1 -0
- package/dist/crewfoundry/components/viz/StepProgress.js +3 -0
- package/dist/crewfoundry/components/viz/Timeline.js +66 -0
- package/dist/crewfoundry/components/viz/Timeline.js.map +1 -0
- package/dist/crewfoundry/components/viz/index.js +23 -0
- package/dist/crewfoundry/components/viz/lib/Avatar.js +30 -0
- package/dist/crewfoundry/components/viz/lib/Avatar.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/CartesianFrame.js +119 -0
- package/dist/crewfoundry/components/viz/lib/CartesianFrame.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js +35 -0
- package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/format.js +21 -0
- package/dist/crewfoundry/components/viz/lib/format.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/geometry.js +69 -0
- package/dist/crewfoundry/components/viz/lib/geometry.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/hooks.js +39 -0
- package/dist/crewfoundry/components/viz/lib/hooks.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/palette.js +27 -0
- package/dist/crewfoundry/components/viz/lib/palette.js.map +1 -0
- package/dist/crewfoundry/lib/analytics.js +323 -0
- package/dist/crewfoundry/lib/analytics.js.map +1 -0
- package/dist/crewfoundry/lib/companyFinance.js +16 -0
- package/dist/crewfoundry/lib/companyFinance.js.map +1 -0
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +226 -283
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +107 -120
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +122 -162
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +121 -158
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +316 -211
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +75 -27
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +167 -165
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +168 -109
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +401 -290
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +84 -75
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +368 -174
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +236 -201
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +369 -196
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +252 -249
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +210 -110
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +216 -178
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +385 -0
- package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js.map +1 -0
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js +189 -130
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +397 -241
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js +262 -147
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +345 -167
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +98 -24
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +35 -31
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +289 -108
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +221 -114
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +136 -133
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +148 -97
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +264 -157
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +85 -93
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +28 -25
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +290 -138
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +65 -61
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +142 -76
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/dist/crewfoundry/utils/cn.js +10 -0
- package/dist/crewfoundry/utils/cn.js.map +1 -0
- package/dist/crewfoundry/utils/courseProgress.js +46 -0
- package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
- package/dist/node_modules/clsx/dist/clsx.js +18 -0
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
2
|
+
import { StatCard as t } from "../components/viz/StatCard.js";
|
|
3
|
+
import { Heatmap as n } from "../components/viz/Heatmap.js";
|
|
4
|
+
import { AllocationBar as r } from "../components/viz/AllocationBar.js";
|
|
5
|
+
import "../components/viz/index.js";
|
|
6
|
+
import { allocationByPerson as i, benchAndOverallocated as a, skillMatch as o, utilizationByPersonWeek as s } from "../lib/analytics.js";
|
|
7
|
+
import { useMemo as c } from "react";
|
|
8
|
+
import { AlertTriangle as l, ArrowLeft as u, TrendingUp as d, Users as f } from "lucide-react";
|
|
9
|
+
import { useNavigate as p } from "react-router-dom";
|
|
10
|
+
import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
11
|
+
import { Badge as _, Button as v, Card as y, CardContent as b, CardDescription as x, CardHeader as S, CardTitle as C, GradientText as w, IllustratedEmptyState as T, PagePurpose as E, Spinner as D } from "@burdenoff/fe-libs/ui";
|
|
12
|
+
//#region src/crewfoundry/pages/ProjectsResourcingPagePage.tsx
|
|
13
|
+
var O = 8, k = 12;
|
|
14
|
+
function A() {
|
|
15
|
+
let A = p(), j = e((e) => e.timeEntries), M = e((e) => e.employees), N = e((e) => e.jobPostings), P = e((e) => e.candidates), F = e((e) => e.initialized), I = c(() => s(j, M, O), [j, M]), L = c(() => a(I, M), [I, M]), R = c(() => i(j, M).slice(0, k), [j, M]), z = c(() => N.find((e) => e.status === "active"), [N]), B = c(() => z ? o(z, M, P) : null, [
|
|
16
|
+
z,
|
|
17
|
+
M,
|
|
18
|
+
P
|
|
19
|
+
]);
|
|
20
|
+
if (!F) return /* @__PURE__ */ h("div", {
|
|
21
|
+
className: "flex min-h-[60vh] items-center justify-center p-6",
|
|
22
|
+
children: /* @__PURE__ */ h(D, { size: "lg" })
|
|
23
|
+
});
|
|
24
|
+
let V = I.hasData && I.weekRanges.length > 0 ? `${I.weekRanges[0]} → ${I.weekRanges[I.weekRanges.length - 1]}` : null;
|
|
25
|
+
return /* @__PURE__ */ g("div", {
|
|
26
|
+
className: "space-y-6 p-6",
|
|
27
|
+
children: [
|
|
28
|
+
/* @__PURE__ */ g(v, {
|
|
29
|
+
variant: "ghost",
|
|
30
|
+
size: "sm",
|
|
31
|
+
onClick: () => A("../projects/projects-page"),
|
|
32
|
+
children: [/* @__PURE__ */ h(u, { className: "mr-1 h-4 w-4" }), "Back to projects"]
|
|
33
|
+
}),
|
|
34
|
+
/* @__PURE__ */ g("div", {
|
|
35
|
+
className: "flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between",
|
|
36
|
+
children: [/* @__PURE__ */ g("div", { children: [
|
|
37
|
+
/* @__PURE__ */ h("p", {
|
|
38
|
+
className: "text-sm text-text-secondary",
|
|
39
|
+
children: "Skills-based staffing & utilization"
|
|
40
|
+
}),
|
|
41
|
+
/* @__PURE__ */ h("h1", {
|
|
42
|
+
className: "text-2xl font-semibold",
|
|
43
|
+
children: /* @__PURE__ */ h(w, { children: "Resourcing & Utilization" })
|
|
44
|
+
}),
|
|
45
|
+
/* @__PURE__ */ h(E, {
|
|
46
|
+
className: "mt-1",
|
|
47
|
+
children: "See who is over- or under-utilized week by week, how people are allocated across projects, and which candidates best match an open role — all from real logged time."
|
|
48
|
+
})
|
|
49
|
+
] }), /* @__PURE__ */ g("div", {
|
|
50
|
+
className: "grid grid-cols-1 gap-3 sm:grid-cols-3 lg:w-auto",
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ h(t, {
|
|
53
|
+
label: "Avg utilization",
|
|
54
|
+
value: `${L.avgUtilization}%`,
|
|
55
|
+
icon: /* @__PURE__ */ h(d, { className: "h-4 w-4" })
|
|
56
|
+
}),
|
|
57
|
+
/* @__PURE__ */ h(t, {
|
|
58
|
+
label: "Bench",
|
|
59
|
+
value: L.bench,
|
|
60
|
+
icon: /* @__PURE__ */ h(f, { className: "h-4 w-4" })
|
|
61
|
+
}),
|
|
62
|
+
/* @__PURE__ */ h(t, {
|
|
63
|
+
label: "Over-allocated",
|
|
64
|
+
value: L.overAllocated,
|
|
65
|
+
icon: /* @__PURE__ */ h(l, { className: "h-4 w-4" })
|
|
66
|
+
})
|
|
67
|
+
]
|
|
68
|
+
})]
|
|
69
|
+
}),
|
|
70
|
+
/* @__PURE__ */ g("div", {
|
|
71
|
+
className: "grid gap-4 lg:grid-cols-3",
|
|
72
|
+
children: [/* @__PURE__ */ g(y, {
|
|
73
|
+
className: "lg:col-span-2",
|
|
74
|
+
children: [/* @__PURE__ */ g(S, { children: [/* @__PURE__ */ h(C, {
|
|
75
|
+
className: "text-base",
|
|
76
|
+
children: "Utilization heatmap"
|
|
77
|
+
}), /* @__PURE__ */ h(x, { children: V ? `Weekly utilization (Σ logged hours ÷ 40h capacity) · ${V}` : "Weekly utilization from logged time" })] }), /* @__PURE__ */ h(b, { children: I.hasData ? /* @__PURE__ */ g("div", {
|
|
78
|
+
className: "space-y-3",
|
|
79
|
+
children: [/* @__PURE__ */ h(n, {
|
|
80
|
+
rows: I.rows,
|
|
81
|
+
colLabels: I.weekLabels,
|
|
82
|
+
showValues: !0,
|
|
83
|
+
valueFormatter: (e) => `${e}%`,
|
|
84
|
+
title: "Per-person weekly utilization"
|
|
85
|
+
}), /* @__PURE__ */ h("ul", {
|
|
86
|
+
className: "flex flex-wrap gap-x-3 gap-y-1 text-xs text-text-muted",
|
|
87
|
+
children: I.weekLabels.map((e, t) => /* @__PURE__ */ g("li", { children: [
|
|
88
|
+
/* @__PURE__ */ h("span", {
|
|
89
|
+
className: "font-medium text-text-secondary",
|
|
90
|
+
children: e
|
|
91
|
+
}),
|
|
92
|
+
" ",
|
|
93
|
+
I.weekRanges[t]
|
|
94
|
+
] }, e))
|
|
95
|
+
})]
|
|
96
|
+
}) : /* @__PURE__ */ h(T, {
|
|
97
|
+
illustration: "empty-data",
|
|
98
|
+
title: "No time entries yet",
|
|
99
|
+
description: "Once your team logs time, per-person weekly utilization will appear here. Nothing is shown for weeks without real entries."
|
|
100
|
+
}) })]
|
|
101
|
+
}), /* @__PURE__ */ g(y, { children: [/* @__PURE__ */ g(S, { children: [/* @__PURE__ */ h(C, {
|
|
102
|
+
className: "text-base",
|
|
103
|
+
children: "Skills match for open role"
|
|
104
|
+
}), B ? /* @__PURE__ */ g(x, { children: [
|
|
105
|
+
B.roleTitle,
|
|
106
|
+
" ·",
|
|
107
|
+
" ",
|
|
108
|
+
B.source === "employee" ? "internal team" : "candidate pool"
|
|
109
|
+
] }) : null] }), /* @__PURE__ */ h(b, {
|
|
110
|
+
className: "space-y-4",
|
|
111
|
+
children: z ? B && B.requiredSkills.length > 0 ? /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h("div", {
|
|
112
|
+
className: "flex flex-wrap gap-1.5",
|
|
113
|
+
children: B.requiredSkills.map((e) => /* @__PURE__ */ h(_, {
|
|
114
|
+
variant: "outline",
|
|
115
|
+
className: "text-[11px]",
|
|
116
|
+
children: e
|
|
117
|
+
}, e))
|
|
118
|
+
}), B.matches.length > 0 ? /* @__PURE__ */ h("ol", {
|
|
119
|
+
className: "space-y-3",
|
|
120
|
+
children: B.matches.map((e, t) => /* @__PURE__ */ g("li", {
|
|
121
|
+
className: "rounded-[var(--radius-card)] border border-border-subtle bg-bg-surface p-3",
|
|
122
|
+
children: [
|
|
123
|
+
/* @__PURE__ */ g("div", {
|
|
124
|
+
className: "flex items-baseline justify-between gap-2",
|
|
125
|
+
children: [/* @__PURE__ */ g("span", {
|
|
126
|
+
className: "text-sm font-medium text-text-primary",
|
|
127
|
+
children: [
|
|
128
|
+
t + 1,
|
|
129
|
+
". ",
|
|
130
|
+
e.name
|
|
131
|
+
]
|
|
132
|
+
}), /* @__PURE__ */ g("span", {
|
|
133
|
+
className: "text-sm font-semibold tabular-nums text-status-success-text",
|
|
134
|
+
children: [e.matchPercent, "% match"]
|
|
135
|
+
})]
|
|
136
|
+
}),
|
|
137
|
+
/* @__PURE__ */ h("div", {
|
|
138
|
+
className: "mt-2 flex flex-wrap gap-1",
|
|
139
|
+
children: e.matchedSkills.map((e) => /* @__PURE__ */ h(_, {
|
|
140
|
+
variant: "secondary",
|
|
141
|
+
className: "text-[10px]",
|
|
142
|
+
children: e
|
|
143
|
+
}, e))
|
|
144
|
+
}),
|
|
145
|
+
e.detail ? /* @__PURE__ */ h("p", {
|
|
146
|
+
className: "mt-2 text-xs text-text-muted",
|
|
147
|
+
children: e.detail
|
|
148
|
+
}) : null
|
|
149
|
+
]
|
|
150
|
+
}, e.id))
|
|
151
|
+
}) : /* @__PURE__ */ h(T, {
|
|
152
|
+
illustration: "empty-people",
|
|
153
|
+
title: "No people match yet",
|
|
154
|
+
description: "No recorded skills overlap this role’s required skills."
|
|
155
|
+
})] }) : /* @__PURE__ */ h(T, {
|
|
156
|
+
illustration: "empty-data",
|
|
157
|
+
title: "No skill tags on this role",
|
|
158
|
+
description: "Add recognised skill keywords to this role’s requirements to rank candidate matches."
|
|
159
|
+
}) : /* @__PURE__ */ h(T, {
|
|
160
|
+
illustration: "empty-search",
|
|
161
|
+
title: "No active roles",
|
|
162
|
+
description: "Publish a job posting to match candidates against its required skills."
|
|
163
|
+
})
|
|
164
|
+
})] })]
|
|
165
|
+
}),
|
|
166
|
+
/* @__PURE__ */ g(y, { children: [/* @__PURE__ */ g(S, { children: [/* @__PURE__ */ h(C, {
|
|
167
|
+
className: "text-base",
|
|
168
|
+
children: "People allocation"
|
|
169
|
+
}), /* @__PURE__ */ h(x, { children: R.length > 0 ? `Project split for the latest week with logged time (${R[0].weekLabel})` : "Per-person project allocation from logged time" })] }), /* @__PURE__ */ h(b, {
|
|
170
|
+
className: "space-y-5",
|
|
171
|
+
children: R.length > 0 ? R.map((e) => /* @__PURE__ */ h(r, {
|
|
172
|
+
segments: e.segments,
|
|
173
|
+
label: e.name,
|
|
174
|
+
rightLabel: `${e.utilization}% utilized`
|
|
175
|
+
}, e.employeeId)) : /* @__PURE__ */ h(T, {
|
|
176
|
+
illustration: "empty-data",
|
|
177
|
+
title: "No allocation to show",
|
|
178
|
+
description: "No time entries have been logged yet, so there is nothing to allocate across projects."
|
|
179
|
+
})
|
|
180
|
+
})] })
|
|
181
|
+
]
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
//#endregion
|
|
185
|
+
export { A as ProjectsResourcingPagePage };
|
|
186
|
+
|
|
187
|
+
//# sourceMappingURL=ProjectsResourcingPagePage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProjectsResourcingPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/ProjectsResourcingPagePage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Spinner,\n} from '@burdenoff/fe-libs/ui';\nimport { AlertTriangle, ArrowLeft, TrendingUp, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport {\n AllocationBar,\n Heatmap,\n StatCard,\n} from '../components/viz';\nimport {\n allocationByPerson,\n benchAndOverallocated,\n skillMatch,\n utilizationByPersonWeek,\n} from '../lib/analytics';\n\nconst UTILIZATION_WEEKS = 8;\nconst MAX_ALLOCATION_ROWS = 12;\n\nexport function ProjectsResourcingPagePage() {\n const navigate = useNavigate();\n const timeEntries = useCrewFoundryStore((state) => state.timeEntries);\n const employees = useCrewFoundryStore((state) => state.employees);\n const jobPostings = useCrewFoundryStore((state) => state.jobPostings);\n const candidates = useCrewFoundryStore((state) => state.candidates);\n const initialized = useCrewFoundryStore((state) => state.initialized);\n\n const matrix = useMemo(\n () => utilizationByPersonWeek(timeEntries, employees, UTILIZATION_WEEKS),\n [timeEntries, employees]\n );\n const kpis = useMemo(() => benchAndOverallocated(matrix, employees), [matrix, employees]);\n const allocation = useMemo(\n () => allocationByPerson(timeEntries, employees).slice(0, MAX_ALLOCATION_ROWS),\n [timeEntries, employees]\n );\n const openJob = useMemo(\n () => jobPostings.find((job) => job.status === 'active'),\n [jobPostings]\n );\n // Prefer real employee skills; skillMatch falls back to the candidate pool\n // when no employee has skills recorded.\n const skills = useMemo(\n () => (openJob ? skillMatch(openJob, employees, candidates) : null),\n [openJob, employees, candidates]\n );\n\n if (!initialized) {\n return (\n <div className=\"flex min-h-[60vh] items-center justify-center p-6\">\n <Spinner size=\"lg\" />\n </div>\n );\n }\n\n const weekRangeCaption =\n matrix.hasData && matrix.weekRanges.length > 0\n ? `${matrix.weekRanges[0]} → ${matrix.weekRanges[matrix.weekRanges.length - 1]}`\n : null;\n\n return (\n <div className=\"space-y-6 p-6\">\n <Button variant=\"ghost\" size=\"sm\" onClick={() => navigate('../projects/projects-page')}>\n <ArrowLeft className=\"mr-1 h-4 w-4\" />\n Back to projects\n </Button>\n\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between\">\n <div>\n <p className=\"text-sm text-text-secondary\">Skills-based staffing & utilization</p>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Resourcing & Utilization</GradientText>\n </h1>\n <PagePurpose className=\"mt-1\">\n See who is over- or under-utilized week by week, how people are allocated across\n projects, and which candidates best match an open role — all from real logged time.\n </PagePurpose>\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-3 lg:w-auto\">\n <StatCard\n label=\"Avg utilization\"\n value={`${kpis.avgUtilization}%`}\n icon={<TrendingUp className=\"h-4 w-4\" />}\n />\n <StatCard label=\"Bench\" value={kpis.bench} icon={<Users className=\"h-4 w-4\" />} />\n <StatCard\n label=\"Over-allocated\"\n value={kpis.overAllocated}\n icon={<AlertTriangle className=\"h-4 w-4\" />}\n />\n </div>\n </div>\n\n <div className=\"grid gap-4 lg:grid-cols-3\">\n {/* Utilization heatmap */}\n <Card className=\"lg:col-span-2\">\n <CardHeader>\n <CardTitle className=\"text-base\">Utilization heatmap</CardTitle>\n <CardDescription>\n {weekRangeCaption\n ? `Weekly utilization (Σ logged hours ÷ 40h capacity) · ${weekRangeCaption}`\n : 'Weekly utilization from logged time'}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {matrix.hasData ? (\n <div className=\"space-y-3\">\n <Heatmap\n rows={matrix.rows}\n colLabels={matrix.weekLabels}\n showValues\n valueFormatter={(value) => `${value}%`}\n title=\"Per-person weekly utilization\"\n />\n <ul className=\"flex flex-wrap gap-x-3 gap-y-1 text-xs text-text-muted\">\n {matrix.weekLabels.map((label, index) => (\n <li key={label}>\n <span className=\"font-medium text-text-secondary\">{label}</span>{' '}\n {matrix.weekRanges[index]}\n </li>\n ))}\n </ul>\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No time entries yet\"\n description=\"Once your team logs time, per-person weekly utilization will appear here. Nothing is shown for weeks without real entries.\"\n />\n )}\n </CardContent>\n </Card>\n\n {/* Skills match for open role */}\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Skills match for open role</CardTitle>\n {skills ? (\n <CardDescription>\n {skills.roleTitle} ·{' '}\n {skills.source === 'employee' ? 'internal team' : 'candidate pool'}\n </CardDescription>\n ) : null}\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {!openJob ? (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No active roles\"\n description=\"Publish a job posting to match candidates against its required skills.\"\n />\n ) : skills && skills.requiredSkills.length > 0 ? (\n <>\n <div className=\"flex flex-wrap gap-1.5\">\n {skills.requiredSkills.map((skill) => (\n <Badge key={skill} variant=\"outline\" className=\"text-[11px]\">\n {skill}\n </Badge>\n ))}\n </div>\n {skills.matches.length > 0 ? (\n <ol className=\"space-y-3\">\n {skills.matches.map((match, index) => (\n <li\n key={match.id}\n className=\"rounded-[var(--radius-card)] border border-border-subtle bg-bg-surface p-3\"\n >\n <div className=\"flex items-baseline justify-between gap-2\">\n <span className=\"text-sm font-medium text-text-primary\">\n {index + 1}. {match.name}\n </span>\n <span className=\"text-sm font-semibold tabular-nums text-status-success-text\">\n {match.matchPercent}% match\n </span>\n </div>\n <div className=\"mt-2 flex flex-wrap gap-1\">\n {match.matchedSkills.map((skill) => (\n <Badge key={skill} variant=\"secondary\" className=\"text-[10px]\">\n {skill}\n </Badge>\n ))}\n </div>\n {match.detail ? (\n <p className=\"mt-2 text-xs text-text-muted\">{match.detail}</p>\n ) : null}\n </li>\n ))}\n </ol>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title=\"No people match yet\"\n description=\"No recorded skills overlap this role’s required skills.\"\n />\n )}\n </>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No skill tags on this role\"\n description=\"Add recognised skill keywords to this role’s requirements to rank candidate matches.\"\n />\n )}\n </CardContent>\n </Card>\n </div>\n\n {/* People allocation this week */}\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">People allocation</CardTitle>\n <CardDescription>\n {allocation.length > 0\n ? `Project split for the latest week with logged time (${allocation[0].weekLabel})`\n : 'Per-person project allocation from logged time'}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-5\">\n {allocation.length > 0 ? (\n allocation.map((row) => (\n <AllocationBar\n key={row.employeeId}\n segments={row.segments}\n label={row.name}\n rightLabel={`${row.utilization}% utilized`}\n />\n ))\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No allocation to show\"\n description=\"No time entries have been logged yet, so there is nothing to allocate across projects.\"\n />\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,124 +1,183 @@
|
|
|
1
1
|
import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
2
2
|
import { formatEnumLabel as t } from "../utils/formatEnumLabel.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
3
|
+
import { getInitials as n } from "../components/viz/lib/format.js";
|
|
4
|
+
import { AvatarStack as r } from "../components/viz/AvatarStack.js";
|
|
5
|
+
import "../components/viz/index.js";
|
|
6
|
+
import { BarChart3 as i, Calendar as a, FolderKanban as o, Settings as s, Star as c, Users as l } from "lucide-react";
|
|
7
|
+
import { useNavigate as u, useSearchParams as d } from "react-router-dom";
|
|
8
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
9
|
+
import { Badge as m, Card as h, CardContent as g, CardHeader as _, CardTitle as v, EmphasisPanel as y, GradientText as b, IllustratedEmptyState as x, NextSteps as S, PagePurpose as C, ResponsiveTable as w, Spinner as T } from "@burdenoff/fe-libs/ui";
|
|
7
10
|
//#region src/crewfoundry/pages/TeamsTeamDetailPagePage.tsx
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
function E({ name: e, src: t, size: r = 32 }) {
|
|
12
|
+
return t ? /* @__PURE__ */ f("img", {
|
|
13
|
+
src: t,
|
|
14
|
+
alt: e,
|
|
15
|
+
width: r,
|
|
16
|
+
height: r,
|
|
17
|
+
loading: "lazy",
|
|
18
|
+
className: "shrink-0 rounded-full object-cover",
|
|
19
|
+
style: {
|
|
20
|
+
width: r,
|
|
21
|
+
height: r
|
|
22
|
+
}
|
|
23
|
+
}) : /* @__PURE__ */ f("span", {
|
|
24
|
+
"aria-hidden": "true",
|
|
25
|
+
className: "inline-flex shrink-0 items-center justify-center rounded-full bg-bg-elevated font-medium text-text-secondary",
|
|
26
|
+
style: {
|
|
27
|
+
width: r,
|
|
28
|
+
height: r,
|
|
29
|
+
fontSize: Math.round(r * .36)
|
|
30
|
+
},
|
|
31
|
+
children: n(e)
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function D() {
|
|
35
|
+
let n = u(), [D] = d(), { teams: O, employees: k, projects: A, initialized: j } = e(), M = D.get("id"), N = O.find((e) => e.id === M) ?? O[0];
|
|
36
|
+
if (!j && !N) return /* @__PURE__ */ f("div", {
|
|
37
|
+
className: "flex min-h-[60vh] items-center justify-center p-6",
|
|
38
|
+
children: /* @__PURE__ */ f(T, { size: "lg" })
|
|
39
|
+
});
|
|
40
|
+
if (!N) return /* @__PURE__ */ f("div", {
|
|
11
41
|
className: "p-6",
|
|
12
|
-
children: /* @__PURE__ */
|
|
42
|
+
children: /* @__PURE__ */ f(x, {
|
|
13
43
|
illustration: "empty-search",
|
|
14
44
|
title: "Team not found",
|
|
15
45
|
description: "This team is no longer available."
|
|
16
46
|
})
|
|
17
47
|
});
|
|
18
|
-
let
|
|
19
|
-
|
|
48
|
+
let P = k.filter((e) => N.members.includes(e.id)), F = A.filter((e) => e.teamId === N.id), I = F.filter((e) => e.status === "active").length, L = k.find((e) => e.id === N.leadId), R = P.map((e) => ({
|
|
49
|
+
name: `${e.firstName} ${e.lastName}`.trim(),
|
|
50
|
+
avatarUrl: e.avatar,
|
|
51
|
+
role: e.position
|
|
52
|
+
}));
|
|
53
|
+
return /* @__PURE__ */ p("div", {
|
|
20
54
|
className: "space-y-6 p-6 max-w-4xl",
|
|
21
55
|
children: [
|
|
22
|
-
/* @__PURE__ */
|
|
56
|
+
/* @__PURE__ */ p("div", {
|
|
23
57
|
className: "flex items-center justify-between",
|
|
24
|
-
children: [/* @__PURE__ */
|
|
25
|
-
/* @__PURE__ */
|
|
58
|
+
children: [/* @__PURE__ */ p("div", { children: [
|
|
59
|
+
/* @__PURE__ */ f("h1", {
|
|
26
60
|
className: "text-2xl font-semibold",
|
|
27
|
-
children: /* @__PURE__ */
|
|
61
|
+
children: /* @__PURE__ */ f(b, { children: N.name })
|
|
28
62
|
}),
|
|
29
|
-
/* @__PURE__ */
|
|
63
|
+
/* @__PURE__ */ f("p", {
|
|
30
64
|
className: "text-sm text-text-secondary",
|
|
31
|
-
children:
|
|
65
|
+
children: N.description
|
|
32
66
|
}),
|
|
33
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ f(C, {
|
|
34
68
|
className: "mt-2",
|
|
35
69
|
children: "A complete view of one team — who's on it, what they're working on, and how they're performing — so you can support the group and keep its projects on track."
|
|
70
|
+
}),
|
|
71
|
+
/* @__PURE__ */ p("div", {
|
|
72
|
+
className: "mt-3 flex flex-wrap items-center gap-x-4 gap-y-2",
|
|
73
|
+
children: [/* @__PURE__ */ p("span", {
|
|
74
|
+
className: "flex items-center gap-2 text-xs text-text-secondary",
|
|
75
|
+
children: [
|
|
76
|
+
"Led by",
|
|
77
|
+
/* @__PURE__ */ f(E, {
|
|
78
|
+
name: L ? `${L.firstName} ${L.lastName}` : N.leadName,
|
|
79
|
+
src: L?.avatar,
|
|
80
|
+
size: 22
|
|
81
|
+
}),
|
|
82
|
+
/* @__PURE__ */ f("span", {
|
|
83
|
+
className: "font-medium text-text-primary",
|
|
84
|
+
children: L ? `${L.firstName} ${L.lastName}` : N.leadName || "—"
|
|
85
|
+
})
|
|
86
|
+
]
|
|
87
|
+
}), R.length > 0 ? /* @__PURE__ */ f(r, {
|
|
88
|
+
people: R,
|
|
89
|
+
max: 6,
|
|
90
|
+
size: 26
|
|
91
|
+
}) : null]
|
|
36
92
|
})
|
|
37
|
-
] }), /* @__PURE__ */
|
|
38
|
-
variant:
|
|
39
|
-
children: t(
|
|
93
|
+
] }), /* @__PURE__ */ f(m, {
|
|
94
|
+
variant: N.status === "active" ? "default" : "secondary",
|
|
95
|
+
children: t(N.status)
|
|
40
96
|
})]
|
|
41
97
|
}),
|
|
42
|
-
/* @__PURE__ */
|
|
98
|
+
/* @__PURE__ */ f(S, {
|
|
43
99
|
storageKey: "crewfoundry-team-details",
|
|
44
100
|
steps: [
|
|
45
101
|
{
|
|
46
102
|
id: "analytics",
|
|
47
103
|
label: "View team analytics",
|
|
48
104
|
description: "See productivity and workload trends for this team.",
|
|
49
|
-
icon: /* @__PURE__ */
|
|
50
|
-
onClick: () =>
|
|
105
|
+
icon: /* @__PURE__ */ f(i, { className: "h-4 w-4" }),
|
|
106
|
+
onClick: () => n("../teams/team-analytics-page")
|
|
51
107
|
},
|
|
52
108
|
{
|
|
53
109
|
id: "settings",
|
|
54
110
|
label: "Adjust team settings",
|
|
55
111
|
description: "Manage membership, permissions, and preferences.",
|
|
56
|
-
icon: /* @__PURE__ */
|
|
57
|
-
onClick: () =>
|
|
112
|
+
icon: /* @__PURE__ */ f(s, { className: "h-4 w-4" }),
|
|
113
|
+
onClick: () => n(`../teams/team-settings-page?id=${encodeURIComponent(N.id)}`)
|
|
58
114
|
},
|
|
59
115
|
{
|
|
60
116
|
id: "directory",
|
|
61
117
|
label: "Browse all teams",
|
|
62
118
|
description: "Explore how the rest of the organization is structured.",
|
|
63
|
-
icon: /* @__PURE__ */
|
|
64
|
-
onClick: () =>
|
|
119
|
+
icon: /* @__PURE__ */ f(l, { className: "h-4 w-4" }),
|
|
120
|
+
onClick: () => n("../teams/team-directory-page")
|
|
65
121
|
}
|
|
66
122
|
]
|
|
67
123
|
}),
|
|
68
|
-
/* @__PURE__ */
|
|
124
|
+
/* @__PURE__ */ p("div", {
|
|
69
125
|
className: "grid gap-4 md:grid-cols-4",
|
|
70
126
|
children: [
|
|
71
|
-
/* @__PURE__ */
|
|
127
|
+
/* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
|
|
72
128
|
className: "p-4 text-center",
|
|
73
129
|
children: [
|
|
74
|
-
/* @__PURE__ */
|
|
75
|
-
/* @__PURE__ */
|
|
130
|
+
/* @__PURE__ */ f(l, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
|
|
131
|
+
/* @__PURE__ */ f("p", {
|
|
76
132
|
className: "text-lg font-bold",
|
|
77
|
-
children:
|
|
133
|
+
children: N.memberCount
|
|
78
134
|
}),
|
|
79
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ f("p", {
|
|
80
136
|
className: "text-xs text-text-secondary",
|
|
81
137
|
children: "Members"
|
|
82
138
|
})
|
|
83
139
|
]
|
|
84
140
|
}) }),
|
|
85
|
-
/* @__PURE__ */
|
|
141
|
+
/* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
|
|
86
142
|
className: "p-4 text-center",
|
|
87
143
|
children: [
|
|
88
|
-
/* @__PURE__ */
|
|
89
|
-
/* @__PURE__ */
|
|
144
|
+
/* @__PURE__ */ f(o, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
|
|
145
|
+
/* @__PURE__ */ p("p", {
|
|
90
146
|
className: "text-lg font-bold",
|
|
91
|
-
children:
|
|
147
|
+
children: [I, /* @__PURE__ */ p("span", {
|
|
148
|
+
className: "text-sm font-normal text-text-secondary",
|
|
149
|
+
children: ["/", F.length]
|
|
150
|
+
})]
|
|
92
151
|
}),
|
|
93
|
-
/* @__PURE__ */
|
|
152
|
+
/* @__PURE__ */ f("p", {
|
|
94
153
|
className: "text-xs text-text-secondary",
|
|
95
|
-
children: "Projects"
|
|
154
|
+
children: "Active Projects"
|
|
96
155
|
})
|
|
97
156
|
]
|
|
98
157
|
}) }),
|
|
99
|
-
/* @__PURE__ */
|
|
158
|
+
/* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
|
|
100
159
|
className: "p-4 text-center",
|
|
101
160
|
children: [
|
|
102
|
-
/* @__PURE__ */
|
|
103
|
-
/* @__PURE__ */
|
|
161
|
+
/* @__PURE__ */ f(c, { className: "h-5 w-5 mx-auto text-status-warning-text mb-1" }),
|
|
162
|
+
/* @__PURE__ */ f("p", {
|
|
104
163
|
className: "text-lg font-bold",
|
|
105
|
-
children:
|
|
164
|
+
children: N.leadName
|
|
106
165
|
}),
|
|
107
|
-
/* @__PURE__ */
|
|
166
|
+
/* @__PURE__ */ f("p", {
|
|
108
167
|
className: "text-xs text-text-secondary",
|
|
109
168
|
children: "Lead"
|
|
110
169
|
})
|
|
111
170
|
]
|
|
112
171
|
}) }),
|
|
113
|
-
/* @__PURE__ */
|
|
172
|
+
/* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
|
|
114
173
|
className: "p-4 text-center",
|
|
115
174
|
children: [
|
|
116
|
-
/* @__PURE__ */
|
|
117
|
-
/* @__PURE__ */
|
|
175
|
+
/* @__PURE__ */ f(a, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
|
|
176
|
+
/* @__PURE__ */ f("p", {
|
|
118
177
|
className: "text-lg font-bold",
|
|
119
|
-
children:
|
|
178
|
+
children: N.createdAt
|
|
120
179
|
}),
|
|
121
|
-
/* @__PURE__ */
|
|
180
|
+
/* @__PURE__ */ f("p", {
|
|
122
181
|
className: "text-xs text-text-secondary",
|
|
123
182
|
children: "Created"
|
|
124
183
|
})
|
|
@@ -126,33 +185,40 @@ function C() {
|
|
|
126
185
|
}) })
|
|
127
186
|
]
|
|
128
187
|
}),
|
|
129
|
-
/* @__PURE__ */
|
|
188
|
+
/* @__PURE__ */ p(y, { children: [/* @__PURE__ */ f("div", {
|
|
130
189
|
className: "mb-2 text-lg font-semibold",
|
|
131
190
|
children: "Team Members"
|
|
132
|
-
}),
|
|
191
|
+
}), P.length === 0 ? /* @__PURE__ */ f(x, {
|
|
133
192
|
illustration: "empty-people",
|
|
134
193
|
title: "No members yet",
|
|
135
194
|
description: "Add people to this team to start collaborating."
|
|
136
|
-
}) : /* @__PURE__ */
|
|
195
|
+
}) : /* @__PURE__ */ f(w, {
|
|
137
196
|
columns: [
|
|
138
197
|
{
|
|
139
198
|
key: "name",
|
|
140
199
|
header: "Name",
|
|
141
200
|
priority: "primary",
|
|
142
|
-
cell: (e) => /* @__PURE__ */
|
|
143
|
-
className: "
|
|
144
|
-
children: [
|
|
145
|
-
e.firstName
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
201
|
+
cell: (e) => /* @__PURE__ */ p("span", {
|
|
202
|
+
className: "flex items-center gap-2.5",
|
|
203
|
+
children: [/* @__PURE__ */ f(E, {
|
|
204
|
+
name: `${e.firstName} ${e.lastName}`,
|
|
205
|
+
src: e.avatar,
|
|
206
|
+
size: 30
|
|
207
|
+
}), /* @__PURE__ */ p("span", {
|
|
208
|
+
className: "font-medium text-text-primary",
|
|
209
|
+
children: [
|
|
210
|
+
e.firstName,
|
|
211
|
+
" ",
|
|
212
|
+
e.lastName
|
|
213
|
+
]
|
|
214
|
+
})]
|
|
149
215
|
})
|
|
150
216
|
},
|
|
151
217
|
{
|
|
152
218
|
key: "position",
|
|
153
219
|
header: "Position",
|
|
154
220
|
priority: "secondary",
|
|
155
|
-
cell: (e) => /* @__PURE__ */
|
|
221
|
+
cell: (e) => /* @__PURE__ */ f("span", {
|
|
156
222
|
className: "text-text-secondary",
|
|
157
223
|
children: e.position
|
|
158
224
|
})
|
|
@@ -161,61 +227,61 @@ function C() {
|
|
|
161
227
|
key: "performance",
|
|
162
228
|
header: "Performance",
|
|
163
229
|
priority: "secondary",
|
|
164
|
-
cell: (e) => /* @__PURE__ */
|
|
230
|
+
cell: (e) => /* @__PURE__ */ p("span", {
|
|
165
231
|
className: "flex items-center gap-1 md:justify-center",
|
|
166
|
-
children: [/* @__PURE__ */
|
|
232
|
+
children: [/* @__PURE__ */ f(c, { className: "h-3 w-3 text-status-warning-text" }), e.performanceScore]
|
|
167
233
|
})
|
|
168
234
|
},
|
|
169
235
|
{
|
|
170
236
|
key: "status",
|
|
171
237
|
header: "Status",
|
|
172
238
|
priority: "primary",
|
|
173
|
-
cell: (e) => /* @__PURE__ */
|
|
239
|
+
cell: (e) => /* @__PURE__ */ f(m, {
|
|
174
240
|
variant: e.status === "active" ? "default" : "secondary",
|
|
175
241
|
className: "text-[10px]",
|
|
176
242
|
children: t(e.status)
|
|
177
243
|
})
|
|
178
244
|
}
|
|
179
245
|
],
|
|
180
|
-
data:
|
|
246
|
+
data: P,
|
|
181
247
|
rowKey: (e) => e.id
|
|
182
248
|
})] }),
|
|
183
|
-
|
|
249
|
+
F.length > 0 && /* @__PURE__ */ p(h, { children: [/* @__PURE__ */ f(_, { children: /* @__PURE__ */ f(v, { children: "Team Projects" }) }), /* @__PURE__ */ f(g, {
|
|
184
250
|
className: "space-y-3",
|
|
185
|
-
children:
|
|
251
|
+
children: F.map((e) => /* @__PURE__ */ p("div", {
|
|
186
252
|
role: "button",
|
|
187
253
|
tabIndex: 0,
|
|
188
254
|
"aria-label": `Open ${e.name} project detail`,
|
|
189
|
-
onClick: () =>
|
|
255
|
+
onClick: () => n(`../projects/project-details-page?id=${encodeURIComponent(e.id)}`),
|
|
190
256
|
onKeyDown: (t) => {
|
|
191
|
-
(t.key === "Enter" || t.key === " ") && (t.preventDefault(),
|
|
257
|
+
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), n(`../projects/project-details-page?id=${encodeURIComponent(e.id)}`));
|
|
192
258
|
},
|
|
193
259
|
className: "flex items-center justify-between rounded border p-3 cursor-pointer hover:bg-bg-sunken/50 focus-visible:outline-none focus-visible:shadow-[var(--shadow-focus)]",
|
|
194
|
-
children: [/* @__PURE__ */
|
|
260
|
+
children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
|
|
195
261
|
className: "text-sm font-medium",
|
|
196
262
|
children: e.name
|
|
197
|
-
}), /* @__PURE__ */
|
|
263
|
+
}), /* @__PURE__ */ p("p", {
|
|
198
264
|
className: "text-xs text-text-secondary",
|
|
199
265
|
children: [
|
|
200
266
|
e.startDate,
|
|
201
267
|
" — ",
|
|
202
268
|
e.endDate
|
|
203
269
|
]
|
|
204
|
-
})] }), /* @__PURE__ */
|
|
270
|
+
})] }), /* @__PURE__ */ p("div", {
|
|
205
271
|
className: "flex items-center gap-2",
|
|
206
272
|
children: [
|
|
207
|
-
/* @__PURE__ */
|
|
273
|
+
/* @__PURE__ */ f("div", {
|
|
208
274
|
className: "w-24 h-2 bg-bg-sunken rounded overflow-hidden",
|
|
209
|
-
children: /* @__PURE__ */
|
|
275
|
+
children: /* @__PURE__ */ f("div", {
|
|
210
276
|
className: "h-2 bg-action-primary-bg rounded",
|
|
211
277
|
style: { width: `${e.progress}%` }
|
|
212
278
|
})
|
|
213
279
|
}),
|
|
214
|
-
/* @__PURE__ */
|
|
280
|
+
/* @__PURE__ */ p("span", {
|
|
215
281
|
className: "text-xs",
|
|
216
282
|
children: [e.progress, "%"]
|
|
217
283
|
}),
|
|
218
|
-
/* @__PURE__ */
|
|
284
|
+
/* @__PURE__ */ f(m, {
|
|
219
285
|
variant: e.status === "active" ? "default" : "secondary",
|
|
220
286
|
className: "text-[10px]",
|
|
221
287
|
children: t(e.status)
|
|
@@ -228,6 +294,6 @@ function C() {
|
|
|
228
294
|
});
|
|
229
295
|
}
|
|
230
296
|
//#endregion
|
|
231
|
-
export {
|
|
297
|
+
export { D as TeamsTeamDetailPagePage };
|
|
232
298
|
|
|
233
299
|
//# sourceMappingURL=TeamsTeamDetailPagePage.js.map
|