@burdenoff/microfe-timecampus 2026.626.2 → 2026.703.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/generated/wspace-operations.js +996 -816
  2. package/dist/generated/wspace-operations.js.map +1 -1
  3. package/dist/generated/wspace-types.js +28 -0
  4. package/dist/generated/wspace-types.js.map +1 -0
  5. package/dist/index.js +4 -4
  6. package/dist/timecampus/TimeCampusRoutes.js +16 -12
  7. package/dist/timecampus/TimeCampusRoutes.js.map +1 -1
  8. package/dist/timecampus/components/Modal.js +65 -0
  9. package/dist/timecampus/components/Modal.js.map +1 -0
  10. package/dist/timecampus/components/StatusBadge.js +28 -0
  11. package/dist/timecampus/components/StatusBadge.js.map +1 -0
  12. package/dist/timecampus/components/Toast.js +87 -0
  13. package/dist/timecampus/components/Toast.js.map +1 -0
  14. package/dist/timecampus/index.js +1 -1
  15. package/dist/timecampus/pages/HomePage.js +143 -135
  16. package/dist/timecampus/pages/HomePage.js.map +1 -1
  17. package/dist/timecampus/pages/applets/AppletStorePage.js +14 -19
  18. package/dist/timecampus/pages/applets/AppletStorePage.js.map +1 -1
  19. package/dist/timecampus/pages/applets/InstalledAppletsPage.js +49 -37
  20. package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +1 -1
  21. package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +315 -87
  22. package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
  23. package/dist/timecampus/pages/channels/ChannelsPage.js +340 -46
  24. package/dist/timecampus/pages/channels/ChannelsPage.js.map +1 -1
  25. package/dist/timecampus/pages/client-portal/ClientPortalPage.js +374 -92
  26. package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
  27. package/dist/timecampus/pages/dashboard/ReportsPage.js +70 -37
  28. package/dist/timecampus/pages/dashboard/ReportsPage.js.map +1 -1
  29. package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +366 -60
  30. package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js.map +1 -1
  31. package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +461 -87
  32. package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
  33. package/dist/timecampus/pages/geofencing/GeofencingPage.js +314 -55
  34. package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
  35. package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +30 -27
  36. package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +1 -1
  37. package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +269 -74
  38. package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
  39. package/dist/timecampus/pages/meetings/ActionItemFormModal.js +127 -0
  40. package/dist/timecampus/pages/meetings/ActionItemFormModal.js.map +1 -0
  41. package/dist/timecampus/pages/meetings/MeetingCreatePage.js +62 -52
  42. package/dist/timecampus/pages/meetings/MeetingCreatePage.js.map +1 -1
  43. package/dist/timecampus/pages/meetings/MeetingDetailPage.js +361 -74
  44. package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
  45. package/dist/timecampus/pages/meetings/MeetingFormModal.js +156 -0
  46. package/dist/timecampus/pages/meetings/MeetingFormModal.js.map +1 -0
  47. package/dist/timecampus/pages/meetings/MeetingsPage.js +175 -74
  48. package/dist/timecampus/pages/meetings/MeetingsPage.js.map +1 -1
  49. package/dist/timecampus/pages/meetings/ParticipantFormModal.js +105 -0
  50. package/dist/timecampus/pages/meetings/ParticipantFormModal.js.map +1 -0
  51. package/dist/timecampus/pages/pomodoro/PomodoroPage.js +307 -67
  52. package/dist/timecampus/pages/pomodoro/PomodoroPage.js.map +1 -1
  53. package/dist/timecampus/pages/projects/ProjectCreatePage.js +51 -48
  54. package/dist/timecampus/pages/projects/ProjectCreatePage.js.map +1 -1
  55. package/dist/timecampus/pages/projects/ProjectDetailPage.js +248 -51
  56. package/dist/timecampus/pages/projects/ProjectDetailPage.js.map +1 -1
  57. package/dist/timecampus/pages/projects/ProjectsPage.js +354 -87
  58. package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
  59. package/dist/timecampus/pages/projects/TasksPage.js +367 -65
  60. package/dist/timecampus/pages/projects/TasksPage.js.map +1 -1
  61. package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +674 -104
  62. package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
  63. package/dist/timecampus/pages/team/TeamAnalyticsPage.js +46 -34
  64. package/dist/timecampus/pages/team/TeamAnalyticsPage.js.map +1 -1
  65. package/dist/timecampus/pages/team/TeamMembersPage.js +93 -69
  66. package/dist/timecampus/pages/team/TeamMembersPage.js.map +1 -1
  67. package/dist/timecampus/pages/team/TeamPage.js +4 -3
  68. package/dist/timecampus/pages/team/TeamPage.js.map +1 -1
  69. package/dist/timecampus/pages/templates/TemplateDetailPage.js +72 -53
  70. package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +1 -1
  71. package/dist/timecampus/pages/templates/TemplatesPage.js +40 -35
  72. package/dist/timecampus/pages/templates/TemplatesPage.js.map +1 -1
  73. package/dist/timecampus/pages/time/TimeEntriesPage.js +484 -97
  74. package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
  75. package/dist/timecampus/pages/time/TimeTrackingPage.js +210 -99
  76. package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
  77. package/dist/timecampus/pages/time/TimerPage.js +229 -97
  78. package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
  79. package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +315 -110
  80. package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
  81. package/dist/timecampus/pages/timeline/TimelinePage.js +250 -0
  82. package/dist/timecampus/pages/timeline/TimelinePage.js.map +1 -0
  83. package/dist/timecampus/pages/widgets/WidgetDetailPage.js +158 -76
  84. package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +1 -1
  85. package/dist/timecampus/pages/widgets/WidgetsPage.js +181 -52
  86. package/dist/timecampus/pages/widgets/WidgetsPage.js.map +1 -1
  87. package/dist/timecampus/pages/workflows/WorkflowsPage.js +212 -61
  88. package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +1 -1
  89. package/dist/timecampus/store/timecampusStore.js +13 -1
  90. package/dist/timecampus/store/timecampusStore.js.map +1 -1
  91. package/dist/timecampus/utils/helpers.js +20 -10
  92. package/dist/timecampus/utils/helpers.js.map +1 -1
  93. package/package.json +1 -1
@@ -1,133 +1,703 @@
1
- import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
2
- import { getInitials as t } from "../../utils/helpers.js";
1
+ import { getInitials as e, getStatusColor as t } from "../../utils/helpers.js";
3
2
  import { StatCard as n } from "../../components/StatCard.js";
4
3
  import { LoadingSkeleton as r } from "../../components/LoadingSkeleton.js";
5
- import { useGetCapacityOverviewQuery as i, useListResourcePlansQuery as a } from "../../../generated/wspace-operations.js";
6
- import { PageLayout as o } from "../../components/PageLayout.js";
7
- import { EmptyState as s } from "../../components/EmptyState.js";
8
- import { CalendarRange as c, TrendingUp as l, Users as u } from "lucide-react";
9
- import { jsx as d, jsxs as f } from "react/jsx-runtime";
4
+ import { useBulkCreateAllocationsMutation as ee, useCreateAllocationMutation as te, useCreateResourcePlanMutation as ne, useDeleteAllocationMutation as re, useDeleteResourcePlanMutation as ie, useGetCapacityOverviewQuery as ae, useListResourcePlansQuery as oe, useUpdateAllocationMutation as se, useUpdateResourcePlanMutation as ce } from "../../../generated/wspace-operations.js";
5
+ import { PageLayout as i } from "../../components/PageLayout.js";
6
+ import { EmptyState as le } from "../../components/EmptyState.js";
7
+ import { Modal as a } from "../../components/Modal.js";
8
+ import { useState as o } from "react";
9
+ import { CalendarRange as ue, Pencil as s, Plus as c, Trash2 as l, TrendingUp as de, UserPlus as fe, Users as u } from "lucide-react";
10
+ import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
10
11
  //#region src/timecampus/pages/resource-planning/ResourcePlanningPage.tsx
11
- function p() {
12
- let { workspaceId: p = "" } = e(), m = /* @__PURE__ */ new Date(), h = new Date(m.getFullYear(), m.getMonth(), m.getDate()).toISOString(), g = new Date(m.getFullYear(), m.getMonth(), m.getDate() + 7).toISOString(), { data: _, loading: v, error: y } = a(), { data: b } = i({ variables: {
13
- startDate: h,
14
- endDate: g
15
- } }), x = _?.resourcePlans?.items ?? [], S = b?.capacityOverview, C = x.flatMap((e) => e.allocations.map((t) => ({
16
- ...t,
17
- planName: e.name
18
- })));
19
- if (v) return /* @__PURE__ */ d(o, {
12
+ var m = 25, h = "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary", g = (e) => e.slice(0, 10), _ = (e) => new Date(e).toISOString(), v = () => {
13
+ let e = /* @__PURE__ */ new Date(), t = new Date(e.getFullYear(), e.getMonth(), e.getDate()), n = new Date(e.getFullYear(), e.getMonth(), e.getDate() + 7);
14
+ return {
15
+ name: "",
16
+ description: "",
17
+ startDate: g(t.toISOString()),
18
+ endDate: g(n.toISOString()),
19
+ status: "active"
20
+ };
21
+ }, y = (e) => ({
22
+ userId: "",
23
+ allocatedHours: "",
24
+ startDate: e ? g(e.startDate) : "",
25
+ endDate: e ? g(e.endDate) : "",
26
+ notes: ""
27
+ });
28
+ function b() {
29
+ let b = /* @__PURE__ */ new Date(), pe = new Date(b.getFullYear(), b.getMonth(), b.getDate()).toISOString(), me = new Date(b.getFullYear(), b.getMonth(), b.getDate() + 7).toISOString(), { data: x, loading: he, error: ge, refetch: _e, fetchMore: ve } = oe({ variables: {
30
+ limit: m,
31
+ offset: 0
32
+ } }), { data: ye, refetch: be } = ae({ variables: {
33
+ startDate: pe,
34
+ endDate: me
35
+ } }), [xe, { loading: S, error: Se }] = ne(), [Ce, { loading: C, error: we }] = ce(), [Te, { loading: w }] = ie(), [Ee, { loading: T }] = te(), [De, { loading: E }] = ee(), [Oe, { loading: D, error: ke }] = se(), [Ae, { loading: O }] = re(), [je, k] = o(!1), [A, j] = o(null), [M, N] = o(v()), [P, F] = o(null), [I, L] = o(null), [R, z] = o([]), [Me, B] = o(!1), [V, H] = o(null), [U, W] = o(null), [G, K] = o(null), [q, J] = o(!1), Y = x?.resourcePlans?.items ?? [], Ne = x?.resourcePlans?.hasMore ?? !1, X = ye?.capacityOverview, Z = async () => {
36
+ await Promise.all([_e(), be()]);
37
+ }, Pe = () => {
38
+ j(null), N(v()), k(!0);
39
+ }, Fe = (e) => {
40
+ j(e), N({
41
+ name: e.name,
42
+ description: e.description ?? "",
43
+ startDate: g(e.startDate),
44
+ endDate: g(e.endDate),
45
+ status: e.status
46
+ }), k(!0);
47
+ }, Ie = async () => {
48
+ M.name.trim() && (A ? await Ce({ variables: {
49
+ id: A.id,
50
+ input: {
51
+ name: M.name.trim(),
52
+ description: M.description.trim() || void 0,
53
+ startDate: _(M.startDate),
54
+ endDate: _(M.endDate),
55
+ status: M.status
56
+ }
57
+ } }) : await xe({ variables: { input: {
58
+ name: M.name.trim(),
59
+ description: M.description.trim() || void 0,
60
+ startDate: _(M.startDate),
61
+ endDate: _(M.endDate)
62
+ } } }), k(!1), await Z());
63
+ }, Le = async () => {
64
+ P && (await Te({ variables: { id: P.id } }), F(null), await Z());
65
+ }, Re = (e) => {
66
+ L(e), z([y(e)]), B(!1);
67
+ }, Q = (e, t) => {
68
+ z((n) => n.map((n, r) => r === e ? {
69
+ ...n,
70
+ ...t
71
+ } : n));
72
+ }, ze = () => {
73
+ z((e) => [...e, y(I ?? void 0)]);
74
+ }, Be = (e) => {
75
+ z((t) => t.filter((t, n) => n !== e));
76
+ }, $ = R.every((e) => e.userId.trim() !== "" && e.allocatedHours.trim() !== "" && e.startDate !== "" && e.endDate !== ""), Ve = async () => {
77
+ if (!(!I || !$ || R.length === 0)) {
78
+ B(!1);
79
+ try {
80
+ if (R.length === 1) {
81
+ let e = R[0];
82
+ await Ee({ variables: { input: {
83
+ resourcePlanId: I.id,
84
+ userId: e.userId.trim(),
85
+ allocatedHours: Number(e.allocatedHours),
86
+ startDate: _(e.startDate),
87
+ endDate: _(e.endDate),
88
+ notes: e.notes.trim() || void 0
89
+ } } });
90
+ } else await De({ variables: {
91
+ planId: I.id,
92
+ allocations: R.map((e) => ({
93
+ userId: e.userId.trim(),
94
+ allocatedHours: Number(e.allocatedHours),
95
+ startDate: _(e.startDate),
96
+ endDate: _(e.endDate),
97
+ notes: e.notes.trim() || void 0
98
+ }))
99
+ } });
100
+ L(null), await Z();
101
+ } catch {
102
+ B(!0);
103
+ }
104
+ }
105
+ }, He = (e) => {
106
+ H(e), W({
107
+ userId: e.userId,
108
+ allocatedHours: String(e.allocatedHours),
109
+ actualHours: String(e.actualHours),
110
+ startDate: g(e.startDate),
111
+ endDate: g(e.endDate),
112
+ notes: e.notes ?? ""
113
+ });
114
+ }, Ue = async () => {
115
+ !V || !U || (await Oe({ variables: {
116
+ id: V.id,
117
+ input: {
118
+ userId: U.userId.trim(),
119
+ allocatedHours: Number(U.allocatedHours),
120
+ actualHours: Number(U.actualHours),
121
+ startDate: _(U.startDate),
122
+ endDate: _(U.endDate),
123
+ notes: U.notes.trim() || void 0
124
+ }
125
+ } }), H(null), W(null), await Z());
126
+ }, We = async () => {
127
+ G && (await Ae({ variables: { id: G.id } }), K(null), await Z());
128
+ }, Ge = async () => {
129
+ J(!0);
130
+ try {
131
+ await ve({
132
+ variables: {
133
+ limit: m,
134
+ offset: Y.length
135
+ },
136
+ updateQuery: (e, { fetchMoreResult: t }) => t ? { resourcePlans: {
137
+ ...t.resourcePlans,
138
+ items: [...e.resourcePlans.items, ...t.resourcePlans.items]
139
+ } } : e
140
+ });
141
+ } finally {
142
+ J(!1);
143
+ }
144
+ }, Ke = /* @__PURE__ */ p("button", {
145
+ onClick: Pe,
146
+ className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
147
+ children: [/* @__PURE__ */ f(c, { className: "h-4 w-4" }), "New Resource Plan"]
148
+ });
149
+ if (he) return /* @__PURE__ */ f(i, {
20
150
  title: "Resource Planning",
21
151
  description: "Plan and optimize team resource allocation",
22
- children: /* @__PURE__ */ d(r, {
152
+ children: /* @__PURE__ */ f(r, {
23
153
  variant: "list",
24
154
  count: 5
25
155
  })
26
156
  });
27
- if (y) return /* @__PURE__ */ d(o, {
157
+ if (ge) return /* @__PURE__ */ f(i, {
28
158
  title: "Resource Planning",
29
159
  description: "Plan and optimize team resource allocation",
30
- children: /* @__PURE__ */ d("div", {
160
+ children: /* @__PURE__ */ f("div", {
31
161
  className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
32
162
  children: "Failed to load resource planning data. Please try again later."
33
163
  })
34
164
  });
35
- let w = S?.utilizationRate ?? 0, T = S?.overallocatedUsers?.length ?? 0, E = S?.availableCapacity ?? 0;
36
- return /* @__PURE__ */ f(o, {
165
+ let qe = X?.utilizationRate ?? 0, Je = X?.overallocatedUsers?.length ?? 0, Ye = X?.availableCapacity ?? 0;
166
+ return /* @__PURE__ */ p(i, {
37
167
  title: "Resource Planning",
38
168
  description: "Plan and optimize team resource allocation",
39
169
  purpose: "Match the work ahead to the people you have — see who's over- or under-booked and how much capacity is free this week — so you can commit to deadlines you can actually hit without burning anyone out.",
40
- children: [/* @__PURE__ */ f("div", {
41
- className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
42
- children: [
43
- /* @__PURE__ */ d(n, {
44
- featured: !0,
45
- title: "Team Utilization",
46
- value: `${Math.round(w)}%`,
47
- icon: /* @__PURE__ */ d(l, { className: "h-5 w-5" })
48
- }),
49
- /* @__PURE__ */ d(n, {
50
- title: "Over-allocated",
51
- value: String(T),
52
- icon: /* @__PURE__ */ d(u, { className: "h-5 w-5" }),
53
- iconBgColor: "bg-status-error-bg text-status-error-text"
54
- }),
55
- /* @__PURE__ */ d(n, {
56
- title: "Active Plans",
57
- value: String(x.length),
58
- icon: /* @__PURE__ */ d(u, { className: "h-5 w-5" })
59
- }),
60
- /* @__PURE__ */ d(n, {
61
- title: "Available Capacity",
62
- value: `${Math.round(E)}h`,
63
- icon: /* @__PURE__ */ d(c, { className: "h-5 w-5" }),
64
- description: "This week"
65
- })
66
- ]
67
- }), C.length === 0 ? /* @__PURE__ */ d(s, {
68
- illustration: "empty-people",
69
- title: "No resource allocations found",
70
- description: "Create a resource plan to start allocating team members and balancing workload across the week."
71
- }) : /* @__PURE__ */ d("div", {
72
- className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop",
73
- children: /* @__PURE__ */ d("div", {
74
- className: "divide-y divide-border",
75
- children: C.map((e) => {
76
- let n = e.utilizationRate ?? (e.allocatedHours > 0 ? Math.round(e.actualHours / e.allocatedHours * 100) : 0);
77
- return /* @__PURE__ */ f("div", {
78
- className: "flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors",
79
- children: [/* @__PURE__ */ f("div", {
80
- className: "flex items-center gap-3",
81
- children: [/* @__PURE__ */ d("div", {
82
- className: "flex h-9 w-9 items-center justify-center rounded-full bg-action-primary-bg/10 text-sm font-medium text-primary",
83
- children: t(e.userId)
84
- }), /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("p", {
85
- className: "text-sm font-medium text-text-primary",
86
- children: e.userId
87
- }), /* @__PURE__ */ f("p", {
88
- className: "text-xs text-text-secondary",
89
- children: [
90
- e.planName,
91
- " ·",
92
- " ",
93
- e.startDate.slice(0, 10),
94
- " to",
95
- " ",
96
- e.endDate.slice(0, 10)
97
- ]
98
- })] })]
99
- }), /* @__PURE__ */ f("div", {
100
- className: "flex items-center gap-4",
101
- children: [/* @__PURE__ */ d("div", {
102
- className: "text-right",
103
- children: /* @__PURE__ */ f("p", {
104
- className: "text-sm font-medium text-text-primary",
105
- children: [e.allocatedHours, "h allocated"]
170
+ actions: Ke,
171
+ children: [
172
+ /* @__PURE__ */ p("div", {
173
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
174
+ children: [
175
+ /* @__PURE__ */ f(n, {
176
+ featured: !0,
177
+ title: "Team Utilization",
178
+ value: `${Math.round(qe)}%`,
179
+ icon: /* @__PURE__ */ f(de, { className: "h-5 w-5" })
180
+ }),
181
+ /* @__PURE__ */ f(n, {
182
+ title: "Over-allocated",
183
+ value: String(Je),
184
+ icon: /* @__PURE__ */ f(u, { className: "h-5 w-5" }),
185
+ iconBgColor: "bg-status-error-bg text-status-error-text"
186
+ }),
187
+ /* @__PURE__ */ f(n, {
188
+ title: "Active Plans",
189
+ value: String(Y.length),
190
+ icon: /* @__PURE__ */ f(u, { className: "h-5 w-5" })
191
+ }),
192
+ /* @__PURE__ */ f(n, {
193
+ title: "Available Capacity",
194
+ value: `${Math.round(Ye)}h`,
195
+ icon: /* @__PURE__ */ f(ue, { className: "h-5 w-5" }),
196
+ description: "This week"
197
+ })
198
+ ]
199
+ }),
200
+ Y.length === 0 ? /* @__PURE__ */ f(le, {
201
+ illustration: "empty-people",
202
+ title: "No resource plans yet",
203
+ description: "Create a resource plan to start allocating team members and balancing workload across the week.",
204
+ action: Ke
205
+ }) : /* @__PURE__ */ p("div", {
206
+ className: "space-y-6",
207
+ children: [Y.map((n) => /* @__PURE__ */ p("div", {
208
+ className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop",
209
+ children: [/* @__PURE__ */ p("div", {
210
+ className: "flex flex-col gap-3 border-b border-border-seam p-5 sm:flex-row sm:items-center sm:justify-between",
211
+ children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ p("div", {
212
+ className: "flex items-center gap-2",
213
+ children: [/* @__PURE__ */ f("p", {
214
+ className: "text-sm font-semibold text-text-primary",
215
+ children: n.name
216
+ }), /* @__PURE__ */ f("span", {
217
+ className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${t(n.status)}`,
218
+ children: n.status
219
+ })]
220
+ }), /* @__PURE__ */ p("p", {
221
+ className: "mt-0.5 text-xs text-text-secondary",
222
+ children: [
223
+ n.startDate.slice(0, 10),
224
+ " to ",
225
+ n.endDate.slice(0, 10),
226
+ " ",
227
+ "· ",
228
+ n.totalAllocatedHours,
229
+ "h allocated ·",
230
+ " ",
231
+ n.allocations.length,
232
+ " people"
233
+ ]
234
+ })] }), /* @__PURE__ */ p("div", {
235
+ className: "flex items-center gap-2",
236
+ children: [
237
+ /* @__PURE__ */ p("button", {
238
+ onClick: () => Re(n),
239
+ className: "inline-flex items-center gap-1 rounded-md bg-action-primary-bg px-2.5 py-1.5 text-xs font-medium text-action-primary-text hover:bg-action-primary-bg/90",
240
+ children: [/* @__PURE__ */ f(fe, { className: "h-3.5 w-3.5" }), "Add Allocation"]
241
+ }),
242
+ /* @__PURE__ */ p("button", {
243
+ onClick: () => Fe(n),
244
+ className: "inline-flex items-center gap-1 rounded-md border border-border-subtle px-2.5 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken/50",
245
+ children: [/* @__PURE__ */ f(s, { className: "h-3.5 w-3.5" }), "Edit"]
246
+ }),
247
+ /* @__PURE__ */ p("button", {
248
+ onClick: () => F(n),
249
+ className: "inline-flex items-center gap-1 rounded-md border border-border-subtle px-2.5 py-1.5 text-xs font-medium text-status-error-text hover:bg-status-error-bg",
250
+ children: [/* @__PURE__ */ f(l, { className: "h-3.5 w-3.5" }), "Delete"]
106
251
  })
107
- }), /* @__PURE__ */ f("div", {
108
- className: "w-24",
109
- children: [/* @__PURE__ */ d("div", {
110
- className: "flex items-center justify-between text-xs mb-0.5",
111
- children: /* @__PURE__ */ f("span", {
112
- className: `font-medium ${n > 100 ? "text-status-error-text" : n < 70 ? "text-status-warning-text" : "text-status-success-text"}`,
113
- children: [n, "%"]
114
- })
115
- }), /* @__PURE__ */ d("div", {
116
- className: "h-2 rounded-full bg-bg-sunken",
117
- children: /* @__PURE__ */ d("div", {
118
- className: `h-2 rounded-full ${n > 100 ? "bg-status-error-text" : n < 70 ? "bg-status-warning-text" : "bg-status-success-text"}`,
119
- style: { width: `${Math.min(n, 100)}%` }
120
- })
252
+ ]
253
+ })]
254
+ }), n.allocations.length === 0 ? /* @__PURE__ */ f("div", {
255
+ className: "p-5 text-sm text-text-secondary",
256
+ children: "No allocations yet. Use “Add Allocation” to assign team members."
257
+ }) : /* @__PURE__ */ f("div", {
258
+ className: "divide-y divide-border",
259
+ children: n.allocations.map((t) => {
260
+ let n = t.utilizationRate ?? (t.allocatedHours > 0 ? Math.round(t.actualHours / t.allocatedHours * 100) : 0);
261
+ return /* @__PURE__ */ p("div", {
262
+ className: "flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors",
263
+ children: [/* @__PURE__ */ p("div", {
264
+ className: "flex items-center gap-3",
265
+ children: [/* @__PURE__ */ f("div", {
266
+ className: "flex h-9 w-9 items-center justify-center rounded-full bg-action-primary-bg/10 text-sm font-medium text-primary",
267
+ children: e(t.userId)
268
+ }), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
269
+ className: "text-sm font-medium text-text-primary",
270
+ children: t.userId
271
+ }), /* @__PURE__ */ p("p", {
272
+ className: "text-xs text-text-secondary",
273
+ children: [
274
+ t.startDate.slice(0, 10),
275
+ " to",
276
+ " ",
277
+ t.endDate.slice(0, 10)
278
+ ]
279
+ })] })]
280
+ }), /* @__PURE__ */ p("div", {
281
+ className: "flex items-center gap-4",
282
+ children: [
283
+ /* @__PURE__ */ f("div", {
284
+ className: "text-right",
285
+ children: /* @__PURE__ */ p("p", {
286
+ className: "text-sm font-medium text-text-primary",
287
+ children: [t.allocatedHours, "h allocated"]
288
+ })
289
+ }),
290
+ /* @__PURE__ */ p("div", {
291
+ className: "w-24",
292
+ children: [/* @__PURE__ */ f("div", {
293
+ className: "flex items-center justify-between text-xs mb-0.5",
294
+ children: /* @__PURE__ */ p("span", {
295
+ className: `font-medium ${n > 100 ? "text-status-error-text" : n < 70 ? "text-status-warning-text" : "text-status-success-text"}`,
296
+ children: [n, "%"]
297
+ })
298
+ }), /* @__PURE__ */ f("div", {
299
+ className: "h-2 rounded-full bg-bg-sunken",
300
+ children: /* @__PURE__ */ f("div", {
301
+ className: `h-2 rounded-full ${n > 100 ? "bg-status-error-text" : n < 70 ? "bg-status-warning-text" : "bg-status-success-text"}`,
302
+ style: { width: `${Math.min(n, 100)}%` }
303
+ })
304
+ })]
305
+ }),
306
+ /* @__PURE__ */ p("div", {
307
+ className: "flex items-center gap-1",
308
+ children: [/* @__PURE__ */ f("button", {
309
+ onClick: () => He(t),
310
+ "aria-label": "Edit allocation",
311
+ className: "rounded-md border border-border-subtle p-1.5 text-text-primary hover:bg-bg-sunken/50",
312
+ children: /* @__PURE__ */ f(s, { className: "h-4 w-4" })
313
+ }), /* @__PURE__ */ f("button", {
314
+ onClick: () => K(t),
315
+ "aria-label": "Delete allocation",
316
+ className: "rounded-md border border-border-subtle p-1.5 text-status-error-text hover:bg-status-error-bg",
317
+ children: /* @__PURE__ */ f(l, { className: "h-4 w-4" })
318
+ })]
319
+ })
320
+ ]
121
321
  })]
322
+ }, t.id);
323
+ })
324
+ })]
325
+ }, n.id)), Ne && /* @__PURE__ */ f("div", {
326
+ className: "flex justify-center",
327
+ children: /* @__PURE__ */ f("button", {
328
+ onClick: Ge,
329
+ disabled: q,
330
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50 disabled:opacity-50",
331
+ children: q ? "Loading..." : "Load more"
332
+ })
333
+ })]
334
+ }),
335
+ /* @__PURE__ */ p(a, {
336
+ open: je,
337
+ onClose: () => k(!1),
338
+ title: A ? "Edit Resource Plan" : "New Resource Plan",
339
+ description: "Set the window this plan covers, then allocate people to it.",
340
+ size: "lg",
341
+ footer: /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("button", {
342
+ onClick: () => k(!1),
343
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
344
+ children: "Cancel"
345
+ }), /* @__PURE__ */ f("button", {
346
+ onClick: Ie,
347
+ disabled: S || C || !M.name.trim(),
348
+ className: "rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50",
349
+ children: S || C ? "Saving..." : A ? "Save Changes" : "Create Plan"
350
+ })] }),
351
+ children: [(Se || we) && /* @__PURE__ */ f("div", {
352
+ className: "mb-4 rounded-lg border border-status-error-bg/40 bg-status-error-bg p-3 text-sm text-status-error-text",
353
+ children: "Failed to save resource plan. Please try again."
354
+ }), /* @__PURE__ */ p("div", {
355
+ className: "space-y-4",
356
+ children: [
357
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
358
+ className: "block text-sm font-medium text-text-primary",
359
+ children: "Plan Name"
360
+ }), /* @__PURE__ */ f("input", {
361
+ type: "text",
362
+ placeholder: "e.g. Q3 Delivery",
363
+ value: M.name,
364
+ onChange: (e) => N({
365
+ ...M,
366
+ name: e.target.value
367
+ }),
368
+ className: h
369
+ })] }),
370
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
371
+ className: "block text-sm font-medium text-text-primary",
372
+ children: "Description (optional)"
373
+ }), /* @__PURE__ */ f("textarea", {
374
+ rows: 2,
375
+ placeholder: "What this plan covers",
376
+ value: M.description,
377
+ onChange: (e) => N({
378
+ ...M,
379
+ description: e.target.value
380
+ }),
381
+ className: h
382
+ })] }),
383
+ /* @__PURE__ */ p("div", {
384
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
385
+ children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
386
+ className: "block text-sm font-medium text-text-primary",
387
+ children: "Start Date"
388
+ }), /* @__PURE__ */ f("input", {
389
+ type: "date",
390
+ value: M.startDate,
391
+ onChange: (e) => N({
392
+ ...M,
393
+ startDate: e.target.value
394
+ }),
395
+ className: h
396
+ })] }), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
397
+ className: "block text-sm font-medium text-text-primary",
398
+ children: "End Date"
399
+ }), /* @__PURE__ */ f("input", {
400
+ type: "date",
401
+ value: M.endDate,
402
+ onChange: (e) => N({
403
+ ...M,
404
+ endDate: e.target.value
405
+ }),
406
+ className: h
407
+ })] })]
408
+ }),
409
+ A && /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
410
+ className: "block text-sm font-medium text-text-primary",
411
+ children: "Status"
412
+ }), /* @__PURE__ */ p("select", {
413
+ value: M.status,
414
+ onChange: (e) => N({
415
+ ...M,
416
+ status: e.target.value
417
+ }),
418
+ className: h,
419
+ children: [
420
+ /* @__PURE__ */ f("option", {
421
+ value: "active",
422
+ children: "Active"
423
+ }),
424
+ /* @__PURE__ */ f("option", {
425
+ value: "draft",
426
+ children: "Draft"
427
+ }),
428
+ /* @__PURE__ */ f("option", {
429
+ value: "completed",
430
+ children: "Completed"
431
+ }),
432
+ /* @__PURE__ */ f("option", {
433
+ value: "archived",
434
+ children: "Archived"
435
+ })
436
+ ]
437
+ })] })
438
+ ]
439
+ })]
440
+ }),
441
+ /* @__PURE__ */ p(a, {
442
+ open: I !== null,
443
+ onClose: () => L(null),
444
+ title: "Add Allocation",
445
+ description: I ? `Assign team members to "${I.name}".` : void 0,
446
+ size: "xl",
447
+ footer: /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("button", {
448
+ onClick: () => L(null),
449
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
450
+ children: "Cancel"
451
+ }), /* @__PURE__ */ f("button", {
452
+ onClick: Ve,
453
+ disabled: T || E || !$,
454
+ className: "rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50",
455
+ children: T || E ? "Saving..." : R.length > 1 ? `Add ${R.length} Allocations` : "Add Allocation"
456
+ })] }),
457
+ children: [Me && /* @__PURE__ */ f("div", {
458
+ className: "mb-4 rounded-lg border border-status-error-bg/40 bg-status-error-bg p-3 text-sm text-status-error-text",
459
+ children: "Failed to add allocations. Please check the values and try again."
460
+ }), /* @__PURE__ */ p("div", {
461
+ className: "space-y-4",
462
+ children: [R.map((e, t) => /* @__PURE__ */ p("div", {
463
+ className: "rounded-lg border border-border-subtle p-3",
464
+ children: [/* @__PURE__ */ p("div", {
465
+ className: "mb-2 flex items-center justify-between",
466
+ children: [/* @__PURE__ */ p("span", {
467
+ className: "text-xs font-medium text-text-secondary",
468
+ children: ["Allocation ", t + 1]
469
+ }), R.length > 1 && /* @__PURE__ */ f("button", {
470
+ onClick: () => Be(t),
471
+ className: "text-xs font-medium text-status-error-text hover:underline",
472
+ children: "Remove"
122
473
  })]
474
+ }), /* @__PURE__ */ p("div", {
475
+ className: "grid grid-cols-1 gap-3 sm:grid-cols-2",
476
+ children: [
477
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
478
+ className: "block text-xs font-medium text-text-primary",
479
+ children: "User ID"
480
+ }), /* @__PURE__ */ f("input", {
481
+ type: "text",
482
+ placeholder: "User identifier",
483
+ value: e.userId,
484
+ onChange: (e) => Q(t, { userId: e.target.value }),
485
+ className: h
486
+ })] }),
487
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
488
+ className: "block text-xs font-medium text-text-primary",
489
+ children: "Allocated Hours"
490
+ }), /* @__PURE__ */ f("input", {
491
+ type: "number",
492
+ placeholder: "0",
493
+ value: e.allocatedHours,
494
+ onChange: (e) => Q(t, { allocatedHours: e.target.value }),
495
+ className: h
496
+ })] }),
497
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
498
+ className: "block text-xs font-medium text-text-primary",
499
+ children: "Start Date"
500
+ }), /* @__PURE__ */ f("input", {
501
+ type: "date",
502
+ value: e.startDate,
503
+ onChange: (e) => Q(t, { startDate: e.target.value }),
504
+ className: h
505
+ })] }),
506
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
507
+ className: "block text-xs font-medium text-text-primary",
508
+ children: "End Date"
509
+ }), /* @__PURE__ */ f("input", {
510
+ type: "date",
511
+ value: e.endDate,
512
+ onChange: (e) => Q(t, { endDate: e.target.value }),
513
+ className: h
514
+ })] }),
515
+ /* @__PURE__ */ p("div", {
516
+ className: "sm:col-span-2",
517
+ children: [/* @__PURE__ */ f("label", {
518
+ className: "block text-xs font-medium text-text-primary",
519
+ children: "Notes (optional)"
520
+ }), /* @__PURE__ */ f("input", {
521
+ type: "text",
522
+ placeholder: "Context for this allocation",
523
+ value: e.notes,
524
+ onChange: (e) => Q(t, { notes: e.target.value }),
525
+ className: h
526
+ })]
527
+ })
528
+ ]
123
529
  })]
124
- }, e.id);
530
+ }, t)), /* @__PURE__ */ p("button", {
531
+ onClick: ze,
532
+ className: "inline-flex items-center gap-1 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
533
+ children: [/* @__PURE__ */ f(c, { className: "h-4 w-4" }), "Add another person"]
534
+ })]
535
+ })]
536
+ }),
537
+ /* @__PURE__ */ p(a, {
538
+ open: V !== null && U !== null,
539
+ onClose: () => {
540
+ H(null), W(null);
541
+ },
542
+ title: "Edit Allocation",
543
+ size: "lg",
544
+ footer: /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("button", {
545
+ onClick: () => {
546
+ H(null), W(null);
547
+ },
548
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
549
+ children: "Cancel"
550
+ }), /* @__PURE__ */ f("button", {
551
+ onClick: Ue,
552
+ disabled: D,
553
+ className: "rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50",
554
+ children: D ? "Saving..." : "Save Changes"
555
+ })] }),
556
+ children: [ke && /* @__PURE__ */ f("div", {
557
+ className: "mb-4 rounded-lg border border-status-error-bg/40 bg-status-error-bg p-3 text-sm text-status-error-text",
558
+ children: "Failed to update allocation. Please try again."
559
+ }), U && /* @__PURE__ */ p("div", {
560
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
561
+ children: [
562
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
563
+ className: "block text-sm font-medium text-text-primary",
564
+ children: "User ID"
565
+ }), /* @__PURE__ */ f("input", {
566
+ type: "text",
567
+ value: U.userId,
568
+ onChange: (e) => W({
569
+ ...U,
570
+ userId: e.target.value
571
+ }),
572
+ className: h
573
+ })] }),
574
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
575
+ className: "block text-sm font-medium text-text-primary",
576
+ children: "Allocated Hours"
577
+ }), /* @__PURE__ */ f("input", {
578
+ type: "number",
579
+ value: U.allocatedHours,
580
+ onChange: (e) => W({
581
+ ...U,
582
+ allocatedHours: e.target.value
583
+ }),
584
+ className: h
585
+ })] }),
586
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
587
+ className: "block text-sm font-medium text-text-primary",
588
+ children: "Actual Hours"
589
+ }), /* @__PURE__ */ f("input", {
590
+ type: "number",
591
+ value: U.actualHours,
592
+ onChange: (e) => W({
593
+ ...U,
594
+ actualHours: e.target.value
595
+ }),
596
+ className: h
597
+ })] }),
598
+ /* @__PURE__ */ f("div", {}),
599
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
600
+ className: "block text-sm font-medium text-text-primary",
601
+ children: "Start Date"
602
+ }), /* @__PURE__ */ f("input", {
603
+ type: "date",
604
+ value: U.startDate,
605
+ onChange: (e) => W({
606
+ ...U,
607
+ startDate: e.target.value
608
+ }),
609
+ className: h
610
+ })] }),
611
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
612
+ className: "block text-sm font-medium text-text-primary",
613
+ children: "End Date"
614
+ }), /* @__PURE__ */ f("input", {
615
+ type: "date",
616
+ value: U.endDate,
617
+ onChange: (e) => W({
618
+ ...U,
619
+ endDate: e.target.value
620
+ }),
621
+ className: h
622
+ })] }),
623
+ /* @__PURE__ */ p("div", {
624
+ className: "sm:col-span-2",
625
+ children: [/* @__PURE__ */ f("label", {
626
+ className: "block text-sm font-medium text-text-primary",
627
+ children: "Notes (optional)"
628
+ }), /* @__PURE__ */ f("input", {
629
+ type: "text",
630
+ value: U.notes,
631
+ onChange: (e) => W({
632
+ ...U,
633
+ notes: e.target.value
634
+ }),
635
+ className: h
636
+ })]
637
+ })
638
+ ]
639
+ })]
640
+ }),
641
+ /* @__PURE__ */ f(a, {
642
+ open: P !== null,
643
+ onClose: () => F(null),
644
+ title: "Delete Resource Plan",
645
+ description: "This action cannot be undone.",
646
+ footer: /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("button", {
647
+ onClick: () => F(null),
648
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
649
+ children: "Cancel"
650
+ }), /* @__PURE__ */ f("button", {
651
+ onClick: Le,
652
+ disabled: w,
653
+ className: "rounded-md bg-status-error-bg px-4 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg/80 disabled:opacity-50",
654
+ children: w ? "Deleting..." : "Delete"
655
+ })] }),
656
+ children: /* @__PURE__ */ p("p", {
657
+ className: "text-sm text-text-secondary",
658
+ children: [
659
+ "Are you sure you want to delete",
660
+ " ",
661
+ /* @__PURE__ */ f("span", {
662
+ className: "font-medium text-text-primary",
663
+ children: P?.name
664
+ }),
665
+ "? All its allocations will be removed."
666
+ ]
667
+ })
668
+ }),
669
+ /* @__PURE__ */ f(a, {
670
+ open: G !== null,
671
+ onClose: () => K(null),
672
+ title: "Delete Allocation",
673
+ description: "This action cannot be undone.",
674
+ footer: /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("button", {
675
+ onClick: () => K(null),
676
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
677
+ children: "Cancel"
678
+ }), /* @__PURE__ */ f("button", {
679
+ onClick: We,
680
+ disabled: O,
681
+ className: "rounded-md bg-status-error-bg px-4 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg/80 disabled:opacity-50",
682
+ children: O ? "Deleting..." : "Delete"
683
+ })] }),
684
+ children: /* @__PURE__ */ p("p", {
685
+ className: "text-sm text-text-secondary",
686
+ children: [
687
+ "Remove the allocation for",
688
+ " ",
689
+ /* @__PURE__ */ f("span", {
690
+ className: "font-medium text-text-primary",
691
+ children: G?.userId
692
+ }),
693
+ "?"
694
+ ]
125
695
  })
126
696
  })
127
- })]
697
+ ]
128
698
  });
129
699
  }
130
700
  //#endregion
131
- export { p as ResourcePlanningPage };
701
+ export { b as ResourcePlanningPage };
132
702
 
133
703
  //# sourceMappingURL=ResourcePlanningPage.js.map