@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,151 +1,322 @@
|
|
|
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 {
|
|
3
|
+
import { AllocationBar as n } from "../components/viz/AllocationBar.js";
|
|
4
|
+
import { AvatarStack as r } from "../components/viz/AvatarStack.js";
|
|
5
|
+
import { SegmentedTabs as i } from "../components/viz/SegmentedTabs.js";
|
|
6
|
+
import "../components/viz/index.js";
|
|
7
|
+
import { allocationByPerson as a } from "../lib/analytics.js";
|
|
8
|
+
import { useMemo as o, useState as s } from "react";
|
|
9
|
+
import { ArrowRight as c, Gauge as l, LayoutGrid as u, Plus as d, Table2 as f } from "lucide-react";
|
|
10
|
+
import { useNavigate as p } from "react-router-dom";
|
|
11
|
+
import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
12
|
+
import { Badge as _, Button as v, Card as y, CardContent as b, CardDescription as x, CardHeader as S, CardTitle as C, GlassCard as w, GradientText as T, IllustratedEmptyState as E, PagePurpose as D, Pagination as O, ResponsiveTable as k } from "@burdenoff/fe-libs/ui";
|
|
13
|
+
import { usePagination as A } from "@burdenoff/fe-libs/shared/hooks";
|
|
14
|
+
import { useI18n as j } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
9
15
|
//#region src/crewfoundry/pages/ProjectsProjectsPagePage.tsx
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
var M = 6;
|
|
17
|
+
function N(e) {
|
|
18
|
+
return e === "active" ? "default" : e === "completed" ? "secondary" : "outline";
|
|
19
|
+
}
|
|
20
|
+
function P(e) {
|
|
21
|
+
return e === "critical" ? "destructive" : e === "high" ? "default" : "secondary";
|
|
22
|
+
}
|
|
23
|
+
function F() {
|
|
24
|
+
let { t: F } = j(), I = p(), { projects: L, teams: R, employees: z, timeEntries: B } = e(), V = L.filter((e) => e.status === "active"), { page: H, pageSize: U, setPage: W } = A({ initialPageSize: 12 }), [G, K] = s("board"), q = (e, t) => {
|
|
25
|
+
let n = F(e);
|
|
13
26
|
return n === e ? t : n;
|
|
14
|
-
},
|
|
15
|
-
|
|
27
|
+
}, J = o(() => new Map(z.map((e) => [e.id, e])), [z]), Y = o(() => new Map(R.map((e) => [e.id, e])), [R]), X = (e) => {
|
|
28
|
+
let t = Y.get(e.teamId);
|
|
29
|
+
return t ? t.members.map((e) => J.get(e)).filter((e) => e !== void 0).map((e) => ({
|
|
30
|
+
name: `${e.firstName} ${e.lastName}`.trim(),
|
|
31
|
+
avatarUrl: e.avatar,
|
|
32
|
+
role: e.position
|
|
33
|
+
})) : [];
|
|
34
|
+
}, Z = o(() => a(B, z).slice(0, M), [B, z]), Q = L.slice((H - 1) * U, (H - 1) * U + U), $ = (e) => I(`../projects/project-details-page?id=${encodeURIComponent(e.id)}`), ee = [
|
|
35
|
+
{
|
|
36
|
+
key: "name",
|
|
37
|
+
header: q("crewfoundry.projects.table.project", "Project"),
|
|
38
|
+
priority: "primary",
|
|
39
|
+
cell: (e) => /* @__PURE__ */ h("span", {
|
|
40
|
+
className: "font-medium text-text-primary",
|
|
41
|
+
children: e.name
|
|
42
|
+
})
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
key: "status",
|
|
46
|
+
header: q("crewfoundry.projects.table.status", "Status"),
|
|
47
|
+
priority: "primary",
|
|
48
|
+
cell: (e) => /* @__PURE__ */ h(_, {
|
|
49
|
+
variant: N(e.status),
|
|
50
|
+
className: "text-[10px]",
|
|
51
|
+
children: t(e.status)
|
|
52
|
+
})
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
key: "progress",
|
|
56
|
+
header: q("crewfoundry.projects.table.progress", "Progress"),
|
|
57
|
+
priority: "secondary",
|
|
58
|
+
cell: (e) => /* @__PURE__ */ g("div", {
|
|
59
|
+
className: "flex items-center gap-2 md:min-w-[160px]",
|
|
60
|
+
children: [/* @__PURE__ */ h("div", {
|
|
61
|
+
className: "h-1.5 flex-1 overflow-hidden rounded-full bg-bg-sunken",
|
|
62
|
+
children: /* @__PURE__ */ h("div", {
|
|
63
|
+
className: "h-1.5 rounded-full bg-action-primary-bg",
|
|
64
|
+
style: { width: `${e.progress}%` }
|
|
65
|
+
})
|
|
66
|
+
}), /* @__PURE__ */ g("span", {
|
|
67
|
+
className: "w-9 shrink-0 text-right text-xs tabular-nums text-text-secondary",
|
|
68
|
+
children: [e.progress, "%"]
|
|
69
|
+
})]
|
|
70
|
+
})
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
key: "team",
|
|
74
|
+
header: q("crewfoundry.projects.table.team", "Team"),
|
|
75
|
+
priority: "secondary",
|
|
76
|
+
cell: (e) => {
|
|
77
|
+
let t = X(e);
|
|
78
|
+
return t.length > 0 ? /* @__PURE__ */ h(r, {
|
|
79
|
+
people: t,
|
|
80
|
+
max: 4,
|
|
81
|
+
size: 26
|
|
82
|
+
}) : /* @__PURE__ */ h("span", {
|
|
83
|
+
className: "text-xs text-text-secondary",
|
|
84
|
+
children: e.teamName || "—"
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
key: "timeline",
|
|
90
|
+
header: q("crewfoundry.projects.table.timeline", "Timeline"),
|
|
91
|
+
priority: "secondary",
|
|
92
|
+
cell: (e) => /* @__PURE__ */ g("span", {
|
|
93
|
+
className: "whitespace-nowrap text-xs text-text-secondary",
|
|
94
|
+
children: [
|
|
95
|
+
e.startDate,
|
|
96
|
+
" — ",
|
|
97
|
+
e.endDate
|
|
98
|
+
]
|
|
99
|
+
})
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
key: "budget",
|
|
103
|
+
header: q("crewfoundry.projects.table.budget", "Budget"),
|
|
104
|
+
priority: "primary",
|
|
105
|
+
cell: (e) => /* @__PURE__ */ g("span", {
|
|
106
|
+
className: "tabular-nums md:text-right md:block",
|
|
107
|
+
children: [
|
|
108
|
+
"$",
|
|
109
|
+
(e.budget / 1e3).toFixed(0),
|
|
110
|
+
"K"
|
|
111
|
+
]
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
];
|
|
115
|
+
return /* @__PURE__ */ g("div", {
|
|
16
116
|
className: "space-y-6 p-6",
|
|
17
117
|
children: [
|
|
18
|
-
/* @__PURE__ */
|
|
19
|
-
className: "flex items-
|
|
20
|
-
children: [/* @__PURE__ */
|
|
21
|
-
/* @__PURE__ */
|
|
118
|
+
/* @__PURE__ */ g("div", {
|
|
119
|
+
className: "flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between",
|
|
120
|
+
children: [/* @__PURE__ */ g("div", { children: [
|
|
121
|
+
/* @__PURE__ */ h("h1", {
|
|
22
122
|
className: "text-2xl font-semibold",
|
|
23
|
-
children: /* @__PURE__ */
|
|
123
|
+
children: /* @__PURE__ */ h(T, { children: q("crewfoundry.projects.title", "Projects") })
|
|
24
124
|
}),
|
|
25
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ g("p", {
|
|
26
126
|
className: "text-sm text-text-secondary",
|
|
27
127
|
children: [
|
|
28
|
-
|
|
128
|
+
V.length,
|
|
29
129
|
" ",
|
|
30
|
-
|
|
130
|
+
q("crewfoundry.projects.summary.activeProjects", "active projects")
|
|
31
131
|
]
|
|
32
132
|
}),
|
|
33
|
-
/* @__PURE__ */
|
|
133
|
+
/* @__PURE__ */ h(D, {
|
|
34
134
|
className: "mt-1",
|
|
35
135
|
children: "All your projects in one view — track status, progress, and budgets so nothing stalls and everything ships on time."
|
|
36
136
|
})
|
|
37
|
-
] }), /* @__PURE__ */
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
treatment: n === 0 && C === 1 ? "glass" : "plain",
|
|
54
|
-
glow: n === 0 && C === 1,
|
|
55
|
-
role: "button",
|
|
56
|
-
tabIndex: 0,
|
|
57
|
-
"aria-label": `Open ${e.name} project detail`,
|
|
58
|
-
onClick: () => O(e),
|
|
59
|
-
onKeyDown: (t) => {
|
|
60
|
-
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), O(e));
|
|
61
|
-
},
|
|
62
|
-
className: "hover:shadow-md transition-shadow cursor-pointer focus-visible:outline-none focus-visible:shadow-[var(--shadow-focus)]",
|
|
63
|
-
children: [/* @__PURE__ */ a(u, { children: [/* @__PURE__ */ a("div", {
|
|
64
|
-
className: "flex items-center justify-between",
|
|
65
|
-
children: [/* @__PURE__ */ i(d, {
|
|
66
|
-
className: "text-base",
|
|
67
|
-
children: e.name
|
|
68
|
-
}), /* @__PURE__ */ i(o, {
|
|
69
|
-
variant: e.status === "active" ? "default" : e.status === "completed" ? "secondary" : "outline",
|
|
70
|
-
className: "text-[10px]",
|
|
71
|
-
children: t(e.status)
|
|
72
|
-
})]
|
|
73
|
-
}), /* @__PURE__ */ i(l, { children: e.description })] }), /* @__PURE__ */ a(c, { children: [
|
|
74
|
-
/* @__PURE__ */ a("div", {
|
|
75
|
-
className: "space-y-2 mb-3",
|
|
76
|
-
children: [/* @__PURE__ */ a("div", {
|
|
77
|
-
className: "flex justify-between text-xs",
|
|
78
|
-
children: [/* @__PURE__ */ a("span", { children: [
|
|
79
|
-
e.completedTasks,
|
|
80
|
-
"/",
|
|
81
|
-
e.tasks,
|
|
82
|
-
" ",
|
|
83
|
-
E("crewfoundry.projects.card.tasks", "tasks")
|
|
84
|
-
] }), /* @__PURE__ */ a("span", { children: [e.progress, "%"] })]
|
|
85
|
-
}), /* @__PURE__ */ i("div", {
|
|
86
|
-
className: "h-2 bg-bg-sunken rounded overflow-hidden",
|
|
87
|
-
children: /* @__PURE__ */ i("div", {
|
|
88
|
-
className: "h-2 bg-action-primary-bg rounded",
|
|
89
|
-
style: { width: `${e.progress}%` }
|
|
90
|
-
})
|
|
91
|
-
})]
|
|
137
|
+
] }), /* @__PURE__ */ g("div", {
|
|
138
|
+
className: "flex flex-wrap items-center gap-2",
|
|
139
|
+
children: [
|
|
140
|
+
/* @__PURE__ */ h(i, {
|
|
141
|
+
"aria-label": "Projects view",
|
|
142
|
+
value: G,
|
|
143
|
+
onChange: (e) => K(e),
|
|
144
|
+
tabs: [{
|
|
145
|
+
id: "board",
|
|
146
|
+
label: "Board",
|
|
147
|
+
icon: /* @__PURE__ */ h(u, { className: "h-4 w-4" })
|
|
148
|
+
}, {
|
|
149
|
+
id: "table",
|
|
150
|
+
label: "Table",
|
|
151
|
+
icon: /* @__PURE__ */ h(f, { className: "h-4 w-4" })
|
|
152
|
+
}]
|
|
92
153
|
}),
|
|
93
|
-
/* @__PURE__ */
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
": ",
|
|
99
|
-
e.teamName
|
|
100
|
-
] }),
|
|
101
|
-
/* @__PURE__ */ a("span", { children: [
|
|
102
|
-
E("crewfoundry.projects.card.manager", "Manager"),
|
|
103
|
-
": ",
|
|
104
|
-
e.managerName
|
|
105
|
-
] }),
|
|
106
|
-
/* @__PURE__ */ a("span", { children: [
|
|
107
|
-
E("crewfoundry.projects.card.budget", "Budget"),
|
|
108
|
-
": $",
|
|
109
|
-
(e.budget / 1e3).toFixed(0),
|
|
110
|
-
"K"
|
|
111
|
-
] }),
|
|
112
|
-
/* @__PURE__ */ a("span", { children: [
|
|
113
|
-
E("crewfoundry.projects.card.spent", "Spent"),
|
|
114
|
-
": $",
|
|
115
|
-
(e.spent / 1e3).toFixed(0),
|
|
116
|
-
"K"
|
|
117
|
-
] })
|
|
118
|
-
]
|
|
154
|
+
/* @__PURE__ */ g(v, {
|
|
155
|
+
variant: "outline",
|
|
156
|
+
size: "sm",
|
|
157
|
+
onClick: () => I("../projects/resourcing-page"),
|
|
158
|
+
children: [/* @__PURE__ */ h(l, { className: "h-4 w-4 mr-1" }), q("crewfoundry.projects.actions.resourcing", "Resourcing & Utilization")]
|
|
119
159
|
}),
|
|
120
|
-
/* @__PURE__ */
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
className: "text-[10px]",
|
|
125
|
-
children: t(e.priority)
|
|
126
|
-
}), /* @__PURE__ */ a(o, {
|
|
127
|
-
variant: "outline",
|
|
128
|
-
className: "text-[10px]",
|
|
129
|
-
children: [
|
|
130
|
-
e.startDate,
|
|
131
|
-
" — ",
|
|
132
|
-
e.endDate
|
|
133
|
-
]
|
|
134
|
-
})]
|
|
160
|
+
/* @__PURE__ */ g(v, {
|
|
161
|
+
size: "sm",
|
|
162
|
+
onClick: () => I("../projects/create-project-page"),
|
|
163
|
+
children: [/* @__PURE__ */ h(d, { className: "h-4 w-4 mr-1" }), q("crewfoundry.projects.actions.newProject", "New Project")]
|
|
135
164
|
})
|
|
136
|
-
]
|
|
137
|
-
}
|
|
165
|
+
]
|
|
166
|
+
})]
|
|
138
167
|
}),
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
168
|
+
L.length === 0 ? /* @__PURE__ */ h(E, {
|
|
169
|
+
illustration: "empty-data",
|
|
170
|
+
title: "No projects yet",
|
|
171
|
+
description: "Create your first project to start tracking work."
|
|
172
|
+
}) : G === "table" ? /* @__PURE__ */ h(w, {
|
|
173
|
+
treatment: "glass",
|
|
174
|
+
glow: !0,
|
|
175
|
+
className: "border-border-seam",
|
|
176
|
+
children: /* @__PURE__ */ g(b, {
|
|
177
|
+
className: "p-4",
|
|
178
|
+
children: [/* @__PURE__ */ h(k, {
|
|
179
|
+
columns: ee,
|
|
180
|
+
data: Q,
|
|
181
|
+
rowKey: (e) => e.id,
|
|
182
|
+
onRowClick: $
|
|
183
|
+
}), L.length > U && /* @__PURE__ */ h("div", {
|
|
184
|
+
className: "mt-4",
|
|
185
|
+
children: /* @__PURE__ */ h(O, {
|
|
186
|
+
page: H,
|
|
187
|
+
pageSize: U,
|
|
188
|
+
totalItems: L.length,
|
|
189
|
+
onPageChange: W
|
|
190
|
+
})
|
|
191
|
+
})]
|
|
192
|
+
})
|
|
193
|
+
}) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h("div", {
|
|
194
|
+
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
|
|
195
|
+
children: Q.map((e) => {
|
|
196
|
+
let n = X(e);
|
|
197
|
+
return /* @__PURE__ */ g(w, {
|
|
198
|
+
role: "button",
|
|
199
|
+
tabIndex: 0,
|
|
200
|
+
"aria-label": `Open ${e.name} project detail`,
|
|
201
|
+
onClick: () => $(e),
|
|
202
|
+
onKeyDown: (t) => {
|
|
203
|
+
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), $(e));
|
|
204
|
+
},
|
|
205
|
+
className: "cursor-pointer transition-shadow hover:shadow-md focus-visible:shadow-[var(--shadow-focus)] focus-visible:outline-none",
|
|
206
|
+
children: [/* @__PURE__ */ g(S, {
|
|
207
|
+
className: "pb-3",
|
|
208
|
+
children: [/* @__PURE__ */ g("div", {
|
|
209
|
+
className: "flex items-center justify-between",
|
|
210
|
+
children: [/* @__PURE__ */ h(C, {
|
|
211
|
+
className: "text-base",
|
|
212
|
+
children: e.name
|
|
213
|
+
}), /* @__PURE__ */ h(_, {
|
|
214
|
+
variant: N(e.status),
|
|
215
|
+
className: "text-[10px]",
|
|
216
|
+
children: t(e.status)
|
|
217
|
+
})]
|
|
218
|
+
}), /* @__PURE__ */ h(x, { children: e.description })]
|
|
219
|
+
}), /* @__PURE__ */ g(b, { children: [
|
|
220
|
+
/* @__PURE__ */ g("div", {
|
|
221
|
+
className: "space-y-2 mb-3",
|
|
222
|
+
children: [/* @__PURE__ */ g("div", {
|
|
223
|
+
className: "flex justify-between text-xs",
|
|
224
|
+
children: [/* @__PURE__ */ g("span", { children: [
|
|
225
|
+
e.completedTasks,
|
|
226
|
+
"/",
|
|
227
|
+
e.tasks,
|
|
228
|
+
" ",
|
|
229
|
+
q("crewfoundry.projects.card.tasks", "tasks")
|
|
230
|
+
] }), /* @__PURE__ */ g("span", {
|
|
231
|
+
className: "tabular-nums",
|
|
232
|
+
children: [e.progress, "%"]
|
|
233
|
+
})]
|
|
234
|
+
}), /* @__PURE__ */ h("div", {
|
|
235
|
+
className: "h-2 overflow-hidden rounded bg-bg-sunken",
|
|
236
|
+
children: /* @__PURE__ */ h("div", {
|
|
237
|
+
className: "h-2 rounded bg-action-primary-bg",
|
|
238
|
+
style: { width: `${e.progress}%` }
|
|
239
|
+
})
|
|
240
|
+
})]
|
|
241
|
+
}),
|
|
242
|
+
/* @__PURE__ */ g("div", {
|
|
243
|
+
className: "mb-3 flex items-center justify-between gap-2",
|
|
244
|
+
children: [n.length > 0 ? /* @__PURE__ */ h(r, {
|
|
245
|
+
people: n,
|
|
246
|
+
max: 4,
|
|
247
|
+
size: 26
|
|
248
|
+
}) : /* @__PURE__ */ g("span", {
|
|
249
|
+
className: "text-xs text-text-secondary",
|
|
250
|
+
children: [
|
|
251
|
+
q("crewfoundry.projects.card.team", "Team"),
|
|
252
|
+
": ",
|
|
253
|
+
e.teamName
|
|
254
|
+
]
|
|
255
|
+
}), /* @__PURE__ */ g("span", {
|
|
256
|
+
className: "shrink-0 text-xs tabular-nums text-text-secondary",
|
|
257
|
+
children: [
|
|
258
|
+
"$",
|
|
259
|
+
(e.spent / 1e3).toFixed(0),
|
|
260
|
+
"K / $",
|
|
261
|
+
(e.budget / 1e3).toFixed(0),
|
|
262
|
+
"K"
|
|
263
|
+
]
|
|
264
|
+
})]
|
|
265
|
+
}),
|
|
266
|
+
/* @__PURE__ */ g("div", {
|
|
267
|
+
className: "flex flex-wrap gap-1",
|
|
268
|
+
children: [/* @__PURE__ */ h(_, {
|
|
269
|
+
variant: P(e.priority),
|
|
270
|
+
className: "text-[10px]",
|
|
271
|
+
children: t(e.priority)
|
|
272
|
+
}), /* @__PURE__ */ g(_, {
|
|
273
|
+
variant: "outline",
|
|
274
|
+
className: "text-[10px]",
|
|
275
|
+
children: [
|
|
276
|
+
e.startDate,
|
|
277
|
+
" — ",
|
|
278
|
+
e.endDate
|
|
279
|
+
]
|
|
280
|
+
})]
|
|
281
|
+
})
|
|
282
|
+
] })]
|
|
283
|
+
}, e.id);
|
|
284
|
+
})
|
|
285
|
+
}), L.length > U && /* @__PURE__ */ h(O, {
|
|
286
|
+
page: H,
|
|
287
|
+
pageSize: U,
|
|
288
|
+
totalItems: L.length,
|
|
289
|
+
onPageChange: W
|
|
290
|
+
})] }),
|
|
291
|
+
Z.length > 0 && /* @__PURE__ */ g(y, { children: [/* @__PURE__ */ h(S, { children: /* @__PURE__ */ g("div", {
|
|
292
|
+
className: "flex flex-wrap items-center justify-between gap-2",
|
|
293
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h(C, {
|
|
294
|
+
className: "text-base",
|
|
295
|
+
children: q("crewfoundry.projects.resourcing.title", "Resourcing")
|
|
296
|
+
}), /* @__PURE__ */ g(x, { children: [
|
|
297
|
+
q("crewfoundry.projects.resourcing.subtitle", "People allocation for the latest week with logged time"),
|
|
298
|
+
" ",
|
|
299
|
+
"(",
|
|
300
|
+
Z[0].weekLabel,
|
|
301
|
+
")"
|
|
302
|
+
] })] }), /* @__PURE__ */ g(v, {
|
|
303
|
+
variant: "ghost",
|
|
304
|
+
size: "sm",
|
|
305
|
+
onClick: () => I("../projects/resourcing-page"),
|
|
306
|
+
children: [q("crewfoundry.projects.resourcing.viewAll", "View full resourcing"), /* @__PURE__ */ h(c, { className: "ml-1 h-4 w-4" })]
|
|
307
|
+
})]
|
|
308
|
+
}) }), /* @__PURE__ */ h(b, {
|
|
309
|
+
className: "space-y-5",
|
|
310
|
+
children: Z.map((e) => /* @__PURE__ */ h(n, {
|
|
311
|
+
segments: e.segments,
|
|
312
|
+
label: e.name,
|
|
313
|
+
rightLabel: `${e.utilization}% utilized`
|
|
314
|
+
}, e.employeeId))
|
|
315
|
+
})] })
|
|
145
316
|
]
|
|
146
317
|
});
|
|
147
318
|
}
|
|
148
319
|
//#endregion
|
|
149
|
-
export {
|
|
320
|
+
export { F as ProjectsProjectsPagePage };
|
|
150
321
|
|
|
151
322
|
//# sourceMappingURL=ProjectsProjectsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectsProjectsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/ProjectsProjectsPagePage.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 { Plus } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore, type Project } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\nexport function ProjectsProjectsPagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { projects } = useCrewFoundryStore();\n const activeProjects = projects.filter((p) => p.status === 'active');\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 pageProjects = projects.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);\n\n const openProject = (project: Project) =>\n navigate(`../projects/project-details-page?id=${encodeURIComponent(project.id)}`);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{t('crewfoundry.projects.title', 'Projects')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {activeProjects.length}{' '}\n {t('crewfoundry.projects.summary.activeProjects', 'active projects')}\n </p>\n <PagePurpose className=\"mt-1\">\n All your projects in one view — track status, progress, and budgets so nothing stalls\n and everything ships on time.\n </PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => navigate('../projects/create-project-page')}>\n <Plus className=\"h-4 w-4 mr-1\" />\n {t('crewfoundry.projects.actions.newProject', 'New Project')}\n </Button>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {projects.length === 0 ? (\n <div className=\"col-span-full\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No projects yet\"\n description=\"Create your first project to start tracking work.\"\n />\n </div>\n ) : (\n pageProjects.map((project, _idx) => (\n <GlassCard\n key={project.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 ${project.name} project detail`}\n onClick={() => openProject(project)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n openProject(project);\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\">{project.name}</CardTitle>\n <Badge\n variant={\n project.status === 'active'\n ? 'default'\n : project.status === 'completed'\n ? 'secondary'\n : 'outline'\n }\n className=\"text-[10px]\"\n >\n {formatEnumLabel(project.status)}\n </Badge>\n </div>\n <CardDescription>{project.description}</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2 mb-3\">\n <div className=\"flex justify-between text-xs\">\n <span>\n {project.completedTasks}/{project.tasks}{' '}\n {t('crewfoundry.projects.card.tasks', 'tasks')}\n </span>\n <span>{project.progress}%</span>\n </div>\n <div className=\"h-2 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-2 bg-action-primary-bg rounded\"\n style={{ width: `${project.progress}%` }}\n />\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-2 text-xs text-text-secondary\">\n <span>\n {t('crewfoundry.projects.card.team', 'Team')}: {project.teamName}\n </span>\n <span>\n {t('crewfoundry.projects.card.manager', 'Manager')}: {project.managerName}\n </span>\n <span>\n {t('crewfoundry.projects.card.budget', 'Budget')}: $\n {(project.budget / 1000).toFixed(0)}K\n </span>\n <span>\n {t('crewfoundry.projects.card.spent', 'Spent')}: $\n {(project.spent / 1000).toFixed(0)}K\n </span>\n </div>\n <div className=\"flex gap-1 mt-2\">\n <Badge\n variant={\n project.priority === 'critical'\n ? 'destructive'\n : project.priority === 'high'\n ? 'default'\n : 'secondary'\n }\n className=\"text-[10px]\"\n >\n {formatEnumLabel(project.priority)}\n </Badge>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {project.startDate} — {project.endDate}\n </Badge>\n </div>\n </CardContent>\n </GlassCard>\n ))\n )}\n </div>\n\n {projects.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={projects.length}\n onPageChange={setPage}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProjectsProjectsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/ProjectsProjectsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n type ResponsiveTableColumn,\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, Gauge, LayoutGrid, Plus, Table2 } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useMemo, useState } from 'react';\nimport {\n useCrewFoundryStore,\n type Employee,\n type Project,\n} from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\nimport { AllocationBar, AvatarStack, SegmentedTabs, type Person } from '../components/viz';\nimport { allocationByPerson } from '../lib/analytics';\n\nconst MAX_ALLOCATION_ROWS = 6;\n\nfunction statusVariant(status: Project['status']): 'default' | 'secondary' | 'outline' {\n if (status === 'active') {\n return 'default';\n }\n if (status === 'completed') {\n return 'secondary';\n }\n return 'outline';\n}\n\nfunction priorityVariant(\n priority: Project['priority']\n): 'destructive' | 'default' | 'secondary' {\n if (priority === 'critical') {\n return 'destructive';\n }\n if (priority === 'high') {\n return 'default';\n }\n return 'secondary';\n}\n\nexport function ProjectsProjectsPagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { projects, teams, employees, timeEntries } = useCrewFoundryStore();\n const activeProjects = projects.filter((p) => p.status === 'active');\n const { page, pageSize, setPage } = usePagination({ initialPageSize: 12 });\n const [view, setView] = useState<'board' | 'table'>('board');\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 const teamById = useMemo(() => new Map(teams.map((team) => [team.id, team])), [teams]);\n\n const teamPeople = (project: Project): Person[] => {\n const team = teamById.get(project.teamId);\n if (!team) {\n return [];\n }\n return team.members\n .map((memberId) => employeeById.get(memberId))\n .filter((employee): employee is Employee => employee !== undefined)\n .map((employee) => ({\n name: `${employee.firstName} ${employee.lastName}`.trim(),\n avatarUrl: employee.avatar,\n role: employee.position,\n }));\n };\n\n const allocation = useMemo(\n () => allocationByPerson(timeEntries, employees).slice(0, MAX_ALLOCATION_ROWS),\n [timeEntries, employees]\n );\n\n const pageProjects = projects.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);\n\n const openProject = (project: Project) =>\n navigate(`../projects/project-details-page?id=${encodeURIComponent(project.id)}`);\n\n const columns: ResponsiveTableColumn<Project>[] = [\n {\n key: 'name',\n header: t('crewfoundry.projects.table.project', 'Project'),\n priority: 'primary',\n cell: (project) => (\n <span className=\"font-medium text-text-primary\">{project.name}</span>\n ),\n },\n {\n key: 'status',\n header: t('crewfoundry.projects.table.status', 'Status'),\n priority: 'primary',\n cell: (project) => (\n <Badge variant={statusVariant(project.status)} className=\"text-[10px]\">\n {formatEnumLabel(project.status)}\n </Badge>\n ),\n },\n {\n key: 'progress',\n header: t('crewfoundry.projects.table.progress', 'Progress'),\n priority: 'secondary',\n cell: (project) => (\n <div className=\"flex items-center gap-2 md:min-w-[160px]\">\n <div className=\"h-1.5 flex-1 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 <span className=\"w-9 shrink-0 text-right text-xs tabular-nums text-text-secondary\">\n {project.progress}%\n </span>\n </div>\n ),\n },\n {\n key: 'team',\n header: t('crewfoundry.projects.table.team', 'Team'),\n priority: 'secondary',\n cell: (project) => {\n const people = teamPeople(project);\n return people.length > 0 ? (\n <AvatarStack people={people} max={4} size={26} />\n ) : (\n <span className=\"text-xs text-text-secondary\">{project.teamName || '—'}</span>\n );\n },\n },\n {\n key: 'timeline',\n header: t('crewfoundry.projects.table.timeline', 'Timeline'),\n priority: 'secondary',\n cell: (project) => (\n <span className=\"whitespace-nowrap text-xs text-text-secondary\">\n {project.startDate} — {project.endDate}\n </span>\n ),\n },\n {\n key: 'budget',\n header: t('crewfoundry.projects.table.budget', 'Budget'),\n priority: 'primary',\n cell: (project) => (\n <span className=\"tabular-nums md:text-right md:block\">\n ${(project.budget / 1000).toFixed(0)}K\n </span>\n ),\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{t('crewfoundry.projects.title', 'Projects')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {activeProjects.length}{' '}\n {t('crewfoundry.projects.summary.activeProjects', 'active projects')}\n </p>\n <PagePurpose className=\"mt-1\">\n All your projects in one view — track status, progress, and budgets so nothing stalls\n and everything ships on time.\n </PagePurpose>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <SegmentedTabs\n aria-label=\"Projects view\"\n value={view}\n onChange={(id) => setView(id as 'board' | 'table')}\n tabs={[\n { id: 'board', label: 'Board', icon: <LayoutGrid className=\"h-4 w-4\" /> },\n { id: 'table', label: 'Table', icon: <Table2 className=\"h-4 w-4\" /> },\n ]}\n />\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigate('../projects/resourcing-page')}\n >\n <Gauge className=\"h-4 w-4 mr-1\" />\n {t('crewfoundry.projects.actions.resourcing', 'Resourcing & Utilization')}\n </Button>\n <Button size=\"sm\" onClick={() => navigate('../projects/create-project-page')}>\n <Plus className=\"h-4 w-4 mr-1\" />\n {t('crewfoundry.projects.actions.newProject', 'New Project')}\n </Button>\n </div>\n </div>\n\n {projects.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No projects yet\"\n description=\"Create your first project to start tracking work.\"\n />\n ) : view === 'table' ? (\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"p-4\">\n <ResponsiveTable\n columns={columns}\n data={pageProjects}\n rowKey={(project) => project.id}\n onRowClick={openProject}\n />\n {projects.length > pageSize && (\n <div className=\"mt-4\">\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={projects.length}\n onPageChange={setPage}\n />\n </div>\n )}\n </CardContent>\n </GlassCard>\n ) : (\n <>\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {pageProjects.map((project) => {\n const people = teamPeople(project);\n return (\n <GlassCard\n key={project.id}\n role=\"button\"\n tabIndex={0}\n aria-label={`Open ${project.name} project detail`}\n onClick={() => openProject(project)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n openProject(project);\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-center justify-between\">\n <CardTitle className=\"text-base\">{project.name}</CardTitle>\n <Badge variant={statusVariant(project.status)} className=\"text-[10px]\">\n {formatEnumLabel(project.status)}\n </Badge>\n </div>\n <CardDescription>{project.description}</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2 mb-3\">\n <div className=\"flex justify-between text-xs\">\n <span>\n {project.completedTasks}/{project.tasks}{' '}\n {t('crewfoundry.projects.card.tasks', 'tasks')}\n </span>\n <span className=\"tabular-nums\">{project.progress}%</span>\n </div>\n <div className=\"h-2 overflow-hidden rounded bg-bg-sunken\">\n <div\n className=\"h-2 rounded bg-action-primary-bg\"\n style={{ width: `${project.progress}%` }}\n />\n </div>\n </div>\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n {people.length > 0 ? (\n <AvatarStack people={people} max={4} size={26} />\n ) : (\n <span className=\"text-xs text-text-secondary\">\n {t('crewfoundry.projects.card.team', 'Team')}: {project.teamName}\n </span>\n )}\n <span className=\"shrink-0 text-xs tabular-nums text-text-secondary\">\n ${(project.spent / 1000).toFixed(0)}K / $\n {(project.budget / 1000).toFixed(0)}K\n </span>\n </div>\n <div className=\"flex flex-wrap gap-1\">\n <Badge variant={priorityVariant(project.priority)} className=\"text-[10px]\">\n {formatEnumLabel(project.priority)}\n </Badge>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {project.startDate} — {project.endDate}\n </Badge>\n </div>\n </CardContent>\n </GlassCard>\n );\n })}\n </div>\n\n {projects.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={projects.length}\n onPageChange={setPage}\n />\n )}\n </>\n )}\n\n {/* Resourcing — People allocation this week */}\n {allocation.length > 0 && (\n <Card>\n <CardHeader>\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <div>\n <CardTitle className=\"text-base\">\n {t('crewfoundry.projects.resourcing.title', 'Resourcing')}\n </CardTitle>\n <CardDescription>\n {t(\n 'crewfoundry.projects.resourcing.subtitle',\n 'People allocation for the latest week with logged time'\n )}{' '}\n ({allocation[0].weekLabel})\n </CardDescription>\n </div>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => navigate('../projects/resourcing-page')}\n >\n {t('crewfoundry.projects.resourcing.viewAll', 'View full resourcing')}\n <ArrowRight className=\"ml-1 h-4 w-4\" />\n </Button>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-5\">\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 </CardContent>\n </Card>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|