@burdenoff/microfe-crewfoundry 2026.802.1 → 2026.830.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/CrewFoundryRoot.d.ts.map +1 -1
- package/dist/crewfoundry/CrewFoundryRoot.js +190 -185
- package/dist/crewfoundry/CrewFoundryRoot.js.map +1 -1
- package/dist/crewfoundry/components/forms/ConfirmDialog.d.ts.map +1 -1
- package/dist/crewfoundry/components/forms/ConfirmDialog.js +25 -24
- package/dist/crewfoundry/components/forms/ConfirmDialog.js.map +1 -1
- package/dist/crewfoundry/components/forms/FormModal.d.ts.map +1 -1
- package/dist/crewfoundry/components/forms/FormModal.js +103 -101
- package/dist/crewfoundry/components/forms/FormModal.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +207 -210
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +75 -78
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +101 -104
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +95 -98
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +153 -69
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +101 -104
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.d.ts +9 -0
- package/dist/crewfoundry/store/crewfoundryStore.d.ts.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +41 -32
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/dist/shared/hooks/useTr.d.ts +17 -0
- package/dist/shared/hooks/useTr.d.ts.map +1 -0
- package/dist/shared/hooks/useTr.js +14 -0
- package/dist/shared/hooks/useTr.js.map +1 -0
- package/dist/utils/pageContext.d.ts.map +1 -1
- package/dist/utils/pageContext.js +20 -24
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,17 +1,17 @@
|
|
|
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 {
|
|
3
|
+
import { useTr as n } from "../../shared/hooks/useTr.js";
|
|
4
|
+
import { AllocationBar as r } from "../components/viz/AllocationBar.js";
|
|
5
|
+
import { AvatarStack as i } from "../components/viz/AvatarStack.js";
|
|
6
|
+
import { SegmentedTabs as a } from "../components/viz/SegmentedTabs.js";
|
|
6
7
|
import "../components/viz/index.js";
|
|
7
|
-
import { allocationByPerson as
|
|
8
|
-
import { useMemo as
|
|
9
|
-
import { ArrowRight as
|
|
10
|
-
import { useNavigate as
|
|
11
|
-
import { Fragment as
|
|
12
|
-
import { Badge as
|
|
13
|
-
import { usePagination as
|
|
14
|
-
import { useI18n as j } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
8
|
+
import { allocationByPerson as o } from "../lib/analytics.js";
|
|
9
|
+
import { useMemo as s, useState as c } from "react";
|
|
10
|
+
import { ArrowRight as l, Gauge as u, LayoutGrid as d, Plus as f, Table2 as p } from "lucide-react";
|
|
11
|
+
import { useNavigate as m } from "react-router";
|
|
12
|
+
import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
13
|
+
import { Badge as v, Button as y, Card as b, CardContent as x, CardDescription as S, CardHeader as C, CardTitle as w, GlassCard as T, GradientText as E, IllustratedEmptyState as D, PagePurpose as O, Pagination as k, ResponsiveTable as A } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
import { usePagination as j } from "@burdenoff/fe-libs/shared/hooks";
|
|
15
15
|
//#region src/crewfoundry/pages/ProjectsProjectsPagePage.tsx
|
|
16
16
|
var M = 6;
|
|
17
17
|
function N(e) {
|
|
@@ -21,31 +21,28 @@ function P(e) {
|
|
|
21
21
|
return e === "critical" ? "destructive" : e === "high" ? "default" : "secondary";
|
|
22
22
|
}
|
|
23
23
|
function F() {
|
|
24
|
-
let
|
|
25
|
-
let
|
|
26
|
-
return
|
|
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) => ({
|
|
24
|
+
let F = n(), I = m(), { projects: L, teams: R, employees: z, timeEntries: B } = e(), V = L.filter((e) => e.status === "active"), { page: H, pageSize: U, setPage: W } = j({ initialPageSize: 12 }), [G, K] = c("board"), q = s(() => new Map(z.map((e) => [e.id, e])), [z]), J = s(() => new Map(R.map((e) => [e.id, e])), [R]), Y = (e) => {
|
|
25
|
+
let t = J.get(e.teamId);
|
|
26
|
+
return t ? t.members.map((e) => q.get(e)).filter((e) => e !== void 0).map((e) => ({
|
|
30
27
|
name: `${e.firstName} ${e.lastName}`.trim(),
|
|
31
28
|
avatarUrl: e.avatar,
|
|
32
29
|
role: e.position
|
|
33
30
|
})) : [];
|
|
34
|
-
},
|
|
31
|
+
}, X = s(() => o(B, z).slice(0, M), [B, z]), Z = L.slice((H - 1) * U, (H - 1) * U + U), Q = (e) => I(`../projects/project-details-page?id=${encodeURIComponent(e.id)}`), $ = [
|
|
35
32
|
{
|
|
36
33
|
key: "name",
|
|
37
|
-
header:
|
|
34
|
+
header: F("crewfoundry.projects.table.project", "Project"),
|
|
38
35
|
priority: "primary",
|
|
39
|
-
cell: (e) => /* @__PURE__ */
|
|
36
|
+
cell: (e) => /* @__PURE__ */ g("span", {
|
|
40
37
|
className: "font-medium text-text-primary",
|
|
41
38
|
children: e.name
|
|
42
39
|
})
|
|
43
40
|
},
|
|
44
41
|
{
|
|
45
42
|
key: "status",
|
|
46
|
-
header:
|
|
43
|
+
header: F("crewfoundry.projects.table.status", "Status"),
|
|
47
44
|
priority: "primary",
|
|
48
|
-
cell: (e) => /* @__PURE__ */
|
|
45
|
+
cell: (e) => /* @__PURE__ */ g(v, {
|
|
49
46
|
variant: N(e.status),
|
|
50
47
|
className: "text-[10px]",
|
|
51
48
|
children: t(e.status)
|
|
@@ -53,17 +50,17 @@ function F() {
|
|
|
53
50
|
},
|
|
54
51
|
{
|
|
55
52
|
key: "progress",
|
|
56
|
-
header:
|
|
53
|
+
header: F("crewfoundry.projects.table.progress", "Progress"),
|
|
57
54
|
priority: "secondary",
|
|
58
|
-
cell: (e) => /* @__PURE__ */
|
|
55
|
+
cell: (e) => /* @__PURE__ */ _("div", {
|
|
59
56
|
className: "flex items-center gap-2 md:min-w-[160px]",
|
|
60
|
-
children: [/* @__PURE__ */
|
|
57
|
+
children: [/* @__PURE__ */ g("div", {
|
|
61
58
|
className: "h-1.5 flex-1 overflow-hidden rounded-full bg-bg-sunken",
|
|
62
|
-
children: /* @__PURE__ */
|
|
59
|
+
children: /* @__PURE__ */ g("div", {
|
|
63
60
|
className: "h-1.5 rounded-full bg-action-primary-bg",
|
|
64
61
|
style: { width: `${e.progress}%` }
|
|
65
62
|
})
|
|
66
|
-
}), /* @__PURE__ */
|
|
63
|
+
}), /* @__PURE__ */ _("span", {
|
|
67
64
|
className: "w-9 shrink-0 text-right text-xs tabular-nums text-text-secondary",
|
|
68
65
|
children: [e.progress, "%"]
|
|
69
66
|
})]
|
|
@@ -71,15 +68,15 @@ function F() {
|
|
|
71
68
|
},
|
|
72
69
|
{
|
|
73
70
|
key: "team",
|
|
74
|
-
header:
|
|
71
|
+
header: F("crewfoundry.projects.table.team", "Team"),
|
|
75
72
|
priority: "secondary",
|
|
76
73
|
cell: (e) => {
|
|
77
|
-
let t =
|
|
78
|
-
return t.length > 0 ? /* @__PURE__ */
|
|
74
|
+
let t = Y(e);
|
|
75
|
+
return t.length > 0 ? /* @__PURE__ */ g(i, {
|
|
79
76
|
people: t,
|
|
80
77
|
max: 4,
|
|
81
78
|
size: 26
|
|
82
|
-
}) : /* @__PURE__ */
|
|
79
|
+
}) : /* @__PURE__ */ g("span", {
|
|
83
80
|
className: "text-xs text-text-secondary",
|
|
84
81
|
children: e.teamName || "—"
|
|
85
82
|
});
|
|
@@ -87,9 +84,9 @@ function F() {
|
|
|
87
84
|
},
|
|
88
85
|
{
|
|
89
86
|
key: "timeline",
|
|
90
|
-
header:
|
|
87
|
+
header: F("crewfoundry.projects.table.timeline", "Timeline"),
|
|
91
88
|
priority: "secondary",
|
|
92
|
-
cell: (e) => /* @__PURE__ */
|
|
89
|
+
cell: (e) => /* @__PURE__ */ _("span", {
|
|
93
90
|
className: "whitespace-nowrap text-xs text-text-secondary",
|
|
94
91
|
children: [
|
|
95
92
|
e.startDate,
|
|
@@ -100,9 +97,9 @@ function F() {
|
|
|
100
97
|
},
|
|
101
98
|
{
|
|
102
99
|
key: "budget",
|
|
103
|
-
header:
|
|
100
|
+
header: F("crewfoundry.projects.table.budget", "Budget"),
|
|
104
101
|
priority: "primary",
|
|
105
|
-
cell: (e) => /* @__PURE__ */
|
|
102
|
+
cell: (e) => /* @__PURE__ */ _("span", {
|
|
106
103
|
className: "tabular-nums md:text-right md:block",
|
|
107
104
|
children: [
|
|
108
105
|
"$",
|
|
@@ -112,77 +109,77 @@ function F() {
|
|
|
112
109
|
})
|
|
113
110
|
}
|
|
114
111
|
];
|
|
115
|
-
return /* @__PURE__ */
|
|
112
|
+
return /* @__PURE__ */ _("div", {
|
|
116
113
|
className: "space-y-6 p-6",
|
|
117
114
|
children: [
|
|
118
|
-
/* @__PURE__ */
|
|
115
|
+
/* @__PURE__ */ _("div", {
|
|
119
116
|
className: "flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between",
|
|
120
|
-
children: [/* @__PURE__ */
|
|
121
|
-
/* @__PURE__ */
|
|
117
|
+
children: [/* @__PURE__ */ _("div", { children: [
|
|
118
|
+
/* @__PURE__ */ g("h1", {
|
|
122
119
|
className: "text-2xl font-semibold",
|
|
123
|
-
children: /* @__PURE__ */
|
|
120
|
+
children: /* @__PURE__ */ g(E, { children: F("crewfoundry.projects.title", "Projects") })
|
|
124
121
|
}),
|
|
125
|
-
/* @__PURE__ */
|
|
122
|
+
/* @__PURE__ */ _("p", {
|
|
126
123
|
className: "text-sm text-text-secondary",
|
|
127
124
|
children: [
|
|
128
125
|
V.length,
|
|
129
126
|
" ",
|
|
130
|
-
|
|
127
|
+
F("crewfoundry.projects.summary.activeProjects", "active projects")
|
|
131
128
|
]
|
|
132
129
|
}),
|
|
133
|
-
/* @__PURE__ */
|
|
130
|
+
/* @__PURE__ */ g(O, {
|
|
134
131
|
className: "mt-1",
|
|
135
132
|
children: "All your projects in one view — track status, progress, and budgets so nothing stalls and everything ships on time."
|
|
136
133
|
})
|
|
137
|
-
] }), /* @__PURE__ */
|
|
134
|
+
] }), /* @__PURE__ */ _("div", {
|
|
138
135
|
className: "flex flex-wrap items-center gap-2",
|
|
139
136
|
children: [
|
|
140
|
-
/* @__PURE__ */
|
|
137
|
+
/* @__PURE__ */ g(a, {
|
|
141
138
|
"aria-label": "Projects view",
|
|
142
139
|
value: G,
|
|
143
140
|
onChange: (e) => K(e),
|
|
144
141
|
tabs: [{
|
|
145
142
|
id: "board",
|
|
146
143
|
label: "Board",
|
|
147
|
-
icon: /* @__PURE__ */
|
|
144
|
+
icon: /* @__PURE__ */ g(d, { className: "h-4 w-4" })
|
|
148
145
|
}, {
|
|
149
146
|
id: "table",
|
|
150
147
|
label: "Table",
|
|
151
|
-
icon: /* @__PURE__ */
|
|
148
|
+
icon: /* @__PURE__ */ g(p, { className: "h-4 w-4" })
|
|
152
149
|
}]
|
|
153
150
|
}),
|
|
154
|
-
/* @__PURE__ */
|
|
151
|
+
/* @__PURE__ */ _(y, {
|
|
155
152
|
variant: "outline",
|
|
156
153
|
size: "sm",
|
|
157
154
|
onClick: () => I("../projects/resourcing-page"),
|
|
158
|
-
children: [/* @__PURE__ */
|
|
155
|
+
children: [/* @__PURE__ */ g(u, { className: "h-4 w-4 mr-1" }), F("crewfoundry.projects.actions.resourcing", "Resourcing & Utilization")]
|
|
159
156
|
}),
|
|
160
|
-
/* @__PURE__ */
|
|
157
|
+
/* @__PURE__ */ _(y, {
|
|
161
158
|
size: "sm",
|
|
162
159
|
onClick: () => I("../projects/create-project-page"),
|
|
163
|
-
children: [/* @__PURE__ */
|
|
160
|
+
children: [/* @__PURE__ */ g(f, { className: "h-4 w-4 mr-1" }), F("crewfoundry.projects.actions.newProject", "New Project")]
|
|
164
161
|
})
|
|
165
162
|
]
|
|
166
163
|
})]
|
|
167
164
|
}),
|
|
168
|
-
L.length === 0 ? /* @__PURE__ */
|
|
165
|
+
L.length === 0 ? /* @__PURE__ */ g(D, {
|
|
169
166
|
illustration: "empty-data",
|
|
170
167
|
title: "No projects yet",
|
|
171
168
|
description: "Create your first project to start tracking work."
|
|
172
|
-
}) : G === "table" ? /* @__PURE__ */
|
|
169
|
+
}) : G === "table" ? /* @__PURE__ */ g(T, {
|
|
173
170
|
treatment: "glass",
|
|
174
171
|
glow: !0,
|
|
175
172
|
className: "border-border-seam",
|
|
176
|
-
children: /* @__PURE__ */
|
|
173
|
+
children: /* @__PURE__ */ _(x, {
|
|
177
174
|
className: "p-4",
|
|
178
|
-
children: [/* @__PURE__ */
|
|
179
|
-
columns:
|
|
180
|
-
data:
|
|
175
|
+
children: [/* @__PURE__ */ g(A, {
|
|
176
|
+
columns: $,
|
|
177
|
+
data: Z,
|
|
181
178
|
rowKey: (e) => e.id,
|
|
182
|
-
onRowClick:
|
|
183
|
-
}), L.length > U && /* @__PURE__ */
|
|
179
|
+
onRowClick: Q
|
|
180
|
+
}), L.length > U && /* @__PURE__ */ g("div", {
|
|
184
181
|
className: "mt-4",
|
|
185
|
-
children: /* @__PURE__ */
|
|
182
|
+
children: /* @__PURE__ */ g(k, {
|
|
186
183
|
page: H,
|
|
187
184
|
pageSize: U,
|
|
188
185
|
totalItems: L.length,
|
|
@@ -190,69 +187,69 @@ function F() {
|
|
|
190
187
|
})
|
|
191
188
|
})]
|
|
192
189
|
})
|
|
193
|
-
}) : /* @__PURE__ */
|
|
190
|
+
}) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("div", {
|
|
194
191
|
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
|
|
195
|
-
children:
|
|
196
|
-
let n =
|
|
197
|
-
return /* @__PURE__ */
|
|
192
|
+
children: Z.map((e) => {
|
|
193
|
+
let n = Y(e);
|
|
194
|
+
return /* @__PURE__ */ _(T, {
|
|
198
195
|
role: "button",
|
|
199
196
|
tabIndex: 0,
|
|
200
197
|
"aria-label": `Open ${e.name} project detail`,
|
|
201
|
-
onClick: () =>
|
|
198
|
+
onClick: () => Q(e),
|
|
202
199
|
onKeyDown: (t) => {
|
|
203
|
-
(t.key === "Enter" || t.key === " ") && (t.preventDefault(),
|
|
200
|
+
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), Q(e));
|
|
204
201
|
},
|
|
205
202
|
className: "cursor-pointer transition-shadow hover:shadow-md focus-visible:shadow-[var(--shadow-focus)] focus-visible:outline-none",
|
|
206
|
-
children: [/* @__PURE__ */
|
|
203
|
+
children: [/* @__PURE__ */ _(C, {
|
|
207
204
|
className: "pb-3",
|
|
208
|
-
children: [/* @__PURE__ */
|
|
205
|
+
children: [/* @__PURE__ */ _("div", {
|
|
209
206
|
className: "flex items-center justify-between",
|
|
210
|
-
children: [/* @__PURE__ */
|
|
207
|
+
children: [/* @__PURE__ */ g(w, {
|
|
211
208
|
className: "text-base",
|
|
212
209
|
children: e.name
|
|
213
|
-
}), /* @__PURE__ */
|
|
210
|
+
}), /* @__PURE__ */ g(v, {
|
|
214
211
|
variant: N(e.status),
|
|
215
212
|
className: "text-[10px]",
|
|
216
213
|
children: t(e.status)
|
|
217
214
|
})]
|
|
218
|
-
}), /* @__PURE__ */
|
|
219
|
-
}), /* @__PURE__ */
|
|
220
|
-
/* @__PURE__ */
|
|
215
|
+
}), /* @__PURE__ */ g(S, { children: e.description })]
|
|
216
|
+
}), /* @__PURE__ */ _(x, { children: [
|
|
217
|
+
/* @__PURE__ */ _("div", {
|
|
221
218
|
className: "space-y-2 mb-3",
|
|
222
|
-
children: [/* @__PURE__ */
|
|
219
|
+
children: [/* @__PURE__ */ _("div", {
|
|
223
220
|
className: "flex justify-between text-xs",
|
|
224
|
-
children: [/* @__PURE__ */
|
|
221
|
+
children: [/* @__PURE__ */ _("span", { children: [
|
|
225
222
|
e.completedTasks,
|
|
226
223
|
"/",
|
|
227
224
|
e.tasks,
|
|
228
225
|
" ",
|
|
229
|
-
|
|
230
|
-
] }), /* @__PURE__ */
|
|
226
|
+
F("crewfoundry.projects.card.tasks", "tasks")
|
|
227
|
+
] }), /* @__PURE__ */ _("span", {
|
|
231
228
|
className: "tabular-nums",
|
|
232
229
|
children: [e.progress, "%"]
|
|
233
230
|
})]
|
|
234
|
-
}), /* @__PURE__ */
|
|
231
|
+
}), /* @__PURE__ */ g("div", {
|
|
235
232
|
className: "h-2 overflow-hidden rounded bg-bg-sunken",
|
|
236
|
-
children: /* @__PURE__ */
|
|
233
|
+
children: /* @__PURE__ */ g("div", {
|
|
237
234
|
className: "h-2 rounded bg-action-primary-bg",
|
|
238
235
|
style: { width: `${e.progress}%` }
|
|
239
236
|
})
|
|
240
237
|
})]
|
|
241
238
|
}),
|
|
242
|
-
/* @__PURE__ */
|
|
239
|
+
/* @__PURE__ */ _("div", {
|
|
243
240
|
className: "mb-3 flex items-center justify-between gap-2",
|
|
244
|
-
children: [n.length > 0 ? /* @__PURE__ */
|
|
241
|
+
children: [n.length > 0 ? /* @__PURE__ */ g(i, {
|
|
245
242
|
people: n,
|
|
246
243
|
max: 4,
|
|
247
244
|
size: 26
|
|
248
|
-
}) : /* @__PURE__ */
|
|
245
|
+
}) : /* @__PURE__ */ _("span", {
|
|
249
246
|
className: "text-xs text-text-secondary",
|
|
250
247
|
children: [
|
|
251
|
-
|
|
248
|
+
F("crewfoundry.projects.card.team", "Team"),
|
|
252
249
|
": ",
|
|
253
250
|
e.teamName
|
|
254
251
|
]
|
|
255
|
-
}), /* @__PURE__ */
|
|
252
|
+
}), /* @__PURE__ */ _("span", {
|
|
256
253
|
className: "shrink-0 text-xs tabular-nums text-text-secondary",
|
|
257
254
|
children: [
|
|
258
255
|
"$",
|
|
@@ -263,13 +260,13 @@ function F() {
|
|
|
263
260
|
]
|
|
264
261
|
})]
|
|
265
262
|
}),
|
|
266
|
-
/* @__PURE__ */
|
|
263
|
+
/* @__PURE__ */ _("div", {
|
|
267
264
|
className: "flex flex-wrap gap-1",
|
|
268
|
-
children: [/* @__PURE__ */
|
|
265
|
+
children: [/* @__PURE__ */ g(v, {
|
|
269
266
|
variant: P(e.priority),
|
|
270
267
|
className: "text-[10px]",
|
|
271
268
|
children: t(e.priority)
|
|
272
|
-
}), /* @__PURE__ */
|
|
269
|
+
}), /* @__PURE__ */ _(v, {
|
|
273
270
|
variant: "outline",
|
|
274
271
|
className: "text-[10px]",
|
|
275
272
|
children: [
|
|
@@ -282,32 +279,32 @@ function F() {
|
|
|
282
279
|
] })]
|
|
283
280
|
}, e.id);
|
|
284
281
|
})
|
|
285
|
-
}), L.length > U && /* @__PURE__ */
|
|
282
|
+
}), L.length > U && /* @__PURE__ */ g(k, {
|
|
286
283
|
page: H,
|
|
287
284
|
pageSize: U,
|
|
288
285
|
totalItems: L.length,
|
|
289
286
|
onPageChange: W
|
|
290
287
|
})] }),
|
|
291
|
-
|
|
288
|
+
X.length > 0 && /* @__PURE__ */ _(b, { children: [/* @__PURE__ */ g(C, { children: /* @__PURE__ */ _("div", {
|
|
292
289
|
className: "flex flex-wrap items-center justify-between gap-2",
|
|
293
|
-
children: [/* @__PURE__ */
|
|
290
|
+
children: [/* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g(w, {
|
|
294
291
|
className: "text-base",
|
|
295
|
-
children:
|
|
296
|
-
}), /* @__PURE__ */
|
|
297
|
-
|
|
292
|
+
children: F("crewfoundry.projects.resourcing.title", "Resourcing")
|
|
293
|
+
}), /* @__PURE__ */ _(S, { children: [
|
|
294
|
+
F("crewfoundry.projects.resourcing.subtitle", "People allocation for the latest week with logged time"),
|
|
298
295
|
" ",
|
|
299
296
|
"(",
|
|
300
|
-
|
|
297
|
+
X[0].weekLabel,
|
|
301
298
|
")"
|
|
302
|
-
] })] }), /* @__PURE__ */
|
|
299
|
+
] })] }), /* @__PURE__ */ _(y, {
|
|
303
300
|
variant: "ghost",
|
|
304
301
|
size: "sm",
|
|
305
302
|
onClick: () => I("../projects/resourcing-page"),
|
|
306
|
-
children: [
|
|
303
|
+
children: [F("crewfoundry.projects.resourcing.viewAll", "View full resourcing"), /* @__PURE__ */ g(l, { className: "ml-1 h-4 w-4" })]
|
|
307
304
|
})]
|
|
308
|
-
}) }), /* @__PURE__ */
|
|
305
|
+
}) }), /* @__PURE__ */ g(x, {
|
|
309
306
|
className: "space-y-5",
|
|
310
|
-
children:
|
|
307
|
+
children: X.map((e) => /* @__PURE__ */ g(r, {
|
|
311
308
|
segments: e.segments,
|
|
312
309
|
label: e.name,
|
|
313
310
|
rightLabel: `${e.utilization}% utilized`
|
|
@@ -1 +1 @@
|
|
|
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';\nimport { useMemo, useState } from 'react';\nimport { useCrewFoundryStore, type Employee, type Project } 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(priority: Project['priority']): '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) => <span className=\"font-medium text-text-primary\">{project.name}</span>,\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":";;;;;;;;;;;;;;;AA0BA,IAAM,IAAsB;AAE5B,SAAS,EAAc,GAAgE;AAOrF,QANI,MAAW,WACN,YAEL,MAAW,cACN,cAEF;;AAGT,SAAS,EAAgB,GAAwE;AAO/F,QANI,MAAa,aACR,gBAEL,MAAa,SACR,YAEF;;AAGT,SAAgB,IAA2B;CACzC,IAAM,EAAE,GAAG,MAAc,GAAS,EAC5B,IAAW,GAAa,EACxB,EAAE,aAAU,UAAO,cAAW,mBAAgB,GAAqB,EACnE,IAAiB,EAAS,QAAQ,MAAM,EAAE,WAAW,SAAS,EAC9D,EAAE,SAAM,aAAU,eAAY,EAAc,EAAE,iBAAiB,IAAI,CAAC,EACpE,CAAC,GAAM,KAAW,EAA4B,QAAQ,EACtD,KAAK,GAAa,MAAqB;EAC3C,IAAM,IAAQ,EAAU,EAAI;AAC5B,SAAO,MAAU,IAAM,IAAW;IAG9B,IAAe,QACb,IAAI,IAAI,EAAU,KAAK,MAAa,CAAC,EAAS,IAAI,EAAS,CAAC,CAAC,EACnE,CAAC,EAAU,CACZ,EACK,IAAW,QAAc,IAAI,IAAI,EAAM,KAAK,MAAS,CAAC,EAAK,IAAI,EAAK,CAAC,CAAC,EAAE,CAAC,EAAM,CAAC,EAEhF,KAAc,MAA+B;EACjD,IAAM,IAAO,EAAS,IAAI,EAAQ,OAAO;AAIzC,SAHK,IAGE,EAAK,QACT,KAAK,MAAa,EAAa,IAAI,EAAS,CAAC,CAC7C,QAAQ,MAAmC,MAAa,KAAA,EAAU,CAClE,KAAK,OAAc;GAClB,MAAM,GAAG,EAAS,UAAU,GAAG,EAAS,WAAW,MAAM;GACzD,WAAW,EAAS;GACpB,MAAM,EAAS;GAChB,EAAE,GATI,EAAE;IAYP,IAAa,QACX,EAAmB,GAAa,EAAU,CAAC,MAAM,GAAG,EAAoB,EAC9E,CAAC,GAAa,EAAU,CACzB,EAEK,IAAe,EAAS,OAAO,IAAO,KAAK,IAAW,IAAO,KAAK,IAAW,EAAS,EAEtF,KAAe,MACnB,EAAS,uCAAuC,mBAAmB,EAAQ,GAAG,GAAG,EAE7E,KAA4C;EAChD;GACE,KAAK;GACL,QAAQ,EAAE,sCAAsC,UAAU;GAC1D,UAAU;GACV,OAAO,MAAY,kBAAC,QAAD;IAAM,WAAU;cAAiC,EAAQ;IAAY,CAAA;GACzF;EACD;GACE,KAAK;GACL,QAAQ,EAAE,qCAAqC,SAAS;GACxD,UAAU;GACV,OAAO,MACL,kBAAC,GAAD;IAAO,SAAS,EAAc,EAAQ,OAAO;IAAE,WAAU;cACtD,EAAgB,EAAQ,OAAO;IAC1B,CAAA;GAEX;EACD;GACE,KAAK;GACL,QAAQ,EAAE,uCAAuC,WAAW;GAC5D,UAAU;GACV,OAAO,MACL,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MACE,WAAU;MACV,OAAO,EAAE,OAAO,GAAG,EAAQ,SAAS,IAAI;MACxC,CAAA;KACE,CAAA,EACN,kBAAC,QAAD;KAAM,WAAU;eAAhB,CACG,EAAQ,UAAS,IACb;OACH;;GAET;EACD;GACE,KAAK;GACL,QAAQ,EAAE,mCAAmC,OAAO;GACpD,UAAU;GACV,OAAO,MAAY;IACjB,IAAM,IAAS,EAAW,EAAQ;AAClC,WAAO,EAAO,SAAS,IACrB,kBAAC,GAAD;KAAqB;KAAQ,KAAK;KAAG,MAAM;KAAM,CAAA,GAEjD,kBAAC,QAAD;KAAM,WAAU;eAA+B,EAAQ,YAAY;KAAW,CAAA;;GAGnF;EACD;GACE,KAAK;GACL,QAAQ,EAAE,uCAAuC,WAAW;GAC5D,UAAU;GACV,OAAO,MACL,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACG,EAAQ;KAAU;KAAI,EAAQ;KAC1B;;GAEV;EACD;GACE,KAAK;GACL,QAAQ,EAAE,qCAAqC,SAAS;GACxD,UAAU;GACV,OAAO,MACL,kBAAC,QAAD;IAAM,WAAU;cAAhB;KAAsD;MACjD,EAAQ,SAAS,KAAM,QAAQ,EAAE;KAAC;KAChC;;GAEV;EACF;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA;KACE,kBAAC,MAAD;MAAI,WAAU;gBACZ,kBAAC,GAAD,EAAA,UAAe,EAAE,8BAA8B,WAAW,EAAgB,CAAA;MACvE,CAAA;KACL,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAe;OAAQ;OACvB,EAAE,+CAA+C,kBAAkB;OAClE;;KACJ,kBAAC,GAAD;MAAa,WAAU;gBAAO;MAGhB,CAAA;KACV,EAAA,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OACE,cAAW;OACX,OAAO;OACP,WAAW,MAAO,EAAQ,EAAwB;OAClD,MAAM,CACJ;QAAE,IAAI;QAAS,OAAO;QAAS,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;QAAE,EACzE;QAAE,IAAI;QAAS,OAAO;QAAS,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;QAAE,CACtE;OACD,CAAA;MACF,kBAAC,GAAD;OACE,SAAQ;OACR,MAAK;OACL,eAAe,EAAS,8BAA8B;iBAHxD,CAKE,kBAAC,GAAD,EAAO,WAAU,gBAAiB,CAAA,EACjC,EAAE,2CAA2C,2BAA2B,CAClE;;MACT,kBAAC,GAAD;OAAQ,MAAK;OAAK,eAAe,EAAS,kCAAkC;iBAA5E,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAChC,EAAE,2CAA2C,cAAc,CACrD;;MACL;OACF;;GAEL,EAAS,WAAW,IACnB,kBAAC,GAAD;IACE,cAAa;IACb,OAAM;IACN,aAAY;IACZ,CAAA,GACA,MAAS,UACX,kBAAC,GAAD;IAAW,WAAU;IAAQ,MAAA;IAAK,WAAU;cAC1C,kBAAC,GAAD;KAAa,WAAU;eAAvB,CACE,kBAAC,GAAD;MACW;MACT,MAAM;MACN,SAAS,MAAY,EAAQ;MAC7B,YAAY;MACZ,CAAA,EACD,EAAS,SAAS,KACjB,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD;OACQ;OACI;OACV,YAAY,EAAS;OACrB,cAAc;OACd,CAAA;MACE,CAAA,CAEI;;IACJ,CAAA,GAEZ,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAa,KAAK,MAAY;KAC7B,IAAM,IAAS,EAAW,EAAQ;AAClC,YACE,kBAAC,GAAD;MAEE,MAAK;MACL,UAAU;MACV,cAAY,QAAQ,EAAQ,KAAK;MACjC,eAAe,EAAY,EAAQ;MACnC,YAAY,MAAM;AAChB,QAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,EAAY,EAAQ;;MAGxB,WAAU;gBAZZ,CAcE,kBAAC,GAAD;OAAY,WAAU;iBAAtB,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAW,WAAU;mBAAa,EAAQ;SAAiB,CAAA,EAC3D,kBAAC,GAAD;SAAO,SAAS,EAAc,EAAQ,OAAO;SAAE,WAAU;mBACtD,EAAgB,EAAQ,OAAO;SAC1B,CAAA,CACJ;WACN,kBAAC,GAAD,EAAA,UAAkB,EAAQ,aAA8B,CAAA,CAC7C;UACb,kBAAC,GAAD,EAAA,UAAA;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD,EAAA,UAAA;UACG,EAAQ;UAAe;UAAE,EAAQ;UAAO;UACxC,EAAE,mCAAmC,QAAQ;UACzC,EAAA,CAAA,EACP,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CAAgC,EAAQ,UAAS,IAAQ;YACrD;YACN,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,OAAD;UACE,WAAU;UACV,OAAO,EAAE,OAAO,GAAG,EAAQ,SAAS,IAAI;UACxC,CAAA;SACE,CAAA,CACF;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACG,EAAO,SAAS,IACf,kBAAC,GAAD;SAAqB;SAAQ,KAAK;SAAG,MAAM;SAAM,CAAA,GAEjD,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UACG,EAAE,kCAAkC,OAAO;UAAC;UAAG,EAAQ;UACnD;YAET,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UAAoE;WAC/D,EAAQ,QAAQ,KAAM,QAAQ,EAAE;UAAC;WAClC,EAAQ,SAAS,KAAM,QAAQ,EAAE;UAAC;UAC/B;WACH;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAS,EAAgB,EAAQ,SAAS;SAAE,WAAU;mBAC1D,EAAgB,EAAQ,SAAS;SAC5B,CAAA,EACR,kBAAC,GAAD;SAAO,SAAQ;SAAU,WAAU;mBAAnC;UACG,EAAQ;UAAU;UAAI,EAAQ;UACzB;WACJ;;OACM,EAAA,CAAA,CACJ;QA5DL,EAAQ,GA4DH;MAEd;IACE,CAAA,EAEL,EAAS,SAAS,KACjB,kBAAC,GAAD;IACQ;IACI;IACV,YAAY,EAAS;IACrB,cAAc;IACd,CAAA,CAEH,EAAA,CAAA;GAIJ,EAAW,SAAS,KACnB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAW,WAAU;eAClB,EAAE,yCAAyC,aAAa;KAC/C,CAAA,EACZ,kBAAC,GAAD,EAAA,UAAA;KACG,EACC,4CACA,yDACD;KAAE;KAAI;KACL,EAAW,GAAG;KAAU;KACV,EAAA,CAAA,CACd,EAAA,CAAA,EACN,kBAAC,GAAD;KACE,SAAQ;KACR,MAAK;KACL,eAAe,EAAS,8BAA8B;eAHxD,CAKG,EAAE,2CAA2C,uBAAuB,EACrE,kBAAC,GAAD,EAAY,WAAU,gBAAiB,CAAA,CAChC;OACL;OACK,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cACpB,EAAW,KAAK,MACf,kBAAC,GAAD;KAEE,UAAU,EAAI;KACd,OAAO,EAAI;KACX,YAAY,GAAG,EAAI,YAAY;KAC/B,EAJK,EAAI,WAIT,CACF;IACU,CAAA,CACT,EAAA,CAAA;GAEL"}
|
|
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 { useTr } from '../../shared/hooks/useTr';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { ArrowRight, Gauge, LayoutGrid, Plus, Table2 } from 'lucide-react';\nimport { useNavigate } from 'react-router';\nimport { useMemo, useState } from 'react';\nimport { useCrewFoundryStore, type Employee, type Project } 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(priority: Project['priority']): '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 tr = useTr();\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\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: tr('crewfoundry.projects.table.project', 'Project'),\n priority: 'primary',\n cell: (project) => <span className=\"font-medium text-text-primary\">{project.name}</span>,\n },\n {\n key: 'status',\n header: tr('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: tr('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: tr('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: tr('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: tr('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>{tr('crewfoundry.projects.title', 'Projects')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {activeProjects.length}{' '}\n {tr('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 {tr('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 {tr('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 {tr('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 {tr('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 {tr('crewfoundry.projects.resourcing.title', 'Resourcing')}\n </CardTitle>\n <CardDescription>\n {tr(\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 {tr('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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectsResourcingPagePage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/ProjectsResourcingPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProjectsResourcingPagePage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/ProjectsResourcingPagePage.tsx"],"names":[],"mappings":"AAyEA,wBAAgB,0BAA0B,gCA8QzC"}
|