@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.
Files changed (155) hide show
  1. package/dist/crewfoundry/CrewFoundryRoutes.js +51 -43
  2. package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
  3. package/dist/crewfoundry/components/forms/formValues.js +5 -2
  4. package/dist/crewfoundry/components/forms/formValues.js.map +1 -1
  5. package/dist/crewfoundry/components/viz/AllocationBar.js +68 -0
  6. package/dist/crewfoundry/components/viz/AllocationBar.js.map +1 -0
  7. package/dist/crewfoundry/components/viz/AreaChart.js +102 -0
  8. package/dist/crewfoundry/components/viz/AreaChart.js.map +1 -0
  9. package/dist/crewfoundry/components/viz/AvatarStack.js +36 -0
  10. package/dist/crewfoundry/components/viz/AvatarStack.js.map +1 -0
  11. package/dist/crewfoundry/components/viz/BarChart.js +83 -0
  12. package/dist/crewfoundry/components/viz/BarChart.js.map +1 -0
  13. package/dist/crewfoundry/components/viz/CertificateCard.js +118 -0
  14. package/dist/crewfoundry/components/viz/CertificateCard.js.map +1 -0
  15. package/dist/crewfoundry/components/viz/DonutChart.js +109 -0
  16. package/dist/crewfoundry/components/viz/DonutChart.js.map +1 -0
  17. package/dist/crewfoundry/components/viz/HBarFunnel.js +54 -0
  18. package/dist/crewfoundry/components/viz/HBarFunnel.js.map +1 -0
  19. package/dist/crewfoundry/components/viz/Heatmap.js +91 -0
  20. package/dist/crewfoundry/components/viz/Heatmap.js.map +1 -0
  21. package/dist/crewfoundry/components/viz/KanbanBoard.js +50 -0
  22. package/dist/crewfoundry/components/viz/KanbanBoard.js.map +1 -0
  23. package/dist/crewfoundry/components/viz/LineChart.js +123 -0
  24. package/dist/crewfoundry/components/viz/LineChart.js.map +1 -0
  25. package/dist/crewfoundry/components/viz/OrgTree.js +83 -0
  26. package/dist/crewfoundry/components/viz/OrgTree.js.map +1 -0
  27. package/dist/crewfoundry/components/viz/PathSteps.js +68 -0
  28. package/dist/crewfoundry/components/viz/PathSteps.js.map +1 -0
  29. package/dist/crewfoundry/components/viz/ProgressRing.js +68 -0
  30. package/dist/crewfoundry/components/viz/ProgressRing.js.map +1 -0
  31. package/dist/crewfoundry/components/viz/RatingStars.js +51 -0
  32. package/dist/crewfoundry/components/viz/RatingStars.js.map +1 -0
  33. package/dist/crewfoundry/components/viz/SegmentedTabs.js +69 -0
  34. package/dist/crewfoundry/components/viz/SegmentedTabs.js.map +1 -0
  35. package/dist/crewfoundry/components/viz/SkillBar.js +3 -0
  36. package/dist/crewfoundry/components/viz/Sparkline.js +74 -0
  37. package/dist/crewfoundry/components/viz/Sparkline.js.map +1 -0
  38. package/dist/crewfoundry/components/viz/StatCard.js +60 -0
  39. package/dist/crewfoundry/components/viz/StatCard.js.map +1 -0
  40. package/dist/crewfoundry/components/viz/StepProgress.js +3 -0
  41. package/dist/crewfoundry/components/viz/Timeline.js +66 -0
  42. package/dist/crewfoundry/components/viz/Timeline.js.map +1 -0
  43. package/dist/crewfoundry/components/viz/index.js +23 -0
  44. package/dist/crewfoundry/components/viz/lib/Avatar.js +30 -0
  45. package/dist/crewfoundry/components/viz/lib/Avatar.js.map +1 -0
  46. package/dist/crewfoundry/components/viz/lib/CartesianFrame.js +119 -0
  47. package/dist/crewfoundry/components/viz/lib/CartesianFrame.js.map +1 -0
  48. package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js +35 -0
  49. package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js.map +1 -0
  50. package/dist/crewfoundry/components/viz/lib/format.js +21 -0
  51. package/dist/crewfoundry/components/viz/lib/format.js.map +1 -0
  52. package/dist/crewfoundry/components/viz/lib/geometry.js +69 -0
  53. package/dist/crewfoundry/components/viz/lib/geometry.js.map +1 -0
  54. package/dist/crewfoundry/components/viz/lib/hooks.js +39 -0
  55. package/dist/crewfoundry/components/viz/lib/hooks.js.map +1 -0
  56. package/dist/crewfoundry/components/viz/lib/palette.js +27 -0
  57. package/dist/crewfoundry/components/viz/lib/palette.js.map +1 -0
  58. package/dist/crewfoundry/lib/analytics.js +323 -0
  59. package/dist/crewfoundry/lib/analytics.js.map +1 -0
  60. package/dist/crewfoundry/lib/companyFinance.js +16 -0
  61. package/dist/crewfoundry/lib/companyFinance.js.map +1 -0
  62. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +226 -283
  63. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  64. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +107 -120
  65. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
  66. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +122 -162
  67. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
  68. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +121 -158
  69. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
  70. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +316 -211
  71. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
  72. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +75 -27
  73. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
  74. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +167 -165
  75. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
  76. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +168 -109
  77. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
  78. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +401 -290
  79. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
  80. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +84 -75
  81. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
  82. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +368 -174
  83. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
  84. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +236 -201
  85. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
  86. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +369 -196
  87. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
  88. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +252 -249
  89. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
  90. package/dist/crewfoundry/pages/HiringJobsPagePage.js +210 -110
  91. package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
  92. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +216 -178
  93. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
  94. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +385 -0
  95. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js.map +1 -0
  96. package/dist/crewfoundry/pages/HrEmployeesPagePage.js +189 -130
  97. package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
  98. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +397 -241
  99. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
  100. package/dist/crewfoundry/pages/HrPayrollPagePage.js +262 -147
  101. package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
  102. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +345 -167
  103. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
  104. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +98 -24
  105. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
  106. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +35 -31
  107. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
  108. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +289 -108
  109. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
  110. package/dist/crewfoundry/pages/LearningCoursesPagePage.js +221 -114
  111. package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
  112. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +136 -133
  113. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
  114. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +148 -97
  115. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
  116. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +264 -157
  117. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
  118. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
  119. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +85 -93
  120. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
  121. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
  122. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
  123. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
  124. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
  125. package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +28 -25
  126. package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
  127. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +290 -138
  128. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
  129. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
  130. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
  131. package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
  132. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +65 -61
  133. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
  134. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
  135. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
  136. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
  137. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
  138. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +142 -76
  139. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
  140. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
  141. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
  142. package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
  143. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
  144. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
  145. package/dist/crewfoundry/store/crewfoundryStore.js +1 -1
  146. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  147. package/dist/crewfoundry/utils/cn.js +10 -0
  148. package/dist/crewfoundry/utils/cn.js.map +1 -0
  149. package/dist/crewfoundry/utils/courseProgress.js +46 -0
  150. package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
  151. package/dist/node_modules/clsx/dist/clsx.js +18 -0
  152. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  153. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
  154. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  155. 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 &amp; utilization</p>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Resourcing &amp; 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 { BarChart3 as n, Calendar as r, FolderKanban as i, Settings as a, Star as o, Users as s } from "lucide-react";
4
- import { useNavigate as c, useSearchParams as l } from "react-router-dom";
5
- import { jsx as u, jsxs as d } from "react/jsx-runtime";
6
- import { Badge as f, Card as p, CardContent as m, CardHeader as h, CardTitle as g, EmphasisPanel as _, GradientText as v, IllustratedEmptyState as y, NextSteps as b, PagePurpose as x, ResponsiveTable as S } from "@burdenoff/fe-libs/ui";
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 C() {
9
- let C = c(), [w] = l(), { teams: T, employees: E, projects: D } = e(), O = w.get("id"), k = T.find((e) => e.id === O) ?? T[0];
10
- if (!k) return /* @__PURE__ */ u("div", {
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__ */ u(y, {
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 A = E.filter((e) => k.members.includes(e.id)), j = D.filter((e) => e.teamId === k.id);
19
- return /* @__PURE__ */ d("div", {
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__ */ d("div", {
56
+ /* @__PURE__ */ p("div", {
23
57
  className: "flex items-center justify-between",
24
- children: [/* @__PURE__ */ d("div", { children: [
25
- /* @__PURE__ */ u("h1", {
58
+ children: [/* @__PURE__ */ p("div", { children: [
59
+ /* @__PURE__ */ f("h1", {
26
60
  className: "text-2xl font-semibold",
27
- children: /* @__PURE__ */ u(v, { children: k.name })
61
+ children: /* @__PURE__ */ f(b, { children: N.name })
28
62
  }),
29
- /* @__PURE__ */ u("p", {
63
+ /* @__PURE__ */ f("p", {
30
64
  className: "text-sm text-text-secondary",
31
- children: k.description
65
+ children: N.description
32
66
  }),
33
- /* @__PURE__ */ u(x, {
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__ */ u(f, {
38
- variant: k.status === "active" ? "default" : "secondary",
39
- children: t(k.status)
93
+ ] }), /* @__PURE__ */ f(m, {
94
+ variant: N.status === "active" ? "default" : "secondary",
95
+ children: t(N.status)
40
96
  })]
41
97
  }),
42
- /* @__PURE__ */ u(b, {
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__ */ u(n, { className: "h-4 w-4" }),
50
- onClick: () => C("../teams/team-analytics-page")
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__ */ u(a, { className: "h-4 w-4" }),
57
- onClick: () => C(`../teams/team-settings-page?id=${encodeURIComponent(k.id)}`)
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__ */ u(s, { className: "h-4 w-4" }),
64
- onClick: () => C("../teams/team-directory-page")
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__ */ d("div", {
124
+ /* @__PURE__ */ p("div", {
69
125
  className: "grid gap-4 md:grid-cols-4",
70
126
  children: [
71
- /* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
127
+ /* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
72
128
  className: "p-4 text-center",
73
129
  children: [
74
- /* @__PURE__ */ u(s, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
75
- /* @__PURE__ */ u("p", {
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: k.memberCount
133
+ children: N.memberCount
78
134
  }),
79
- /* @__PURE__ */ u("p", {
135
+ /* @__PURE__ */ f("p", {
80
136
  className: "text-xs text-text-secondary",
81
137
  children: "Members"
82
138
  })
83
139
  ]
84
140
  }) }),
85
- /* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
141
+ /* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
86
142
  className: "p-4 text-center",
87
143
  children: [
88
- /* @__PURE__ */ u(i, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
89
- /* @__PURE__ */ u("p", {
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: k.projectCount
147
+ children: [I, /* @__PURE__ */ p("span", {
148
+ className: "text-sm font-normal text-text-secondary",
149
+ children: ["/", F.length]
150
+ })]
92
151
  }),
93
- /* @__PURE__ */ u("p", {
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__ */ u(p, { children: /* @__PURE__ */ d(m, {
158
+ /* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
100
159
  className: "p-4 text-center",
101
160
  children: [
102
- /* @__PURE__ */ u(o, { className: "h-5 w-5 mx-auto text-status-warning-text mb-1" }),
103
- /* @__PURE__ */ u("p", {
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: k.leadName
164
+ children: N.leadName
106
165
  }),
107
- /* @__PURE__ */ u("p", {
166
+ /* @__PURE__ */ f("p", {
108
167
  className: "text-xs text-text-secondary",
109
168
  children: "Lead"
110
169
  })
111
170
  ]
112
171
  }) }),
113
- /* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
172
+ /* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
114
173
  className: "p-4 text-center",
115
174
  children: [
116
- /* @__PURE__ */ u(r, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
117
- /* @__PURE__ */ u("p", {
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: k.createdAt
178
+ children: N.createdAt
120
179
  }),
121
- /* @__PURE__ */ u("p", {
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__ */ d(_, { children: [/* @__PURE__ */ u("div", {
188
+ /* @__PURE__ */ p(y, { children: [/* @__PURE__ */ f("div", {
130
189
  className: "mb-2 text-lg font-semibold",
131
190
  children: "Team Members"
132
- }), A.length === 0 ? /* @__PURE__ */ u(y, {
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__ */ u(S, {
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__ */ d("span", {
143
- className: "font-medium text-text-primary",
144
- children: [
145
- e.firstName,
146
- " ",
147
- e.lastName
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__ */ u("span", {
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__ */ d("span", {
230
+ cell: (e) => /* @__PURE__ */ p("span", {
165
231
  className: "flex items-center gap-1 md:justify-center",
166
- children: [/* @__PURE__ */ u(o, { className: "h-3 w-3 text-status-warning-text" }), e.performanceScore]
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__ */ u(f, {
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: A,
246
+ data: P,
181
247
  rowKey: (e) => e.id
182
248
  })] }),
183
- j.length > 0 && /* @__PURE__ */ d(p, { children: [/* @__PURE__ */ u(h, { children: /* @__PURE__ */ u(g, { children: "Team Projects" }) }), /* @__PURE__ */ u(m, {
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: j.map((e) => /* @__PURE__ */ d("div", {
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: () => C(`../projects/project-details-page?id=${encodeURIComponent(e.id)}`),
255
+ onClick: () => n(`../projects/project-details-page?id=${encodeURIComponent(e.id)}`),
190
256
  onKeyDown: (t) => {
191
- (t.key === "Enter" || t.key === " ") && (t.preventDefault(), C(`../projects/project-details-page?id=${encodeURIComponent(e.id)}`));
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__ */ d("div", { children: [/* @__PURE__ */ u("p", {
260
+ children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
195
261
  className: "text-sm font-medium",
196
262
  children: e.name
197
- }), /* @__PURE__ */ d("p", {
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__ */ d("div", {
270
+ })] }), /* @__PURE__ */ p("div", {
205
271
  className: "flex items-center gap-2",
206
272
  children: [
207
- /* @__PURE__ */ u("div", {
273
+ /* @__PURE__ */ f("div", {
208
274
  className: "w-24 h-2 bg-bg-sunken rounded overflow-hidden",
209
- children: /* @__PURE__ */ u("div", {
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__ */ d("span", {
280
+ /* @__PURE__ */ p("span", {
215
281
  className: "text-xs",
216
282
  children: [e.progress, "%"]
217
283
  }),
218
- /* @__PURE__ */ u(f, {
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 { C as TeamsTeamDetailPagePage };
297
+ export { D as TeamsTeamDetailPagePage };
232
298
 
233
299
  //# sourceMappingURL=TeamsTeamDetailPagePage.js.map