@burdenoff/microfe-timecampus 2026.703.7 → 2026.707.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/wspace-operations.js +1023 -1514
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js +12 -18
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/timecampus/TimeCampusRoot.js +82 -150
- package/dist/timecampus/TimeCampusRoot.js.map +1 -1
- package/dist/timecampus/TimeCampusRoutes.js +96 -164
- package/dist/timecampus/TimeCampusRoutes.js.map +1 -1
- package/dist/timecampus/components/index.js +2 -2
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +7 -7
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js +6 -6
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +8 -8
- package/dist/timecampus/pages/geofencing/GeofencingPage.js +6 -6
- package/dist/timecampus/pages/lifetime/FiniteLifePage.js +91 -91
- package/dist/timecampus/pages/lifetime/FiniteLifePage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/LifeBalancePage.js +18 -18
- package/dist/timecampus/pages/lifetime/LifeTimelinePage.js +7 -7
- package/dist/timecampus/pages/lifetime/ValuesGoalsPage.js +1 -1
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +6 -6
- package/dist/timecampus/pages/projects/ProjectDetailPage.js +7 -7
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +212 -212
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamMembersPage.js +4 -4
- package/dist/timecampus/pages/time/TimeTrackingPage.js +143 -143
- package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +1 -1
- package/dist/timecampus/pages/timeline/TimelinePage.js +1 -1
- package/dist/timecampus/pages/timeline/TimelinePage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +87 -93
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
- package/package.json +1 -1
- package/dist/timecampus/pages/applets/AppletStorePage.js +0 -167
- package/dist/timecampus/pages/applets/AppletStorePage.js.map +0 -1
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js +0 -162
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +0 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js +0 -133
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js.map +0 -1
- package/dist/timecampus/pages/channels/ChannelsPage.js +0 -418
- package/dist/timecampus/pages/channels/ChannelsPage.js.map +0 -1
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js +0 -142
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js.map +0 -1
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js +0 -119
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js.map +0 -1
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js +0 -110
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js.map +0 -1
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +0 -83
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +0 -1
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js +0 -198
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js.map +0 -1
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js +0 -124
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js.map +0 -1
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js +0 -88
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js.map +0 -1
- package/dist/timecampus/pages/templates/TemplateDetailPage.js +0 -135
- package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +0 -1
- package/dist/timecampus/pages/templates/TemplatesPage.js +0 -191
- package/dist/timecampus/pages/templates/TemplatesPage.js.map +0 -1
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js +0 -196
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +0 -1
- package/dist/timecampus/pages/widgets/WidgetsPage.js +0 -297
- package/dist/timecampus/pages/widgets/WidgetsPage.js.map +0 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js +0 -133
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js.map +0 -1
- package/dist/timecampus/pages/workflows/WorkflowsPage.js +0 -311
- package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +0 -1
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
import { useTimeCampusNavigate as e } from "../../providers/TimeCampusProvider.js";
|
|
2
|
-
import { formatDate as t } from "../../utils/helpers.js";
|
|
3
|
-
import { StatCard as n } from "../../components/StatCard.js";
|
|
4
|
-
import { LoadingSkeleton as r } from "../../components/LoadingSkeleton.js";
|
|
5
|
-
import { useDeleteConfigurationMutation as i, useListConfigurationsQuery as a, useSetConfigurationMutation as o } from "../../../generated/wspace-operations.js";
|
|
6
|
-
import { PageLayout as s } from "../../components/PageLayout.js";
|
|
7
|
-
import { StatusBadge as c } from "../../components/StatusBadge.js";
|
|
8
|
-
import { EmptyState as l } from "../../components/EmptyState.js";
|
|
9
|
-
import { ChartCard as u } from "../../components/ChartCard.js";
|
|
10
|
-
import { Modal as d } from "../../components/Modal.js";
|
|
11
|
-
import { DonutChart as f } from "../../components/charts/DonutChart.js";
|
|
12
|
-
import "../../components/index.js";
|
|
13
|
-
import { TimeCampusConfigScope as p } from "../../../generated/wspace-types.js";
|
|
14
|
-
import { useState as m } from "react";
|
|
15
|
-
import { ArrowRight as h, Brain as g, CircleDollarSign as _, Clock as v, FileText as y, FolderKanban as b, Layers as x, LayoutGrid as S, Plus as C, Timer as w, Trash2 as T, Users as E } from "lucide-react";
|
|
16
|
-
import { Fragment as D, jsx as O, jsxs as k } from "react/jsx-runtime";
|
|
17
|
-
import { GlassCard as A } from "@burdenoff/fe-libs/ui";
|
|
18
|
-
//#region src/timecampus/pages/widgets/WidgetsPage.tsx
|
|
19
|
-
var j = [
|
|
20
|
-
{
|
|
21
|
-
value: "timer",
|
|
22
|
-
label: "Active timer"
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
value: "project-progress",
|
|
26
|
-
label: "Project progress"
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
value: "focus-score",
|
|
30
|
-
label: "Focus score"
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
value: "team-stats",
|
|
34
|
-
label: "Team stats"
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
value: "billable-hours",
|
|
38
|
-
label: "Billable hours"
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
value: "recent-entries",
|
|
42
|
-
label: "Recent time entries"
|
|
43
|
-
}
|
|
44
|
-
], M = {
|
|
45
|
-
timer: w,
|
|
46
|
-
"project-progress": b,
|
|
47
|
-
"focus-score": g,
|
|
48
|
-
"team-stats": E,
|
|
49
|
-
"billable-hours": _,
|
|
50
|
-
"recent-entries": v
|
|
51
|
-
};
|
|
52
|
-
function N(e) {
|
|
53
|
-
return j.find((t) => t.value === e)?.label ?? e;
|
|
54
|
-
}
|
|
55
|
-
function ee(e) {
|
|
56
|
-
return M[e] ?? S;
|
|
57
|
-
}
|
|
58
|
-
function P() {
|
|
59
|
-
let g = e(), { data: _, loading: v, error: b, refetch: w } = a({ variables: { scope: p.Workspace } }), [E, { loading: M, error: P }] = o(), [F] = i(), [I, L] = m(!1), [R, z] = m(""), [B, V] = m(j[0].value), [H, U] = m(""), [W, G] = m(null), K = (_?.timeCampusConfigurations ?? []).filter((e) => e.key.startsWith("widget.")), q = K.reduce((e, t) => {
|
|
60
|
-
let n = (t.value ?? {}).type ?? "timer";
|
|
61
|
-
return e[n] = (e[n] ?? 0) + 1, e;
|
|
62
|
-
}, {}), J = Object.keys(q).length, Y = K.filter((e) => !!((e.value ?? {}).description ?? e.description)).length, X = Object.entries(q).sort((e, t) => t[1] - e[1]).map(([e, t]) => ({
|
|
63
|
-
name: N(e),
|
|
64
|
-
value: t
|
|
65
|
-
})), Z = () => {
|
|
66
|
-
z(""), V(j[0].value), U("");
|
|
67
|
-
}, Q = () => {
|
|
68
|
-
Z(), L(!0);
|
|
69
|
-
}, te = async () => {
|
|
70
|
-
if (!R.trim()) return;
|
|
71
|
-
let e = typeof crypto < "u" && "randomUUID" in crypto ? crypto.randomUUID() : `${Date.now()}`, t = H.trim();
|
|
72
|
-
await E({ variables: { input: {
|
|
73
|
-
key: `widget.${e}`,
|
|
74
|
-
scope: p.Workspace,
|
|
75
|
-
value: {
|
|
76
|
-
name: R.trim(),
|
|
77
|
-
type: B,
|
|
78
|
-
description: t || void 0,
|
|
79
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
80
|
-
},
|
|
81
|
-
description: t || void 0
|
|
82
|
-
} } }), await w(), L(!1), Z();
|
|
83
|
-
}, ne = async (e) => {
|
|
84
|
-
G(e);
|
|
85
|
-
try {
|
|
86
|
-
await F({ variables: { id: e } }), await w();
|
|
87
|
-
} finally {
|
|
88
|
-
G(null);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
if (v) return /* @__PURE__ */ O(s, {
|
|
92
|
-
title: "Widgets",
|
|
93
|
-
description: "Customize your dashboard with widgets",
|
|
94
|
-
children: /* @__PURE__ */ O(r, {
|
|
95
|
-
variant: "card",
|
|
96
|
-
count: 6
|
|
97
|
-
})
|
|
98
|
-
});
|
|
99
|
-
if (b) return /* @__PURE__ */ O(s, {
|
|
100
|
-
title: "Widgets",
|
|
101
|
-
description: "Customize your dashboard with widgets",
|
|
102
|
-
children: /* @__PURE__ */ O("div", {
|
|
103
|
-
className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
|
|
104
|
-
children: "Failed to load widget configurations. Please try again later."
|
|
105
|
-
})
|
|
106
|
-
});
|
|
107
|
-
let $ = /* @__PURE__ */ k("button", {
|
|
108
|
-
type: "button",
|
|
109
|
-
onClick: Q,
|
|
110
|
-
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",
|
|
111
|
-
children: [/* @__PURE__ */ O(C, { className: "h-4 w-4" }), "Create Widget"]
|
|
112
|
-
});
|
|
113
|
-
return /* @__PURE__ */ k(s, {
|
|
114
|
-
title: "Widgets",
|
|
115
|
-
description: "Customize your dashboard with widgets",
|
|
116
|
-
purpose: "Build a dashboard that shows what you care about — define widgets for timers, projects, focus and team stats so your most important numbers are the first thing you see. Each widget you create is saved to your workspace configuration.",
|
|
117
|
-
actions: $,
|
|
118
|
-
children: [K.length === 0 ? /* @__PURE__ */ O(l, {
|
|
119
|
-
illustration: "empty-generic",
|
|
120
|
-
title: "No widgets configured yet",
|
|
121
|
-
description: "Add your first widget to start customising your dashboard — widgets are stored as workspace configurations and appear here.",
|
|
122
|
-
action: $
|
|
123
|
-
}) : /* @__PURE__ */ k("div", {
|
|
124
|
-
className: "space-y-6",
|
|
125
|
-
children: [/* @__PURE__ */ k("div", {
|
|
126
|
-
className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
|
|
127
|
-
children: [
|
|
128
|
-
/* @__PURE__ */ O(n, {
|
|
129
|
-
featured: !0,
|
|
130
|
-
title: "Widgets",
|
|
131
|
-
value: K.length,
|
|
132
|
-
icon: /* @__PURE__ */ O(S, { className: "h-5 w-5" }),
|
|
133
|
-
description: "On your dashboard"
|
|
134
|
-
}),
|
|
135
|
-
/* @__PURE__ */ O(n, {
|
|
136
|
-
title: "Metric Types",
|
|
137
|
-
value: J,
|
|
138
|
-
icon: /* @__PURE__ */ O(x, { className: "h-5 w-5" }),
|
|
139
|
-
description: "Distinct metrics",
|
|
140
|
-
iconBgColor: "bg-status-info-bg text-status-info-text"
|
|
141
|
-
}),
|
|
142
|
-
/* @__PURE__ */ O(n, {
|
|
143
|
-
title: "Documented",
|
|
144
|
-
value: Y,
|
|
145
|
-
icon: /* @__PURE__ */ O(y, { className: "h-5 w-5" }),
|
|
146
|
-
description: "Have a description",
|
|
147
|
-
iconBgColor: "bg-status-success-bg text-status-success-text"
|
|
148
|
-
})
|
|
149
|
-
]
|
|
150
|
-
}), /* @__PURE__ */ k("div", {
|
|
151
|
-
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
152
|
-
children: [/* @__PURE__ */ O(u, {
|
|
153
|
-
title: "Dashboard composition",
|
|
154
|
-
description: "Widgets by metric",
|
|
155
|
-
className: "lg:col-span-1",
|
|
156
|
-
children: /* @__PURE__ */ O(f, {
|
|
157
|
-
data: X,
|
|
158
|
-
centerLabel: "Widgets",
|
|
159
|
-
centerValue: K.length,
|
|
160
|
-
height: 240,
|
|
161
|
-
ariaLabel: "Widgets grouped by metric type",
|
|
162
|
-
emptyLabel: "No widgets to summarise yet."
|
|
163
|
-
})
|
|
164
|
-
}), /* @__PURE__ */ O("div", {
|
|
165
|
-
className: "lg:col-span-2",
|
|
166
|
-
children: /* @__PURE__ */ O("div", {
|
|
167
|
-
className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
168
|
-
children: K.map((e) => {
|
|
169
|
-
let n = e.value ?? {}, r = n.name ?? e.key.replace("widget.", ""), i = n.type ?? "timer", a = n.description ?? e.description ?? "", o = n.createdAt;
|
|
170
|
-
return /* @__PURE__ */ k(A, {
|
|
171
|
-
treatment: "glass",
|
|
172
|
-
role: "button",
|
|
173
|
-
tabIndex: 0,
|
|
174
|
-
onClick: () => g(`/widgets/${e.id}`),
|
|
175
|
-
onKeyDown: (t) => {
|
|
176
|
-
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), g(`/widgets/${e.id}`));
|
|
177
|
-
},
|
|
178
|
-
className: "flex cursor-pointer flex-col p-5",
|
|
179
|
-
children: [
|
|
180
|
-
/* @__PURE__ */ k("div", {
|
|
181
|
-
className: "flex items-start justify-between gap-3",
|
|
182
|
-
children: [/* @__PURE__ */ k("div", {
|
|
183
|
-
className: "flex min-w-0 items-center gap-3",
|
|
184
|
-
children: [/* @__PURE__ */ O("div", {
|
|
185
|
-
className: "flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-action-primary-bg/10 text-primary",
|
|
186
|
-
children: /* @__PURE__ */ O(ee(i), { className: "h-5 w-5" })
|
|
187
|
-
}), /* @__PURE__ */ k("div", {
|
|
188
|
-
className: "min-w-0",
|
|
189
|
-
children: [/* @__PURE__ */ O("p", {
|
|
190
|
-
className: "truncate text-sm font-semibold text-text-primary",
|
|
191
|
-
children: r
|
|
192
|
-
}), /* @__PURE__ */ O("div", {
|
|
193
|
-
className: "mt-1",
|
|
194
|
-
children: /* @__PURE__ */ O(c, {
|
|
195
|
-
variant: "default",
|
|
196
|
-
label: N(i)
|
|
197
|
-
})
|
|
198
|
-
})]
|
|
199
|
-
})]
|
|
200
|
-
}), /* @__PURE__ */ O("button", {
|
|
201
|
-
type: "button",
|
|
202
|
-
"aria-label": `Delete ${r}`,
|
|
203
|
-
disabled: W === e.id,
|
|
204
|
-
onClick: (t) => {
|
|
205
|
-
t.stopPropagation(), ne(e.id);
|
|
206
|
-
},
|
|
207
|
-
className: "rounded-md p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-status-error-text disabled:opacity-50",
|
|
208
|
-
children: /* @__PURE__ */ O(T, { className: "h-4 w-4" })
|
|
209
|
-
})]
|
|
210
|
-
}),
|
|
211
|
-
a && /* @__PURE__ */ O("p", {
|
|
212
|
-
className: "mt-3 line-clamp-2 text-xs text-text-secondary",
|
|
213
|
-
children: a
|
|
214
|
-
}),
|
|
215
|
-
/* @__PURE__ */ k("div", {
|
|
216
|
-
className: "mt-4 flex items-center justify-between border-t border-border-seam pt-3",
|
|
217
|
-
children: [/* @__PURE__ */ O("span", {
|
|
218
|
-
className: "text-xs text-text-secondary",
|
|
219
|
-
children: o ? `Added ${t(o)}` : "Widget"
|
|
220
|
-
}), /* @__PURE__ */ k("span", {
|
|
221
|
-
className: "inline-flex items-center gap-1 text-xs font-medium text-primary",
|
|
222
|
-
children: ["Configure", /* @__PURE__ */ O(h, { className: "h-3 w-3" })]
|
|
223
|
-
})]
|
|
224
|
-
})
|
|
225
|
-
]
|
|
226
|
-
}, e.id);
|
|
227
|
-
})
|
|
228
|
-
})
|
|
229
|
-
})]
|
|
230
|
-
})]
|
|
231
|
-
}), /* @__PURE__ */ k(d, {
|
|
232
|
-
open: I,
|
|
233
|
-
onClose: () => L(!1),
|
|
234
|
-
title: "Create Widget",
|
|
235
|
-
description: "Define a dashboard widget for your workspace.",
|
|
236
|
-
footer: /* @__PURE__ */ k(D, { children: [/* @__PURE__ */ O("button", {
|
|
237
|
-
type: "button",
|
|
238
|
-
onClick: () => L(!1),
|
|
239
|
-
className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
|
|
240
|
-
children: "Cancel"
|
|
241
|
-
}), /* @__PURE__ */ O("button", {
|
|
242
|
-
type: "button",
|
|
243
|
-
onClick: te,
|
|
244
|
-
disabled: M || !R.trim(),
|
|
245
|
-
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",
|
|
246
|
-
children: M ? "Creating..." : "Create Widget"
|
|
247
|
-
})] }),
|
|
248
|
-
children: [P && /* @__PURE__ */ O("div", {
|
|
249
|
-
className: "mb-4 rounded-lg border border-status-error-bg/40 bg-status-error-bg p-3 text-sm text-status-error-text",
|
|
250
|
-
children: "Failed to create widget. Please try again."
|
|
251
|
-
}), /* @__PURE__ */ k("div", {
|
|
252
|
-
className: "space-y-4",
|
|
253
|
-
children: [
|
|
254
|
-
/* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("label", {
|
|
255
|
-
className: "block text-sm font-medium text-text-primary",
|
|
256
|
-
children: "Widget Name"
|
|
257
|
-
}), /* @__PURE__ */ O("input", {
|
|
258
|
-
type: "text",
|
|
259
|
-
placeholder: "e.g. This week's billable hours",
|
|
260
|
-
value: R,
|
|
261
|
-
onChange: (e) => z(e.target.value),
|
|
262
|
-
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"
|
|
263
|
-
})] }),
|
|
264
|
-
/* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("label", {
|
|
265
|
-
className: "block text-sm font-medium text-text-primary",
|
|
266
|
-
children: "Metric"
|
|
267
|
-
}), /* @__PURE__ */ O("select", {
|
|
268
|
-
value: B,
|
|
269
|
-
onChange: (e) => V(e.target.value),
|
|
270
|
-
className: "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary",
|
|
271
|
-
children: j.map((e) => /* @__PURE__ */ O("option", {
|
|
272
|
-
value: e.value,
|
|
273
|
-
children: e.label
|
|
274
|
-
}, e.value))
|
|
275
|
-
})] }),
|
|
276
|
-
/* @__PURE__ */ k("div", { children: [/* @__PURE__ */ k("label", {
|
|
277
|
-
className: "block text-sm font-medium text-text-primary",
|
|
278
|
-
children: ["Description", /* @__PURE__ */ O("span", {
|
|
279
|
-
className: "ml-1 font-normal text-text-secondary",
|
|
280
|
-
children: "(optional)"
|
|
281
|
-
})]
|
|
282
|
-
}), /* @__PURE__ */ O("textarea", {
|
|
283
|
-
placeholder: "What this widget shows",
|
|
284
|
-
rows: 3,
|
|
285
|
-
value: H,
|
|
286
|
-
onChange: (e) => U(e.target.value),
|
|
287
|
-
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"
|
|
288
|
-
})] })
|
|
289
|
-
]
|
|
290
|
-
})]
|
|
291
|
-
})]
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
//#endregion
|
|
295
|
-
export { P as WidgetsPage };
|
|
296
|
-
|
|
297
|
-
//# sourceMappingURL=WidgetsPage.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetsPage.js","names":[],"sources":["../../../../src/timecampus/pages/widgets/WidgetsPage.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport {\n LayoutGrid,\n Plus,\n Trash2,\n ArrowRight,\n Timer,\n FolderKanban,\n Brain,\n Users,\n CircleDollarSign,\n Clock,\n Layers,\n FileText,\n type LucideIcon,\n} from \"lucide-react\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport {\n PageLayout,\n EmptyState,\n LoadingSkeleton,\n Modal,\n StatCard,\n StatusBadge,\n ChartCard,\n DonutChart,\n} from \"../../components\";\nimport { formatDate } from \"../../utils/helpers\";\nimport { useTimeCampusNavigate } from \"../../providers/TimeCampusProvider\";\nimport {\n useListConfigurationsQuery,\n useSetConfigurationMutation,\n useDeleteConfigurationMutation,\n type ConfigurationFieldsFragment,\n} from \"@/generated/wspace-operations\";\nimport { TimeCampusConfigScope } from \"@/generated/wspace-types\";\n\nconst WIDGET_TYPES = [\n { value: \"timer\", label: \"Active timer\" },\n { value: \"project-progress\", label: \"Project progress\" },\n { value: \"focus-score\", label: \"Focus score\" },\n { value: \"team-stats\", label: \"Team stats\" },\n { value: \"billable-hours\", label: \"Billable hours\" },\n { value: \"recent-entries\", label: \"Recent time entries\" },\n];\n\nconst WIDGET_TYPE_ICONS: Record<string, LucideIcon> = {\n timer: Timer,\n \"project-progress\": FolderKanban,\n \"focus-score\": Brain,\n \"team-stats\": Users,\n \"billable-hours\": CircleDollarSign,\n \"recent-entries\": Clock,\n};\n\nfunction widgetTypeLabel(value: string): string {\n return WIDGET_TYPES.find((t) => t.value === value)?.label ?? value;\n}\n\nfunction widgetTypeIcon(value: string): LucideIcon {\n return WIDGET_TYPE_ICONS[value] ?? LayoutGrid;\n}\n\nexport function WidgetsPage() {\n const navigate = useTimeCampusNavigate();\n\n const { data, loading, error, refetch } = useListConfigurationsQuery({\n variables: { scope: TimeCampusConfigScope.Workspace },\n });\n\n const [setConfiguration, { loading: creating, error: createError }] =\n useSetConfigurationMutation();\n const [deleteConfiguration] = useDeleteConfigurationMutation();\n\n const [modalOpen, setModalOpen] = useState(false);\n const [name, setName] = useState(\"\");\n const [type, setType] = useState(WIDGET_TYPES[0].value);\n const [description, setDescription] = useState(\"\");\n const [deletingId, setDeletingId] = useState<string | null>(null);\n\n const configurations: ConfigurationFieldsFragment[] =\n data?.timeCampusConfigurations ?? [];\n const widgets = configurations.filter((c: ConfigurationFieldsFragment) =>\n c.key.startsWith(\"widget.\"),\n );\n\n // Real, derived aggregates over the widget definitions the page already loads.\n const typeCounts = widgets.reduce<Record<string, number>>((acc, widget) => {\n const val = (widget.value as Record<string, unknown>) ?? {};\n const t = (val.type as string) ?? \"timer\";\n acc[t] = (acc[t] ?? 0) + 1;\n return acc;\n }, {});\n const distinctTypes = Object.keys(typeCounts).length;\n const documentedCount = widgets.filter((widget) => {\n const val = (widget.value as Record<string, unknown>) ?? {};\n return Boolean((val.description as string) ?? widget.description);\n }).length;\n const mixData = Object.entries(typeCounts)\n .sort((a, b) => b[1] - a[1])\n .map(([t, count]) => ({ name: widgetTypeLabel(t), value: count }));\n\n const resetForm = () => {\n setName(\"\");\n setType(WIDGET_TYPES[0].value);\n setDescription(\"\");\n };\n\n const openModal = () => {\n resetForm();\n setModalOpen(true);\n };\n\n const handleCreate = async () => {\n if (!name.trim()) return;\n const id =\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\n ? crypto.randomUUID()\n : `${Date.now()}`;\n const trimmedDescription = description.trim();\n await setConfiguration({\n variables: {\n input: {\n key: `widget.${id}`,\n scope: TimeCampusConfigScope.Workspace,\n value: {\n name: name.trim(),\n type,\n description: trimmedDescription || undefined,\n createdAt: new Date().toISOString(),\n },\n description: trimmedDescription || undefined,\n },\n },\n });\n await refetch();\n setModalOpen(false);\n resetForm();\n };\n\n const handleDelete = async (id: string) => {\n setDeletingId(id);\n try {\n await deleteConfiguration({ variables: { id } });\n await refetch();\n } finally {\n setDeletingId(null);\n }\n };\n\n if (loading) {\n return (\n <PageLayout\n title=\"Widgets\"\n description=\"Customize your dashboard with widgets\"\n >\n <LoadingSkeleton variant=\"card\" count={6} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Widgets\"\n description=\"Customize your dashboard with widgets\"\n >\n <div className=\"rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text\">\n Failed to load widget configurations. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n const createButton = (\n <button\n type=\"button\"\n onClick={openModal}\n 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\"\n >\n <Plus className=\"h-4 w-4\" />\n Create Widget\n </button>\n );\n\n return (\n <PageLayout\n title=\"Widgets\"\n description=\"Customize your dashboard with widgets\"\n purpose=\"Build a dashboard that shows what you care about — define widgets for timers, projects, focus and team stats so your most important numbers are the first thing you see. Each widget you create is saved to your workspace configuration.\"\n actions={createButton}\n >\n {widgets.length === 0 ? (\n <EmptyState\n illustration=\"empty-generic\"\n title=\"No widgets configured yet\"\n description=\"Add your first widget to start customising your dashboard — widgets are stored as workspace configurations and appear here.\"\n action={createButton}\n />\n ) : (\n <div className=\"space-y-6\">\n {/* KPI summary — derived from the widget definitions above */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <StatCard\n featured\n title=\"Widgets\"\n value={widgets.length}\n icon={<LayoutGrid className=\"h-5 w-5\" />}\n description=\"On your dashboard\"\n />\n <StatCard\n title=\"Metric Types\"\n value={distinctTypes}\n icon={<Layers className=\"h-5 w-5\" />}\n description=\"Distinct metrics\"\n iconBgColor=\"bg-status-info-bg text-status-info-text\"\n />\n <StatCard\n title=\"Documented\"\n value={documentedCount}\n icon={<FileText className=\"h-5 w-5\" />}\n description=\"Have a description\"\n iconBgColor=\"bg-status-success-bg text-status-success-text\"\n />\n </div>\n\n {/* Composition ring + widget gallery */}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <ChartCard\n title=\"Dashboard composition\"\n description=\"Widgets by metric\"\n className=\"lg:col-span-1\"\n >\n <DonutChart\n data={mixData}\n centerLabel=\"Widgets\"\n centerValue={widgets.length}\n height={240}\n ariaLabel=\"Widgets grouped by metric type\"\n emptyLabel=\"No widgets to summarise yet.\"\n />\n </ChartCard>\n\n <div className=\"lg:col-span-2\">\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n {widgets.map((widget: ConfigurationFieldsFragment) => {\n const val = (widget.value as Record<string, unknown>) ?? {};\n const widgetName =\n (val.name as string) ?? widget.key.replace(\"widget.\", \"\");\n const widgetType = (val.type as string) ?? \"timer\";\n const widgetDescription =\n (val.description as string) ?? widget.description ?? \"\";\n const createdAt = val.createdAt as string | undefined;\n const Icon = widgetTypeIcon(widgetType);\n\n return (\n <GlassCard\n key={widget.id}\n treatment=\"glass\"\n role=\"button\"\n tabIndex={0}\n onClick={() => navigate(`/widgets/${widget.id}`)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n navigate(`/widgets/${widget.id}`);\n }\n }}\n className=\"flex cursor-pointer flex-col p-5\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-center gap-3\">\n <div className=\"flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-action-primary-bg/10 text-primary\">\n <Icon className=\"h-5 w-5\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold text-text-primary\">\n {widgetName}\n </p>\n <div className=\"mt-1\">\n <StatusBadge\n variant=\"default\"\n label={widgetTypeLabel(widgetType)}\n />\n </div>\n </div>\n </div>\n <button\n type=\"button\"\n aria-label={`Delete ${widgetName}`}\n disabled={deletingId === widget.id}\n onClick={(e) => {\n e.stopPropagation();\n void handleDelete(widget.id);\n }}\n className=\"rounded-md p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-status-error-text disabled:opacity-50\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </div>\n {widgetDescription && (\n <p className=\"mt-3 line-clamp-2 text-xs text-text-secondary\">\n {widgetDescription}\n </p>\n )}\n <div className=\"mt-4 flex items-center justify-between border-t border-border-seam pt-3\">\n <span className=\"text-xs text-text-secondary\">\n {createdAt\n ? `Added ${formatDate(createdAt)}`\n : \"Widget\"}\n </span>\n <span className=\"inline-flex items-center gap-1 text-xs font-medium text-primary\">\n Configure\n <ArrowRight className=\"h-3 w-3\" />\n </span>\n </div>\n </GlassCard>\n );\n })}\n </div>\n </div>\n </div>\n </div>\n )}\n\n <Modal\n open={modalOpen}\n onClose={() => setModalOpen(false)}\n title=\"Create Widget\"\n description=\"Define a dashboard widget for your workspace.\"\n footer={\n <>\n <button\n type=\"button\"\n onClick={() => setModalOpen(false)}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleCreate}\n disabled={creating || !name.trim()}\n 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\"\n >\n {creating ? \"Creating...\" : \"Create Widget\"}\n </button>\n </>\n }\n >\n {createError && (\n <div className=\"mb-4 rounded-lg border border-status-error-bg/40 bg-status-error-bg p-3 text-sm text-status-error-text\">\n Failed to create widget. Please try again.\n </div>\n )}\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary\">\n Widget Name\n </label>\n <input\n type=\"text\"\n placeholder=\"e.g. This week's billable hours\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n 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\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary\">\n Metric\n </label>\n <select\n value={type}\n onChange={(e) => setType(e.target.value)}\n className=\"mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n {WIDGET_TYPES.map((t) => (\n <option key={t.value} value={t.value}>\n {t.label}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary\">\n Description\n <span className=\"ml-1 font-normal text-text-secondary\">\n (optional)\n </span>\n </label>\n <textarea\n placeholder=\"What this widget shows\"\n rows={3}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n 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\"\n />\n </div>\n </div>\n </Modal>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqCA,IAAM,IAAe;CACnB;EAAE,OAAO;EAAS,OAAO;EAAgB;CACzC;EAAE,OAAO;EAAoB,OAAO;EAAoB;CACxD;EAAE,OAAO;EAAe,OAAO;EAAe;CAC9C;EAAE,OAAO;EAAc,OAAO;EAAc;CAC5C;EAAE,OAAO;EAAkB,OAAO;EAAkB;CACpD;EAAE,OAAO;EAAkB,OAAO;EAAuB;CAC1D,EAEK,IAAgD;CACpD,OAAO;CACP,oBAAoB;CACpB,eAAe;CACf,cAAc;CACd,kBAAkB;CAClB,kBAAkB;CACnB;AAED,SAAS,EAAgB,GAAuB;AAC9C,QAAO,EAAa,MAAM,MAAM,EAAE,UAAU,EAAM,EAAE,SAAS;;AAG/D,SAAS,GAAe,GAA2B;AACjD,QAAO,EAAkB,MAAU;;AAGrC,SAAgB,IAAc;CAC5B,IAAM,IAAW,GAAuB,EAElC,EAAE,SAAM,YAAS,UAAO,eAAY,EAA2B,EACnE,WAAW,EAAE,OAAO,EAAsB,WAAW,EACtD,CAAC,EAEI,CAAC,GAAkB,EAAE,SAAS,GAAU,OAAO,OACnD,GAA6B,EACzB,CAAC,KAAuB,GAAgC,EAExD,CAAC,GAAW,KAAgB,EAAS,GAAM,EAC3C,CAAC,GAAM,KAAW,EAAS,GAAG,EAC9B,CAAC,GAAM,KAAW,EAAS,EAAa,GAAG,MAAM,EACjD,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAY,KAAiB,EAAwB,KAAK,EAI3D,KADJ,GAAM,4BAA4B,EAAE,EACP,QAAQ,MACrC,EAAE,IAAI,WAAW,UAAU,CAC5B,EAGK,IAAa,EAAQ,QAAgC,GAAK,MAAW;EAEzE,IAAM,KADO,EAAO,SAAqC,EAAE,EAC5C,QAAmB;AAElC,SADA,EAAI,MAAM,EAAI,MAAM,KAAK,GAClB;IACN,EAAE,CAAC,EACA,IAAgB,OAAO,KAAK,EAAW,CAAC,QACxC,IAAkB,EAAQ,QAAQ,MAE/B,IADM,EAAO,SAAqC,EAAE,EACvC,eAA0B,EAAO,aACrD,CAAC,QACG,IAAU,OAAO,QAAQ,EAAW,CACvC,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG,CAC3B,KAAK,CAAC,GAAG,QAAY;EAAE,MAAM,EAAgB,EAAE;EAAE,OAAO;EAAO,EAAE,EAE9D,UAAkB;AAGtB,EAFA,EAAQ,GAAG,EACX,EAAQ,EAAa,GAAG,MAAM,EAC9B,EAAe,GAAG;IAGd,UAAkB;AAEtB,EADA,GAAW,EACX,EAAa,GAAK;IAGd,KAAe,YAAY;AAC/B,MAAI,CAAC,EAAK,MAAM,CAAE;EAClB,IAAM,IACJ,OAAO,SAAW,OAAe,gBAAgB,SAC7C,OAAO,YAAY,GACnB,GAAG,KAAK,KAAK,IACb,IAAqB,EAAY,MAAM;AAkB7C,EAjBA,MAAM,EAAiB,EACrB,WAAW,EACT,OAAO;GACL,KAAK,UAAU;GACf,OAAO,EAAsB;GAC7B,OAAO;IACL,MAAM,EAAK,MAAM;IACjB;IACA,aAAa,KAAsB,KAAA;IACnC,4BAAW,IAAI,MAAM,EAAC,aAAa;IACpC;GACD,aAAa,KAAsB,KAAA;GACpC,EACF,EACF,CAAC,EACF,MAAM,GAAS,EACf,EAAa,GAAM,EACnB,GAAW;IAGP,KAAe,OAAO,MAAe;AACzC,IAAc,EAAG;AACjB,MAAI;AAEF,GADA,MAAM,EAAoB,EAAE,WAAW,EAAE,OAAI,EAAE,CAAC,EAChD,MAAM,GAAS;YACP;AACR,KAAc,KAAK;;;AAIvB,KAAI,EACF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA;AAIjB,KAAI,EACF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAAoG;GAE7G,CAAA;EACK,CAAA;CAIjB,IAAM,IACJ,kBAAC,UAAD;EACE,MAAK;EACL,SAAS;EACT,WAAU;YAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,gBAErB;;AAGX,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SAAQ;EACR,SAAS;YAJX,CAMG,EAAQ,WAAW,IAClB,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,QAAQ;GACR,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aAAf,CAEE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,UAAA;MACA,OAAM;MACN,OAAO,EAAQ;MACf,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;MACxC,aAAY;MACZ,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO;MACP,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;MACpC,aAAY;MACZ,aAAY;MACZ,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO;MACP,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;MACtC,aAAY;MACZ,aAAY;MACZ,CAAA;KACE;OAGN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACE,OAAM;KACN,aAAY;KACZ,WAAU;eAEV,kBAAC,GAAD;MACE,MAAM;MACN,aAAY;MACZ,aAAa,EAAQ;MACrB,QAAQ;MACR,WAAU;MACV,YAAW;MACX,CAAA;KACQ,CAAA,EAEZ,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAQ,KAAK,MAAwC;OACpD,IAAM,IAAO,EAAO,SAAqC,EAAE,EACrD,IACH,EAAI,QAAmB,EAAO,IAAI,QAAQ,WAAW,GAAG,EACrD,IAAc,EAAI,QAAmB,SACrC,IACH,EAAI,eAA0B,EAAO,eAAe,IACjD,IAAY,EAAI;AAGtB,cACE,kBAAC,GAAD;QAEE,WAAU;QACV,MAAK;QACL,UAAU;QACV,eAAe,EAAS,YAAY,EAAO,KAAK;QAChD,YAAY,MAAM;AAChB,UAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,EAAS,YAAY,EAAO,KAAK;;QAGrC,WAAU;kBAZZ;SAcE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,OAAD;YAAK,WAAU;sBACb,kBApBG,GAAe,EAAW,EAoB7B,EAAM,WAAU,WAAY,CAAA;YACxB,CAAA,EACN,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,KAAD;aAAG,WAAU;uBACV;aACC,CAAA,EACJ,kBAAC,OAAD;aAAK,WAAU;uBACb,kBAAC,GAAD;cACE,SAAQ;cACR,OAAO,EAAgB,EAAW;cAClC,CAAA;aACE,CAAA,CACF;cACF;cACN,kBAAC,UAAD;WACE,MAAK;WACL,cAAY,UAAU;WACtB,UAAU,MAAe,EAAO;WAChC,UAAU,MAAM;AAET,YADL,EAAE,iBAAiB,EACd,GAAa,EAAO,GAAG;;WAE9B,WAAU;qBAEV,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;WACvB,CAAA,CACL;;SACL,KACC,kBAAC,KAAD;UAAG,WAAU;oBACV;UACC,CAAA;SAEN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBACb,IACG,SAAS,EAAW,EAAU,KAC9B;WACC,CAAA,EACP,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAAkF,aAEhF,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA,CAC7B;aACH;;SACI;UA3DL,EAAO,GA2DF;QAEd;MACE,CAAA;KACF,CAAA,CACF;MACF;MAGR,kBAAC,GAAD;GACE,MAAM;GACN,eAAe,EAAa,GAAM;GAClC,OAAM;GACN,aAAY;GACZ,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAa,GAAM;IAClC,WAAU;cACX;IAEQ,CAAA,EACT,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,UAAU,KAAY,CAAC,EAAK,MAAM;IAClC,WAAU;cAET,IAAW,gBAAgB;IACrB,CAAA,CACR,EAAA,CAAA;aAtBP,CAyBG,KACC,kBAAC,OAAD;IAAK,WAAU;cAAyG;IAElH,CAAA,EAER,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAA8C;MAEvD,CAAA,EACR,kBAAC,SAAD;MACE,MAAK;MACL,aAAY;MACZ,OAAO;MACP,WAAW,MAAM,EAAQ,EAAE,OAAO,MAAM;MACxC,WAAU;MACV,CAAA,CACE,EAAA,CAAA;KACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAA8C;MAEvD,CAAA,EACR,kBAAC,UAAD;MACE,OAAO;MACP,WAAW,MAAM,EAAQ,EAAE,OAAO,MAAM;MACxC,WAAU;gBAET,EAAa,KAAK,MACjB,kBAAC,UAAD;OAAsB,OAAO,EAAE;iBAC5B,EAAE;OACI,EAFI,EAAE,MAEN,CACT;MACK,CAAA,CACL,EAAA,CAAA;KACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CAA+D,eAE7D,kBAAC,QAAD;OAAM,WAAU;iBAAuC;OAEhD,CAAA,CACD;SACR,kBAAC,YAAD;MACE,aAAY;MACZ,MAAM;MACN,OAAO;MACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;MAC/C,WAAU;MACV,CAAA,CACE,EAAA,CAAA;KACF;MACA;KACG"}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
|
-
import { LoadingSkeleton as t } from "../../components/LoadingSkeleton.js";
|
|
3
|
-
import { useListConfigurationsQuery as n, useSetConfigurationMutation as r } from "../../../generated/wspace-operations.js";
|
|
4
|
-
import { PageLayout as i } from "../../components/PageLayout.js";
|
|
5
|
-
import { useCallback as a, useEffect as o, useState as s } from "react";
|
|
6
|
-
import { Settings 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";
|
|
9
|
-
//#region src/timecampus/pages/work-patterns/WorkPatternsSettingsPage.tsx
|
|
10
|
-
var f = "timecampus.workpatterns.settings", p = {
|
|
11
|
-
trackEnergyLevels: !0,
|
|
12
|
-
trackMood: !0,
|
|
13
|
-
interruptionTracking: !0
|
|
14
|
-
};
|
|
15
|
-
function m() {
|
|
16
|
-
let { workspaceId: m = "" } = e(), { data: h, loading: g, error: _ } = n({
|
|
17
|
-
variables: {
|
|
18
|
-
scope: "WORKSPACE",
|
|
19
|
-
limit: 100
|
|
20
|
-
},
|
|
21
|
-
skip: !m
|
|
22
|
-
}), [v, { loading: y }] = r(), [b, x] = s(p);
|
|
23
|
-
o(() => {
|
|
24
|
-
if (h?.configurations) {
|
|
25
|
-
let e = h.configurations.find((e) => e.key === f);
|
|
26
|
-
if (e?.value) {
|
|
27
|
-
let t = e.value;
|
|
28
|
-
x({
|
|
29
|
-
trackEnergyLevels: t.trackEnergyLevels ?? p.trackEnergyLevels,
|
|
30
|
-
trackMood: t.trackMood ?? p.trackMood,
|
|
31
|
-
interruptionTracking: t.interruptionTracking ?? p.interruptionTracking
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}, [h]);
|
|
36
|
-
let S = a(async () => {
|
|
37
|
-
await v({ variables: { input: {
|
|
38
|
-
key: f,
|
|
39
|
-
value: b,
|
|
40
|
-
description: "Work patterns tracking settings",
|
|
41
|
-
scope: "WORKSPACE"
|
|
42
|
-
} } });
|
|
43
|
-
}, [v, b]);
|
|
44
|
-
return g ? /* @__PURE__ */ l(i, {
|
|
45
|
-
title: "Work Patterns Settings",
|
|
46
|
-
description: "Configure work pattern tracking",
|
|
47
|
-
children: /* @__PURE__ */ l(t, { variant: "detail" })
|
|
48
|
-
}) : _ ? /* @__PURE__ */ l(i, {
|
|
49
|
-
title: "Work Patterns Settings",
|
|
50
|
-
description: "Configure work pattern tracking",
|
|
51
|
-
children: /* @__PURE__ */ l("div", {
|
|
52
|
-
className: "rounded-xl border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
|
|
53
|
-
children: "Failed to load settings. Please try again later."
|
|
54
|
-
})
|
|
55
|
-
}) : /* @__PURE__ */ l(i, {
|
|
56
|
-
title: "Work Patterns Settings",
|
|
57
|
-
description: "Configure work pattern tracking",
|
|
58
|
-
purpose: "Choose how much TimeCampus learns about your workday — energy, mood and interruptions — so the work-pattern insights it gives back are based on the signals you're comfortable sharing.",
|
|
59
|
-
children: /* @__PURE__ */ u("div", {
|
|
60
|
-
className: "mx-auto max-w-2xl space-y-6",
|
|
61
|
-
children: [/* @__PURE__ */ u(d, {
|
|
62
|
-
treatment: "glass",
|
|
63
|
-
glow: !0,
|
|
64
|
-
className: "p-6",
|
|
65
|
-
children: [/* @__PURE__ */ u("h3", {
|
|
66
|
-
className: "mb-4 flex items-center gap-2 text-sm font-semibold text-text-primary",
|
|
67
|
-
children: [/* @__PURE__ */ l(c, { className: "h-4 w-4" }), "Tracking Preferences"]
|
|
68
|
-
}), /* @__PURE__ */ u("div", {
|
|
69
|
-
className: "space-y-3",
|
|
70
|
-
children: [
|
|
71
|
-
/* @__PURE__ */ u("label", {
|
|
72
|
-
className: "flex items-center justify-between",
|
|
73
|
-
children: [/* @__PURE__ */ l("span", {
|
|
74
|
-
className: "text-sm text-text-primary",
|
|
75
|
-
children: "Track energy levels"
|
|
76
|
-
}), /* @__PURE__ */ l("input", {
|
|
77
|
-
type: "checkbox",
|
|
78
|
-
checked: b.trackEnergyLevels,
|
|
79
|
-
onChange: (e) => x((t) => ({
|
|
80
|
-
...t,
|
|
81
|
-
trackEnergyLevels: e.target.checked
|
|
82
|
-
})),
|
|
83
|
-
className: "h-4 w-4 rounded border-border-subtle"
|
|
84
|
-
})]
|
|
85
|
-
}),
|
|
86
|
-
/* @__PURE__ */ u("label", {
|
|
87
|
-
className: "flex items-center justify-between",
|
|
88
|
-
children: [/* @__PURE__ */ l("span", {
|
|
89
|
-
className: "text-sm text-text-primary",
|
|
90
|
-
children: "Track mood"
|
|
91
|
-
}), /* @__PURE__ */ l("input", {
|
|
92
|
-
type: "checkbox",
|
|
93
|
-
checked: b.trackMood,
|
|
94
|
-
onChange: (e) => x((t) => ({
|
|
95
|
-
...t,
|
|
96
|
-
trackMood: e.target.checked
|
|
97
|
-
})),
|
|
98
|
-
className: "h-4 w-4 rounded border-border-subtle"
|
|
99
|
-
})]
|
|
100
|
-
}),
|
|
101
|
-
/* @__PURE__ */ u("label", {
|
|
102
|
-
className: "flex items-center justify-between",
|
|
103
|
-
children: [/* @__PURE__ */ l("span", {
|
|
104
|
-
className: "text-sm text-text-primary",
|
|
105
|
-
children: "Interruption tracking"
|
|
106
|
-
}), /* @__PURE__ */ l("input", {
|
|
107
|
-
type: "checkbox",
|
|
108
|
-
checked: b.interruptionTracking,
|
|
109
|
-
onChange: (e) => x((t) => ({
|
|
110
|
-
...t,
|
|
111
|
-
interruptionTracking: e.target.checked
|
|
112
|
-
})),
|
|
113
|
-
className: "h-4 w-4 rounded border-border-subtle"
|
|
114
|
-
})]
|
|
115
|
-
})
|
|
116
|
-
]
|
|
117
|
-
})]
|
|
118
|
-
}), /* @__PURE__ */ l("div", {
|
|
119
|
-
className: "flex justify-end",
|
|
120
|
-
children: /* @__PURE__ */ l("button", {
|
|
121
|
-
onClick: S,
|
|
122
|
-
disabled: y,
|
|
123
|
-
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",
|
|
124
|
-
children: y ? "Saving..." : "Save Settings"
|
|
125
|
-
})
|
|
126
|
-
})]
|
|
127
|
-
})
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
//#endregion
|
|
131
|
-
export { m as WorkPatternsSettingsPage };
|
|
132
|
-
|
|
133
|
-
//# sourceMappingURL=WorkPatternsSettingsPage.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WorkPatternsSettingsPage.js","names":[],"sources":["../../../../src/timecampus/pages/work-patterns/WorkPatternsSettingsPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { Settings } from \"lucide-react\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListConfigurationsQuery,\n useSetConfigurationMutation,\n type ConfigurationFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nconst WORK_PATTERNS_SETTINGS_KEY = \"timecampus.workpatterns.settings\";\n\ninterface WorkPatternsSettings {\n trackEnergyLevels: boolean;\n trackMood: boolean;\n interruptionTracking: boolean;\n}\n\nconst DEFAULT_SETTINGS: WorkPatternsSettings = {\n trackEnergyLevels: true,\n trackMood: true,\n interruptionTracking: true,\n};\n\nexport function WorkPatternsSettingsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const { data, loading, error } = useListConfigurationsQuery({\n variables: { scope: \"WORKSPACE\" as never, limit: 100 },\n skip: !workspaceId,\n });\n\n const [setConfiguration, { loading: saving }] = useSetConfigurationMutation();\n const [settings, setSettings] =\n useState<WorkPatternsSettings>(DEFAULT_SETTINGS);\n\n useEffect(() => {\n if (data?.configurations) {\n const config = data.configurations.find(\n (c: ConfigurationFieldsFragment) =>\n c.key === WORK_PATTERNS_SETTINGS_KEY,\n );\n if (config?.value) {\n const val = config.value as Partial<WorkPatternsSettings>;\n setSettings({\n trackEnergyLevels:\n val.trackEnergyLevels ?? DEFAULT_SETTINGS.trackEnergyLevels,\n trackMood: val.trackMood ?? DEFAULT_SETTINGS.trackMood,\n interruptionTracking:\n val.interruptionTracking ?? DEFAULT_SETTINGS.interruptionTracking,\n });\n }\n }\n }, [data]);\n\n const handleSave = useCallback(async () => {\n await setConfiguration({\n variables: {\n input: {\n key: WORK_PATTERNS_SETTINGS_KEY,\n value: settings as unknown as Record<string, unknown>,\n description: \"Work patterns tracking settings\",\n scope: \"WORKSPACE\" as never,\n },\n },\n });\n }, [setConfiguration, settings]);\n\n if (loading) {\n return (\n <PageLayout\n title=\"Work Patterns Settings\"\n description=\"Configure work pattern tracking\"\n >\n <LoadingSkeleton variant=\"detail\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Work Patterns Settings\"\n description=\"Configure work pattern tracking\"\n >\n <div className=\"rounded-xl border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n Failed to load settings. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Work Patterns Settings\"\n description=\"Configure work pattern tracking\"\n purpose=\"Choose how much TimeCampus learns about your workday — energy, mood and interruptions — so the work-pattern insights it gives back are based on the signals you're comfortable sharing.\"\n >\n <div className=\"mx-auto max-w-2xl space-y-6\">\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <h3 className=\"mb-4 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <Settings className=\"h-4 w-4\" />\n Tracking Preferences\n </h3>\n <div className=\"space-y-3\">\n <label className=\"flex items-center justify-between\">\n <span className=\"text-sm text-text-primary\">\n Track energy levels\n </span>\n <input\n type=\"checkbox\"\n checked={settings.trackEnergyLevels}\n onChange={(e) =>\n setSettings((s) => ({\n ...s,\n trackEnergyLevels: e.target.checked,\n }))\n }\n className=\"h-4 w-4 rounded border-border-subtle\"\n />\n </label>\n <label className=\"flex items-center justify-between\">\n <span className=\"text-sm text-text-primary\">Track mood</span>\n <input\n type=\"checkbox\"\n checked={settings.trackMood}\n onChange={(e) =>\n setSettings((s) => ({ ...s, trackMood: e.target.checked }))\n }\n className=\"h-4 w-4 rounded border-border-subtle\"\n />\n </label>\n <label className=\"flex items-center justify-between\">\n <span className=\"text-sm text-text-primary\">\n Interruption tracking\n </span>\n <input\n type=\"checkbox\"\n checked={settings.interruptionTracking}\n onChange={(e) =>\n setSettings((s) => ({\n ...s,\n interruptionTracking: e.target.checked,\n }))\n }\n className=\"h-4 w-4 rounded border-border-subtle\"\n />\n </label>\n </div>\n </GlassCard>\n <div className=\"flex justify-end\">\n <button\n onClick={handleSave}\n disabled={saving}\n 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\"\n >\n {saving ? \"Saving...\" : \"Save Settings\"}\n </button>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;AAYA,IAAM,IAA6B,oCAQ7B,IAAyC;CAC7C,mBAAmB;CACnB,WAAW;CACX,sBAAsB;CACvB;AAED,SAAgB,IAA2B;CACzC,IAAM,EAAE,iBAAc,OAAO,GAAe,EACtC,EAAE,SAAM,YAAS,aAAU,EAA2B;EAC1D,WAAW;GAAE,OAAO;GAAsB,OAAO;GAAK;EACtD,MAAM,CAAC;EACR,CAAC,EAEI,CAAC,GAAkB,EAAE,SAAS,OAAY,GAA6B,EACvE,CAAC,GAAU,KACf,EAA+B,EAAiB;AAElD,SAAgB;AACd,MAAI,GAAM,gBAAgB;GACxB,IAAM,IAAS,EAAK,eAAe,MAChC,MACC,EAAE,QAAQ,EACb;AACD,OAAI,GAAQ,OAAO;IACjB,IAAM,IAAM,EAAO;AACnB,MAAY;KACV,mBACE,EAAI,qBAAqB,EAAiB;KAC5C,WAAW,EAAI,aAAa,EAAiB;KAC7C,sBACE,EAAI,wBAAwB,EAAiB;KAChD,CAAC;;;IAGL,CAAC,EAAK,CAAC;CAEV,IAAM,IAAa,EAAY,YAAY;AACzC,QAAM,EAAiB,EACrB,WAAW,EACT,OAAO;GACL,KAAK;GACL,OAAO;GACP,aAAa;GACb,OAAO;GACR,EACF,EACF,CAAC;IACD,CAAC,GAAkB,EAAS,CAAC;AA0BhC,QAxBI,IAEA,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD,EAAiB,SAAQ,UAAW,CAAA;EACzB,CAAA,GAIb,IAEA,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAA2G;GAEpH,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SAAQ;YAER,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IAAW,WAAU;IAAQ,MAAA;IAAK,WAAU;cAA5C,CACE,kBAAC,MAAD;KAAI,WAAU;eAAd,CACE,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA,EAAA,uBAE7B;QACL,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,QAAD;QAAM,WAAU;kBAA4B;QAErC,CAAA,EACP,kBAAC,SAAD;QACE,MAAK;QACL,SAAS,EAAS;QAClB,WAAW,MACT,GAAa,OAAO;SAClB,GAAG;SACH,mBAAmB,EAAE,OAAO;SAC7B,EAAE;QAEL,WAAU;QACV,CAAA,CACI;;MACR,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,QAAD;QAAM,WAAU;kBAA4B;QAAiB,CAAA,EAC7D,kBAAC,SAAD;QACE,MAAK;QACL,SAAS,EAAS;QAClB,WAAW,MACT,GAAa,OAAO;SAAE,GAAG;SAAG,WAAW,EAAE,OAAO;SAAS,EAAE;QAE7D,WAAU;QACV,CAAA,CACI;;MACR,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,QAAD;QAAM,WAAU;kBAA4B;QAErC,CAAA,EACP,kBAAC,SAAD;QACE,MAAK;QACL,SAAS,EAAS;QAClB,WAAW,MACT,GAAa,OAAO;SAClB,GAAG;SACH,sBAAsB,EAAE,OAAO;SAChC,EAAE;QAEL,WAAU;QACV,CAAA,CACI;;MACJ;OACI;OACZ,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,UAAD;KACE,SAAS;KACT,UAAU;KACV,WAAU;eAET,IAAS,cAAc;KACjB,CAAA;IACL,CAAA,CACF;;EACK,CAAA"}
|