@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,110 +1,484 @@
1
1
  import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
2
- import { formatCurrency as t, formatDate as n, getStatusColor as r } from "../../utils/helpers.js";
3
- import { StatCard as i } from "../../components/StatCard.js";
4
- import { LoadingSkeleton as a } from "../../components/LoadingSkeleton.js";
5
- import { useGetExpenseStatsQuery as o, useListExpensesQuery as s } from "../../../generated/wspace-operations.js";
6
- import { PageLayout as c } from "../../components/PageLayout.js";
7
- import { EmptyState as l } from "../../components/EmptyState.js";
8
- import { DollarSign as u, Plus as d, Receipt as f } from "lucide-react";
9
- import { jsx as p, jsxs as m } from "react/jsx-runtime";
2
+ import { formatCurrency as t, formatDate as ee } from "../../utils/helpers.js";
3
+ import { StatCard as n } from "../../components/StatCard.js";
4
+ import { LoadingSkeleton as r } from "../../components/LoadingSkeleton.js";
5
+ import { useApproveExpenseMutation as i, useCreateExpenseMutation as te, useDeleteExpenseMutation as ne, useGetExpenseStatsQuery as re, useListExpensesQuery as ie, useRejectExpenseMutation as ae, useSubmitExpenseForApprovalMutation as oe, useUpdateExpenseMutation as se } from "../../../generated/wspace-operations.js";
6
+ import { PageLayout as a } from "../../components/PageLayout.js";
7
+ import { EmptyState as ce } from "../../components/EmptyState.js";
8
+ import { ExpenseStatus as o } from "../../../generated/wspace-types.js";
9
+ import { Modal as s } from "../../components/Modal.js";
10
+ import { StatusBadge as le } from "../../components/StatusBadge.js";
11
+ import { ToastContainer as ue, useToast as de } from "../../components/Toast.js";
12
+ import { useState as c } from "react";
13
+ import { Check as l, DollarSign as u, Pencil as fe, Plus as pe, Receipt as d, Send as me, Trash2 as he, X as ge } from "lucide-react";
14
+ import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
10
15
  //#region src/timecampus/pages/expense-tracking/ExpenseTrackingPage.tsx
11
- function h() {
12
- let { workspaceId: h = "" } = e(), { data: g, loading: _, error: v } = s({ variables: { workspaceId: h } }), { data: y, loading: b, error: x } = o({ variables: { workspaceId: h } }), S = g?.expenses ?? [], C = y?.expenseStats;
13
- return _ && b ? /* @__PURE__ */ p(c, {
16
+ var h = 25, g = [
17
+ "Travel",
18
+ "Meals",
19
+ "Software",
20
+ "Hardware",
21
+ "Office",
22
+ "Training",
23
+ "Other"
24
+ ], _ = "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";
25
+ function v() {
26
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
27
+ }
28
+ var y = {
29
+ amount: "",
30
+ category: g[0],
31
+ description: "",
32
+ projectId: "",
33
+ date: v()
34
+ };
35
+ function b() {
36
+ let { workspaceId: b = "" } = e(), { toasts: _e, addToast: x, dismissToast: ve } = de(), { data: ye, loading: S, error: be, refetch: xe, fetchMore: Se } = ie({
37
+ variables: {
38
+ workspaceId: b,
39
+ limit: h,
40
+ offset: 0
41
+ },
42
+ notifyOnNetworkStatusChange: !0
43
+ }), { data: C, loading: w, error: T, refetch: E } = re({ variables: { workspaceId: b } }), [D, { loading: O }] = te(), [k, { loading: A }] = se(), [j, { loading: M }] = ne(), [Ce] = oe(), [we] = i(), [Te, { loading: N }] = ae(), P = ye?.expenses ?? [], F = C?.expenseStats, [I, L] = c(!1), [Ee, De] = c(!0), [Oe, R] = c(!1), [z, B] = c(null), [V, H] = c(y), [U, W] = c(null), [G, K] = c(null), [q, J] = c(""), [ke, Y] = c(null), X = async () => {
44
+ await Promise.all([xe(), E()]);
45
+ }, Ae = () => {
46
+ B(null), H({
47
+ ...y,
48
+ date: v()
49
+ }), R(!0);
50
+ }, je = (e) => {
51
+ B(e), H({
52
+ amount: String(e.amount),
53
+ category: e.category,
54
+ description: e.description ?? "",
55
+ projectId: e.projectId ?? "",
56
+ date: e.date ? e.date.slice(0, 10) : v()
57
+ }), R(!0);
58
+ }, Z = () => {
59
+ R(!1), B(null);
60
+ }, Q = async () => {
61
+ let e = Number(V.amount);
62
+ if (!V.amount || Number.isNaN(e) || !V.category.trim()) return;
63
+ let t = new Date(V.date).toISOString();
64
+ try {
65
+ z ? (await k({ variables: {
66
+ id: z.id,
67
+ workspaceId: b,
68
+ input: {
69
+ amount: e,
70
+ category: V.category.trim(),
71
+ description: V.description.trim() || void 0,
72
+ projectId: V.projectId.trim() || void 0,
73
+ date: t
74
+ }
75
+ } }), x({
76
+ title: "Expense updated",
77
+ variant: "success"
78
+ })) : (await D({ variables: { input: {
79
+ workspaceId: b,
80
+ amount: e,
81
+ category: V.category.trim(),
82
+ description: V.description.trim() || void 0,
83
+ projectId: V.projectId.trim() || void 0,
84
+ date: t
85
+ } } }), x({
86
+ title: "Expense added",
87
+ variant: "success"
88
+ })), Z(), await X();
89
+ } catch {
90
+ x({
91
+ title: z ? "Failed to update expense" : "Failed to add expense",
92
+ variant: "error"
93
+ });
94
+ }
95
+ }, Me = async () => {
96
+ if (U) try {
97
+ await j({ variables: {
98
+ id: U.id,
99
+ workspaceId: b
100
+ } }), x({
101
+ title: "Expense deleted",
102
+ variant: "success"
103
+ }), W(null), await X();
104
+ } catch {
105
+ x({
106
+ title: "Failed to delete expense",
107
+ variant: "error"
108
+ });
109
+ }
110
+ }, Ne = async (e) => {
111
+ Y(e.id);
112
+ try {
113
+ await Ce({ variables: {
114
+ id: e.id,
115
+ workspaceId: b
116
+ } }), x({
117
+ title: "Submitted for approval",
118
+ variant: "success"
119
+ }), await X();
120
+ } catch {
121
+ x({
122
+ title: "Failed to submit expense",
123
+ variant: "error"
124
+ });
125
+ } finally {
126
+ Y(null);
127
+ }
128
+ }, Pe = async (e) => {
129
+ Y(e.id);
130
+ try {
131
+ await we({ variables: {
132
+ id: e.id,
133
+ workspaceId: b
134
+ } }), x({
135
+ title: "Expense approved",
136
+ variant: "success"
137
+ }), await X();
138
+ } catch {
139
+ x({
140
+ title: "Failed to approve expense",
141
+ variant: "error"
142
+ });
143
+ } finally {
144
+ Y(null);
145
+ }
146
+ }, Fe = async () => {
147
+ if (G) try {
148
+ await Te({ variables: {
149
+ id: G.id,
150
+ workspaceId: b,
151
+ reason: q.trim() || void 0
152
+ } }), x({
153
+ title: "Expense rejected",
154
+ variant: "success"
155
+ }), K(null), J(""), await X();
156
+ } catch {
157
+ x({
158
+ title: "Failed to reject expense",
159
+ variant: "error"
160
+ });
161
+ }
162
+ }, Ie = async () => {
163
+ L(!0);
164
+ try {
165
+ ((await Se({
166
+ variables: {
167
+ workspaceId: b,
168
+ limit: h,
169
+ offset: P.length
170
+ },
171
+ updateQuery: (e, { fetchMoreResult: t }) => t ? {
172
+ ...e,
173
+ expenses: [...e.expenses, ...t.expenses]
174
+ } : e
175
+ })).data?.expenses?.length ?? 0) < h && De(!1);
176
+ } finally {
177
+ L(!1);
178
+ }
179
+ };
180
+ if (S && w && P.length === 0) return /* @__PURE__ */ p(a, {
14
181
  title: "Expense Tracking",
15
182
  description: "Track and manage work expenses",
16
- children: /* @__PURE__ */ p(a, {
183
+ children: /* @__PURE__ */ p(r, {
17
184
  variant: "list",
18
185
  count: 4
19
186
  })
20
- }) : v && x ? /* @__PURE__ */ p(c, {
187
+ });
188
+ if (be && T) return /* @__PURE__ */ p(a, {
21
189
  title: "Expense Tracking",
22
190
  description: "Track and manage work expenses",
23
191
  children: /* @__PURE__ */ p("div", {
24
192
  className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
25
193
  children: "Failed to load expense data. Please try again later."
26
194
  })
27
- }) : /* @__PURE__ */ m(c, {
195
+ });
196
+ let $ = /* @__PURE__ */ m("button", {
197
+ onClick: Ae,
198
+ 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",
199
+ children: [/* @__PURE__ */ p(pe, { className: "h-4 w-4" }), "Add Expense"]
200
+ });
201
+ return /* @__PURE__ */ m(a, {
28
202
  title: "Expense Tracking",
29
203
  description: "Track and manage work expenses",
30
204
  purpose: "Capture project-related costs alongside the hours you log — receipts, categories and approvals in one place — so the bill you send a client reflects the full cost of the work, not just time.",
31
- actions: /* @__PURE__ */ m("button", {
32
- 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",
33
- children: [/* @__PURE__ */ p(d, { className: "h-4 w-4" }), "Add Expense"]
34
- }),
35
- children: [/* @__PURE__ */ m("div", {
36
- className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
37
- children: [
38
- /* @__PURE__ */ p(i, {
39
- featured: !0,
40
- title: "Total This Month",
41
- value: t(C?.totalAmount ?? 0),
42
- icon: /* @__PURE__ */ p(u, { className: "h-5 w-5" })
43
- }),
44
- /* @__PURE__ */ p(i, {
45
- title: "Pending",
46
- value: String(C?.pendingCount ?? 0),
47
- description: "expenses awaiting approval"
48
- }),
49
- /* @__PURE__ */ p(i, {
50
- title: "Approved",
51
- value: String(C?.approvedCount ?? 0),
52
- description: "expenses approved"
53
- }),
54
- /* @__PURE__ */ p(i, {
55
- title: "Average",
56
- value: t(C?.averageAmount ?? 0),
57
- icon: /* @__PURE__ */ p(f, { className: "h-5 w-5" }),
58
- description: "per expense"
205
+ actions: $,
206
+ children: [
207
+ /* @__PURE__ */ m("div", {
208
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
209
+ children: [
210
+ /* @__PURE__ */ p(n, {
211
+ featured: !0,
212
+ title: "Total This Month",
213
+ value: t(F?.totalAmount ?? 0),
214
+ icon: /* @__PURE__ */ p(u, { className: "h-5 w-5" })
215
+ }),
216
+ /* @__PURE__ */ p(n, {
217
+ title: "Pending",
218
+ value: String(F?.pendingCount ?? 0),
219
+ description: "expenses awaiting approval"
220
+ }),
221
+ /* @__PURE__ */ p(n, {
222
+ title: "Approved",
223
+ value: String(F?.approvedCount ?? 0),
224
+ description: "expenses approved"
225
+ }),
226
+ /* @__PURE__ */ p(n, {
227
+ title: "Average",
228
+ value: t(F?.averageAmount ?? 0),
229
+ icon: /* @__PURE__ */ p(d, { className: "h-5 w-5" }),
230
+ description: "per expense"
231
+ })
232
+ ]
233
+ }),
234
+ P.length === 0 && !S ? /* @__PURE__ */ p(ce, {
235
+ illustration: "empty-data",
236
+ title: "No expenses recorded yet",
237
+ description: "Add your first expense to track project costs and route them for approval.",
238
+ action: $
239
+ }) : /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("div", {
240
+ className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop",
241
+ children: /* @__PURE__ */ p("div", {
242
+ className: "divide-y divide-border",
243
+ children: P.map((e) => {
244
+ let n = ke === e.id, r = e.status === o.Pending, i = e.status === o.Rejected;
245
+ return /* @__PURE__ */ m("div", {
246
+ className: "flex flex-col gap-3 p-4 hover:bg-bg-sunken/50 transition-colors sm:flex-row sm:items-center sm:justify-between",
247
+ children: [/* @__PURE__ */ m("div", {
248
+ className: "flex items-center gap-3",
249
+ children: [/* @__PURE__ */ p(d, { className: "h-5 w-5 shrink-0 text-text-secondary" }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
250
+ className: "text-sm font-medium text-text-primary",
251
+ children: e.description ?? "Untitled expense"
252
+ }), /* @__PURE__ */ m("p", {
253
+ className: "text-xs text-text-secondary",
254
+ children: [
255
+ e.category,
256
+ " ·",
257
+ " ",
258
+ e.projectId ?? "No project",
259
+ " ·",
260
+ " ",
261
+ ee(e.date)
262
+ ]
263
+ })] })]
264
+ }), /* @__PURE__ */ m("div", {
265
+ className: "flex items-center gap-3",
266
+ children: [
267
+ /* @__PURE__ */ p("p", {
268
+ className: "text-sm font-medium text-text-primary",
269
+ children: t(e.amount, e.currency)
270
+ }),
271
+ /* @__PURE__ */ p(le, {
272
+ label: e.status.toLowerCase(),
273
+ status: e.status.toLowerCase()
274
+ }),
275
+ /* @__PURE__ */ m("div", {
276
+ className: "flex items-center gap-1",
277
+ children: [
278
+ r && /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("button", {
279
+ type: "button",
280
+ disabled: n,
281
+ onClick: () => Pe(e),
282
+ title: "Approve expense",
283
+ className: "rounded-md p-1.5 text-status-success-text hover:bg-status-success-bg disabled:opacity-50",
284
+ children: /* @__PURE__ */ p(l, { className: "h-4 w-4" })
285
+ }), /* @__PURE__ */ p("button", {
286
+ type: "button",
287
+ disabled: n,
288
+ onClick: () => {
289
+ K(e), J("");
290
+ },
291
+ title: "Reject expense",
292
+ className: "rounded-md p-1.5 text-status-error-text hover:bg-status-error-bg disabled:opacity-50",
293
+ children: /* @__PURE__ */ p(ge, { className: "h-4 w-4" })
294
+ })] }),
295
+ i && /* @__PURE__ */ p("button", {
296
+ type: "button",
297
+ disabled: n,
298
+ onClick: () => Ne(e),
299
+ title: "Resubmit for approval",
300
+ className: "rounded-md p-1.5 text-text-secondary hover:bg-bg-sunken disabled:opacity-50",
301
+ children: /* @__PURE__ */ p(me, { className: "h-4 w-4" })
302
+ }),
303
+ /* @__PURE__ */ p("button", {
304
+ type: "button",
305
+ onClick: () => je(e),
306
+ title: "Edit expense",
307
+ className: "rounded-md p-1.5 text-text-secondary hover:bg-bg-sunken",
308
+ children: /* @__PURE__ */ p(fe, { className: "h-4 w-4" })
309
+ }),
310
+ /* @__PURE__ */ p("button", {
311
+ type: "button",
312
+ onClick: () => W(e),
313
+ title: "Delete expense",
314
+ className: "rounded-md p-1.5 text-status-error-text hover:bg-status-error-bg",
315
+ children: /* @__PURE__ */ p(he, { className: "h-4 w-4" })
316
+ })
317
+ ]
318
+ })
319
+ ]
320
+ })]
321
+ }, e.id);
322
+ })
59
323
  })
60
- ]
61
- }), S.length === 0 && !_ ? /* @__PURE__ */ p(l, {
62
- illustration: "empty-data",
63
- title: "No expenses recorded yet",
64
- description: "Add your first expense to track project costs and route them for approval.",
65
- action: /* @__PURE__ */ m("button", {
66
- 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",
67
- children: [/* @__PURE__ */ p(d, { className: "h-4 w-4" }), "Add Expense"]
68
- })
69
- }) : /* @__PURE__ */ p("div", {
70
- className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop",
71
- children: /* @__PURE__ */ p("div", {
72
- className: "divide-y divide-border",
73
- children: S.map((e) => /* @__PURE__ */ m("div", {
74
- className: "flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors",
75
- children: [/* @__PURE__ */ m("div", {
76
- className: "flex items-center gap-3",
77
- children: [/* @__PURE__ */ p(f, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
78
- className: "text-sm font-medium text-text-primary",
79
- children: e.description ?? "Untitled expense"
80
- }), /* @__PURE__ */ m("p", {
81
- className: "text-xs text-text-secondary",
82
- children: [
83
- e.category,
84
- " ·",
85
- " ",
86
- e.projectId ?? "No project",
87
- " ·",
88
- " ",
89
- n(e.date)
90
- ]
91
- })] })]
92
- }), /* @__PURE__ */ m("div", {
93
- className: "flex items-center gap-3",
94
- children: [/* @__PURE__ */ p("p", {
95
- className: "text-sm font-medium text-text-primary",
96
- children: t(e.amount)
97
- }), /* @__PURE__ */ p("span", {
98
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${r(e.status)}`,
99
- children: e.status
100
- })]
101
- })]
102
- }, e.id))
324
+ }), Ee && P.length >= h && /* @__PURE__ */ p("div", {
325
+ className: "mt-4 flex justify-center",
326
+ children: /* @__PURE__ */ p("button", {
327
+ onClick: Ie,
328
+ disabled: I,
329
+ 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",
330
+ children: I ? "Loading..." : "Load more"
331
+ })
332
+ })] }),
333
+ /* @__PURE__ */ p(s, {
334
+ open: Oe,
335
+ onClose: Z,
336
+ title: z ? "Edit Expense" : "Add Expense",
337
+ description: z ? "Update this expense's details." : "Record a project-related cost to track alongside your logged hours.",
338
+ footer: /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("button", {
339
+ onClick: Z,
340
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
341
+ children: "Cancel"
342
+ }), /* @__PURE__ */ p("button", {
343
+ onClick: Q,
344
+ disabled: O || A || !V.amount || Number.isNaN(Number(V.amount)) || !V.category.trim(),
345
+ 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",
346
+ children: O || A ? "Saving..." : z ? "Save Changes" : "Add Expense"
347
+ })] }),
348
+ children: /* @__PURE__ */ m("div", {
349
+ className: "space-y-4",
350
+ children: [
351
+ /* @__PURE__ */ m("div", {
352
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
353
+ children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
354
+ className: "block text-sm font-medium text-text-primary",
355
+ children: "Amount"
356
+ }), /* @__PURE__ */ p("input", {
357
+ type: "number",
358
+ min: 0,
359
+ step: "0.01",
360
+ placeholder: "0.00",
361
+ value: V.amount,
362
+ onChange: (e) => H({
363
+ ...V,
364
+ amount: e.target.value
365
+ }),
366
+ className: _
367
+ })] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
368
+ className: "block text-sm font-medium text-text-primary",
369
+ children: "Category"
370
+ }), /* @__PURE__ */ p("select", {
371
+ value: V.category,
372
+ onChange: (e) => H({
373
+ ...V,
374
+ category: e.target.value
375
+ }),
376
+ className: _,
377
+ children: g.map((e) => /* @__PURE__ */ p("option", {
378
+ value: e,
379
+ children: e
380
+ }, e))
381
+ })] })]
382
+ }),
383
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
384
+ className: "block text-sm font-medium text-text-primary",
385
+ children: "Description"
386
+ }), /* @__PURE__ */ p("input", {
387
+ type: "text",
388
+ placeholder: "What was this expense for?",
389
+ value: V.description,
390
+ onChange: (e) => H({
391
+ ...V,
392
+ description: e.target.value
393
+ }),
394
+ className: _
395
+ })] }),
396
+ /* @__PURE__ */ m("div", {
397
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
398
+ children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
399
+ className: "block text-sm font-medium text-text-primary",
400
+ children: "Project ID"
401
+ }), /* @__PURE__ */ p("input", {
402
+ type: "text",
403
+ placeholder: "Optional project ID",
404
+ value: V.projectId,
405
+ onChange: (e) => H({
406
+ ...V,
407
+ projectId: e.target.value
408
+ }),
409
+ className: _
410
+ })] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
411
+ className: "block text-sm font-medium text-text-primary",
412
+ children: "Date"
413
+ }), /* @__PURE__ */ p("input", {
414
+ type: "date",
415
+ value: V.date,
416
+ onChange: (e) => H({
417
+ ...V,
418
+ date: e.target.value
419
+ }),
420
+ className: _
421
+ })] })]
422
+ })
423
+ ]
424
+ })
425
+ }),
426
+ /* @__PURE__ */ p(s, {
427
+ open: U !== null,
428
+ onClose: () => W(null),
429
+ title: "Delete expense?",
430
+ description: U ? `${t(U.amount, U.currency)} · ${U.category} will be removed.` : void 0,
431
+ size: "sm",
432
+ footer: /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("button", {
433
+ onClick: () => W(null),
434
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
435
+ children: "Cancel"
436
+ }), /* @__PURE__ */ p("button", {
437
+ onClick: Me,
438
+ disabled: M,
439
+ 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",
440
+ children: M ? "Deleting..." : "Delete"
441
+ })] }),
442
+ children: /* @__PURE__ */ p("p", {
443
+ className: "text-sm text-text-secondary",
444
+ children: "This permanently removes the expense. This action cannot be undone."
445
+ })
446
+ }),
447
+ /* @__PURE__ */ m(s, {
448
+ open: G !== null,
449
+ onClose: () => K(null),
450
+ title: "Reject expense",
451
+ description: "Let the submitter know why this expense was rejected.",
452
+ size: "sm",
453
+ footer: /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("button", {
454
+ onClick: () => K(null),
455
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
456
+ children: "Cancel"
457
+ }), /* @__PURE__ */ p("button", {
458
+ onClick: Fe,
459
+ disabled: N,
460
+ 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",
461
+ children: N ? "Rejecting..." : "Reject Expense"
462
+ })] }),
463
+ children: [/* @__PURE__ */ p("label", {
464
+ className: "block text-sm font-medium text-text-primary",
465
+ children: "Reason"
466
+ }), /* @__PURE__ */ p("textarea", {
467
+ rows: 3,
468
+ placeholder: "Reason for rejection (optional)",
469
+ value: q,
470
+ onChange: (e) => J(e.target.value),
471
+ className: _
472
+ })]
473
+ }),
474
+ /* @__PURE__ */ p(ue, {
475
+ toasts: _e,
476
+ onDismiss: ve
103
477
  })
104
- })]
478
+ ]
105
479
  });
106
480
  }
107
481
  //#endregion
108
- export { h as ExpenseTrackingPage };
482
+ export { b as ExpenseTrackingPage };
109
483
 
110
484
  //# sourceMappingURL=ExpenseTrackingPage.js.map