@burdenoff/microfe-crewfoundry 2026.704.6 → 2026.707.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/crewfoundry/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/HelpApiDocumentationPagePage.js +0 -41
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.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 +269 -270
- 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 +1 -1
- 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 +134 -135
- 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/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/MarketplaceServiceDetailsPagePage.js +289 -140
- 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/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 +140 -78
- 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/TeamsTeamsPagePage.js +250 -98
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +142 -184
- 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
|
@@ -1,14 +1,18 @@
|
|
|
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 {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
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 { FormModal as i, useFormModal as a } from "../components/forms/FormModal.js";
|
|
7
|
+
import { useMemo as o, useState as s } from "react";
|
|
8
|
+
import { ArrowRight as c, FolderKanban as l, Plus as u, Users as d } from "lucide-react";
|
|
9
|
+
import { useNavigate as f } from "react-router-dom";
|
|
10
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
11
|
+
import { Badge as h, Button as g, CardContent as _, CardDescription as v, CardHeader as y, CardTitle as b, GlassCard as x, GradientText as S, IllustratedEmptyState as C, PagePurpose as w, Pagination as T } from "@burdenoff/fe-libs/ui";
|
|
12
|
+
import { usePagination as E } from "@burdenoff/fe-libs/shared/hooks";
|
|
13
|
+
import { useI18n as D } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
10
14
|
//#region src/crewfoundry/pages/TeamsTeamsPagePage.tsx
|
|
11
|
-
var
|
|
15
|
+
var O = [
|
|
12
16
|
{
|
|
13
17
|
name: "name",
|
|
14
18
|
label: "Team Name",
|
|
@@ -46,118 +50,266 @@ var C = [
|
|
|
46
50
|
colSpan: 2
|
|
47
51
|
}
|
|
48
52
|
];
|
|
49
|
-
function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
function k({ name: e, src: t, size: r = 32 }) {
|
|
54
|
+
return t ? /* @__PURE__ */ p("img", {
|
|
55
|
+
src: t,
|
|
56
|
+
alt: e,
|
|
57
|
+
width: r,
|
|
58
|
+
height: r,
|
|
59
|
+
loading: "lazy",
|
|
60
|
+
className: "shrink-0 rounded-full object-cover",
|
|
61
|
+
style: {
|
|
62
|
+
width: r,
|
|
63
|
+
height: r
|
|
64
|
+
}
|
|
65
|
+
}) : /* @__PURE__ */ p("span", {
|
|
66
|
+
"aria-hidden": "true",
|
|
67
|
+
className: "inline-flex shrink-0 items-center justify-center rounded-full bg-bg-elevated font-medium text-text-secondary",
|
|
68
|
+
style: {
|
|
69
|
+
width: r,
|
|
70
|
+
height: r,
|
|
71
|
+
fontSize: Math.round(r * .36)
|
|
72
|
+
},
|
|
73
|
+
children: n(e)
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function A(e) {
|
|
77
|
+
return `${e.firstName} ${e.lastName}`.trim();
|
|
78
|
+
}
|
|
79
|
+
function j() {
|
|
80
|
+
let { t: n } = D(), j = f(), { teams: M, employees: N, projects: P } = e(), F = e((e) => e.addTeam), I = a(), { page: L, pageSize: R, setPage: z } = E({ initialPageSize: 12 }), [B, V] = s(null), H = (e, t) => {
|
|
81
|
+
let r = n(e);
|
|
82
|
+
return r === e ? t : r;
|
|
83
|
+
}, U = o(() => new Map(N.map((e) => [e.id, e])), [N]), W = o(() => {
|
|
84
|
+
let e = /* @__PURE__ */ new Map();
|
|
85
|
+
for (let t of P) t.status === "active" && e.set(t.teamId, (e.get(t.teamId) ?? 0) + 1);
|
|
86
|
+
return e;
|
|
87
|
+
}, [P]), G = (e) => e.members.map((e) => U.get(e)).filter((e) => e !== void 0), K = (e) => G(e).map((e) => ({
|
|
88
|
+
name: A(e),
|
|
89
|
+
avatarUrl: e.avatar,
|
|
90
|
+
role: e.position
|
|
91
|
+
})), q = M.slice((L - 1) * R, (L - 1) * R + R), J = M.find((e) => e.id === B) ?? q[0] ?? M[0] ?? null, Y = J ? G(J) : [], X = J ? P.filter((e) => e.teamId === J.id && e.status === "active") : [], Z = (e) => j(`../teams/team-detail-page?id=${encodeURIComponent(e.id)}`);
|
|
92
|
+
return /* @__PURE__ */ m("div", {
|
|
55
93
|
className: "space-y-6 p-6",
|
|
56
94
|
children: [
|
|
57
|
-
/* @__PURE__ */
|
|
95
|
+
/* @__PURE__ */ m("div", {
|
|
58
96
|
className: "flex items-start justify-between gap-4",
|
|
59
|
-
children: [/* @__PURE__ */
|
|
60
|
-
/* @__PURE__ */
|
|
97
|
+
children: [/* @__PURE__ */ m("div", { children: [
|
|
98
|
+
/* @__PURE__ */ p("h1", {
|
|
61
99
|
className: "text-2xl font-semibold",
|
|
62
|
-
children: /* @__PURE__ */
|
|
100
|
+
children: /* @__PURE__ */ p(S, { children: H("crewfoundry.teams.title", "Teams") })
|
|
63
101
|
}),
|
|
64
|
-
/* @__PURE__ */
|
|
102
|
+
/* @__PURE__ */ m("p", {
|
|
65
103
|
className: "text-sm text-text-secondary",
|
|
66
104
|
children: [
|
|
67
|
-
|
|
105
|
+
M.length,
|
|
68
106
|
" ",
|
|
69
|
-
|
|
107
|
+
H("crewfoundry.teams.summary.count", "teams across the organization")
|
|
70
108
|
]
|
|
71
109
|
}),
|
|
72
|
-
/* @__PURE__ */
|
|
110
|
+
/* @__PURE__ */ p(w, {
|
|
73
111
|
className: "mt-1",
|
|
74
112
|
children: "Manage your teams — create groups, assign members, and organize people around the work they do together."
|
|
75
113
|
})
|
|
76
|
-
] }), /* @__PURE__ */
|
|
114
|
+
] }), /* @__PURE__ */ m(g, {
|
|
77
115
|
size: "sm",
|
|
78
|
-
onClick: () =>
|
|
79
|
-
children: [/* @__PURE__ */
|
|
116
|
+
onClick: () => I.openModal(),
|
|
117
|
+
children: [/* @__PURE__ */ p(u, { className: "h-4 w-4 mr-1" }), H("crewfoundry.teams.actions.createTeam", "Create Team")]
|
|
80
118
|
})]
|
|
81
119
|
}),
|
|
82
|
-
/* @__PURE__ */
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
M.length === 0 ? /* @__PURE__ */ p(C, {
|
|
121
|
+
illustration: "empty-people",
|
|
122
|
+
title: "No teams yet",
|
|
123
|
+
description: "Create a team to organize people around their work."
|
|
124
|
+
}) : /* @__PURE__ */ m("div", {
|
|
125
|
+
className: "grid gap-6 lg:grid-cols-3",
|
|
126
|
+
children: [/* @__PURE__ */ m("div", {
|
|
127
|
+
className: "space-y-4 lg:col-span-2",
|
|
128
|
+
children: [/* @__PURE__ */ p("div", {
|
|
129
|
+
className: "grid gap-4 sm:grid-cols-2",
|
|
130
|
+
children: q.map((e) => {
|
|
131
|
+
let n = e.leadId ? U.get(e.leadId) : void 0, i = W.get(e.id) ?? 0, a = J?.id === e.id;
|
|
132
|
+
return /* @__PURE__ */ m(x, {
|
|
133
|
+
treatment: a ? "glass" : "plain",
|
|
134
|
+
glow: a,
|
|
135
|
+
role: "button",
|
|
136
|
+
tabIndex: 0,
|
|
137
|
+
"aria-pressed": a,
|
|
138
|
+
"aria-label": `Select ${e.name} team`,
|
|
139
|
+
onClick: () => V(e.id),
|
|
140
|
+
onKeyDown: (t) => {
|
|
141
|
+
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), V(e.id));
|
|
142
|
+
},
|
|
143
|
+
className: "cursor-pointer transition-shadow hover:shadow-md focus-visible:shadow-[var(--shadow-focus)] focus-visible:outline-none",
|
|
144
|
+
children: [/* @__PURE__ */ m(y, {
|
|
145
|
+
className: "pb-3",
|
|
146
|
+
children: [/* @__PURE__ */ m("div", {
|
|
147
|
+
className: "flex items-start justify-between gap-2",
|
|
148
|
+
children: [/* @__PURE__ */ p(b, {
|
|
149
|
+
className: "text-base",
|
|
150
|
+
children: e.name
|
|
151
|
+
}), /* @__PURE__ */ p(h, {
|
|
152
|
+
variant: e.status === "active" ? "default" : "secondary",
|
|
153
|
+
className: "text-[10px]",
|
|
154
|
+
children: t(e.status)
|
|
155
|
+
})]
|
|
156
|
+
}), /* @__PURE__ */ m("div", {
|
|
157
|
+
className: "flex items-center gap-2 text-xs text-text-secondary",
|
|
158
|
+
children: [
|
|
159
|
+
/* @__PURE__ */ p("span", { children: H("crewfoundry.teams.card.ledBy", "Led by") }),
|
|
160
|
+
/* @__PURE__ */ p(k, {
|
|
161
|
+
name: n ? A(n) : e.leadName,
|
|
162
|
+
src: n?.avatar,
|
|
163
|
+
size: 20
|
|
164
|
+
}),
|
|
165
|
+
/* @__PURE__ */ p("span", {
|
|
166
|
+
className: "font-medium text-text-primary",
|
|
167
|
+
children: n ? A(n) : e.leadName || "—"
|
|
168
|
+
})
|
|
169
|
+
]
|
|
170
|
+
})]
|
|
171
|
+
}), /* @__PURE__ */ m(_, {
|
|
172
|
+
className: "space-y-3",
|
|
173
|
+
children: [/* @__PURE__ */ p(r, {
|
|
174
|
+
people: K(e),
|
|
175
|
+
max: 5,
|
|
176
|
+
size: 30
|
|
177
|
+
}), /* @__PURE__ */ m("div", {
|
|
178
|
+
className: "flex items-center gap-4 text-sm text-text-secondary",
|
|
179
|
+
children: [/* @__PURE__ */ m("span", {
|
|
180
|
+
className: "flex items-center gap-1",
|
|
181
|
+
children: [
|
|
182
|
+
/* @__PURE__ */ p(d, { className: "h-3.5 w-3.5" }),
|
|
183
|
+
e.memberCount,
|
|
184
|
+
" ",
|
|
185
|
+
H("crewfoundry.teams.card.members", "Members")
|
|
186
|
+
]
|
|
187
|
+
}), /* @__PURE__ */ m("span", {
|
|
188
|
+
className: "flex items-center gap-1",
|
|
189
|
+
children: [
|
|
190
|
+
/* @__PURE__ */ p(l, { className: "h-3.5 w-3.5" }),
|
|
191
|
+
i,
|
|
192
|
+
" ",
|
|
193
|
+
H("crewfoundry.teams.card.activeProjects", "Active Projects")
|
|
194
|
+
]
|
|
195
|
+
})]
|
|
196
|
+
})]
|
|
197
|
+
})]
|
|
198
|
+
}, e.id);
|
|
199
|
+
})
|
|
200
|
+
}), M.length > R && /* @__PURE__ */ p(T, {
|
|
201
|
+
page: L,
|
|
202
|
+
pageSize: R,
|
|
203
|
+
totalItems: M.length,
|
|
204
|
+
onPageChange: z
|
|
205
|
+
})]
|
|
206
|
+
}), /* @__PURE__ */ p("div", {
|
|
207
|
+
className: "lg:col-span-1",
|
|
208
|
+
children: J ? /* @__PURE__ */ m(x, {
|
|
209
|
+
treatment: "glass",
|
|
210
|
+
className: "border-border-seam lg:sticky lg:top-6",
|
|
211
|
+
"aria-live": "polite",
|
|
212
|
+
children: [/* @__PURE__ */ m(y, {
|
|
213
|
+
className: "pb-3",
|
|
214
|
+
children: [/* @__PURE__ */ m("div", {
|
|
215
|
+
className: "flex items-start justify-between gap-2",
|
|
216
|
+
children: [/* @__PURE__ */ p(b, {
|
|
217
|
+
className: "text-lg",
|
|
218
|
+
children: J.name
|
|
219
|
+
}), /* @__PURE__ */ p(h, {
|
|
220
|
+
variant: J.status === "active" ? "default" : "secondary",
|
|
221
|
+
className: "text-[10px]",
|
|
222
|
+
children: t(J.status)
|
|
223
|
+
})]
|
|
224
|
+
}), /* @__PURE__ */ p(v, { children: J.description })]
|
|
225
|
+
}), /* @__PURE__ */ m(_, {
|
|
226
|
+
className: "space-y-5",
|
|
124
227
|
children: [
|
|
125
|
-
/* @__PURE__ */
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
228
|
+
/* @__PURE__ */ m("section", { children: [/* @__PURE__ */ m("h3", {
|
|
229
|
+
className: "mb-2 text-sm font-semibold",
|
|
230
|
+
children: [
|
|
231
|
+
H("crewfoundry.teams.panel.members", "Members"),
|
|
232
|
+
" (",
|
|
233
|
+
Y.length,
|
|
234
|
+
")"
|
|
235
|
+
]
|
|
236
|
+
}), Y.length === 0 ? /* @__PURE__ */ p("p", {
|
|
237
|
+
className: "text-xs text-text-secondary",
|
|
238
|
+
children: "No members have been added to this team yet."
|
|
239
|
+
}) : /* @__PURE__ */ p("ul", {
|
|
240
|
+
className: "space-y-2 max-h-72 overflow-y-auto pr-1",
|
|
241
|
+
children: Y.map((e) => /* @__PURE__ */ m("li", {
|
|
242
|
+
className: "flex items-center gap-2.5",
|
|
243
|
+
children: [/* @__PURE__ */ p(k, {
|
|
244
|
+
name: A(e),
|
|
245
|
+
src: e.avatar,
|
|
246
|
+
size: 32
|
|
247
|
+
}), /* @__PURE__ */ m("div", {
|
|
248
|
+
className: "min-w-0",
|
|
249
|
+
children: [/* @__PURE__ */ m("p", {
|
|
250
|
+
className: "truncate text-sm font-medium text-text-primary",
|
|
251
|
+
children: [A(e), e.id === J.leadId ? /* @__PURE__ */ p("span", {
|
|
252
|
+
className: "ml-1.5 text-[10px] font-medium text-action-primary-text",
|
|
253
|
+
children: "· Lead"
|
|
254
|
+
}) : null]
|
|
255
|
+
}), /* @__PURE__ */ p("p", {
|
|
256
|
+
className: "truncate text-xs text-text-secondary",
|
|
257
|
+
children: e.position
|
|
258
|
+
})]
|
|
259
|
+
})]
|
|
260
|
+
}, e.id))
|
|
261
|
+
})] }),
|
|
262
|
+
/* @__PURE__ */ m("section", { children: [/* @__PURE__ */ m("h3", {
|
|
263
|
+
className: "mb-2 text-sm font-semibold",
|
|
264
|
+
children: [
|
|
265
|
+
H("crewfoundry.teams.panel.activeProjects", "Active Projects"),
|
|
266
|
+
" (",
|
|
267
|
+
X.length,
|
|
268
|
+
")"
|
|
269
|
+
]
|
|
270
|
+
}), X.length === 0 ? /* @__PURE__ */ p("p", {
|
|
271
|
+
className: "text-xs text-text-secondary",
|
|
272
|
+
children: "No active projects for this team right now."
|
|
273
|
+
}) : /* @__PURE__ */ p("ul", {
|
|
274
|
+
className: "space-y-3",
|
|
275
|
+
children: X.map((e) => /* @__PURE__ */ m("li", { children: [/* @__PURE__ */ m("div", {
|
|
276
|
+
className: "mb-1 flex items-center justify-between gap-2 text-xs",
|
|
277
|
+
children: [/* @__PURE__ */ p("span", {
|
|
278
|
+
className: "truncate font-medium text-text-primary",
|
|
279
|
+
children: e.name
|
|
280
|
+
}), /* @__PURE__ */ m("span", {
|
|
281
|
+
className: "shrink-0 tabular-nums text-text-secondary",
|
|
282
|
+
children: [e.progress, "%"]
|
|
283
|
+
})]
|
|
284
|
+
}), /* @__PURE__ */ p("div", {
|
|
285
|
+
className: "h-1.5 overflow-hidden rounded-full bg-bg-sunken",
|
|
286
|
+
children: /* @__PURE__ */ p("div", {
|
|
287
|
+
className: "h-1.5 rounded-full bg-action-primary-bg",
|
|
288
|
+
style: { width: `${e.progress}%` }
|
|
289
|
+
})
|
|
290
|
+
})] }, e.id))
|
|
291
|
+
})] }),
|
|
292
|
+
/* @__PURE__ */ m(g, {
|
|
293
|
+
variant: "outline",
|
|
294
|
+
size: "sm",
|
|
295
|
+
className: "w-full",
|
|
296
|
+
onClick: () => Z(J),
|
|
297
|
+
children: [H("crewfoundry.teams.panel.openDetail", "Open full team detail"), /* @__PURE__ */ p(c, { className: "ml-1 h-4 w-4" })]
|
|
298
|
+
})
|
|
129
299
|
]
|
|
130
300
|
})]
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
children: [
|
|
134
|
-
/* @__PURE__ */ l("span", { children: [
|
|
135
|
-
M("crewfoundry.teams.card.lead", "Lead"),
|
|
136
|
-
": ",
|
|
137
|
-
e.leadName
|
|
138
|
-
] }),
|
|
139
|
-
" ",
|
|
140
|
-
"· ",
|
|
141
|
-
/* @__PURE__ */ c("span", { children: e.department })
|
|
142
|
-
]
|
|
143
|
-
})] })]
|
|
144
|
-
}, e.id))
|
|
145
|
-
}),
|
|
146
|
-
E.length > A && /* @__PURE__ */ c(b, {
|
|
147
|
-
page: k,
|
|
148
|
-
pageSize: A,
|
|
149
|
-
totalItems: E.length,
|
|
150
|
-
onPageChange: j
|
|
301
|
+
}) : null
|
|
302
|
+
})]
|
|
151
303
|
}),
|
|
152
|
-
/* @__PURE__ */
|
|
153
|
-
open:
|
|
154
|
-
onOpenChange:
|
|
155
|
-
title:
|
|
304
|
+
/* @__PURE__ */ p(i, {
|
|
305
|
+
open: I.open,
|
|
306
|
+
onOpenChange: I.onOpenChange,
|
|
307
|
+
title: H("crewfoundry.teams.actions.createTeam", "Create Team"),
|
|
156
308
|
description: "Organize people around the work they do together.",
|
|
157
|
-
fields:
|
|
309
|
+
fields: O,
|
|
158
310
|
submitLabel: "Create Team",
|
|
159
311
|
onSubmit: async (e) => {
|
|
160
|
-
await
|
|
312
|
+
await F({
|
|
161
313
|
name: String(e.name ?? "").trim(),
|
|
162
314
|
description: String(e.description ?? "").trim(),
|
|
163
315
|
department: String(e.department ?? "").trim() || "operations",
|
|
@@ -171,6 +323,6 @@ function w() {
|
|
|
171
323
|
});
|
|
172
324
|
}
|
|
173
325
|
//#endregion
|
|
174
|
-
export {
|
|
326
|
+
export { j as TeamsTeamsPagePage };
|
|
175
327
|
|
|
176
328
|
//# sourceMappingURL=TeamsTeamsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamsTeamsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/TeamsTeamsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { FolderKanban, Plus, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { useCrewFoundryStore, type Team } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\nconst TEAM_FIELDS: FieldConfig[] = [\n { name: 'name', label: 'Team Name', type: 'text', required: true },\n { name: 'department', label: 'Department', type: 'text', placeholder: 'e.g. Engineering' },\n { name: 'leadName', label: 'Team Lead', type: 'text', placeholder: 'Lead full name' },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Forming', value: 'forming' },\n ],\n },\n { name: 'description', label: 'Description', type: 'textarea', colSpan: 2 },\n];\n\nexport function TeamsTeamsPagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { teams } = useCrewFoundryStore();\n const addTeam = useCrewFoundryStore((state) => state.addTeam);\n const createModal = useFormModal();\n const { page, pageSize, setPage } = usePagination({ initialPageSize: 12 });\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n\n const pageTeams = teams.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);\n\n const openTeam = (team: Team) =>\n navigate(`../teams/team-detail-page?id=${encodeURIComponent(team.id)}`);\n\n const handleCreate = async (values: FormValues) => {\n // CreateCrewTeamInput accepts only this field subset; the store spreads the\n // object straight into `input`, so we send exactly the accepted shape and\n // let the server response replace the optimistic row.\n const payload: Partial<Team> = {\n name: String(values.name ?? '').trim(),\n description: String(values.description ?? '').trim(),\n department: String(values.department ?? '').trim() || 'operations',\n leadName: String(values.leadName ?? '').trim(),\n status: (String(values.status ?? 'forming') as Team['status']) || 'forming',\n members: [],\n };\n await addTeam(payload as Team);\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{t('crewfoundry.teams.title', 'Teams')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {teams.length} {t('crewfoundry.teams.summary.count', 'teams across the organization')}\n </p>\n <PagePurpose className=\"mt-1\">\n Manage your teams — create groups, assign members, and organize people around the work\n they do together.\n </PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => createModal.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n {t('crewfoundry.teams.actions.createTeam', 'Create Team')}\n </Button>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {teams.length === 0 ? (\n <div className=\"col-span-full\">\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title=\"No teams yet\"\n description=\"Create a team to organize people around their work.\"\n />\n </div>\n ) : (\n pageTeams.map((team, _idx) => (\n <GlassCard\n key={team.id}\n treatment={_idx === 0 && page === 1 ? 'glass' : 'plain'}\n glow={_idx === 0 && page === 1}\n role=\"button\"\n tabIndex={0}\n aria-label={`Open ${team.name} team detail`}\n onClick={() => openTeam(team)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n openTeam(team);\n }\n }}\n className=\"hover:shadow-md transition-shadow cursor-pointer focus-visible:outline-none focus-visible:shadow-[var(--shadow-focus)]\"\n >\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{team.name}</CardTitle>\n <Badge\n variant={team.status === 'active' ? 'default' : 'secondary'}\n className=\"text-[10px]\"\n >\n {formatEnumLabel(team.status)}\n </Badge>\n </div>\n <CardDescription>{team.description}</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 gap-2 text-sm text-text-secondary mb-2\">\n <span className=\"flex items-center gap-1\">\n <Users className=\"h-3 w-3\" />\n {team.memberCount} {t('crewfoundry.teams.card.members', 'members')}\n </span>\n <span className=\"flex items-center gap-1\">\n <FolderKanban className=\"h-3 w-3\" />\n {team.projectCount} {t('crewfoundry.teams.card.projects', 'projects')}\n </span>\n </div>\n <div className=\"text-xs text-text-secondary\">\n <span>\n {t('crewfoundry.teams.card.lead', 'Lead')}: {team.leadName}\n </span>{' '}\n · <span>{team.department}</span>\n </div>\n </CardContent>\n </GlassCard>\n ))\n )}\n </div>\n\n {teams.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={teams.length}\n onPageChange={setPage}\n />\n )}\n\n <FormModal\n open={createModal.open}\n onOpenChange={createModal.onOpenChange}\n title={t('crewfoundry.teams.actions.createTeam', 'Create Team')}\n description=\"Organize people around the work they do together.\"\n fields={TEAM_FIELDS}\n submitLabel=\"Create Team\"\n onSubmit={handleCreate}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TeamsTeamsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/TeamsTeamsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { ArrowRight, FolderKanban, Plus, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useMemo, useState } from 'react';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport {\n useCrewFoundryStore,\n type Employee,\n type Team,\n} from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\nimport { AvatarStack, getInitials, type Person } from '../components/viz';\n\nconst TEAM_FIELDS: FieldConfig[] = [\n { name: 'name', label: 'Team Name', type: 'text', required: true },\n { name: 'department', label: 'Department', type: 'text', placeholder: 'e.g. Engineering' },\n { name: 'leadName', label: 'Team Lead', type: 'text', placeholder: 'Lead full name' },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Forming', value: 'forming' },\n ],\n },\n { name: 'description', label: 'Description', type: 'textarea', colSpan: 2 },\n];\n\nfunction InitialsAvatar({ name, src, size = 32 }: { name: string; src?: string; size?: number }) {\n if (src) {\n return (\n <img\n src={src}\n alt={name}\n width={size}\n height={size}\n loading=\"lazy\"\n className=\"shrink-0 rounded-full object-cover\"\n style={{ width: size, height: size }}\n />\n );\n }\n return (\n <span\n aria-hidden=\"true\"\n className=\"inline-flex shrink-0 items-center justify-center rounded-full bg-bg-elevated font-medium text-text-secondary\"\n style={{ width: size, height: size, fontSize: Math.round(size * 0.36) }}\n >\n {getInitials(name)}\n </span>\n );\n}\n\nfunction employeeName(employee: Employee): string {\n return `${employee.firstName} ${employee.lastName}`.trim();\n}\n\nexport function TeamsTeamsPagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { teams, employees, projects } = useCrewFoundryStore();\n const addTeam = useCrewFoundryStore((state) => state.addTeam);\n const createModal = useFormModal();\n const { page, pageSize, setPage } = usePagination({ initialPageSize: 12 });\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n\n const employeeById = useMemo(\n () => new Map(employees.map((employee) => [employee.id, employee])),\n [employees]\n );\n\n const activeProjectsByTeam = useMemo(() => {\n const map = new Map<string, number>();\n for (const project of projects) {\n if (project.status === 'active') {\n map.set(project.teamId, (map.get(project.teamId) ?? 0) + 1);\n }\n }\n return map;\n }, [projects]);\n\n const membersOf = (team: Team): Employee[] =>\n team.members\n .map((memberId) => employeeById.get(memberId))\n .filter((employee): employee is Employee => employee !== undefined);\n\n const peopleOf = (team: Team): Person[] =>\n membersOf(team).map((employee) => ({\n name: employeeName(employee),\n avatarUrl: employee.avatar,\n role: employee.position,\n }));\n\n const pageTeams = teams.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);\n const selectedTeam =\n teams.find((team) => team.id === selectedId) ?? pageTeams[0] ?? teams[0] ?? null;\n const selectedMembers = selectedTeam ? membersOf(selectedTeam) : [];\n const selectedActiveProjects = selectedTeam\n ? projects.filter((project) => project.teamId === selectedTeam.id && project.status === 'active')\n : [];\n\n const openTeam = (team: Team) =>\n navigate(`../teams/team-detail-page?id=${encodeURIComponent(team.id)}`);\n\n const handleCreate = async (values: FormValues) => {\n // CreateCrewTeamInput accepts only this field subset; the store spreads the\n // object straight into `input`, so we send exactly the accepted shape and\n // let the server response replace the optimistic row.\n const payload: Partial<Team> = {\n name: String(values.name ?? '').trim(),\n description: String(values.description ?? '').trim(),\n department: String(values.department ?? '').trim() || 'operations',\n leadName: String(values.leadName ?? '').trim(),\n status: (String(values.status ?? 'forming') as Team['status']) || 'forming',\n members: [],\n };\n await addTeam(payload as Team);\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{t('crewfoundry.teams.title', 'Teams')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {teams.length} {t('crewfoundry.teams.summary.count', 'teams across the organization')}\n </p>\n <PagePurpose className=\"mt-1\">\n Manage your teams — create groups, assign members, and organize people around the work\n they do together.\n </PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => createModal.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n {t('crewfoundry.teams.actions.createTeam', 'Create Team')}\n </Button>\n </div>\n\n {teams.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title=\"No teams yet\"\n description=\"Create a team to organize people around their work.\"\n />\n ) : (\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Team cards */}\n <div className=\"space-y-4 lg:col-span-2\">\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {pageTeams.map((team) => {\n const lead = team.leadId ? employeeById.get(team.leadId) : undefined;\n const activeCount = activeProjectsByTeam.get(team.id) ?? 0;\n const selected = selectedTeam?.id === team.id;\n return (\n <GlassCard\n key={team.id}\n treatment={selected ? 'glass' : 'plain'}\n glow={selected}\n role=\"button\"\n tabIndex={0}\n aria-pressed={selected}\n aria-label={`Select ${team.name} team`}\n onClick={() => setSelectedId(team.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setSelectedId(team.id);\n }\n }}\n className=\"cursor-pointer transition-shadow hover:shadow-md focus-visible:shadow-[var(--shadow-focus)] focus-visible:outline-none\"\n >\n <CardHeader className=\"pb-3\">\n <div className=\"flex items-start justify-between gap-2\">\n <CardTitle className=\"text-base\">{team.name}</CardTitle>\n <Badge\n variant={team.status === 'active' ? 'default' : 'secondary'}\n className=\"text-[10px]\"\n >\n {formatEnumLabel(team.status)}\n </Badge>\n </div>\n <div className=\"flex items-center gap-2 text-xs text-text-secondary\">\n <span>{t('crewfoundry.teams.card.ledBy', 'Led by')}</span>\n <InitialsAvatar\n name={lead ? employeeName(lead) : team.leadName}\n src={lead?.avatar}\n size={20}\n />\n <span className=\"font-medium text-text-primary\">\n {lead ? employeeName(lead) : team.leadName || '—'}\n </span>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <AvatarStack people={peopleOf(team)} max={5} size={30} />\n <div className=\"flex items-center gap-4 text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Users className=\"h-3.5 w-3.5\" />\n {team.memberCount} {t('crewfoundry.teams.card.members', 'Members')}\n </span>\n <span className=\"flex items-center gap-1\">\n <FolderKanban className=\"h-3.5 w-3.5\" />\n {activeCount}{' '}\n {t('crewfoundry.teams.card.activeProjects', 'Active Projects')}\n </span>\n </div>\n </CardContent>\n </GlassCard>\n );\n })}\n </div>\n\n {teams.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={teams.length}\n onPageChange={setPage}\n />\n )}\n </div>\n\n {/* Selected-team detail panel */}\n <div className=\"lg:col-span-1\">\n {selectedTeam ? (\n <GlassCard\n treatment=\"glass\"\n className=\"border-border-seam lg:sticky lg:top-6\"\n aria-live=\"polite\"\n >\n <CardHeader className=\"pb-3\">\n <div className=\"flex items-start justify-between gap-2\">\n <CardTitle className=\"text-lg\">{selectedTeam.name}</CardTitle>\n <Badge\n variant={selectedTeam.status === 'active' ? 'default' : 'secondary'}\n className=\"text-[10px]\"\n >\n {formatEnumLabel(selectedTeam.status)}\n </Badge>\n </div>\n <CardDescription>{selectedTeam.description}</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-5\">\n <section>\n <h3 className=\"mb-2 text-sm font-semibold\">\n {t('crewfoundry.teams.panel.members', 'Members')} ({selectedMembers.length})\n </h3>\n {selectedMembers.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">\n No members have been added to this team yet.\n </p>\n ) : (\n <ul className=\"space-y-2 max-h-72 overflow-y-auto pr-1\">\n {selectedMembers.map((member) => (\n <li key={member.id} className=\"flex items-center gap-2.5\">\n <InitialsAvatar\n name={employeeName(member)}\n src={member.avatar}\n size={32}\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {employeeName(member)}\n {member.id === selectedTeam.leadId ? (\n <span className=\"ml-1.5 text-[10px] font-medium text-action-primary-text\">\n · Lead\n </span>\n ) : null}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">\n {member.position}\n </p>\n </div>\n </li>\n ))}\n </ul>\n )}\n </section>\n\n <section>\n <h3 className=\"mb-2 text-sm font-semibold\">\n {t('crewfoundry.teams.panel.activeProjects', 'Active Projects')} (\n {selectedActiveProjects.length})\n </h3>\n {selectedActiveProjects.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">\n No active projects for this team right now.\n </p>\n ) : (\n <ul className=\"space-y-3\">\n {selectedActiveProjects.map((project) => (\n <li key={project.id}>\n <div className=\"mb-1 flex items-center justify-between gap-2 text-xs\">\n <span className=\"truncate font-medium text-text-primary\">\n {project.name}\n </span>\n <span className=\"shrink-0 tabular-nums text-text-secondary\">\n {project.progress}%\n </span>\n </div>\n <div className=\"h-1.5 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-1.5 rounded-full bg-action-primary-bg\"\n style={{ width: `${project.progress}%` }}\n />\n </div>\n </li>\n ))}\n </ul>\n )}\n </section>\n\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"w-full\"\n onClick={() => openTeam(selectedTeam)}\n >\n {t('crewfoundry.teams.panel.openDetail', 'Open full team detail')}\n <ArrowRight className=\"ml-1 h-4 w-4\" />\n </Button>\n </CardContent>\n </GlassCard>\n ) : null}\n </div>\n </div>\n )}\n\n <FormModal\n open={createModal.open}\n onOpenChange={createModal.onOpenChange}\n title={t('crewfoundry.teams.actions.createTeam', 'Create Team')}\n description=\"Organize people around the work they do together.\"\n fields={TEAM_FIELDS}\n submitLabel=\"Create Team\"\n onSubmit={handleCreate}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|