@burdenoff/microfe-crewfoundry 2026.704.6 → 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 (148) 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 +269 -270
  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 +1 -1
  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 +134 -135
  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/MarketplaceFreelancerProfilePagePage.js +85 -93
  119. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
  120. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
  121. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
  122. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
  123. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
  124. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +289 -140
  125. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
  126. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
  127. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
  128. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
  129. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
  130. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
  131. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
  132. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +140 -78
  133. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
  134. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
  135. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
  136. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
  137. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
  138. package/dist/crewfoundry/store/crewfoundryStore.js +1 -1
  139. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  140. package/dist/crewfoundry/utils/cn.js +10 -0
  141. package/dist/crewfoundry/utils/cn.js.map +1 -0
  142. package/dist/crewfoundry/utils/courseProgress.js +46 -0
  143. package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
  144. package/dist/node_modules/clsx/dist/clsx.js +18 -0
  145. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  146. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
  147. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  148. 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,128 +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, Spinner as C } 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 w() {
9
- let w = c(), [T] = l(), { teams: E, employees: D, projects: O, initialized: k } = e(), A = T.get("id"), j = E.find((e) => e.id === A) ?? E[0];
10
- if (!k && !j) 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", {
11
37
  className: "flex min-h-[60vh] items-center justify-center p-6",
12
- children: /* @__PURE__ */ u(C, { size: "lg" })
38
+ children: /* @__PURE__ */ f(T, { size: "lg" })
13
39
  });
14
- if (!j) return /* @__PURE__ */ u("div", {
40
+ if (!N) return /* @__PURE__ */ f("div", {
15
41
  className: "p-6",
16
- children: /* @__PURE__ */ u(y, {
42
+ children: /* @__PURE__ */ f(x, {
17
43
  illustration: "empty-search",
18
44
  title: "Team not found",
19
45
  description: "This team is no longer available."
20
46
  })
21
47
  });
22
- let M = D.filter((e) => j.members.includes(e.id)), N = O.filter((e) => e.teamId === j.id);
23
- 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", {
24
54
  className: "space-y-6 p-6 max-w-4xl",
25
55
  children: [
26
- /* @__PURE__ */ d("div", {
56
+ /* @__PURE__ */ p("div", {
27
57
  className: "flex items-center justify-between",
28
- children: [/* @__PURE__ */ d("div", { children: [
29
- /* @__PURE__ */ u("h1", {
58
+ children: [/* @__PURE__ */ p("div", { children: [
59
+ /* @__PURE__ */ f("h1", {
30
60
  className: "text-2xl font-semibold",
31
- children: /* @__PURE__ */ u(v, { children: j.name })
61
+ children: /* @__PURE__ */ f(b, { children: N.name })
32
62
  }),
33
- /* @__PURE__ */ u("p", {
63
+ /* @__PURE__ */ f("p", {
34
64
  className: "text-sm text-text-secondary",
35
- children: j.description
65
+ children: N.description
36
66
  }),
37
- /* @__PURE__ */ u(x, {
67
+ /* @__PURE__ */ f(C, {
38
68
  className: "mt-2",
39
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]
40
92
  })
41
- ] }), /* @__PURE__ */ u(f, {
42
- variant: j.status === "active" ? "default" : "secondary",
43
- children: t(j.status)
93
+ ] }), /* @__PURE__ */ f(m, {
94
+ variant: N.status === "active" ? "default" : "secondary",
95
+ children: t(N.status)
44
96
  })]
45
97
  }),
46
- /* @__PURE__ */ u(b, {
98
+ /* @__PURE__ */ f(S, {
47
99
  storageKey: "crewfoundry-team-details",
48
100
  steps: [
49
101
  {
50
102
  id: "analytics",
51
103
  label: "View team analytics",
52
104
  description: "See productivity and workload trends for this team.",
53
- icon: /* @__PURE__ */ u(n, { className: "h-4 w-4" }),
54
- onClick: () => w("../teams/team-analytics-page")
105
+ icon: /* @__PURE__ */ f(i, { className: "h-4 w-4" }),
106
+ onClick: () => n("../teams/team-analytics-page")
55
107
  },
56
108
  {
57
109
  id: "settings",
58
110
  label: "Adjust team settings",
59
111
  description: "Manage membership, permissions, and preferences.",
60
- icon: /* @__PURE__ */ u(a, { className: "h-4 w-4" }),
61
- onClick: () => w(`../teams/team-settings-page?id=${encodeURIComponent(j.id)}`)
112
+ icon: /* @__PURE__ */ f(s, { className: "h-4 w-4" }),
113
+ onClick: () => n(`../teams/team-settings-page?id=${encodeURIComponent(N.id)}`)
62
114
  },
63
115
  {
64
116
  id: "directory",
65
117
  label: "Browse all teams",
66
118
  description: "Explore how the rest of the organization is structured.",
67
- icon: /* @__PURE__ */ u(s, { className: "h-4 w-4" }),
68
- onClick: () => w("../teams/team-directory-page")
119
+ icon: /* @__PURE__ */ f(l, { className: "h-4 w-4" }),
120
+ onClick: () => n("../teams/team-directory-page")
69
121
  }
70
122
  ]
71
123
  }),
72
- /* @__PURE__ */ d("div", {
124
+ /* @__PURE__ */ p("div", {
73
125
  className: "grid gap-4 md:grid-cols-4",
74
126
  children: [
75
- /* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
127
+ /* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
76
128
  className: "p-4 text-center",
77
129
  children: [
78
- /* @__PURE__ */ u(s, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
79
- /* @__PURE__ */ u("p", {
130
+ /* @__PURE__ */ f(l, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
131
+ /* @__PURE__ */ f("p", {
80
132
  className: "text-lg font-bold",
81
- children: j.memberCount
133
+ children: N.memberCount
82
134
  }),
83
- /* @__PURE__ */ u("p", {
135
+ /* @__PURE__ */ f("p", {
84
136
  className: "text-xs text-text-secondary",
85
137
  children: "Members"
86
138
  })
87
139
  ]
88
140
  }) }),
89
- /* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
141
+ /* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
90
142
  className: "p-4 text-center",
91
143
  children: [
92
- /* @__PURE__ */ u(i, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
93
- /* @__PURE__ */ u("p", {
144
+ /* @__PURE__ */ f(o, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
145
+ /* @__PURE__ */ p("p", {
94
146
  className: "text-lg font-bold",
95
- children: j.projectCount
147
+ children: [I, /* @__PURE__ */ p("span", {
148
+ className: "text-sm font-normal text-text-secondary",
149
+ children: ["/", F.length]
150
+ })]
96
151
  }),
97
- /* @__PURE__ */ u("p", {
152
+ /* @__PURE__ */ f("p", {
98
153
  className: "text-xs text-text-secondary",
99
- children: "Projects"
154
+ children: "Active Projects"
100
155
  })
101
156
  ]
102
157
  }) }),
103
- /* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
158
+ /* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
104
159
  className: "p-4 text-center",
105
160
  children: [
106
- /* @__PURE__ */ u(o, { className: "h-5 w-5 mx-auto text-status-warning-text mb-1" }),
107
- /* @__PURE__ */ u("p", {
161
+ /* @__PURE__ */ f(c, { className: "h-5 w-5 mx-auto text-status-warning-text mb-1" }),
162
+ /* @__PURE__ */ f("p", {
108
163
  className: "text-lg font-bold",
109
- children: j.leadName
164
+ children: N.leadName
110
165
  }),
111
- /* @__PURE__ */ u("p", {
166
+ /* @__PURE__ */ f("p", {
112
167
  className: "text-xs text-text-secondary",
113
168
  children: "Lead"
114
169
  })
115
170
  ]
116
171
  }) }),
117
- /* @__PURE__ */ u(p, { children: /* @__PURE__ */ d(m, {
172
+ /* @__PURE__ */ f(h, { children: /* @__PURE__ */ p(g, {
118
173
  className: "p-4 text-center",
119
174
  children: [
120
- /* @__PURE__ */ u(r, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
121
- /* @__PURE__ */ u("p", {
175
+ /* @__PURE__ */ f(a, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
176
+ /* @__PURE__ */ f("p", {
122
177
  className: "text-lg font-bold",
123
- children: j.createdAt
178
+ children: N.createdAt
124
179
  }),
125
- /* @__PURE__ */ u("p", {
180
+ /* @__PURE__ */ f("p", {
126
181
  className: "text-xs text-text-secondary",
127
182
  children: "Created"
128
183
  })
@@ -130,33 +185,40 @@ function w() {
130
185
  }) })
131
186
  ]
132
187
  }),
133
- /* @__PURE__ */ d(_, { children: [/* @__PURE__ */ u("div", {
188
+ /* @__PURE__ */ p(y, { children: [/* @__PURE__ */ f("div", {
134
189
  className: "mb-2 text-lg font-semibold",
135
190
  children: "Team Members"
136
- }), M.length === 0 ? /* @__PURE__ */ u(y, {
191
+ }), P.length === 0 ? /* @__PURE__ */ f(x, {
137
192
  illustration: "empty-people",
138
193
  title: "No members yet",
139
194
  description: "Add people to this team to start collaborating."
140
- }) : /* @__PURE__ */ u(S, {
195
+ }) : /* @__PURE__ */ f(w, {
141
196
  columns: [
142
197
  {
143
198
  key: "name",
144
199
  header: "Name",
145
200
  priority: "primary",
146
- cell: (e) => /* @__PURE__ */ d("span", {
147
- className: "font-medium text-text-primary",
148
- children: [
149
- e.firstName,
150
- " ",
151
- e.lastName
152
- ]
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
+ })]
153
215
  })
154
216
  },
155
217
  {
156
218
  key: "position",
157
219
  header: "Position",
158
220
  priority: "secondary",
159
- cell: (e) => /* @__PURE__ */ u("span", {
221
+ cell: (e) => /* @__PURE__ */ f("span", {
160
222
  className: "text-text-secondary",
161
223
  children: e.position
162
224
  })
@@ -165,61 +227,61 @@ function w() {
165
227
  key: "performance",
166
228
  header: "Performance",
167
229
  priority: "secondary",
168
- cell: (e) => /* @__PURE__ */ d("span", {
230
+ cell: (e) => /* @__PURE__ */ p("span", {
169
231
  className: "flex items-center gap-1 md:justify-center",
170
- 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]
171
233
  })
172
234
  },
173
235
  {
174
236
  key: "status",
175
237
  header: "Status",
176
238
  priority: "primary",
177
- cell: (e) => /* @__PURE__ */ u(f, {
239
+ cell: (e) => /* @__PURE__ */ f(m, {
178
240
  variant: e.status === "active" ? "default" : "secondary",
179
241
  className: "text-[10px]",
180
242
  children: t(e.status)
181
243
  })
182
244
  }
183
245
  ],
184
- data: M,
246
+ data: P,
185
247
  rowKey: (e) => e.id
186
248
  })] }),
187
- N.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, {
188
250
  className: "space-y-3",
189
- children: N.map((e) => /* @__PURE__ */ d("div", {
251
+ children: F.map((e) => /* @__PURE__ */ p("div", {
190
252
  role: "button",
191
253
  tabIndex: 0,
192
254
  "aria-label": `Open ${e.name} project detail`,
193
- onClick: () => w(`../projects/project-details-page?id=${encodeURIComponent(e.id)}`),
255
+ onClick: () => n(`../projects/project-details-page?id=${encodeURIComponent(e.id)}`),
194
256
  onKeyDown: (t) => {
195
- (t.key === "Enter" || t.key === " ") && (t.preventDefault(), w(`../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)}`));
196
258
  },
197
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)]",
198
- children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("p", {
260
+ children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
199
261
  className: "text-sm font-medium",
200
262
  children: e.name
201
- }), /* @__PURE__ */ d("p", {
263
+ }), /* @__PURE__ */ p("p", {
202
264
  className: "text-xs text-text-secondary",
203
265
  children: [
204
266
  e.startDate,
205
267
  " — ",
206
268
  e.endDate
207
269
  ]
208
- })] }), /* @__PURE__ */ d("div", {
270
+ })] }), /* @__PURE__ */ p("div", {
209
271
  className: "flex items-center gap-2",
210
272
  children: [
211
- /* @__PURE__ */ u("div", {
273
+ /* @__PURE__ */ f("div", {
212
274
  className: "w-24 h-2 bg-bg-sunken rounded overflow-hidden",
213
- children: /* @__PURE__ */ u("div", {
275
+ children: /* @__PURE__ */ f("div", {
214
276
  className: "h-2 bg-action-primary-bg rounded",
215
277
  style: { width: `${e.progress}%` }
216
278
  })
217
279
  }),
218
- /* @__PURE__ */ d("span", {
280
+ /* @__PURE__ */ p("span", {
219
281
  className: "text-xs",
220
282
  children: [e.progress, "%"]
221
283
  }),
222
- /* @__PURE__ */ u(f, {
284
+ /* @__PURE__ */ f(m, {
223
285
  variant: e.status === "active" ? "default" : "secondary",
224
286
  className: "text-[10px]",
225
287
  children: t(e.status)
@@ -232,6 +294,6 @@ function w() {
232
294
  });
233
295
  }
234
296
  //#endregion
235
- export { w as TeamsTeamDetailPagePage };
297
+ export { D as TeamsTeamDetailPagePage };
236
298
 
237
299
  //# sourceMappingURL=TeamsTeamDetailPagePage.js.map