@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.
- package/dist/generated/wspace-operations.js +996 -816
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js +28 -0
- package/dist/generated/wspace-types.js.map +1 -0
- package/dist/index.js +4 -4
- package/dist/timecampus/TimeCampusRoutes.js +16 -12
- package/dist/timecampus/TimeCampusRoutes.js.map +1 -1
- package/dist/timecampus/components/Modal.js +65 -0
- package/dist/timecampus/components/Modal.js.map +1 -0
- package/dist/timecampus/components/StatusBadge.js +28 -0
- package/dist/timecampus/components/StatusBadge.js.map +1 -0
- package/dist/timecampus/components/Toast.js +87 -0
- package/dist/timecampus/components/Toast.js.map +1 -0
- package/dist/timecampus/index.js +1 -1
- package/dist/timecampus/pages/HomePage.js +143 -135
- package/dist/timecampus/pages/HomePage.js.map +1 -1
- package/dist/timecampus/pages/applets/AppletStorePage.js +14 -19
- package/dist/timecampus/pages/applets/AppletStorePage.js.map +1 -1
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js +49 -37
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +315 -87
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
- package/dist/timecampus/pages/channels/ChannelsPage.js +340 -46
- package/dist/timecampus/pages/channels/ChannelsPage.js.map +1 -1
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js +374 -92
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/ReportsPage.js +70 -37
- package/dist/timecampus/pages/dashboard/ReportsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +366 -60
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +461 -87
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingPage.js +314 -55
- package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +30 -27
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +269 -74
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/ActionItemFormModal.js +127 -0
- package/dist/timecampus/pages/meetings/ActionItemFormModal.js.map +1 -0
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js +62 -52
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js +361 -74
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingFormModal.js +156 -0
- package/dist/timecampus/pages/meetings/MeetingFormModal.js.map +1 -0
- package/dist/timecampus/pages/meetings/MeetingsPage.js +175 -74
- package/dist/timecampus/pages/meetings/MeetingsPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/ParticipantFormModal.js +105 -0
- package/dist/timecampus/pages/meetings/ParticipantFormModal.js.map +1 -0
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js +307 -67
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectCreatePage.js +51 -48
- package/dist/timecampus/pages/projects/ProjectCreatePage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectDetailPage.js +248 -51
- package/dist/timecampus/pages/projects/ProjectDetailPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectsPage.js +354 -87
- package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/TasksPage.js +367 -65
- package/dist/timecampus/pages/projects/TasksPage.js.map +1 -1
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +674 -104
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js +46 -34
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamMembersPage.js +93 -69
- package/dist/timecampus/pages/team/TeamMembersPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamPage.js +4 -3
- package/dist/timecampus/pages/team/TeamPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateDetailPage.js +72 -53
- package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplatesPage.js +40 -35
- package/dist/timecampus/pages/templates/TemplatesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeEntriesPage.js +484 -97
- package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeTrackingPage.js +210 -99
- package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimerPage.js +229 -97
- package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +315 -110
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
- package/dist/timecampus/pages/timeline/TimelinePage.js +250 -0
- package/dist/timecampus/pages/timeline/TimelinePage.js.map +1 -0
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js +158 -76
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetsPage.js +181 -52
- package/dist/timecampus/pages/widgets/WidgetsPage.js.map +1 -1
- package/dist/timecampus/pages/workflows/WorkflowsPage.js +212 -61
- package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +1 -1
- package/dist/timecampus/store/timecampusStore.js +13 -1
- package/dist/timecampus/store/timecampusStore.js.map +1 -1
- package/dist/timecampus/utils/helpers.js +20 -10
- package/dist/timecampus/utils/helpers.js.map +1 -1
- 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
|
|
3
|
-
import { StatCard as
|
|
4
|
-
import { LoadingSkeleton as
|
|
5
|
-
import { useGetExpenseStatsQuery as
|
|
6
|
-
import { PageLayout as
|
|
7
|
-
import { EmptyState as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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(
|
|
183
|
+
children: /* @__PURE__ */ p(r, {
|
|
17
184
|
variant: "list",
|
|
18
185
|
count: 4
|
|
19
186
|
})
|
|
20
|
-
})
|
|
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
|
-
})
|
|
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:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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 {
|
|
482
|
+
export { b as ExpenseTrackingPage };
|
|
109
483
|
|
|
110
484
|
//# sourceMappingURL=ExpenseTrackingPage.js.map
|