@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,70 +1,130 @@
|
|
|
1
1
|
import { useTimeCampus as e, useTimeCampusNavigate as t } from "../../providers/TimeCampusProvider.js";
|
|
2
2
|
import { StatCard as n } from "../../components/StatCard.js";
|
|
3
3
|
import { LoadingSkeleton as r } from "../../components/LoadingSkeleton.js";
|
|
4
|
-
import { useCompletePomodoroSessionMutation as i, useGetActivePomodoroSessionQuery as
|
|
4
|
+
import { useCompletePomodoroSessionMutation as i, useCreatePomodoroGoalMutation as ee, useDeletePomodoroGoalMutation as te, useGetActivePomodoroSessionQuery as ne, useGetPomodoroStatsQuery as re, useListPomodoroGoalsQuery as a, useStartPomodoroSessionMutation as o, useUpdatePomodoroGoalMutation as s } from "../../../generated/wspace-operations.js";
|
|
5
5
|
import { PageLayout as c } from "../../components/PageLayout.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { PomodoroGoalType as l } from "../../../generated/wspace-types.js";
|
|
7
|
+
import { Modal as u } from "../../components/Modal.js";
|
|
8
|
+
import { useCallback as d, useEffect as f, useState as p } from "react";
|
|
9
|
+
import { Pause as ie, Pencil as ae, Play as oe, Plus as se, RotateCcw as m, SkipForward as ce, Target as le, Trash2 as ue } from "lucide-react";
|
|
10
|
+
import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
11
|
+
import { GlassCard as v, NextSteps as de } from "@burdenoff/fe-libs/ui";
|
|
10
12
|
//#region src/timecampus/pages/pomodoro/PomodoroPage.tsx
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
var y = "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", b = "block text-sm font-medium text-text-primary";
|
|
14
|
+
function x(e) {
|
|
15
|
+
let t = new Date(e);
|
|
16
|
+
return Number.isNaN(t.getTime()) ? "" : (/* @__PURE__ */ new Date(t.getTime() - t.getTimezoneOffset() * 6e4)).toISOString().slice(0, 10);
|
|
17
|
+
}
|
|
18
|
+
function S() {
|
|
19
|
+
let e = /* @__PURE__ */ new Date();
|
|
20
|
+
return (/* @__PURE__ */ new Date(e.getTime() - e.getTimezoneOffset() * 6e4)).toISOString().slice(0, 10);
|
|
21
|
+
}
|
|
22
|
+
function C(e) {
|
|
23
|
+
let t = /* @__PURE__ */ new Date();
|
|
24
|
+
return t.setDate(t.getDate() + e), (/* @__PURE__ */ new Date(t.getTime() - t.getTimezoneOffset() * 6e4)).toISOString().slice(0, 10);
|
|
25
|
+
}
|
|
26
|
+
function w(e) {
|
|
27
|
+
return {
|
|
28
|
+
type: e?.type ?? l.Daily,
|
|
29
|
+
target: e?.target == null ? "8" : String(e.target),
|
|
30
|
+
period: e?.period ?? "DAILY",
|
|
31
|
+
startDate: e?.startDate ? x(e.startDate) : S(),
|
|
32
|
+
endDate: e?.endDate ? x(e.endDate) : C(0)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function T() {
|
|
36
|
+
let { workspaceId: x = "" } = e(), S = t(), { data: T, loading: fe, error: pe } = re({
|
|
37
|
+
variables: { workspaceId: x },
|
|
38
|
+
skip: !x
|
|
39
|
+
}), { data: me, loading: he, error: ge } = ne({
|
|
40
|
+
variables: { workspaceId: x },
|
|
41
|
+
skip: !x
|
|
42
|
+
}), [E] = o(), [D] = i(), { data: O, refetch: k } = a({
|
|
43
|
+
variables: { workspaceId: x },
|
|
44
|
+
skip: !x
|
|
45
|
+
}), A = O?.pomodoroGoals ?? [], [j, { loading: M, error: N }] = ee(), [P, { loading: F, error: I }] = s(), [L, { loading: R, error: _e }] = te(), [ve, z] = p(!1), [B, V] = p(null), [H, U] = p(null), [W, G] = p(w()), K = (e, t) => G((n) => ({
|
|
46
|
+
...n,
|
|
47
|
+
[e]: t
|
|
48
|
+
})), ye = () => {
|
|
49
|
+
V(null), G(w()), z(!0);
|
|
50
|
+
}, be = (e) => {
|
|
51
|
+
V(e), G(w(e)), z(!0);
|
|
52
|
+
}, xe = async () => {
|
|
53
|
+
if (!x) return;
|
|
54
|
+
let e = Number(W.target);
|
|
55
|
+
!e || e <= 0 || (B ? await P({ variables: {
|
|
56
|
+
id: B.id,
|
|
57
|
+
workspaceId: x,
|
|
58
|
+
input: {
|
|
59
|
+
type: W.type,
|
|
60
|
+
target: e,
|
|
61
|
+
period: W.period.trim() || W.type,
|
|
62
|
+
startDate: new Date(W.startDate).toISOString(),
|
|
63
|
+
endDate: new Date(W.endDate).toISOString()
|
|
64
|
+
}
|
|
65
|
+
} }) : await j({ variables: { input: {
|
|
66
|
+
workspaceId: x,
|
|
67
|
+
type: W.type,
|
|
68
|
+
target: e,
|
|
69
|
+
period: W.period.trim() || W.type,
|
|
70
|
+
startDate: new Date(W.startDate).toISOString(),
|
|
71
|
+
endDate: new Date(W.endDate).toISOString()
|
|
72
|
+
} } }), z(!1), await k());
|
|
73
|
+
}, Se = async () => {
|
|
74
|
+
!H || !x || (await L({ variables: {
|
|
75
|
+
id: H.id,
|
|
76
|
+
workspaceId: x
|
|
77
|
+
} }), U(null), await k());
|
|
78
|
+
}, q = T?.pomodoroStats, J = me?.activePomodoroSession, [Y, X] = p(1500), [Z, Q] = p(!1);
|
|
79
|
+
f(() => {
|
|
80
|
+
if (J && !J.completed) {
|
|
81
|
+
let e = Math.floor((Date.now() - new Date(J.startTime).getTime()) / 1e3), t = J.duration ?? 1500, n = Math.max(0, t - e);
|
|
82
|
+
X(n), Q(n > 0);
|
|
23
83
|
}
|
|
24
|
-
}, [
|
|
25
|
-
if (!
|
|
84
|
+
}, [J]), f(() => {
|
|
85
|
+
if (!Z || Y <= 0) return;
|
|
26
86
|
let e = setInterval(() => {
|
|
27
|
-
|
|
87
|
+
X((e) => e <= 1 ? (Q(!1), 0) : e - 1);
|
|
28
88
|
}, 1e3);
|
|
29
89
|
return () => clearInterval(e);
|
|
30
|
-
}, [
|
|
31
|
-
let
|
|
90
|
+
}, [Z, Y]);
|
|
91
|
+
let Ce = (e) => {
|
|
32
92
|
let t = Math.floor(e / 60), n = e % 60;
|
|
33
93
|
return `${String(t).padStart(2, "0")}:${String(n).padStart(2, "0")}`;
|
|
34
|
-
},
|
|
35
|
-
if (
|
|
36
|
-
if (
|
|
37
|
-
|
|
94
|
+
}, $ = d(async () => {
|
|
95
|
+
if (x) {
|
|
96
|
+
if (J && !J.completed) {
|
|
97
|
+
Q(!0);
|
|
38
98
|
return;
|
|
39
99
|
}
|
|
40
|
-
await
|
|
100
|
+
await E({
|
|
41
101
|
variables: { input: {
|
|
42
|
-
workspaceId:
|
|
102
|
+
workspaceId: x,
|
|
43
103
|
type: "FOCUS"
|
|
44
104
|
} },
|
|
45
105
|
refetchQueries: ["GetActivePomodoroSession", "GetPomodoroStats"]
|
|
46
|
-
}),
|
|
106
|
+
}), X(1500), Q(!0);
|
|
47
107
|
}
|
|
48
108
|
}, [
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
]),
|
|
53
|
-
!
|
|
109
|
+
x,
|
|
110
|
+
J,
|
|
111
|
+
E
|
|
112
|
+
]), we = d(async () => {
|
|
113
|
+
!J || !x || (await D({
|
|
54
114
|
variables: {
|
|
55
|
-
id:
|
|
56
|
-
workspaceId:
|
|
115
|
+
id: J.id,
|
|
116
|
+
workspaceId: x
|
|
57
117
|
},
|
|
58
118
|
refetchQueries: ["GetActivePomodoroSession", "GetPomodoroStats"]
|
|
59
|
-
}),
|
|
119
|
+
}), Q(!1), X(1500));
|
|
60
120
|
}, [
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
]),
|
|
65
|
-
|
|
121
|
+
J,
|
|
122
|
+
x,
|
|
123
|
+
D
|
|
124
|
+
]), Te = () => {
|
|
125
|
+
Q(!1), X(1500);
|
|
66
126
|
};
|
|
67
|
-
if (
|
|
127
|
+
if (fe || he) return /* @__PURE__ */ g(c, {
|
|
68
128
|
title: "Pomodoro Timer",
|
|
69
129
|
description: "Focus with the Pomodoro Technique",
|
|
70
130
|
children: /* @__PURE__ */ g(r, {
|
|
@@ -72,7 +132,7 @@ function b() {
|
|
|
72
132
|
count: 3
|
|
73
133
|
})
|
|
74
134
|
});
|
|
75
|
-
if (
|
|
135
|
+
if (pe || ge) return /* @__PURE__ */ g(c, {
|
|
76
136
|
title: "Pomodoro Timer",
|
|
77
137
|
description: "Focus with the Pomodoro Technique",
|
|
78
138
|
children: /* @__PURE__ */ g("div", {
|
|
@@ -80,13 +140,13 @@ function b() {
|
|
|
80
140
|
children: "Failed to load pomodoro data. Please try again later."
|
|
81
141
|
})
|
|
82
142
|
});
|
|
83
|
-
let
|
|
143
|
+
let Ee = Math.floor((q?.totalFocusMinutes ?? 0) / 60), De = (q?.totalFocusMinutes ?? 0) % 60;
|
|
84
144
|
return /* @__PURE__ */ _(c, {
|
|
85
145
|
title: "Pomodoro Timer",
|
|
86
146
|
description: "Focus with the Pomodoro Technique",
|
|
87
147
|
purpose: "Work in focused 25-minute sprints with short breaks — the Pomodoro technique helps you beat procrastination and build a streak of deep-work sessions you can actually measure.",
|
|
88
148
|
children: [
|
|
89
|
-
/* @__PURE__ */ g(
|
|
149
|
+
/* @__PURE__ */ g(de, {
|
|
90
150
|
storageKey: "timecampus-pomodoro",
|
|
91
151
|
className: "mb-6",
|
|
92
152
|
steps: [
|
|
@@ -94,19 +154,19 @@ function b() {
|
|
|
94
154
|
id: "start",
|
|
95
155
|
label: "Start a focus session",
|
|
96
156
|
description: "Begin a 25-minute sprint on one task.",
|
|
97
|
-
onClick: () =>
|
|
157
|
+
onClick: () => $()
|
|
98
158
|
},
|
|
99
159
|
{
|
|
100
160
|
id: "analytics",
|
|
101
161
|
label: "Review your pomodoro stats",
|
|
102
162
|
description: "See streaks, completion rate and focus time.",
|
|
103
|
-
onClick: () =>
|
|
163
|
+
onClick: () => S("/pomodoro/analytics")
|
|
104
164
|
},
|
|
105
165
|
{
|
|
106
166
|
id: "settings",
|
|
107
167
|
label: "Tune your intervals",
|
|
108
168
|
description: "Adjust focus and break lengths to fit you.",
|
|
109
|
-
onClick: () =>
|
|
169
|
+
onClick: () => S("/pomodoro/settings")
|
|
110
170
|
}
|
|
111
171
|
]
|
|
112
172
|
}),
|
|
@@ -115,21 +175,21 @@ function b() {
|
|
|
115
175
|
children: [
|
|
116
176
|
/* @__PURE__ */ g(n, {
|
|
117
177
|
title: "Sessions Today",
|
|
118
|
-
value: String(
|
|
119
|
-
description: `Total: ${
|
|
178
|
+
value: String(q?.completedSessions ?? 0),
|
|
179
|
+
description: `Total: ${q?.totalSessions ?? 0} sessions`
|
|
120
180
|
}),
|
|
121
181
|
/* @__PURE__ */ g(n, {
|
|
122
182
|
title: "Focus Time",
|
|
123
|
-
value: `${
|
|
183
|
+
value: `${Ee}h ${De}m`,
|
|
124
184
|
trend: {
|
|
125
|
-
value:
|
|
185
|
+
value: q?.completionRate ?? 0,
|
|
126
186
|
label: "completion rate"
|
|
127
187
|
}
|
|
128
188
|
}),
|
|
129
189
|
/* @__PURE__ */ g(n, {
|
|
130
190
|
title: "Current Streak",
|
|
131
|
-
value: `${
|
|
132
|
-
description: `Avg: ${
|
|
191
|
+
value: `${q?.streakDays ?? 0} days`,
|
|
192
|
+
description: `Avg: ${q?.averageSessionMinutes ?? 0}m per session`
|
|
133
193
|
})
|
|
134
194
|
]
|
|
135
195
|
}),
|
|
@@ -144,36 +204,36 @@ function b() {
|
|
|
144
204
|
className: "mb-2",
|
|
145
205
|
children: /* @__PURE__ */ g("span", {
|
|
146
206
|
className: "inline-flex rounded-full bg-action-primary-bg/10 px-3 py-1 text-xs font-medium text-primary",
|
|
147
|
-
children:
|
|
207
|
+
children: J ? "Focus Session" : "Ready"
|
|
148
208
|
})
|
|
149
209
|
}),
|
|
150
210
|
/* @__PURE__ */ g("p", {
|
|
151
211
|
className: "text-7xl font-mono font-bold text-text-primary",
|
|
152
|
-
children:
|
|
212
|
+
children: Ce(Y)
|
|
153
213
|
}),
|
|
154
214
|
/* @__PURE__ */ g("p", {
|
|
155
215
|
className: "mt-2 text-sm text-text-secondary",
|
|
156
|
-
children:
|
|
216
|
+
children: q ? `${q.completedSessions} of ${q.totalSessions} sessions` : "No sessions yet"
|
|
157
217
|
}),
|
|
158
218
|
/* @__PURE__ */ _("div", {
|
|
159
219
|
className: "mt-6 flex items-center justify-center gap-3",
|
|
160
220
|
children: [
|
|
161
|
-
|
|
162
|
-
onClick: () =>
|
|
221
|
+
Z ? /* @__PURE__ */ _("button", {
|
|
222
|
+
onClick: () => Q(!1),
|
|
163
223
|
className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-6 py-3 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
164
|
-
children: [/* @__PURE__ */ g(
|
|
224
|
+
children: [/* @__PURE__ */ g(ie, { className: "h-4 w-4" }), "Pause"]
|
|
165
225
|
}) : /* @__PURE__ */ _("button", {
|
|
166
|
-
onClick:
|
|
226
|
+
onClick: $,
|
|
167
227
|
className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-6 py-3 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
168
|
-
children: [/* @__PURE__ */ g(
|
|
228
|
+
children: [/* @__PURE__ */ g(oe, { className: "h-4 w-4" }), "Start"]
|
|
169
229
|
}),
|
|
170
230
|
/* @__PURE__ */ _("button", {
|
|
171
|
-
onClick:
|
|
231
|
+
onClick: we,
|
|
172
232
|
className: "inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-3 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
|
|
173
|
-
children: [/* @__PURE__ */ g(
|
|
233
|
+
children: [/* @__PURE__ */ g(ce, { className: "h-4 w-4" }), "Skip"]
|
|
174
234
|
}),
|
|
175
235
|
/* @__PURE__ */ _("button", {
|
|
176
|
-
onClick:
|
|
236
|
+
onClick: Te,
|
|
177
237
|
className: "inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-3 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
|
|
178
238
|
children: [/* @__PURE__ */ g(m, { className: "h-4 w-4" }), "Reset"]
|
|
179
239
|
})
|
|
@@ -181,11 +241,191 @@ function b() {
|
|
|
181
241
|
})
|
|
182
242
|
]
|
|
183
243
|
})
|
|
244
|
+
}),
|
|
245
|
+
/* @__PURE__ */ _(v, {
|
|
246
|
+
treatment: "glass",
|
|
247
|
+
className: "p-6",
|
|
248
|
+
children: [/* @__PURE__ */ _("div", {
|
|
249
|
+
className: "mb-4 flex items-center justify-between",
|
|
250
|
+
children: [/* @__PURE__ */ _("h3", {
|
|
251
|
+
className: "flex items-center gap-2 text-sm font-semibold text-text-primary",
|
|
252
|
+
children: [/* @__PURE__ */ g(le, { className: "h-4 w-4" }), "Focus Goals"]
|
|
253
|
+
}), /* @__PURE__ */ _("button", {
|
|
254
|
+
onClick: ye,
|
|
255
|
+
className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
256
|
+
children: [/* @__PURE__ */ g(se, { className: "h-4 w-4" }), "Add Goal"]
|
|
257
|
+
})]
|
|
258
|
+
}), A.length === 0 ? /* @__PURE__ */ g("p", {
|
|
259
|
+
className: "py-6 text-center text-sm text-text-secondary",
|
|
260
|
+
children: "No focus goals yet. Set a daily or weekly target to build a consistent focus habit."
|
|
261
|
+
}) : /* @__PURE__ */ g("div", {
|
|
262
|
+
className: "space-y-3",
|
|
263
|
+
children: A.map((e) => {
|
|
264
|
+
let t = e.target ? Math.min(100, Math.round(e.current / e.target * 100)) : 0;
|
|
265
|
+
return /* @__PURE__ */ _("div", {
|
|
266
|
+
className: "rounded-lg border border-border-subtle p-4",
|
|
267
|
+
children: [/* @__PURE__ */ _("div", {
|
|
268
|
+
className: "flex items-center justify-between",
|
|
269
|
+
children: [/* @__PURE__ */ _("div", { children: [/* @__PURE__ */ _("p", {
|
|
270
|
+
className: "text-sm font-medium capitalize text-text-primary",
|
|
271
|
+
children: [e.type.toLowerCase(), " goal"]
|
|
272
|
+
}), /* @__PURE__ */ _("p", {
|
|
273
|
+
className: "text-xs text-text-secondary",
|
|
274
|
+
children: [
|
|
275
|
+
e.current,
|
|
276
|
+
" of ",
|
|
277
|
+
e.target,
|
|
278
|
+
" sessions"
|
|
279
|
+
]
|
|
280
|
+
})] }), /* @__PURE__ */ _("div", {
|
|
281
|
+
className: "flex items-center gap-2",
|
|
282
|
+
children: [
|
|
283
|
+
/* @__PURE__ */ _("span", {
|
|
284
|
+
className: "text-sm font-medium text-text-primary",
|
|
285
|
+
children: [t, "%"]
|
|
286
|
+
}),
|
|
287
|
+
/* @__PURE__ */ g("button", {
|
|
288
|
+
onClick: () => be(e),
|
|
289
|
+
className: "rounded-md p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-text-primary",
|
|
290
|
+
"aria-label": "Edit goal",
|
|
291
|
+
children: /* @__PURE__ */ g(ae, { className: "h-4 w-4" })
|
|
292
|
+
}),
|
|
293
|
+
/* @__PURE__ */ g("button", {
|
|
294
|
+
onClick: () => U(e),
|
|
295
|
+
className: "rounded-md p-1.5 text-text-secondary hover:bg-status-error-bg hover:text-status-error-text",
|
|
296
|
+
"aria-label": "Delete goal",
|
|
297
|
+
children: /* @__PURE__ */ g(ue, { className: "h-4 w-4" })
|
|
298
|
+
})
|
|
299
|
+
]
|
|
300
|
+
})]
|
|
301
|
+
}), /* @__PURE__ */ g("div", {
|
|
302
|
+
className: "mt-3 h-2 w-full rounded-full bg-bg-sunken",
|
|
303
|
+
children: /* @__PURE__ */ g("div", {
|
|
304
|
+
className: "h-2 rounded-full bg-action-primary-bg",
|
|
305
|
+
style: { width: `${t}%` }
|
|
306
|
+
})
|
|
307
|
+
})]
|
|
308
|
+
}, e.id);
|
|
309
|
+
})
|
|
310
|
+
})]
|
|
311
|
+
}),
|
|
312
|
+
/* @__PURE__ */ _(u, {
|
|
313
|
+
open: ve,
|
|
314
|
+
onClose: () => z(!1),
|
|
315
|
+
title: B ? "Edit Focus Goal" : "Add Focus Goal",
|
|
316
|
+
description: "Set a target number of focus sessions",
|
|
317
|
+
footer: /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("button", {
|
|
318
|
+
onClick: () => z(!1),
|
|
319
|
+
className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
|
|
320
|
+
children: "Cancel"
|
|
321
|
+
}), /* @__PURE__ */ g("button", {
|
|
322
|
+
onClick: xe,
|
|
323
|
+
disabled: M || F || Number(W.target) <= 0,
|
|
324
|
+
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",
|
|
325
|
+
children: M || F ? "Saving..." : B ? "Save Changes" : "Add Goal"
|
|
326
|
+
})] }),
|
|
327
|
+
children: [(N || I) && /* @__PURE__ */ g("div", {
|
|
328
|
+
className: "mb-4 rounded-lg border border-status-error-bg/40 bg-status-error-bg p-3 text-sm text-status-error-text",
|
|
329
|
+
children: "Failed to save goal. Please try again."
|
|
330
|
+
}), /* @__PURE__ */ _("div", {
|
|
331
|
+
className: "space-y-4",
|
|
332
|
+
children: [
|
|
333
|
+
/* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
|
|
334
|
+
className: b,
|
|
335
|
+
children: "Goal Type"
|
|
336
|
+
}), /* @__PURE__ */ _("select", {
|
|
337
|
+
value: W.type,
|
|
338
|
+
onChange: (e) => {
|
|
339
|
+
let t = e.target.value;
|
|
340
|
+
G((e) => ({
|
|
341
|
+
...e,
|
|
342
|
+
type: t,
|
|
343
|
+
period: t,
|
|
344
|
+
endDate: t === l.Daily ? C(0) : t === l.Weekly ? C(7) : C(30)
|
|
345
|
+
}));
|
|
346
|
+
},
|
|
347
|
+
className: y,
|
|
348
|
+
children: [
|
|
349
|
+
/* @__PURE__ */ g("option", {
|
|
350
|
+
value: l.Daily,
|
|
351
|
+
children: "Daily"
|
|
352
|
+
}),
|
|
353
|
+
/* @__PURE__ */ g("option", {
|
|
354
|
+
value: l.Weekly,
|
|
355
|
+
children: "Weekly"
|
|
356
|
+
}),
|
|
357
|
+
/* @__PURE__ */ g("option", {
|
|
358
|
+
value: l.Monthly,
|
|
359
|
+
children: "Monthly"
|
|
360
|
+
})
|
|
361
|
+
]
|
|
362
|
+
})] }),
|
|
363
|
+
/* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
|
|
364
|
+
className: b,
|
|
365
|
+
children: "Target Sessions"
|
|
366
|
+
}), /* @__PURE__ */ g("input", {
|
|
367
|
+
type: "number",
|
|
368
|
+
min: "1",
|
|
369
|
+
placeholder: "8",
|
|
370
|
+
value: W.target,
|
|
371
|
+
onChange: (e) => K("target", e.target.value),
|
|
372
|
+
className: y
|
|
373
|
+
})] }),
|
|
374
|
+
/* @__PURE__ */ _("div", {
|
|
375
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
376
|
+
children: [/* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
|
|
377
|
+
className: b,
|
|
378
|
+
children: "Start Date"
|
|
379
|
+
}), /* @__PURE__ */ g("input", {
|
|
380
|
+
type: "date",
|
|
381
|
+
value: W.startDate,
|
|
382
|
+
onChange: (e) => K("startDate", e.target.value),
|
|
383
|
+
className: y
|
|
384
|
+
})] }), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("label", {
|
|
385
|
+
className: b,
|
|
386
|
+
children: "End Date"
|
|
387
|
+
}), /* @__PURE__ */ g("input", {
|
|
388
|
+
type: "date",
|
|
389
|
+
value: W.endDate,
|
|
390
|
+
onChange: (e) => K("endDate", e.target.value),
|
|
391
|
+
className: y
|
|
392
|
+
})] })]
|
|
393
|
+
})
|
|
394
|
+
]
|
|
395
|
+
})]
|
|
396
|
+
}),
|
|
397
|
+
/* @__PURE__ */ _(u, {
|
|
398
|
+
open: H !== null,
|
|
399
|
+
onClose: () => U(null),
|
|
400
|
+
title: "Delete Focus Goal",
|
|
401
|
+
size: "sm",
|
|
402
|
+
footer: /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("button", {
|
|
403
|
+
onClick: () => U(null),
|
|
404
|
+
className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
|
|
405
|
+
children: "Cancel"
|
|
406
|
+
}), /* @__PURE__ */ g("button", {
|
|
407
|
+
onClick: Se,
|
|
408
|
+
disabled: R,
|
|
409
|
+
className: "rounded-md bg-status-error-bg px-4 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg/90 disabled:opacity-50",
|
|
410
|
+
children: R ? "Deleting..." : "Delete"
|
|
411
|
+
})] }),
|
|
412
|
+
children: [_e && /* @__PURE__ */ g("div", {
|
|
413
|
+
className: "mb-4 rounded-lg border border-status-error-bg/40 bg-status-error-bg p-3 text-sm text-status-error-text",
|
|
414
|
+
children: "Failed to delete goal. Please try again."
|
|
415
|
+
}), /* @__PURE__ */ _("p", {
|
|
416
|
+
className: "text-sm text-text-secondary",
|
|
417
|
+
children: [
|
|
418
|
+
"Are you sure you want to delete this",
|
|
419
|
+
" ",
|
|
420
|
+
H?.type.toLowerCase(),
|
|
421
|
+
" focus goal? This action cannot be undone."
|
|
422
|
+
]
|
|
423
|
+
})]
|
|
184
424
|
})
|
|
185
425
|
]
|
|
186
426
|
});
|
|
187
427
|
}
|
|
188
428
|
//#endregion
|
|
189
|
-
export {
|
|
429
|
+
export { T as PomodoroPage };
|
|
190
430
|
|
|
191
431
|
//# sourceMappingURL=PomodoroPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PomodoroPage.js","names":[],"sources":["../../../../src/timecampus/pages/pomodoro/PomodoroPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { Play, Pause, SkipForward, RotateCcw } from \"lucide-react\";\nimport { GlassCard, NextSteps } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport {\n useTimeCampus,\n useTimeCampusNavigate,\n} from \"../../providers/TimeCampusProvider\";\nimport {\n useGetActivePomodoroSessionQuery,\n useGetPomodoroStatsQuery,\n useStartPomodoroSessionMutation,\n useCompletePomodoroSessionMutation,\n} from \"@/generated/wspace-operations\";\n\nexport function PomodoroPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const navigate = useTimeCampusNavigate();\n\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetPomodoroStatsQuery({\n variables: { workspaceId },\n skip: !workspaceId,\n });\n\n const {\n data: activeData,\n loading: activeLoading,\n error: activeError,\n } = useGetActivePomodoroSessionQuery({\n variables: { workspaceId },\n skip: !workspaceId,\n });\n\n const [startSession] = useStartPomodoroSessionMutation();\n const [completeSession] = useCompletePomodoroSessionMutation();\n\n const stats = statsData?.pomodoroStats;\n const activeSession = activeData?.activePomodoroSession;\n\n const [timerSeconds, setTimerSeconds] = useState(25 * 60);\n const [isRunning, setIsRunning] = useState(false);\n\n useEffect(() => {\n if (activeSession && !activeSession.completed) {\n const elapsed = Math.floor(\n (Date.now() - new Date(activeSession.startTime).getTime()) / 1000,\n );\n const duration = activeSession.duration ?? 25 * 60;\n const remaining = Math.max(0, duration - elapsed);\n setTimerSeconds(remaining);\n setIsRunning(remaining > 0);\n }\n }, [activeSession]);\n\n useEffect(() => {\n if (!isRunning || timerSeconds <= 0) return;\n const interval = setInterval(() => {\n setTimerSeconds((prev) => {\n if (prev <= 1) {\n setIsRunning(false);\n return 0;\n }\n return prev - 1;\n });\n }, 1000);\n return () => clearInterval(interval);\n }, [isRunning, timerSeconds]);\n\n const formatTimer = (seconds: number) => {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return `${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n };\n\n const handleStart = useCallback(async () => {\n if (!workspaceId) return;\n if (activeSession && !activeSession.completed) {\n setIsRunning(true);\n return;\n }\n await startSession({\n variables: { input: { workspaceId, type: \"FOCUS\" as never } },\n refetchQueries: [\"GetActivePomodoroSession\", \"GetPomodoroStats\"],\n });\n setTimerSeconds(25 * 60);\n setIsRunning(true);\n }, [workspaceId, activeSession, startSession]);\n\n const handleComplete = useCallback(async () => {\n if (!activeSession || !workspaceId) return;\n await completeSession({\n variables: { id: activeSession.id, workspaceId },\n refetchQueries: [\"GetActivePomodoroSession\", \"GetPomodoroStats\"],\n });\n setIsRunning(false);\n setTimerSeconds(25 * 60);\n }, [activeSession, workspaceId, completeSession]);\n\n const handleReset = () => {\n setIsRunning(false);\n setTimerSeconds(25 * 60);\n };\n\n if (statsLoading || activeLoading) {\n return (\n <PageLayout\n title=\"Pomodoro Timer\"\n description=\"Focus with the Pomodoro Technique\"\n >\n <LoadingSkeleton variant=\"card\" count={3} />\n </PageLayout>\n );\n }\n\n if (statsError || activeError) {\n return (\n <PageLayout\n title=\"Pomodoro Timer\"\n description=\"Focus with the Pomodoro Technique\"\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 pomodoro data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n const totalFocusH = Math.floor((stats?.totalFocusMinutes ?? 0) / 60);\n const totalFocusM = (stats?.totalFocusMinutes ?? 0) % 60;\n\n return (\n <PageLayout\n title=\"Pomodoro Timer\"\n description=\"Focus with the Pomodoro Technique\"\n purpose=\"Work in focused 25-minute sprints with short breaks — the Pomodoro technique helps you beat procrastination and build a streak of deep-work sessions you can actually measure.\"\n >\n <NextSteps\n storageKey=\"timecampus-pomodoro\"\n className=\"mb-6\"\n steps={[\n {\n id: \"start\",\n label: \"Start a focus session\",\n description: \"Begin a 25-minute sprint on one task.\",\n onClick: () => handleStart(),\n },\n {\n id: \"analytics\",\n label: \"Review your pomodoro stats\",\n description: \"See streaks, completion rate and focus time.\",\n onClick: () => navigate(\"/pomodoro/analytics\"),\n },\n {\n id: \"settings\",\n label: \"Tune your intervals\",\n description: \"Adjust focus and break lengths to fit you.\",\n onClick: () => navigate(\"/pomodoro/settings\"),\n },\n ]}\n />\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <StatCard\n title=\"Sessions Today\"\n value={String(stats?.completedSessions ?? 0)}\n description={`Total: ${stats?.totalSessions ?? 0} sessions`}\n />\n <StatCard\n title=\"Focus Time\"\n value={`${totalFocusH}h ${totalFocusM}m`}\n trend={{\n value: stats?.completionRate ?? 0,\n label: \"completion rate\",\n }}\n />\n <StatCard\n title=\"Current Streak\"\n value={`${stats?.streakDays ?? 0} days`}\n description={`Avg: ${stats?.averageSessionMinutes ?? 0}m per session`}\n />\n </div>\n\n <div className=\"mx-auto max-w-md\">\n <GlassCard treatment=\"glass\" glow className=\"p-8 text-center\">\n <div className=\"mb-2\">\n <span className=\"inline-flex rounded-full bg-action-primary-bg/10 px-3 py-1 text-xs font-medium text-primary\">\n {activeSession ? \"Focus Session\" : \"Ready\"}\n </span>\n </div>\n <p className=\"text-7xl font-mono font-bold text-text-primary\">\n {formatTimer(timerSeconds)}\n </p>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {stats\n ? `${stats.completedSessions} of ${stats.totalSessions} sessions`\n : \"No sessions yet\"}\n </p>\n <div className=\"mt-6 flex items-center justify-center gap-3\">\n {!isRunning ? (\n <button\n onClick={handleStart}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-6 py-3 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Play className=\"h-4 w-4\" />\n Start\n </button>\n ) : (\n <button\n onClick={() => setIsRunning(false)}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-6 py-3 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Pause className=\"h-4 w-4\" />\n Pause\n </button>\n )}\n <button\n onClick={handleComplete}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-3 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\"\n >\n <SkipForward className=\"h-4 w-4\" />\n Skip\n </button>\n <button\n onClick={handleReset}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-3 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\"\n >\n <RotateCcw className=\"h-4 w-4\" />\n Reset\n </button>\n </div>\n </GlassCard>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PomodoroPage.js","names":[],"sources":["../../../../src/timecampus/pages/pomodoro/PomodoroPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport {\n Play,\n Pause,\n SkipForward,\n RotateCcw,\n Target,\n Plus,\n Pencil,\n Trash2,\n} from \"lucide-react\";\nimport { GlassCard, NextSteps } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { Modal } from \"../../components/Modal\";\nimport {\n useTimeCampus,\n useTimeCampusNavigate,\n} from \"../../providers/TimeCampusProvider\";\nimport {\n useGetActivePomodoroSessionQuery,\n useGetPomodoroStatsQuery,\n useStartPomodoroSessionMutation,\n useCompletePomodoroSessionMutation,\n useListPomodoroGoalsQuery,\n useCreatePomodoroGoalMutation,\n useUpdatePomodoroGoalMutation,\n useDeletePomodoroGoalMutation,\n type PomodoroGoalFieldsFragment,\n} from \"@/generated/wspace-operations\";\nimport { PomodoroGoalType } from \"@/generated/wspace-types\";\n\ninterface GoalFormState {\n type: PomodoroGoalType;\n target: string;\n period: string;\n startDate: string;\n endDate: string;\n}\n\nconst inputClasses =\n \"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\";\nconst labelClasses = \"block text-sm font-medium text-text-primary\";\n\nfunction toDateInput(iso: string): string {\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return \"\";\n const local = new Date(d.getTime() - d.getTimezoneOffset() * 60000);\n return local.toISOString().slice(0, 10);\n}\n\nfunction todayInput(): string {\n const d = new Date();\n const local = new Date(d.getTime() - d.getTimezoneOffset() * 60000);\n return local.toISOString().slice(0, 10);\n}\n\nfunction futureInput(days: number): string {\n const d = new Date();\n d.setDate(d.getDate() + days);\n const local = new Date(d.getTime() - d.getTimezoneOffset() * 60000);\n return local.toISOString().slice(0, 10);\n}\n\nfunction toGoalState(goal?: PomodoroGoalFieldsFragment): GoalFormState {\n return {\n type: goal?.type ?? PomodoroGoalType.Daily,\n target: goal?.target != null ? String(goal.target) : \"8\",\n period: goal?.period ?? \"DAILY\",\n startDate: goal?.startDate ? toDateInput(goal.startDate) : todayInput(),\n endDate: goal?.endDate ? toDateInput(goal.endDate) : futureInput(0),\n };\n}\n\nexport function PomodoroPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const navigate = useTimeCampusNavigate();\n\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetPomodoroStatsQuery({\n variables: { workspaceId },\n skip: !workspaceId,\n });\n\n const {\n data: activeData,\n loading: activeLoading,\n error: activeError,\n } = useGetActivePomodoroSessionQuery({\n variables: { workspaceId },\n skip: !workspaceId,\n });\n\n const [startSession] = useStartPomodoroSessionMutation();\n const [completeSession] = useCompletePomodoroSessionMutation();\n\n // Focus goals\n const { data: goalsData, refetch: refetchGoals } = useListPomodoroGoalsQuery({\n variables: { workspaceId },\n skip: !workspaceId,\n });\n const goals = goalsData?.pomodoroGoals ?? [];\n\n const [createGoal, { loading: creatingGoal, error: createGoalError }] =\n useCreatePomodoroGoalMutation();\n const [updateGoal, { loading: updatingGoal, error: updateGoalError }] =\n useUpdatePomodoroGoalMutation();\n const [deleteGoal, { loading: deletingGoal, error: deleteGoalError }] =\n useDeletePomodoroGoalMutation();\n\n const [goalModalOpen, setGoalModalOpen] = useState(false);\n const [editingGoal, setEditingGoal] =\n useState<PomodoroGoalFieldsFragment | null>(null);\n const [deletingGoalEntry, setDeletingGoalEntry] =\n useState<PomodoroGoalFieldsFragment | null>(null);\n const [goalForm, setGoalForm] = useState<GoalFormState>(toGoalState());\n\n const setGoalField = <K extends keyof GoalFormState>(\n key: K,\n v: GoalFormState[K],\n ) => setGoalForm((f) => ({ ...f, [key]: v }));\n\n const openCreateGoal = () => {\n setEditingGoal(null);\n setGoalForm(toGoalState());\n setGoalModalOpen(true);\n };\n\n const openEditGoal = (goal: PomodoroGoalFieldsFragment) => {\n setEditingGoal(goal);\n setGoalForm(toGoalState(goal));\n setGoalModalOpen(true);\n };\n\n const handleSaveGoal = async () => {\n if (!workspaceId) return;\n const target = Number(goalForm.target);\n if (!target || target <= 0) return;\n if (editingGoal) {\n await updateGoal({\n variables: {\n id: editingGoal.id,\n workspaceId,\n input: {\n type: goalForm.type,\n target,\n period: goalForm.period.trim() || goalForm.type,\n startDate: new Date(goalForm.startDate).toISOString(),\n endDate: new Date(goalForm.endDate).toISOString(),\n },\n },\n });\n } else {\n await createGoal({\n variables: {\n input: {\n workspaceId,\n type: goalForm.type,\n target,\n period: goalForm.period.trim() || goalForm.type,\n startDate: new Date(goalForm.startDate).toISOString(),\n endDate: new Date(goalForm.endDate).toISOString(),\n },\n },\n });\n }\n setGoalModalOpen(false);\n await refetchGoals();\n };\n\n const handleDeleteGoal = async () => {\n if (!deletingGoalEntry || !workspaceId) return;\n await deleteGoal({\n variables: { id: deletingGoalEntry.id, workspaceId },\n });\n setDeletingGoalEntry(null);\n await refetchGoals();\n };\n\n const stats = statsData?.pomodoroStats;\n const activeSession = activeData?.activePomodoroSession;\n\n const [timerSeconds, setTimerSeconds] = useState(25 * 60);\n const [isRunning, setIsRunning] = useState(false);\n\n useEffect(() => {\n if (activeSession && !activeSession.completed) {\n const elapsed = Math.floor(\n (Date.now() - new Date(activeSession.startTime).getTime()) / 1000,\n );\n const duration = activeSession.duration ?? 25 * 60;\n const remaining = Math.max(0, duration - elapsed);\n setTimerSeconds(remaining);\n setIsRunning(remaining > 0);\n }\n }, [activeSession]);\n\n useEffect(() => {\n if (!isRunning || timerSeconds <= 0) return;\n const interval = setInterval(() => {\n setTimerSeconds((prev) => {\n if (prev <= 1) {\n setIsRunning(false);\n return 0;\n }\n return prev - 1;\n });\n }, 1000);\n return () => clearInterval(interval);\n }, [isRunning, timerSeconds]);\n\n const formatTimer = (seconds: number) => {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return `${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n };\n\n const handleStart = useCallback(async () => {\n if (!workspaceId) return;\n if (activeSession && !activeSession.completed) {\n setIsRunning(true);\n return;\n }\n await startSession({\n variables: { input: { workspaceId, type: \"FOCUS\" as never } },\n refetchQueries: [\"GetActivePomodoroSession\", \"GetPomodoroStats\"],\n });\n setTimerSeconds(25 * 60);\n setIsRunning(true);\n }, [workspaceId, activeSession, startSession]);\n\n const handleComplete = useCallback(async () => {\n if (!activeSession || !workspaceId) return;\n await completeSession({\n variables: { id: activeSession.id, workspaceId },\n refetchQueries: [\"GetActivePomodoroSession\", \"GetPomodoroStats\"],\n });\n setIsRunning(false);\n setTimerSeconds(25 * 60);\n }, [activeSession, workspaceId, completeSession]);\n\n const handleReset = () => {\n setIsRunning(false);\n setTimerSeconds(25 * 60);\n };\n\n if (statsLoading || activeLoading) {\n return (\n <PageLayout\n title=\"Pomodoro Timer\"\n description=\"Focus with the Pomodoro Technique\"\n >\n <LoadingSkeleton variant=\"card\" count={3} />\n </PageLayout>\n );\n }\n\n if (statsError || activeError) {\n return (\n <PageLayout\n title=\"Pomodoro Timer\"\n description=\"Focus with the Pomodoro Technique\"\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 pomodoro data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n const totalFocusH = Math.floor((stats?.totalFocusMinutes ?? 0) / 60);\n const totalFocusM = (stats?.totalFocusMinutes ?? 0) % 60;\n\n return (\n <PageLayout\n title=\"Pomodoro Timer\"\n description=\"Focus with the Pomodoro Technique\"\n purpose=\"Work in focused 25-minute sprints with short breaks — the Pomodoro technique helps you beat procrastination and build a streak of deep-work sessions you can actually measure.\"\n >\n <NextSteps\n storageKey=\"timecampus-pomodoro\"\n className=\"mb-6\"\n steps={[\n {\n id: \"start\",\n label: \"Start a focus session\",\n description: \"Begin a 25-minute sprint on one task.\",\n onClick: () => handleStart(),\n },\n {\n id: \"analytics\",\n label: \"Review your pomodoro stats\",\n description: \"See streaks, completion rate and focus time.\",\n onClick: () => navigate(\"/pomodoro/analytics\"),\n },\n {\n id: \"settings\",\n label: \"Tune your intervals\",\n description: \"Adjust focus and break lengths to fit you.\",\n onClick: () => navigate(\"/pomodoro/settings\"),\n },\n ]}\n />\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <StatCard\n title=\"Sessions Today\"\n value={String(stats?.completedSessions ?? 0)}\n description={`Total: ${stats?.totalSessions ?? 0} sessions`}\n />\n <StatCard\n title=\"Focus Time\"\n value={`${totalFocusH}h ${totalFocusM}m`}\n trend={{\n value: stats?.completionRate ?? 0,\n label: \"completion rate\",\n }}\n />\n <StatCard\n title=\"Current Streak\"\n value={`${stats?.streakDays ?? 0} days`}\n description={`Avg: ${stats?.averageSessionMinutes ?? 0}m per session`}\n />\n </div>\n\n <div className=\"mx-auto max-w-md\">\n <GlassCard treatment=\"glass\" glow className=\"p-8 text-center\">\n <div className=\"mb-2\">\n <span className=\"inline-flex rounded-full bg-action-primary-bg/10 px-3 py-1 text-xs font-medium text-primary\">\n {activeSession ? \"Focus Session\" : \"Ready\"}\n </span>\n </div>\n <p className=\"text-7xl font-mono font-bold text-text-primary\">\n {formatTimer(timerSeconds)}\n </p>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {stats\n ? `${stats.completedSessions} of ${stats.totalSessions} sessions`\n : \"No sessions yet\"}\n </p>\n <div className=\"mt-6 flex items-center justify-center gap-3\">\n {!isRunning ? (\n <button\n onClick={handleStart}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-6 py-3 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Play className=\"h-4 w-4\" />\n Start\n </button>\n ) : (\n <button\n onClick={() => setIsRunning(false)}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-6 py-3 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Pause className=\"h-4 w-4\" />\n Pause\n </button>\n )}\n <button\n onClick={handleComplete}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-3 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\"\n >\n <SkipForward className=\"h-4 w-4\" />\n Skip\n </button>\n <button\n onClick={handleReset}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-3 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\"\n >\n <RotateCcw className=\"h-4 w-4\" />\n Reset\n </button>\n </div>\n </GlassCard>\n </div>\n\n {/* Focus Goals */}\n <GlassCard treatment=\"glass\" className=\"p-6\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <Target className=\"h-4 w-4\" />\n Focus Goals\n </h3>\n <button\n onClick={openCreateGoal}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus className=\"h-4 w-4\" />\n Add Goal\n </button>\n </div>\n {goals.length === 0 ? (\n <p className=\"py-6 text-center text-sm text-text-secondary\">\n No focus goals yet. Set a daily or weekly target to build a\n consistent focus habit.\n </p>\n ) : (\n <div className=\"space-y-3\">\n {goals.map((goal: PomodoroGoalFieldsFragment) => {\n const pct = goal.target\n ? Math.min(100, Math.round((goal.current / goal.target) * 100))\n : 0;\n return (\n <div\n key={goal.id}\n className=\"rounded-lg border border-border-subtle p-4\"\n >\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-sm font-medium capitalize text-text-primary\">\n {goal.type.toLowerCase()} goal\n </p>\n <p className=\"text-xs text-text-secondary\">\n {goal.current} of {goal.target} sessions\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium text-text-primary\">\n {pct}%\n </span>\n <button\n onClick={() => openEditGoal(goal)}\n className=\"rounded-md p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-text-primary\"\n aria-label=\"Edit goal\"\n >\n <Pencil className=\"h-4 w-4\" />\n </button>\n <button\n onClick={() => setDeletingGoalEntry(goal)}\n className=\"rounded-md p-1.5 text-text-secondary hover:bg-status-error-bg hover:text-status-error-text\"\n aria-label=\"Delete goal\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n <div className=\"mt-3 h-2 w-full rounded-full bg-bg-sunken\">\n <div\n className=\"h-2 rounded-full bg-action-primary-bg\"\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n );\n })}\n </div>\n )}\n </GlassCard>\n\n {/* Goal create/edit modal */}\n <Modal\n open={goalModalOpen}\n onClose={() => setGoalModalOpen(false)}\n title={editingGoal ? \"Edit Focus Goal\" : \"Add Focus Goal\"}\n description=\"Set a target number of focus sessions\"\n footer={\n <>\n <button\n onClick={() => setGoalModalOpen(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 onClick={handleSaveGoal}\n disabled={\n creatingGoal || updatingGoal || Number(goalForm.target) <= 0\n }\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 {creatingGoal || updatingGoal\n ? \"Saving...\"\n : editingGoal\n ? \"Save Changes\"\n : \"Add Goal\"}\n </button>\n </>\n }\n >\n {(createGoalError || updateGoalError) && (\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 save goal. Please try again.\n </div>\n )}\n <div className=\"space-y-4\">\n <div>\n <label className={labelClasses}>Goal Type</label>\n <select\n value={goalForm.type}\n onChange={(e) => {\n const type = e.target.value as PomodoroGoalType;\n setGoalForm((f) => ({\n ...f,\n type,\n period: type,\n endDate:\n type === PomodoroGoalType.Daily\n ? futureInput(0)\n : type === PomodoroGoalType.Weekly\n ? futureInput(7)\n : futureInput(30),\n }));\n }}\n className={inputClasses}\n >\n <option value={PomodoroGoalType.Daily}>Daily</option>\n <option value={PomodoroGoalType.Weekly}>Weekly</option>\n <option value={PomodoroGoalType.Monthly}>Monthly</option>\n </select>\n </div>\n <div>\n <label className={labelClasses}>Target Sessions</label>\n <input\n type=\"number\"\n min=\"1\"\n placeholder=\"8\"\n value={goalForm.target}\n onChange={(e) => setGoalField(\"target\", e.target.value)}\n className={inputClasses}\n />\n </div>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className={labelClasses}>Start Date</label>\n <input\n type=\"date\"\n value={goalForm.startDate}\n onChange={(e) => setGoalField(\"startDate\", e.target.value)}\n className={inputClasses}\n />\n </div>\n <div>\n <label className={labelClasses}>End Date</label>\n <input\n type=\"date\"\n value={goalForm.endDate}\n onChange={(e) => setGoalField(\"endDate\", e.target.value)}\n className={inputClasses}\n />\n </div>\n </div>\n </div>\n </Modal>\n\n {/* Goal delete confirm modal */}\n <Modal\n open={deletingGoalEntry !== null}\n onClose={() => setDeletingGoalEntry(null)}\n title=\"Delete Focus Goal\"\n size=\"sm\"\n footer={\n <>\n <button\n onClick={() => setDeletingGoalEntry(null)}\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 onClick={handleDeleteGoal}\n disabled={deletingGoal}\n className=\"rounded-md bg-status-error-bg px-4 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg/90 disabled:opacity-50\"\n >\n {deletingGoal ? \"Deleting...\" : \"Delete\"}\n </button>\n </>\n }\n >\n {deleteGoalError && (\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 delete goal. Please try again.\n </div>\n )}\n <p className=\"text-sm text-text-secondary\">\n Are you sure you want to delete this{\" \"}\n {deletingGoalEntry?.type.toLowerCase()} focus goal? This action cannot\n be undone.\n </p>\n </Modal>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|