@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,126 +1,513 @@
1
1
  import { formatDate as e, formatHours as t, getStatusColor as n } from "../../utils/helpers.js";
2
2
  import { LoadingSkeleton as r } from "../../components/LoadingSkeleton.js";
3
- import { useListTimeEntriesQuery as i } from "../../../generated/wspace-operations.js";
4
- import { PageLayout as a } from "../../components/PageLayout.js";
5
- import { EmptyState as o } from "../../components/EmptyState.js";
6
- import { Filter as s, Plus as c } from "lucide-react";
7
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
8
- import { GlassCard as d } from "@burdenoff/fe-libs/ui";
3
+ import { useCreateTimeEntryMutation as i, useDeleteTimeEntryMutation as a, useDuplicateTimeEntryMutation as o, useListProjectsQuery as s, useListTimeEntriesQuery as c, useUpdateTimeEntryMutation as ee } from "../../../generated/wspace-operations.js";
4
+ import { PageLayout as l } from "../../components/PageLayout.js";
5
+ import { EmptyState as te } from "../../components/EmptyState.js";
6
+ import { Modal as u } from "../../components/Modal.js";
7
+ import { useMemo as d, useState as f } from "react";
8
+ import { Copy as ne, Download as p, Filter as re, Pencil as ie, Plus as m, Trash2 as ae } from "lucide-react";
9
+ import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
10
+ import { GlassCard as oe } from "@burdenoff/fe-libs/ui";
9
11
  //#region src/timecampus/pages/time/TimeEntriesPage.tsx
10
- function f() {
11
- let { data: f, loading: p, error: m } = i({ variables: { limit: 50 } }), h = f?.timeEntries?.items ?? [];
12
- return m ? /* @__PURE__ */ l(a, {
12
+ var se = 50;
13
+ function v(e) {
14
+ if (!e) return "";
15
+ let t = new Date(e);
16
+ return Number.isNaN(t.getTime()) ? "" : (/* @__PURE__ */ new Date(t.getTime() - t.getTimezoneOffset() * 6e4)).toISOString().slice(0, 16);
17
+ }
18
+ function y(e) {
19
+ if (!e) return;
20
+ let t = new Date(e);
21
+ if (!Number.isNaN(t.getTime())) return t.toISOString();
22
+ }
23
+ function b() {
24
+ let e = /* @__PURE__ */ new Date();
25
+ return {
26
+ description: "",
27
+ projectId: "",
28
+ startTime: (/* @__PURE__ */ new Date(e.getTime() - e.getTimezoneOffset() * 6e4)).toISOString().slice(0, 16),
29
+ endTime: "",
30
+ billable: !1
31
+ };
32
+ }
33
+ function x({ form: e, onChange: t, projects: n }) {
34
+ return /* @__PURE__ */ _("div", {
35
+ className: "space-y-4",
36
+ children: [
37
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
38
+ className: "block text-sm font-medium text-text-primary",
39
+ children: "Description"
40
+ }), /* @__PURE__ */ g("input", {
41
+ type: "text",
42
+ placeholder: "What did you work on?",
43
+ value: e.description,
44
+ onChange: (e) => t({ description: e.target.value }),
45
+ className: "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"
46
+ })] }),
47
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
48
+ className: "block text-sm font-medium text-text-primary",
49
+ children: "Project"
50
+ }), /* @__PURE__ */ _("select", {
51
+ value: e.projectId,
52
+ onChange: (e) => t({ projectId: e.target.value }),
53
+ className: "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary",
54
+ children: [/* @__PURE__ */ g("option", {
55
+ value: "",
56
+ children: "No Project"
57
+ }), n.map((e) => /* @__PURE__ */ g("option", {
58
+ value: e.id,
59
+ children: e.name
60
+ }, e.id))]
61
+ })] }),
62
+ /* @__PURE__ */ _("div", {
63
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
64
+ children: [/* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
65
+ className: "block text-sm font-medium text-text-primary",
66
+ children: "Start"
67
+ }), /* @__PURE__ */ g("input", {
68
+ type: "datetime-local",
69
+ value: e.startTime,
70
+ onChange: (e) => t({ startTime: e.target.value }),
71
+ className: "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary"
72
+ })] }), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
73
+ className: "block text-sm font-medium text-text-primary",
74
+ children: "End"
75
+ }), /* @__PURE__ */ g("input", {
76
+ type: "datetime-local",
77
+ value: e.endTime,
78
+ onChange: (e) => t({ endTime: e.target.value }),
79
+ className: "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary"
80
+ })] })]
81
+ }),
82
+ /* @__PURE__ */ _("label", {
83
+ className: "flex items-center gap-2 text-sm text-text-primary",
84
+ children: [/* @__PURE__ */ g("input", {
85
+ type: "checkbox",
86
+ checked: e.billable,
87
+ onChange: (e) => t({ billable: e.target.checked }),
88
+ className: "h-4 w-4 rounded border-border-subtle"
89
+ }), "Billable"]
90
+ })
91
+ ]
92
+ });
93
+ }
94
+ function S() {
95
+ let [S, C] = f({}), [ce, w] = f(!1), [T, E] = f("all"), [D, O] = f(""), [k, A] = f(""), [le, j] = f(!1), [M, N] = f(b), [P, F] = f(null), [I, L] = f(b), [R, z] = f(null), B = Object.keys(S).length > 0, { data: V, loading: H, error: U, fetchMore: W, refetch: G } = c({
96
+ variables: {
97
+ limit: se,
98
+ offset: 0,
99
+ filter: B ? S : void 0
100
+ },
101
+ notifyOnNetworkStatusChange: !0
102
+ }), { data: ue } = s({ variables: { limit: 100 } }), K = ue?.projects?.items ?? [], q = d(() => V?.timeEntries?.items ?? [], [V?.timeEntries?.items]), de = V?.timeEntries?.hasMore ?? !1, fe = V?.timeEntries?.total ?? 0, [pe, { loading: J, error: me }] = i(), [he, { loading: Y, error: ge }] = ee(), [_e, { loading: X }] = a(), [ve, { loading: ye }] = o(), [Z, Q] = f(!1), be = async () => {
103
+ Q(!0);
104
+ try {
105
+ await W({
106
+ variables: { offset: q.length },
107
+ updateQuery: (e, { fetchMoreResult: t }) => t ? {
108
+ ...t,
109
+ timeEntries: {
110
+ ...t.timeEntries,
111
+ items: [...e.timeEntries.items, ...t.timeEntries.items]
112
+ }
113
+ } : e
114
+ });
115
+ } finally {
116
+ Q(!1);
117
+ }
118
+ }, $ = () => {
119
+ N(b()), j(!0);
120
+ }, xe = async () => {
121
+ let e = y(M.startTime);
122
+ e && (await pe({ variables: { input: {
123
+ description: M.description.trim() || void 0,
124
+ projectId: M.projectId || void 0,
125
+ startTime: e,
126
+ endTime: y(M.endTime),
127
+ billable: M.billable,
128
+ source: "manual"
129
+ } } }), j(!1), await G());
130
+ }, Se = (e) => {
131
+ F(e), L({
132
+ description: e.description ?? "",
133
+ projectId: e.projectId ?? "",
134
+ startTime: v(e.startTime),
135
+ endTime: v(e.endTime),
136
+ billable: e.billable
137
+ });
138
+ }, Ce = async () => {
139
+ if (!P) return;
140
+ let e = y(I.startTime);
141
+ e && (await he({ variables: {
142
+ id: P.id,
143
+ input: {
144
+ description: I.description.trim() || void 0,
145
+ projectId: I.projectId || void 0,
146
+ startTime: e,
147
+ endTime: y(I.endTime),
148
+ billable: I.billable
149
+ }
150
+ } }), F(null), await G());
151
+ }, we = async (e) => {
152
+ await ve({ variables: { id: e.id } }), await G();
153
+ };
154
+ return U ? /* @__PURE__ */ g(l, {
13
155
  title: "Time Entries",
14
156
  description: "View and manage all time entries",
15
- children: /* @__PURE__ */ l("div", {
157
+ children: /* @__PURE__ */ g("div", {
16
158
  className: "rounded-xl border border-status-error-bg/40 bg-status-error-bg p-6 text-sm text-status-error-text",
17
159
  children: "Failed to load time entries. Please try again later."
18
160
  })
19
- }) : /* @__PURE__ */ l(a, {
161
+ }) : /* @__PURE__ */ _(l, {
20
162
  title: "Time Entries",
21
163
  description: "View and manage all time entries",
22
164
  purpose: "Every tracked block of work in one auditable list — filter, correct and confirm entries here before they roll into timesheets, approvals and client invoices.",
23
- actions: /* @__PURE__ */ u("div", {
165
+ actions: /* @__PURE__ */ _("div", {
24
166
  className: "flex items-center gap-2",
25
- children: [/* @__PURE__ */ u("button", {
26
- className: "inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
27
- children: [/* @__PURE__ */ l(s, { className: "h-4 w-4" }), "Filter"]
28
- }), /* @__PURE__ */ u("button", {
29
- 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",
30
- children: [/* @__PURE__ */ l(c, { className: "h-4 w-4" }), "Add Entry"]
31
- })]
167
+ children: [
168
+ /* @__PURE__ */ _("button", {
169
+ onClick: () => {
170
+ E(S.billable === void 0 ? "all" : S.billable ? "yes" : "no"), O(S.projectId ?? ""), A(S.search ?? ""), w(!0);
171
+ },
172
+ className: `inline-flex items-center gap-1.5 rounded-md border px-3 py-2 text-sm font-medium hover:bg-bg-sunken/50 ${B ? "border-action-primary-border text-primary" : "border-border-subtle text-text-primary"}`,
173
+ children: [
174
+ /* @__PURE__ */ g(re, { className: "h-4 w-4" }),
175
+ "Filter",
176
+ B ? ` (${Object.keys(S).length})` : ""
177
+ ]
178
+ }),
179
+ /* @__PURE__ */ _("button", {
180
+ onClick: () => {
181
+ let t = [
182
+ "Date",
183
+ "Project",
184
+ "Task/Description",
185
+ "Duration (hours)",
186
+ "Billable",
187
+ "Status"
188
+ ], n = q.map((t) => [
189
+ e(t.startTime),
190
+ t.project?.name ?? "No Project",
191
+ t.task?.title ?? t.description ?? "",
192
+ ((t.duration ?? 0) / 3600).toFixed(2),
193
+ t.billable ? "Yes" : "No",
194
+ t.isRunning ? "running" : "completed"
195
+ ]), r = (e) => `"${e.replace(/"/g, "\"\"")}"`, i = [t, ...n].map((e) => e.map((e) => r(String(e))).join(",")).join("\n"), a = new Blob([i], { type: "text/csv;charset=utf-8;" }), o = URL.createObjectURL(a), s = document.createElement("a");
196
+ s.href = o, s.download = `time-entries-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.csv`, document.body.appendChild(s), s.click(), document.body.removeChild(s), URL.revokeObjectURL(o);
197
+ },
198
+ disabled: q.length === 0,
199
+ className: "inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50 disabled:opacity-50",
200
+ children: [/* @__PURE__ */ g(p, { className: "h-4 w-4" }), "Export"]
201
+ }),
202
+ /* @__PURE__ */ _("button", {
203
+ onClick: $,
204
+ 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",
205
+ children: [/* @__PURE__ */ g(m, { className: "h-4 w-4" }), "New Entry"]
206
+ })
207
+ ]
32
208
  }),
33
- children: p ? /* @__PURE__ */ l(r, {
34
- variant: "table",
35
- count: 5
36
- }) : h.length === 0 ? /* @__PURE__ */ l(o, {
37
- illustration: "empty-data",
38
- title: "No time entries found",
39
- description: "Track time with a timer or add a manual entry — your entries will appear here.",
40
- action: /* @__PURE__ */ u("button", {
41
- 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",
42
- children: [/* @__PURE__ */ l(c, { className: "h-4 w-4" }), "Add Entry"]
43
- })
44
- }) : /* @__PURE__ */ l(d, {
45
- treatment: "glass",
46
- glow: !0,
47
- className: "overflow-hidden",
48
- children: /* @__PURE__ */ l("div", {
49
- className: "overflow-x-auto",
50
- children: /* @__PURE__ */ u("table", {
51
- className: "w-full",
52
- children: [/* @__PURE__ */ l("thead", { children: /* @__PURE__ */ u("tr", {
53
- className: "border-b border-border-subtle",
54
- children: [
55
- /* @__PURE__ */ l("th", {
56
- className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
57
- children: "Date"
58
- }),
59
- /* @__PURE__ */ l("th", {
60
- className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
61
- children: "Project"
62
- }),
63
- /* @__PURE__ */ l("th", {
64
- className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
65
- children: "Task"
66
- }),
67
- /* @__PURE__ */ l("th", {
68
- className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
69
- children: "Duration"
70
- }),
71
- /* @__PURE__ */ l("th", {
72
- className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
73
- children: "Billable"
74
- }),
75
- /* @__PURE__ */ l("th", {
76
- className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
77
- children: "Status"
78
- })
79
- ]
80
- }) }), /* @__PURE__ */ l("tbody", {
81
- className: "divide-y divide-border",
82
- children: h.map((r) => /* @__PURE__ */ u("tr", {
83
- className: "hover:bg-bg-sunken/50 transition-colors",
209
+ children: [
210
+ H && q.length === 0 ? /* @__PURE__ */ g(r, {
211
+ variant: "table",
212
+ count: 5
213
+ }) : q.length === 0 ? /* @__PURE__ */ g(te, {
214
+ illustration: "empty-data",
215
+ title: "No time entries found",
216
+ description: "Track time with a timer or add a manual entry — your entries will appear here.",
217
+ action: /* @__PURE__ */ _("button", {
218
+ onClick: $,
219
+ 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",
220
+ children: [/* @__PURE__ */ g(m, { className: "h-4 w-4" }), "New Entry"]
221
+ })
222
+ }) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(oe, {
223
+ treatment: "glass",
224
+ glow: !0,
225
+ className: "overflow-hidden",
226
+ children: /* @__PURE__ */ g("div", {
227
+ className: "overflow-x-auto",
228
+ children: /* @__PURE__ */ _("table", {
229
+ className: "w-full",
230
+ children: [/* @__PURE__ */ g("thead", { children: /* @__PURE__ */ _("tr", {
231
+ className: "border-b border-border-subtle",
84
232
  children: [
85
- /* @__PURE__ */ l("td", {
86
- className: "px-4 py-3 text-sm text-text-secondary",
87
- children: e(r.startTime)
233
+ /* @__PURE__ */ g("th", {
234
+ className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
235
+ children: "Date"
88
236
  }),
89
- /* @__PURE__ */ l("td", {
90
- className: "px-4 py-3 text-sm font-medium text-text-primary",
91
- children: r.project?.name ?? "No Project"
237
+ /* @__PURE__ */ g("th", {
238
+ className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
239
+ children: "Project"
92
240
  }),
93
- /* @__PURE__ */ l("td", {
94
- className: "px-4 py-3 text-sm text-text-secondary",
95
- children: r.task?.title ?? r.description ?? "No description"
241
+ /* @__PURE__ */ g("th", {
242
+ className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
243
+ children: "Task"
96
244
  }),
97
- /* @__PURE__ */ l("td", {
98
- className: "px-4 py-3 text-sm font-mono text-text-primary",
99
- children: t((r.duration ?? 0) / 3600)
245
+ /* @__PURE__ */ g("th", {
246
+ className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
247
+ children: "Duration"
100
248
  }),
101
- /* @__PURE__ */ l("td", {
102
- className: "px-4 py-3",
103
- children: /* @__PURE__ */ l("span", {
104
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${r.billable ? "bg-status-success-bg text-status-success-text" : "bg-bg-sunken text-text-secondary"}`,
105
- children: r.billable ? "Yes" : "No"
106
- })
249
+ /* @__PURE__ */ g("th", {
250
+ className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
251
+ children: "Billable"
107
252
  }),
108
- /* @__PURE__ */ l("td", {
109
- className: "px-4 py-3",
110
- children: /* @__PURE__ */ l("span", {
111
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${n(r.isRunning ? "running" : "completed")}`,
112
- children: r.isRunning ? "running" : "completed"
253
+ /* @__PURE__ */ g("th", {
254
+ className: "px-4 py-3 text-left text-xs font-medium text-text-secondary",
255
+ children: "Status"
256
+ }),
257
+ /* @__PURE__ */ g("th", {
258
+ className: "px-4 py-3 text-right text-xs font-medium text-text-secondary",
259
+ children: "Actions"
260
+ })
261
+ ]
262
+ }) }), /* @__PURE__ */ g("tbody", {
263
+ className: "divide-y divide-border",
264
+ children: q.map((r) => /* @__PURE__ */ _("tr", {
265
+ className: "hover:bg-bg-sunken/50 transition-colors",
266
+ children: [
267
+ /* @__PURE__ */ g("td", {
268
+ className: "px-4 py-3 text-sm text-text-secondary",
269
+ children: e(r.startTime)
270
+ }),
271
+ /* @__PURE__ */ g("td", {
272
+ className: "px-4 py-3 text-sm font-medium text-text-primary",
273
+ children: r.project?.name ?? "No Project"
274
+ }),
275
+ /* @__PURE__ */ g("td", {
276
+ className: "px-4 py-3 text-sm text-text-secondary",
277
+ children: r.task?.title ?? r.description ?? "No description"
278
+ }),
279
+ /* @__PURE__ */ g("td", {
280
+ className: "px-4 py-3 text-sm font-mono text-text-primary",
281
+ children: t((r.duration ?? 0) / 3600)
282
+ }),
283
+ /* @__PURE__ */ g("td", {
284
+ className: "px-4 py-3",
285
+ children: /* @__PURE__ */ g("span", {
286
+ className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${r.billable ? "bg-status-success-bg text-status-success-text" : "bg-bg-sunken text-text-secondary"}`,
287
+ children: r.billable ? "Yes" : "No"
288
+ })
289
+ }),
290
+ /* @__PURE__ */ g("td", {
291
+ className: "px-4 py-3",
292
+ children: /* @__PURE__ */ g("span", {
293
+ className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${n(r.isRunning ? "running" : "completed")}`,
294
+ children: r.isRunning ? "running" : "completed"
295
+ })
296
+ }),
297
+ /* @__PURE__ */ g("td", {
298
+ className: "px-4 py-3",
299
+ children: /* @__PURE__ */ _("div", {
300
+ className: "flex items-center justify-end gap-1",
301
+ children: [
302
+ /* @__PURE__ */ g("button", {
303
+ onClick: () => Se(r),
304
+ title: "Edit entry",
305
+ "aria-label": "Edit entry",
306
+ className: "rounded-md p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-text-primary",
307
+ children: /* @__PURE__ */ g(ie, { className: "h-4 w-4" })
308
+ }),
309
+ /* @__PURE__ */ g("button", {
310
+ onClick: () => we(r),
311
+ disabled: ye,
312
+ title: "Duplicate entry",
313
+ "aria-label": "Duplicate entry",
314
+ className: "rounded-md p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-text-primary disabled:opacity-50",
315
+ children: /* @__PURE__ */ g(ne, { className: "h-4 w-4" })
316
+ }),
317
+ /* @__PURE__ */ g("button", {
318
+ onClick: () => z(r),
319
+ title: "Delete entry",
320
+ "aria-label": "Delete entry",
321
+ className: "rounded-md p-1.5 text-status-error-text hover:bg-status-error-bg",
322
+ children: /* @__PURE__ */ g(ae, { className: "h-4 w-4" })
323
+ })
324
+ ]
325
+ })
113
326
  })
327
+ ]
328
+ }, r.id))
329
+ })]
330
+ })
331
+ })
332
+ }), /* @__PURE__ */ _("div", {
333
+ className: "mt-4 flex items-center justify-between",
334
+ children: [/* @__PURE__ */ _("p", {
335
+ className: "text-xs text-text-secondary",
336
+ children: [
337
+ "Showing ",
338
+ q.length,
339
+ " of ",
340
+ fe
341
+ ]
342
+ }), de && /* @__PURE__ */ g("button", {
343
+ onClick: be,
344
+ disabled: Z,
345
+ className: "inline-flex items-center gap-1.5 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",
346
+ children: Z ? "Loading..." : "Load more"
347
+ })]
348
+ })] }),
349
+ /* @__PURE__ */ _(u, {
350
+ open: le,
351
+ onClose: () => j(!1),
352
+ title: "New Time Entry",
353
+ description: "Manually log a block of work.",
354
+ size: "lg",
355
+ footer: /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("button", {
356
+ onClick: () => j(!1),
357
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
358
+ children: "Cancel"
359
+ }), /* @__PURE__ */ g("button", {
360
+ onClick: xe,
361
+ disabled: J || !M.startTime,
362
+ 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",
363
+ children: J ? "Saving..." : "Create Entry"
364
+ })] }),
365
+ children: [me && /* @__PURE__ */ g("div", {
366
+ className: "mb-4 rounded-lg border border-status-error-bg/40 bg-status-error-bg p-3 text-sm text-status-error-text",
367
+ children: "Failed to create entry. Please try again."
368
+ }), /* @__PURE__ */ g(x, {
369
+ form: M,
370
+ onChange: (e) => N((t) => ({
371
+ ...t,
372
+ ...e
373
+ })),
374
+ projects: K
375
+ })]
376
+ }),
377
+ /* @__PURE__ */ _(u, {
378
+ open: !!P,
379
+ onClose: () => F(null),
380
+ title: "Edit Time Entry",
381
+ description: "Correct the details of this logged block.",
382
+ size: "lg",
383
+ footer: /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("button", {
384
+ onClick: () => F(null),
385
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
386
+ children: "Cancel"
387
+ }), /* @__PURE__ */ g("button", {
388
+ onClick: Ce,
389
+ disabled: Y || !I.startTime,
390
+ 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",
391
+ children: Y ? "Saving..." : "Save Changes"
392
+ })] }),
393
+ children: [ge && /* @__PURE__ */ g("div", {
394
+ className: "mb-4 rounded-lg border border-status-error-bg/40 bg-status-error-bg p-3 text-sm text-status-error-text",
395
+ children: "Failed to update entry. Please try again."
396
+ }), /* @__PURE__ */ g(x, {
397
+ form: I,
398
+ onChange: (e) => L((t) => ({
399
+ ...t,
400
+ ...e
401
+ })),
402
+ projects: K
403
+ })]
404
+ }),
405
+ /* @__PURE__ */ g(u, {
406
+ open: !!R,
407
+ onClose: () => z(null),
408
+ title: "Delete time entry?",
409
+ description: "This permanently removes the entry. It cannot be undone.",
410
+ footer: /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("button", {
411
+ onClick: () => z(null),
412
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
413
+ children: "Cancel"
414
+ }), /* @__PURE__ */ g("button", {
415
+ onClick: async () => {
416
+ R && (await _e({ variables: { id: R.id } }), z(null), await G());
417
+ },
418
+ disabled: X,
419
+ className: "rounded-md bg-action-danger-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-danger-bg/90 disabled:opacity-50",
420
+ children: X ? "Deleting..." : "Delete"
421
+ })] }),
422
+ children: /* @__PURE__ */ _("p", {
423
+ className: "text-sm text-text-secondary",
424
+ children: [
425
+ "Delete the entry for",
426
+ " ",
427
+ /* @__PURE__ */ g("span", {
428
+ className: "font-medium text-text-primary",
429
+ children: R?.project?.name ?? R?.description ?? "this block of work"
430
+ }),
431
+ "?"
432
+ ]
433
+ })
434
+ }),
435
+ /* @__PURE__ */ g(u, {
436
+ open: ce,
437
+ onClose: () => w(!1),
438
+ title: "Filter entries",
439
+ description: "Narrow the list to what you need.",
440
+ footer: /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("button", {
441
+ onClick: () => {
442
+ E("all"), O(""), A(""), C({}), w(!1);
443
+ },
444
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
445
+ children: "Clear"
446
+ }), /* @__PURE__ */ g("button", {
447
+ onClick: () => {
448
+ let e = {};
449
+ T !== "all" && (e.billable = T === "yes"), D && (e.projectId = D), k.trim() && (e.search = k.trim()), C(e), w(!1);
450
+ },
451
+ 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",
452
+ children: "Apply"
453
+ })] }),
454
+ children: /* @__PURE__ */ _("div", {
455
+ className: "space-y-4",
456
+ children: [
457
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
458
+ className: "block text-sm font-medium text-text-primary",
459
+ children: "Search"
460
+ }), /* @__PURE__ */ g("input", {
461
+ type: "text",
462
+ placeholder: "Description contains...",
463
+ value: k,
464
+ onChange: (e) => A(e.target.value),
465
+ className: "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"
466
+ })] }),
467
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
468
+ className: "block text-sm font-medium text-text-primary",
469
+ children: "Project"
470
+ }), /* @__PURE__ */ _("select", {
471
+ value: D,
472
+ onChange: (e) => O(e.target.value),
473
+ className: "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary",
474
+ children: [/* @__PURE__ */ g("option", {
475
+ value: "",
476
+ children: "All Projects"
477
+ }), K.map((e) => /* @__PURE__ */ g("option", {
478
+ value: e.id,
479
+ children: e.name
480
+ }, e.id))]
481
+ })] }),
482
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
483
+ className: "block text-sm font-medium text-text-primary",
484
+ children: "Billable"
485
+ }), /* @__PURE__ */ _("select", {
486
+ value: T,
487
+ onChange: (e) => E(e.target.value),
488
+ className: "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary",
489
+ children: [
490
+ /* @__PURE__ */ g("option", {
491
+ value: "all",
492
+ children: "All"
493
+ }),
494
+ /* @__PURE__ */ g("option", {
495
+ value: "yes",
496
+ children: "Billable only"
497
+ }),
498
+ /* @__PURE__ */ g("option", {
499
+ value: "no",
500
+ children: "Non-billable only"
114
501
  })
115
502
  ]
116
- }, r.id))
117
- })]
503
+ })] })
504
+ ]
118
505
  })
119
506
  })
120
- })
507
+ ]
121
508
  });
122
509
  }
123
510
  //#endregion
124
- export { f as TimeEntriesPage };
511
+ export { S as TimeEntriesPage };
125
512
 
126
513
  //# sourceMappingURL=TimeEntriesPage.js.map