@burdenoff/microfe-crewfoundry 2026.626.1 → 2026.703.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/components/forms/ConfirmDialog.js +43 -0
- package/dist/crewfoundry/components/forms/ConfirmDialog.js.map +1 -0
- package/dist/crewfoundry/components/forms/FormModal.js +220 -0
- package/dist/crewfoundry/components/forms/FormModal.js.map +1 -0
- package/dist/crewfoundry/components/forms/formValues.js +20 -0
- package/dist/crewfoundry/components/forms/formValues.js.map +1 -0
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +255 -65
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js +28 -17
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js +57 -53
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +32 -23
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js +44 -29
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +183 -57
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +214 -92
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +165 -131
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js +163 -133
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +269 -54
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +225 -78
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +213 -59
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +287 -90
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +49 -47
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +166 -59
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js +274 -83
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +198 -88
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js +216 -88
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +216 -66
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js +6 -7
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +83 -68
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +167 -46
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +75 -55
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +152 -79
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +75 -63
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js +3 -1
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js +235 -87
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +199 -86
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js +21 -40
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js +117 -45
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +249 -90
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +47 -45
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js +262 -133
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +144 -77
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +306 -51
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,118 +1,231 @@
|
|
|
1
1
|
import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { FormModal as t, useFormModal as n } from "../components/forms/FormModal.js";
|
|
3
|
+
import { useState as r } from "react";
|
|
4
|
+
import { Calendar as i, DollarSign as a, FolderKanban as o, Pencil as s, Target as c, Trash2 as l, Users as u } from "lucide-react";
|
|
5
|
+
import { useNavigate as d } from "react-router-dom";
|
|
6
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
7
|
+
import { Badge as m, Button as h, Card as g, CardContent as _, CardHeader as v, CardTitle as y, EmphasisPanel as b, GradientText as x, IllustratedEmptyState as S, NextSteps as C, PagePurpose as w, ResponsiveDialog as T, ResponsiveDialogContent as E, ResponsiveDialogDescription as D, ResponsiveDialogFooter as O, ResponsiveDialogHeader as k, ResponsiveDialogTitle as A } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
import { useGlobalUi as j } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
6
9
|
//#region src/crewfoundry/pages/ProjectsProjectDetailsPagePage.tsx
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
var M = [
|
|
11
|
+
{
|
|
12
|
+
name: "name",
|
|
13
|
+
label: "Project Name",
|
|
14
|
+
type: "text",
|
|
15
|
+
required: !0,
|
|
16
|
+
colSpan: 2
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: "description",
|
|
20
|
+
label: "Description",
|
|
21
|
+
type: "textarea",
|
|
22
|
+
colSpan: 2
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: "status",
|
|
26
|
+
label: "Status",
|
|
27
|
+
type: "select",
|
|
28
|
+
options: [
|
|
29
|
+
{
|
|
30
|
+
label: "Planning",
|
|
31
|
+
value: "planning"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
label: "Active",
|
|
35
|
+
value: "active"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
label: "On Hold",
|
|
39
|
+
value: "on_hold"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
label: "Completed",
|
|
43
|
+
value: "completed"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
label: "Cancelled",
|
|
47
|
+
value: "cancelled"
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "priority",
|
|
53
|
+
label: "Priority",
|
|
54
|
+
type: "select",
|
|
55
|
+
options: [
|
|
56
|
+
{
|
|
57
|
+
label: "Low",
|
|
58
|
+
value: "low"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
label: "Medium",
|
|
62
|
+
value: "medium"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
label: "High",
|
|
66
|
+
value: "high"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
label: "Critical",
|
|
70
|
+
value: "critical"
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: "budget",
|
|
76
|
+
label: "Budget ($)",
|
|
77
|
+
type: "number"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "progress",
|
|
81
|
+
label: "Progress (%)",
|
|
82
|
+
type: "number"
|
|
83
|
+
}
|
|
84
|
+
];
|
|
85
|
+
function N() {
|
|
86
|
+
let N = d(), { showToast: P } = j(), F = e((e) => e.projects), I = e((e) => e.updateProject), L = e((e) => e.removeProject), R = n(), [z, B] = r(!1), [V, H] = r(!1), U = F[1];
|
|
87
|
+
if (!U) return /* @__PURE__ */ f("div", {
|
|
88
|
+
className: "p-6",
|
|
89
|
+
children: /* @__PURE__ */ f(S, {
|
|
90
|
+
illustration: "empty-search",
|
|
91
|
+
title: "Project not found",
|
|
92
|
+
description: "This project is no longer available."
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
let W = {
|
|
96
|
+
name: U.name,
|
|
97
|
+
description: U.description,
|
|
98
|
+
status: U.status,
|
|
99
|
+
priority: U.priority,
|
|
100
|
+
budget: U.budget,
|
|
101
|
+
progress: U.progress
|
|
102
|
+
};
|
|
103
|
+
return /* @__PURE__ */ p("div", {
|
|
10
104
|
className: "space-y-6 p-6 max-w-4xl",
|
|
11
105
|
children: [
|
|
12
|
-
/* @__PURE__ */
|
|
13
|
-
className: "flex items-center justify-between",
|
|
14
|
-
children: [/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ p("div", {
|
|
107
|
+
className: "flex items-center justify-between gap-4",
|
|
108
|
+
children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("h1", {
|
|
15
109
|
className: "text-2xl font-semibold",
|
|
16
|
-
children: /* @__PURE__ */
|
|
17
|
-
}), /* @__PURE__ */
|
|
110
|
+
children: /* @__PURE__ */ f(x, { children: U.name })
|
|
111
|
+
}), /* @__PURE__ */ f("p", {
|
|
18
112
|
className: "text-sm text-text-secondary",
|
|
19
|
-
children:
|
|
20
|
-
})] }), /* @__PURE__ */
|
|
21
|
-
className: "flex gap-
|
|
22
|
-
children: [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
113
|
+
children: U.description
|
|
114
|
+
})] }), /* @__PURE__ */ p("div", {
|
|
115
|
+
className: "flex items-center gap-2",
|
|
116
|
+
children: [
|
|
117
|
+
/* @__PURE__ */ p("div", {
|
|
118
|
+
className: "hidden gap-1 sm:flex",
|
|
119
|
+
children: [/* @__PURE__ */ f(m, {
|
|
120
|
+
variant: U.priority === "critical" ? "destructive" : "default",
|
|
121
|
+
children: U.priority
|
|
122
|
+
}), /* @__PURE__ */ f(m, {
|
|
123
|
+
variant: U.status === "active" ? "default" : "secondary",
|
|
124
|
+
children: U.status
|
|
125
|
+
})]
|
|
126
|
+
}),
|
|
127
|
+
/* @__PURE__ */ p(h, {
|
|
128
|
+
variant: "outline",
|
|
129
|
+
size: "sm",
|
|
130
|
+
onClick: () => R.openModal(),
|
|
131
|
+
children: [/* @__PURE__ */ f(s, { className: "h-4 w-4 mr-1" }), "Edit"]
|
|
132
|
+
}),
|
|
133
|
+
/* @__PURE__ */ f(h, {
|
|
134
|
+
variant: "ghost",
|
|
135
|
+
size: "sm",
|
|
136
|
+
"aria-label": "Delete project",
|
|
137
|
+
className: "h-9 w-9 p-0 text-text-secondary hover:text-status-error-text",
|
|
138
|
+
onClick: () => B(!0),
|
|
139
|
+
children: /* @__PURE__ */ f(l, { className: "h-4 w-4" })
|
|
140
|
+
})
|
|
141
|
+
]
|
|
29
142
|
})]
|
|
30
143
|
}),
|
|
31
|
-
/* @__PURE__ */
|
|
32
|
-
/* @__PURE__ */
|
|
144
|
+
/* @__PURE__ */ f(w, { children: "Track a single project end-to-end — progress, budget, team, and timeline in one place — so you can spot risks early and keep delivery on schedule and on budget." }),
|
|
145
|
+
/* @__PURE__ */ f(C, {
|
|
33
146
|
storageKey: "crewfoundry-project-details",
|
|
34
147
|
steps: [
|
|
35
148
|
{
|
|
36
149
|
id: "all-projects",
|
|
37
150
|
label: "View all projects",
|
|
38
151
|
description: "See how this project compares across your portfolio.",
|
|
39
|
-
icon: /* @__PURE__ */
|
|
40
|
-
onClick: () =>
|
|
152
|
+
icon: /* @__PURE__ */ f(o, { className: "h-4 w-4" }),
|
|
153
|
+
onClick: () => N("../../projects/projects-page")
|
|
41
154
|
},
|
|
42
155
|
{
|
|
43
156
|
id: "team",
|
|
44
157
|
label: "Check the team",
|
|
45
158
|
description: "Review who is working on this and their workload.",
|
|
46
|
-
icon: /* @__PURE__ */
|
|
47
|
-
onClick: () =>
|
|
159
|
+
icon: /* @__PURE__ */ f(u, { className: "h-4 w-4" }),
|
|
160
|
+
onClick: () => N("../../teams/teams-page")
|
|
48
161
|
},
|
|
49
162
|
{
|
|
50
163
|
id: "new-project",
|
|
51
164
|
label: "Start a new project",
|
|
52
165
|
description: "Kick off the next piece of work.",
|
|
53
|
-
icon: /* @__PURE__ */
|
|
54
|
-
onClick: () =>
|
|
166
|
+
icon: /* @__PURE__ */ f(c, { className: "h-4 w-4" }),
|
|
167
|
+
onClick: () => N("../../projects/create-project-page")
|
|
55
168
|
}
|
|
56
169
|
]
|
|
57
170
|
}),
|
|
58
|
-
/* @__PURE__ */
|
|
171
|
+
/* @__PURE__ */ p("div", {
|
|
59
172
|
className: "grid gap-4 md:grid-cols-4",
|
|
60
173
|
children: [
|
|
61
|
-
/* @__PURE__ */
|
|
174
|
+
/* @__PURE__ */ f(g, { children: /* @__PURE__ */ p(_, {
|
|
62
175
|
className: "p-4 text-center",
|
|
63
176
|
children: [
|
|
64
|
-
/* @__PURE__ */
|
|
65
|
-
/* @__PURE__ */
|
|
177
|
+
/* @__PURE__ */ f(c, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
|
|
178
|
+
/* @__PURE__ */ p("p", {
|
|
66
179
|
className: "text-lg font-bold",
|
|
67
|
-
children: [
|
|
180
|
+
children: [U.progress, "%"]
|
|
68
181
|
}),
|
|
69
|
-
/* @__PURE__ */
|
|
182
|
+
/* @__PURE__ */ f("p", {
|
|
70
183
|
className: "text-xs text-text-secondary",
|
|
71
184
|
children: "Progress"
|
|
72
185
|
})
|
|
73
186
|
]
|
|
74
187
|
}) }),
|
|
75
|
-
/* @__PURE__ */
|
|
188
|
+
/* @__PURE__ */ f(g, { children: /* @__PURE__ */ p(_, {
|
|
76
189
|
className: "p-4 text-center",
|
|
77
190
|
children: [
|
|
78
|
-
/* @__PURE__ */
|
|
79
|
-
/* @__PURE__ */
|
|
191
|
+
/* @__PURE__ */ f(a, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
|
|
192
|
+
/* @__PURE__ */ p("p", {
|
|
80
193
|
className: "text-lg font-bold",
|
|
81
194
|
children: [
|
|
82
195
|
"$",
|
|
83
|
-
(
|
|
196
|
+
(U.budget / 1e3).toFixed(0),
|
|
84
197
|
"K"
|
|
85
198
|
]
|
|
86
199
|
}),
|
|
87
|
-
/* @__PURE__ */
|
|
200
|
+
/* @__PURE__ */ f("p", {
|
|
88
201
|
className: "text-xs text-text-secondary",
|
|
89
202
|
children: "Budget"
|
|
90
203
|
})
|
|
91
204
|
]
|
|
92
205
|
}) }),
|
|
93
|
-
/* @__PURE__ */
|
|
206
|
+
/* @__PURE__ */ f(g, { children: /* @__PURE__ */ p(_, {
|
|
94
207
|
className: "p-4 text-center",
|
|
95
208
|
children: [
|
|
96
|
-
/* @__PURE__ */
|
|
97
|
-
/* @__PURE__ */
|
|
209
|
+
/* @__PURE__ */ f(u, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
|
|
210
|
+
/* @__PURE__ */ f("p", {
|
|
98
211
|
className: "text-lg font-bold",
|
|
99
|
-
children:
|
|
212
|
+
children: U.teamName
|
|
100
213
|
}),
|
|
101
|
-
/* @__PURE__ */
|
|
214
|
+
/* @__PURE__ */ f("p", {
|
|
102
215
|
className: "text-xs text-text-secondary",
|
|
103
216
|
children: "Team"
|
|
104
217
|
})
|
|
105
218
|
]
|
|
106
219
|
}) }),
|
|
107
|
-
/* @__PURE__ */
|
|
220
|
+
/* @__PURE__ */ f(g, { children: /* @__PURE__ */ p(_, {
|
|
108
221
|
className: "p-4 text-center",
|
|
109
222
|
children: [
|
|
110
|
-
/* @__PURE__ */
|
|
111
|
-
/* @__PURE__ */
|
|
223
|
+
/* @__PURE__ */ f(i, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
|
|
224
|
+
/* @__PURE__ */ f("p", {
|
|
112
225
|
className: "text-lg font-bold",
|
|
113
|
-
children:
|
|
226
|
+
children: U.endDate
|
|
114
227
|
}),
|
|
115
|
-
/* @__PURE__ */
|
|
228
|
+
/* @__PURE__ */ f("p", {
|
|
116
229
|
className: "text-xs text-text-secondary",
|
|
117
230
|
children: "Deadline"
|
|
118
231
|
})
|
|
@@ -120,79 +233,125 @@ function y() {
|
|
|
120
233
|
}) })
|
|
121
234
|
]
|
|
122
235
|
}),
|
|
123
|
-
/* @__PURE__ */
|
|
236
|
+
/* @__PURE__ */ p(b, { children: [/* @__PURE__ */ f("div", {
|
|
124
237
|
className: "mb-2 text-lg font-semibold",
|
|
125
238
|
children: "Task Progress"
|
|
126
|
-
}), /* @__PURE__ */
|
|
239
|
+
}), /* @__PURE__ */ p("div", {
|
|
127
240
|
className: "space-y-2",
|
|
128
|
-
children: [/* @__PURE__ */
|
|
241
|
+
children: [/* @__PURE__ */ p("div", {
|
|
129
242
|
className: "flex justify-between text-sm",
|
|
130
|
-
children: [/* @__PURE__ */
|
|
131
|
-
|
|
243
|
+
children: [/* @__PURE__ */ p("span", { children: [
|
|
244
|
+
U.completedTasks,
|
|
132
245
|
" of ",
|
|
133
|
-
|
|
246
|
+
U.tasks,
|
|
134
247
|
" tasks completed"
|
|
135
|
-
] }), /* @__PURE__ */
|
|
248
|
+
] }), /* @__PURE__ */ p("span", {
|
|
136
249
|
className: "font-medium",
|
|
137
|
-
children: [
|
|
250
|
+
children: [U.progress, "%"]
|
|
138
251
|
})]
|
|
139
|
-
}), /* @__PURE__ */
|
|
252
|
+
}), /* @__PURE__ */ f("div", {
|
|
140
253
|
className: "h-3 bg-bg-sunken rounded overflow-hidden",
|
|
141
|
-
children: /* @__PURE__ */
|
|
254
|
+
children: /* @__PURE__ */ f("div", {
|
|
142
255
|
className: "h-3 bg-action-primary-bg rounded",
|
|
143
|
-
style: { width: `${
|
|
256
|
+
style: { width: `${U.progress}%` }
|
|
144
257
|
})
|
|
145
258
|
})]
|
|
146
259
|
})] }),
|
|
147
|
-
/* @__PURE__ */
|
|
260
|
+
/* @__PURE__ */ p(g, { children: [/* @__PURE__ */ f(v, { children: /* @__PURE__ */ f(y, { children: "Budget Tracking" }) }), /* @__PURE__ */ p(_, { children: [/* @__PURE__ */ p("div", {
|
|
148
261
|
className: "space-y-2",
|
|
149
|
-
children: [/* @__PURE__ */
|
|
262
|
+
children: [/* @__PURE__ */ p("div", {
|
|
150
263
|
className: "flex justify-between text-sm",
|
|
151
|
-
children: [/* @__PURE__ */
|
|
264
|
+
children: [/* @__PURE__ */ p("span", { children: [
|
|
152
265
|
"Spent $",
|
|
153
|
-
(
|
|
266
|
+
(U.spent / 1e3).toFixed(0),
|
|
154
267
|
"K of $",
|
|
155
|
-
(
|
|
268
|
+
(U.budget / 1e3).toFixed(0),
|
|
156
269
|
"K"
|
|
157
|
-
] }), /* @__PURE__ */
|
|
270
|
+
] }), /* @__PURE__ */ p("span", {
|
|
158
271
|
className: "font-medium",
|
|
159
|
-
children: [Math.round(
|
|
272
|
+
children: [Math.round(U.spent / U.budget * 100), "%"]
|
|
160
273
|
})]
|
|
161
|
-
}), /* @__PURE__ */
|
|
274
|
+
}), /* @__PURE__ */ f("div", {
|
|
162
275
|
className: "h-3 bg-bg-sunken rounded overflow-hidden",
|
|
163
|
-
children: /* @__PURE__ */
|
|
164
|
-
className: `h-3 rounded ${
|
|
165
|
-
style: { width: `${Math.round(
|
|
276
|
+
children: /* @__PURE__ */ f("div", {
|
|
277
|
+
className: `h-3 rounded ${U.spent / U.budget > .9 ? "bg-status-error-text" : "bg-status-success-text"}`,
|
|
278
|
+
style: { width: `${Math.round(U.spent / U.budget * 100)}%` }
|
|
166
279
|
})
|
|
167
280
|
})]
|
|
168
|
-
}), /* @__PURE__ */
|
|
281
|
+
}), /* @__PURE__ */ p("div", {
|
|
169
282
|
className: "grid grid-cols-2 gap-4 mt-4 text-sm",
|
|
170
|
-
children: [/* @__PURE__ */
|
|
283
|
+
children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
|
|
171
284
|
className: "text-xs text-text-secondary",
|
|
172
285
|
children: "Manager"
|
|
173
|
-
}), /* @__PURE__ */
|
|
286
|
+
}), /* @__PURE__ */ f("p", {
|
|
174
287
|
className: "font-medium",
|
|
175
|
-
children:
|
|
176
|
-
})] }), /* @__PURE__ */
|
|
288
|
+
children: U.managerName
|
|
289
|
+
})] }), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
|
|
177
290
|
className: "text-xs text-text-secondary",
|
|
178
291
|
children: "Timeline"
|
|
179
|
-
}), /* @__PURE__ */
|
|
180
|
-
|
|
292
|
+
}), /* @__PURE__ */ p("p", { children: [
|
|
293
|
+
U.startDate,
|
|
181
294
|
" — ",
|
|
182
|
-
|
|
295
|
+
U.endDate
|
|
183
296
|
] })] })]
|
|
184
|
-
})] })] })
|
|
297
|
+
})] })] }),
|
|
298
|
+
/* @__PURE__ */ f(t, {
|
|
299
|
+
open: R.open,
|
|
300
|
+
onOpenChange: R.onOpenChange,
|
|
301
|
+
title: "Edit Project",
|
|
302
|
+
description: `Update the details for ${U.name}.`,
|
|
303
|
+
fields: M,
|
|
304
|
+
initialValues: W,
|
|
305
|
+
submitLabel: "Save Changes",
|
|
306
|
+
onSubmit: async (e) => {
|
|
307
|
+
let t = {
|
|
308
|
+
name: String(e.name ?? "").trim(),
|
|
309
|
+
description: String(e.description ?? "").trim(),
|
|
310
|
+
status: String(e.status ?? U.status),
|
|
311
|
+
priority: String(e.priority ?? U.priority)
|
|
312
|
+
};
|
|
313
|
+
typeof e.budget == "number" && !Number.isNaN(e.budget) && (t.budget = e.budget), typeof e.progress == "number" && !Number.isNaN(e.progress) && (t.progress = e.progress), await I(U.id, t), P("Project updated", "success");
|
|
314
|
+
}
|
|
315
|
+
}),
|
|
316
|
+
/* @__PURE__ */ f(T, {
|
|
317
|
+
open: z,
|
|
318
|
+
onOpenChange: B,
|
|
319
|
+
children: /* @__PURE__ */ p(E, {
|
|
320
|
+
className: "sm:max-w-[440px]",
|
|
321
|
+
children: [/* @__PURE__ */ p(k, { children: [/* @__PURE__ */ p(A, { children: [
|
|
322
|
+
"Delete ",
|
|
323
|
+
U.name,
|
|
324
|
+
"?"
|
|
325
|
+
] }), /* @__PURE__ */ f(D, { children: "This permanently removes the project and its tracking data. This cannot be undone." })] }), /* @__PURE__ */ p(O, { children: [/* @__PURE__ */ f(h, {
|
|
326
|
+
type: "button",
|
|
327
|
+
variant: "outline",
|
|
328
|
+
onClick: () => B(!1),
|
|
329
|
+
disabled: V,
|
|
330
|
+
children: "Cancel"
|
|
331
|
+
}), /* @__PURE__ */ f(h, {
|
|
332
|
+
type: "button",
|
|
333
|
+
variant: "destructive",
|
|
334
|
+
onClick: async () => {
|
|
335
|
+
if (!V) {
|
|
336
|
+
H(!0);
|
|
337
|
+
try {
|
|
338
|
+
await L(U.id), P("Project deleted", "success"), B(!1), N("../../projects/projects-page");
|
|
339
|
+
} catch (e) {
|
|
340
|
+
P(e instanceof Error ? e.message : "Unable to delete project", "error");
|
|
341
|
+
} finally {
|
|
342
|
+
H(!1);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
disabled: V,
|
|
347
|
+
children: V ? "Deleting…" : "Delete Project"
|
|
348
|
+
})] })]
|
|
349
|
+
})
|
|
350
|
+
})
|
|
185
351
|
]
|
|
186
|
-
}) : /* @__PURE__ */ s("div", {
|
|
187
|
-
className: "p-6",
|
|
188
|
-
children: /* @__PURE__ */ s(g, {
|
|
189
|
-
illustration: "empty-search",
|
|
190
|
-
title: "Project not found",
|
|
191
|
-
description: "This project is no longer available."
|
|
192
|
-
})
|
|
193
352
|
});
|
|
194
353
|
}
|
|
195
354
|
//#endregion
|
|
196
|
-
export {
|
|
355
|
+
export { N as ProjectsProjectDetailsPagePage };
|
|
197
356
|
|
|
198
357
|
//# sourceMappingURL=ProjectsProjectDetailsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectsProjectDetailsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/ProjectsProjectDetailsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Calendar, DollarSign, FolderKanban, Target, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function ProjectsProjectDetailsPagePage() {\n const navigate = useNavigate();\n const { projects } = useCrewFoundryStore();\n const project = projects[1]; // Show second project for variety\n if (!project)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Project not found\"\n description=\"This project is no longer available.\"\n />\n </div>\n );\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{project.name}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{project.description}</p>\n </div>\n <div className=\"flex gap-1\">\n <Badge variant={project.priority === 'critical' ? 'destructive' : 'default'}>\n {project.priority}\n </Badge>\n <Badge variant={project.status === 'active' ? 'default' : 'secondary'}>\n {project.status}\n </Badge>\n </div>\n </div>\n <PagePurpose>\n Track a single project end-to-end — progress, budget, team, and timeline in one place — so\n you can spot risks early and keep delivery on schedule and on budget.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"crewfoundry-project-details\"\n steps={[\n {\n id: 'all-projects',\n label: 'View all projects',\n description: 'See how this project compares across your portfolio.',\n icon: <FolderKanban className=\"h-4 w-4\" />,\n onClick: () => navigate('../../projects/projects-page'),\n },\n {\n id: 'team',\n label: 'Check the team',\n description: 'Review who is working on this and their workload.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('../../teams/teams-page'),\n },\n {\n id: 'new-project',\n label: 'Start a new project',\n description: 'Kick off the next piece of work.',\n icon: <Target className=\"h-4 w-4\" />,\n onClick: () => navigate('../../projects/create-project-page'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Target className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{project.progress}%</p>\n <p className=\"text-xs text-text-secondary\">Progress</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <DollarSign className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">${(project.budget / 1000).toFixed(0)}K</p>\n <p className=\"text-xs text-text-secondary\">Budget</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Users className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{project.teamName}</p>\n <p className=\"text-xs text-text-secondary\">Team</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Calendar className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{project.endDate}</p>\n <p className=\"text-xs text-text-secondary\">Deadline</p>\n </CardContent>\n </Card>\n </div>\n <EmphasisPanel>\n <div className=\"mb-2 text-lg font-semibold\">Task Progress</div>\n <div className=\"space-y-2\">\n <div className=\"flex justify-between text-sm\">\n <span>\n {project.completedTasks} of {project.tasks} tasks completed\n </span>\n <span className=\"font-medium\">{project.progress}%</span>\n </div>\n <div className=\"h-3 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-3 bg-action-primary-bg rounded\"\n style={{ width: `${project.progress}%` }}\n />\n </div>\n </div>\n </EmphasisPanel>\n <Card>\n <CardHeader>\n <CardTitle>Budget Tracking</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2\">\n <div className=\"flex justify-between text-sm\">\n <span>\n Spent ${(project.spent / 1000).toFixed(0)}K of ${(project.budget / 1000).toFixed(0)}\n K\n </span>\n <span className=\"font-medium\">\n {Math.round((project.spent / project.budget) * 100)}%\n </span>\n </div>\n <div className=\"h-3 bg-bg-sunken rounded overflow-hidden\">\n <div\n className={`h-3 rounded ${project.spent / project.budget > 0.9 ? 'bg-status-error-text' : 'bg-status-success-text'}`}\n style={{ width: `${Math.round((project.spent / project.budget) * 100)}%` }}\n />\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4 mt-4 text-sm\">\n <div>\n <p className=\"text-xs text-text-secondary\">Manager</p>\n <p className=\"font-medium\">{project.managerName}</p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Timeline</p>\n <p>\n {project.startDate} — {project.endDate}\n </p>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProjectsProjectDetailsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/ProjectsProjectDetailsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { Calendar, DollarSign, FolderKanban, Pencil, Target, Trash2, 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 Project } from '../store/crewfoundryStore';\n\nconst PROJECT_EDIT_FIELDS: FieldConfig[] = [\n { name: 'name', label: 'Project Name', type: 'text', required: true, colSpan: 2 },\n { name: 'description', label: 'Description', type: 'textarea', colSpan: 2 },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n options: [\n { label: 'Planning', value: 'planning' },\n { label: 'Active', value: 'active' },\n { label: 'On Hold', value: 'on_hold' },\n { label: 'Completed', value: 'completed' },\n { label: 'Cancelled', value: 'cancelled' },\n ],\n },\n {\n name: 'priority',\n label: 'Priority',\n type: 'select',\n options: [\n { label: 'Low', value: 'low' },\n { label: 'Medium', value: 'medium' },\n { label: 'High', value: 'high' },\n { label: 'Critical', value: 'critical' },\n ],\n },\n { name: 'budget', label: 'Budget ($)', type: 'number' },\n { name: 'progress', label: 'Progress (%)', type: 'number' },\n];\n\nexport function ProjectsProjectDetailsPagePage() {\n const navigate = useNavigate();\n const { showToast } = useGlobalUi();\n const projects = useCrewFoundryStore((state) => state.projects);\n const updateProject = useCrewFoundryStore((state) => state.updateProject);\n const removeProject = useCrewFoundryStore((state) => state.removeProject);\n const editModal = useFormModal();\n const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);\n const [deleting, setDeleting] = useState(false);\n const project = projects[1]; // Show second project for variety\n if (!project)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Project not found\"\n description=\"This project is no longer available.\"\n />\n </div>\n );\n\n const editInitialValues: FormValues = {\n name: project.name,\n description: project.description,\n status: project.status,\n priority: project.priority,\n budget: project.budget,\n progress: project.progress,\n };\n\n const handleEdit = async (values: FormValues) => {\n const updates: Partial<Project> = {\n name: String(values.name ?? '').trim(),\n description: String(values.description ?? '').trim(),\n status: String(values.status ?? project.status) as Project['status'],\n priority: String(values.priority ?? project.priority) as Project['priority'],\n };\n if (typeof values.budget === 'number' && !Number.isNaN(values.budget)) {\n updates.budget = values.budget;\n }\n if (typeof values.progress === 'number' && !Number.isNaN(values.progress)) {\n updates.progress = values.progress;\n }\n await updateProject(project.id, updates);\n showToast('Project updated', 'success');\n };\n\n const handleDelete = async () => {\n if (deleting) return;\n setDeleting(true);\n try {\n await removeProject(project.id);\n showToast('Project deleted', 'success');\n setConfirmDeleteOpen(false);\n navigate('../../projects/projects-page');\n } catch (error) {\n showToast(error instanceof Error ? error.message : 'Unable to delete project', 'error');\n } finally {\n setDeleting(false);\n }\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{project.name}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{project.description}</p>\n </div>\n <div className=\"flex items-center gap-2\">\n <div className=\"hidden gap-1 sm:flex\">\n <Badge variant={project.priority === 'critical' ? 'destructive' : 'default'}>\n {project.priority}\n </Badge>\n <Badge variant={project.status === 'active' ? 'default' : 'secondary'}>\n {project.status}\n </Badge>\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={() => editModal.openModal()}>\n <Pencil className=\"h-4 w-4 mr-1\" />\n Edit\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"Delete project\"\n className=\"h-9 w-9 p-0 text-text-secondary hover:text-status-error-text\"\n onClick={() => setConfirmDeleteOpen(true)}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n <PagePurpose>\n Track a single project end-to-end — progress, budget, team, and timeline in one place — so\n you can spot risks early and keep delivery on schedule and on budget.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"crewfoundry-project-details\"\n steps={[\n {\n id: 'all-projects',\n label: 'View all projects',\n description: 'See how this project compares across your portfolio.',\n icon: <FolderKanban className=\"h-4 w-4\" />,\n onClick: () => navigate('../../projects/projects-page'),\n },\n {\n id: 'team',\n label: 'Check the team',\n description: 'Review who is working on this and their workload.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('../../teams/teams-page'),\n },\n {\n id: 'new-project',\n label: 'Start a new project',\n description: 'Kick off the next piece of work.',\n icon: <Target className=\"h-4 w-4\" />,\n onClick: () => navigate('../../projects/create-project-page'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Target className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{project.progress}%</p>\n <p className=\"text-xs text-text-secondary\">Progress</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <DollarSign className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">${(project.budget / 1000).toFixed(0)}K</p>\n <p className=\"text-xs text-text-secondary\">Budget</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Users className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{project.teamName}</p>\n <p className=\"text-xs text-text-secondary\">Team</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Calendar className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{project.endDate}</p>\n <p className=\"text-xs text-text-secondary\">Deadline</p>\n </CardContent>\n </Card>\n </div>\n <EmphasisPanel>\n <div className=\"mb-2 text-lg font-semibold\">Task Progress</div>\n <div className=\"space-y-2\">\n <div className=\"flex justify-between text-sm\">\n <span>\n {project.completedTasks} of {project.tasks} tasks completed\n </span>\n <span className=\"font-medium\">{project.progress}%</span>\n </div>\n <div className=\"h-3 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-3 bg-action-primary-bg rounded\"\n style={{ width: `${project.progress}%` }}\n />\n </div>\n </div>\n </EmphasisPanel>\n <Card>\n <CardHeader>\n <CardTitle>Budget Tracking</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2\">\n <div className=\"flex justify-between text-sm\">\n <span>\n Spent ${(project.spent / 1000).toFixed(0)}K of ${(project.budget / 1000).toFixed(0)}\n K\n </span>\n <span className=\"font-medium\">\n {Math.round((project.spent / project.budget) * 100)}%\n </span>\n </div>\n <div className=\"h-3 bg-bg-sunken rounded overflow-hidden\">\n <div\n className={`h-3 rounded ${project.spent / project.budget > 0.9 ? 'bg-status-error-text' : 'bg-status-success-text'}`}\n style={{ width: `${Math.round((project.spent / project.budget) * 100)}%` }}\n />\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4 mt-4 text-sm\">\n <div>\n <p className=\"text-xs text-text-secondary\">Manager</p>\n <p className=\"font-medium\">{project.managerName}</p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Timeline</p>\n <p>\n {project.startDate} — {project.endDate}\n </p>\n </div>\n </div>\n </CardContent>\n </Card>\n\n <FormModal\n open={editModal.open}\n onOpenChange={editModal.onOpenChange}\n title=\"Edit Project\"\n description={`Update the details for ${project.name}.`}\n fields={PROJECT_EDIT_FIELDS}\n initialValues={editInitialValues}\n submitLabel=\"Save Changes\"\n onSubmit={handleEdit}\n />\n\n <ResponsiveDialog open={confirmDeleteOpen} onOpenChange={setConfirmDeleteOpen}>\n <ResponsiveDialogContent className=\"sm:max-w-[440px]\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Delete {project.name}?</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n This permanently removes the project and its tracking data. This cannot be undone.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setConfirmDeleteOpen(false)}\n disabled={deleting}\n >\n Cancel\n </Button>\n <Button type=\"button\" variant=\"destructive\" onClick={handleDelete} disabled={deleting}>\n {deleting ? 'Deleting…' : 'Delete Project'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </div>\n );\n}\n"],"mappings":"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"}
|