@burdenoff/microfe-timecampus 2026.624.1 → 2026.626.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/timecampus/components/EmptyState.js +14 -0
- package/dist/timecampus/components/EmptyState.js.map +1 -0
- package/dist/timecampus/components/ErrorBoundary.js +2 -2
- package/dist/timecampus/components/ErrorBoundary.js.map +1 -1
- package/dist/timecampus/components/LoadingSkeleton.js +1 -1
- package/dist/timecampus/components/LoadingSkeleton.js.map +1 -1
- package/dist/timecampus/components/PageLayout.js +26 -14
- package/dist/timecampus/components/PageLayout.js.map +1 -1
- package/dist/timecampus/components/StatCard.js +19 -16
- package/dist/timecampus/components/StatCard.js.map +1 -1
- package/dist/timecampus/pages/HomePage.js +169 -149
- package/dist/timecampus/pages/HomePage.js.map +1 -1
- package/dist/timecampus/pages/applets/AppletStorePage.js +38 -35
- package/dist/timecampus/pages/applets/AppletStorePage.js.map +1 -1
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js +42 -36
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +57 -53
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js +40 -36
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/channels/ChannelsPage.js +32 -29
- package/dist/timecampus/pages/channels/ChannelsPage.js.map +1 -1
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js +52 -44
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/AnalyticsPage.js +65 -38
- package/dist/timecampus/pages/dashboard/AnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/ReportsPage.js +47 -41
- package/dist/timecampus/pages/dashboard/ReportsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js +16 -14
- package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js +40 -36
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +34 -28
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +49 -41
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScorePage.js +66 -62
- package/dist/timecampus/pages/focus-score/FocusScorePage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js +37 -33
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingPage.js +37 -30
- package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js +35 -31
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +37 -34
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js +35 -31
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +45 -41
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js +17 -15
- package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js +36 -32
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js +120 -102
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingsPage.js +46 -36
- package/dist/timecampus/pages/meetings/MeetingsPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js +19 -17
- package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js +143 -112
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js +55 -51
- package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectCreatePage.js +32 -28
- package/dist/timecampus/pages/projects/ProjectCreatePage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectDetailPage.js +107 -76
- package/dist/timecampus/pages/projects/ProjectDetailPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectsPage.js +21 -17
- package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/TasksPage.js +44 -34
- package/dist/timecampus/pages/projects/TasksPage.js.map +1 -1
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +59 -55
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js +24 -20
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamMembersPage.js +47 -41
- package/dist/timecampus/pages/team/TeamMembersPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamPage.js +89 -59
- package/dist/timecampus/pages/team/TeamPage.js.map +1 -1
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js +47 -43
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js.map +1 -1
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js +39 -35
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js +24 -20
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateDetailPage.js +66 -48
- package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplatesPage.js +39 -36
- package/dist/timecampus/pages/templates/TemplatesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeEntriesPage.js +53 -44
- package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeTrackingPage.js +72 -71
- package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimerPage.js +100 -66
- package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +63 -59
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js +64 -46
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetsPage.js +44 -37
- package/dist/timecampus/pages/widgets/WidgetsPage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +18 -16
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js +40 -36
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/workflows/WorkflowsPage.js +47 -37
- package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,121 +1,125 @@
|
|
|
1
1
|
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { StatCard as t } from "../../components/StatCard.js";
|
|
3
|
+
import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
|
|
4
|
+
import { useGetFocusScoreSummaryQuery as r, useGetTodayFocusScoreQuery as i, useListFocusScoresQuery as a } from "../../../generated/wspace-operations.js";
|
|
5
|
+
import { PageLayout as o } from "../../components/PageLayout.js";
|
|
6
|
+
import { EmptyState as s } from "../../components/EmptyState.js";
|
|
7
|
+
import { Brain as c, Shield as l, Target as u, Zap as d } from "lucide-react";
|
|
8
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
8
9
|
//#region src/timecampus/pages/focus-score/FocusScorePage.tsx
|
|
9
|
-
var
|
|
10
|
-
deepWork: "bg-blue
|
|
11
|
-
consistency: "bg-
|
|
12
|
-
taskCompletion: "bg-
|
|
13
|
-
distractionResistance: "bg-
|
|
14
|
-
energyManagement: "bg-
|
|
10
|
+
var m = {
|
|
11
|
+
deepWork: "bg-accent-blue",
|
|
12
|
+
consistency: "bg-status-success-text",
|
|
13
|
+
taskCompletion: "bg-accent-purple",
|
|
14
|
+
distractionResistance: "bg-status-warning-text",
|
|
15
|
+
energyManagement: "bg-accent-teal"
|
|
15
16
|
};
|
|
16
|
-
function
|
|
17
|
-
let { workspaceId:
|
|
17
|
+
function h() {
|
|
18
|
+
let { workspaceId: h = "" } = e(), { data: g, loading: _, error: v } = a({
|
|
18
19
|
variables: { limit: 30 },
|
|
19
|
-
skip: !
|
|
20
|
-
}), { data:
|
|
20
|
+
skip: !h
|
|
21
|
+
}), { data: y, loading: b, error: x } = r({ skip: !h }), { data: S, loading: C, error: w } = i({ skip: !h }), T = _ || b || C, E = v || x || w, D = S?.todayFocusScore, O = y?.focusScoreSummary, k = g?.focusScores ?? [], A = D ? [
|
|
21
22
|
{
|
|
22
23
|
label: "Deep Work",
|
|
23
|
-
score:
|
|
24
|
-
color:
|
|
24
|
+
score: D.deepWorkScore ?? 0,
|
|
25
|
+
color: m.deepWork
|
|
25
26
|
},
|
|
26
27
|
{
|
|
27
28
|
label: "Consistency",
|
|
28
|
-
score:
|
|
29
|
-
color:
|
|
29
|
+
score: D.consistencyScore ?? 0,
|
|
30
|
+
color: m.consistency
|
|
30
31
|
},
|
|
31
32
|
{
|
|
32
33
|
label: "Task Completion",
|
|
33
|
-
score:
|
|
34
|
-
color:
|
|
34
|
+
score: D.taskCompletionScore ?? 0,
|
|
35
|
+
color: m.taskCompletion
|
|
35
36
|
},
|
|
36
37
|
{
|
|
37
38
|
label: "Distraction Resistance",
|
|
38
|
-
score:
|
|
39
|
-
color:
|
|
39
|
+
score: D.distractionResistanceScore ?? 0,
|
|
40
|
+
color: m.distractionResistance
|
|
40
41
|
},
|
|
41
42
|
{
|
|
42
43
|
label: "Energy Management",
|
|
43
|
-
score:
|
|
44
|
-
color:
|
|
44
|
+
score: D.energyManagementScore ?? 0,
|
|
45
|
+
color: m.energyManagement
|
|
45
46
|
}
|
|
46
|
-
] : [],
|
|
47
|
-
return
|
|
47
|
+
] : [], j = D?.overallScore == null ? "--" : `${D.overallScore}/100`, M = k.filter((e) => e.overallScore >= 70).length, N = k.reduce((e, t) => e + (t.overallScore ?? 0), 0), P = Math.floor(N / 60), F = N % 60, I = P > 0 ? `${P}h ${F}m` : `${F}m`, L = O?.trend === "up" ? 7 : O?.trend === "down" ? -5 : 0, R = O?.highestScore == null ? "--" : `${O.highestScore}`;
|
|
48
|
+
return T ? /* @__PURE__ */ f(o, {
|
|
48
49
|
title: "Focus Score",
|
|
49
50
|
description: "Measure and improve your focus",
|
|
50
|
-
children: /* @__PURE__ */
|
|
51
|
+
children: /* @__PURE__ */ f(n, {
|
|
51
52
|
variant: "card",
|
|
52
53
|
count: 4
|
|
53
54
|
})
|
|
54
|
-
}) :
|
|
55
|
+
}) : E ? /* @__PURE__ */ f(o, {
|
|
55
56
|
title: "Focus Score",
|
|
56
57
|
description: "Measure and improve your focus",
|
|
57
|
-
children: /* @__PURE__ */
|
|
58
|
+
children: /* @__PURE__ */ f("div", {
|
|
58
59
|
className: "rounded-xl border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
|
|
59
60
|
children: "Failed to load focus score data. Please try again later."
|
|
60
61
|
})
|
|
61
|
-
}) : /* @__PURE__ */
|
|
62
|
+
}) : /* @__PURE__ */ p(o, {
|
|
62
63
|
title: "Focus Score",
|
|
63
64
|
description: "Measure and improve your focus",
|
|
64
|
-
|
|
65
|
+
purpose: "Get a single, honest number for how focused you were today — built from deep work, consistency, follow-through and distraction resistance — so you can see what's improving and what to work on next.",
|
|
66
|
+
children: [/* @__PURE__ */ p("div", {
|
|
65
67
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
66
68
|
children: [
|
|
67
|
-
/* @__PURE__ */
|
|
69
|
+
/* @__PURE__ */ f(t, {
|
|
70
|
+
featured: !0,
|
|
68
71
|
title: "Overall Score",
|
|
69
|
-
value:
|
|
70
|
-
icon: /* @__PURE__ */
|
|
71
|
-
trend:
|
|
72
|
-
value:
|
|
72
|
+
value: j,
|
|
73
|
+
icon: /* @__PURE__ */ f(c, { className: "h-5 w-5" }),
|
|
74
|
+
trend: L === 0 ? void 0 : {
|
|
75
|
+
value: L,
|
|
73
76
|
label: "vs last week"
|
|
74
77
|
},
|
|
75
|
-
iconBgColor: "bg-
|
|
78
|
+
iconBgColor: "bg-status-info-bg text-status-info-text"
|
|
76
79
|
}),
|
|
77
|
-
/* @__PURE__ */
|
|
80
|
+
/* @__PURE__ */ f(t, {
|
|
78
81
|
title: "Focus Sessions",
|
|
79
|
-
value: String(
|
|
80
|
-
icon: /* @__PURE__ */
|
|
82
|
+
value: String(M),
|
|
83
|
+
icon: /* @__PURE__ */ f(u, { className: "h-5 w-5" }),
|
|
81
84
|
description: "Completed today"
|
|
82
85
|
}),
|
|
83
|
-
/* @__PURE__ */
|
|
86
|
+
/* @__PURE__ */ f(t, {
|
|
84
87
|
title: "Total Focus Time",
|
|
85
|
-
value:
|
|
86
|
-
icon: /* @__PURE__ */ d
|
|
88
|
+
value: I,
|
|
89
|
+
icon: /* @__PURE__ */ f(d, { className: "h-5 w-5" })
|
|
87
90
|
}),
|
|
88
|
-
/* @__PURE__ */
|
|
91
|
+
/* @__PURE__ */ f(t, {
|
|
89
92
|
title: "Highest Score",
|
|
90
|
-
value:
|
|
91
|
-
icon: /* @__PURE__ */
|
|
93
|
+
value: R,
|
|
94
|
+
icon: /* @__PURE__ */ f(l, { className: "h-5 w-5" }),
|
|
92
95
|
description: "Personal best"
|
|
93
96
|
})
|
|
94
97
|
]
|
|
95
|
-
}), /* @__PURE__ */
|
|
96
|
-
className: "rounded-xl border border-border-
|
|
97
|
-
children: [/* @__PURE__ */
|
|
98
|
+
}), /* @__PURE__ */ p("div", {
|
|
99
|
+
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6",
|
|
100
|
+
children: [/* @__PURE__ */ f("h3", {
|
|
98
101
|
className: "mb-4 text-sm font-semibold text-text-primary",
|
|
99
102
|
children: "Focus Components"
|
|
100
|
-
}),
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
}), A.length === 0 ? /* @__PURE__ */ f(s, {
|
|
104
|
+
illustration: "empty-data",
|
|
105
|
+
title: "No focus score recorded today",
|
|
106
|
+
description: "Track some focused work today and your score breakdown will appear here."
|
|
107
|
+
}) : /* @__PURE__ */ f("div", {
|
|
104
108
|
className: "space-y-4",
|
|
105
|
-
children:
|
|
109
|
+
children: A.map((e) => /* @__PURE__ */ p("div", {
|
|
106
110
|
className: "space-y-1",
|
|
107
|
-
children: [/* @__PURE__ */
|
|
111
|
+
children: [/* @__PURE__ */ p("div", {
|
|
108
112
|
className: "flex items-center justify-between text-sm",
|
|
109
|
-
children: [/* @__PURE__ */
|
|
113
|
+
children: [/* @__PURE__ */ f("span", {
|
|
110
114
|
className: "font-medium text-text-primary",
|
|
111
115
|
children: e.label
|
|
112
|
-
}), /* @__PURE__ */
|
|
116
|
+
}), /* @__PURE__ */ p("span", {
|
|
113
117
|
className: "text-text-secondary",
|
|
114
118
|
children: [e.score, "%"]
|
|
115
119
|
})]
|
|
116
|
-
}), /* @__PURE__ */
|
|
120
|
+
}), /* @__PURE__ */ f("div", {
|
|
117
121
|
className: "h-2.5 w-full rounded-full bg-bg-sunken",
|
|
118
|
-
children: /* @__PURE__ */
|
|
122
|
+
children: /* @__PURE__ */ f("div", {
|
|
119
123
|
className: `h-2.5 rounded-full ${e.color}`,
|
|
120
124
|
style: { width: `${e.score}%` }
|
|
121
125
|
})
|
|
@@ -126,6 +130,6 @@ function m() {
|
|
|
126
130
|
});
|
|
127
131
|
}
|
|
128
132
|
//#endregion
|
|
129
|
-
export {
|
|
133
|
+
export { h as FocusScorePage };
|
|
130
134
|
|
|
131
135
|
//# sourceMappingURL=FocusScorePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FocusScorePage.js","names":[],"sources":["../../../../src/timecampus/pages/focus-score/FocusScorePage.tsx"],"sourcesContent":["import { Brain, Target, Zap, Shield } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListFocusScoresQuery,\n useGetFocusScoreSummaryQuery,\n useGetTodayFocusScoreQuery,\n type FocusScoreFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nconst COMPONENT_COLORS: Record<string, string> = {\n deepWork: \"bg-blue
|
|
1
|
+
{"version":3,"file":"FocusScorePage.js","names":[],"sources":["../../../../src/timecampus/pages/focus-score/FocusScorePage.tsx"],"sourcesContent":["import { Brain, Target, Zap, Shield } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { EmptyState } from \"../../components/EmptyState\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListFocusScoresQuery,\n useGetFocusScoreSummaryQuery,\n useGetTodayFocusScoreQuery,\n type FocusScoreFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nconst COMPONENT_COLORS: Record<string, string> = {\n deepWork: \"bg-accent-blue\",\n consistency: \"bg-status-success-text\",\n taskCompletion: \"bg-accent-purple\",\n distractionResistance: \"bg-status-warning-text\",\n energyManagement: \"bg-accent-teal\",\n};\n\nexport function FocusScorePage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const {\n data: scoresData,\n loading: scoresLoading,\n error: scoresError,\n } = useListFocusScoresQuery({\n variables: { limit: 30 },\n skip: !workspaceId,\n });\n\n const {\n data: summaryData,\n loading: summaryLoading,\n error: summaryError,\n } = useGetFocusScoreSummaryQuery({\n skip: !workspaceId,\n });\n\n const {\n data: todayData,\n loading: todayLoading,\n error: todayError,\n } = useGetTodayFocusScoreQuery({\n skip: !workspaceId,\n });\n\n const loading = scoresLoading || summaryLoading || todayLoading;\n const error = scoresError || summaryError || todayError;\n const today = todayData?.todayFocusScore;\n const summary = summaryData?.focusScoreSummary;\n const scores = scoresData?.focusScores ?? [];\n\n // Build focus components from today's score\n const focusComponents = today\n ? [\n {\n label: \"Deep Work\",\n score: today.deepWorkScore ?? 0,\n color: COMPONENT_COLORS.deepWork,\n },\n {\n label: \"Consistency\",\n score: today.consistencyScore ?? 0,\n color: COMPONENT_COLORS.consistency,\n },\n {\n label: \"Task Completion\",\n score: today.taskCompletionScore ?? 0,\n color: COMPONENT_COLORS.taskCompletion,\n },\n {\n label: \"Distraction Resistance\",\n score: today.distractionResistanceScore ?? 0,\n color: COMPONENT_COLORS.distractionResistance,\n },\n {\n label: \"Energy Management\",\n score: today.energyManagementScore ?? 0,\n color: COMPONENT_COLORS.energyManagement,\n },\n ]\n : [];\n\n // Calculate stats\n const overallScore =\n today?.overallScore != null ? `${today.overallScore}/100` : \"--\";\n const completedSessions = scores.filter(\n (s: FocusScoreFieldsFragment) => s.overallScore >= 70,\n ).length;\n const totalFocusMinutes = scores.reduce(\n (sum: number, s: FocusScoreFieldsFragment) => sum + (s.overallScore ?? 0),\n 0,\n );\n const totalFocusHours = Math.floor(totalFocusMinutes / 60);\n const totalFocusMins = totalFocusMinutes % 60;\n const focusTimeDisplay =\n totalFocusHours > 0\n ? `${totalFocusHours}h ${totalFocusMins}m`\n : `${totalFocusMins}m`;\n const trendValue =\n summary?.trend === \"up\" ? 7 : summary?.trend === \"down\" ? -5 : 0;\n\n // Longest streak from highest score\n const highestScore =\n summary?.highestScore != null ? `${summary.highestScore}` : \"--\";\n\n if (loading) {\n return (\n <PageLayout\n title=\"Focus Score\"\n description=\"Measure and improve your focus\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Focus Score\"\n description=\"Measure and improve your focus\"\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 focus score data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Focus Score\"\n description=\"Measure and improve your focus\"\n purpose=\"Get a single, honest number for how focused you were today — built from deep work, consistency, follow-through and distraction resistance — so you can see what's improving and what to work on next.\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n featured\n title=\"Overall Score\"\n value={overallScore}\n icon={<Brain className=\"h-5 w-5\" />}\n trend={\n trendValue !== 0\n ? { value: trendValue, label: \"vs last week\" }\n : undefined\n }\n iconBgColor=\"bg-status-info-bg text-status-info-text\"\n />\n <StatCard\n title=\"Focus Sessions\"\n value={String(completedSessions)}\n icon={<Target className=\"h-5 w-5\" />}\n description=\"Completed today\"\n />\n <StatCard\n title=\"Total Focus Time\"\n value={focusTimeDisplay}\n icon={<Zap className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Highest Score\"\n value={highestScore}\n icon={<Shield className=\"h-5 w-5\" />}\n description=\"Personal best\"\n />\n </div>\n\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6\">\n <h3 className=\"mb-4 text-sm font-semibold text-text-primary\">\n Focus Components\n </h3>\n {focusComponents.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No focus score recorded today\"\n description=\"Track some focused work today and your score breakdown will appear here.\"\n />\n ) : (\n <div className=\"space-y-4\">\n {focusComponents.map((component) => (\n <div key={component.label} className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-medium text-text-primary\">\n {component.label}\n </span>\n <span className=\"text-text-secondary\">\n {component.score}%\n </span>\n </div>\n <div className=\"h-2.5 w-full rounded-full bg-bg-sunken\">\n <div\n className={`h-2.5 rounded-full ${component.color}`}\n style={{ width: `${component.score}%` }}\n />\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;AAaA,IAAM,IAA2C;CAC/C,UAAU;CACV,aAAa;CACb,gBAAgB;CAChB,uBAAuB;CACvB,kBAAkB;CACnB;AAED,SAAgB,IAAiB;CAC/B,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAAwB;EAC1B,WAAW,EAAE,OAAO,IAAI;EACxB,MAAM,CAAC;EACR,CAAC,EAEI,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAA6B,EAC/B,MAAM,CAAC,GACR,CAAC,EAEI,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAA2B,EAC7B,MAAM,CAAC,GACR,CAAC,EAEI,IAAU,KAAiB,KAAkB,GAC7C,IAAQ,KAAe,KAAgB,GACvC,IAAQ,GAAW,iBACnB,IAAU,GAAa,mBACvB,IAAS,GAAY,eAAe,EAAE,EAGtC,IAAkB,IACpB;EACE;GACE,OAAO;GACP,OAAO,EAAM,iBAAiB;GAC9B,OAAO,EAAiB;GACzB;EACD;GACE,OAAO;GACP,OAAO,EAAM,oBAAoB;GACjC,OAAO,EAAiB;GACzB;EACD;GACE,OAAO;GACP,OAAO,EAAM,uBAAuB;GACpC,OAAO,EAAiB;GACzB;EACD;GACE,OAAO;GACP,OAAO,EAAM,8BAA8B;GAC3C,OAAO,EAAiB;GACzB;EACD;GACE,OAAO;GACP,OAAO,EAAM,yBAAyB;GACtC,OAAO,EAAiB;GACzB;EACF,GACD,EAAE,EAGA,IACJ,GAAO,gBAAgB,OAAqC,OAA9B,GAAG,EAAM,aAAa,OAChD,IAAoB,EAAO,QAC9B,MAAgC,EAAE,gBAAgB,GACpD,CAAC,QACI,IAAoB,EAAO,QAC9B,GAAa,MAAgC,KAAO,EAAE,gBAAgB,IACvE,EACD,EACK,IAAkB,KAAK,MAAM,IAAoB,GAAG,EACpD,IAAiB,IAAoB,IACrC,IACJ,IAAkB,IACd,GAAG,EAAgB,IAAI,EAAe,KACtC,GAAG,EAAe,IAClB,IACJ,GAAS,UAAU,OAAO,IAAI,GAAS,UAAU,SAAS,KAAK,GAG3D,IACJ,GAAS,gBAAgB,OAAmC,OAA5B,GAAG,EAAQ;AA0B7C,QAxBI,IAEA,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,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;YAHV,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,UAAA;KACA,OAAM;KACN,OAAO;KACP,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,OACE,MAAe,IAEX,KAAA,IADA;MAAE,OAAO;MAAY,OAAO;MAAgB;KAGlD,aAAY;KACZ,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,OAAO,EAAkB;KAChC,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;KACpC,aAAY;KACZ,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO;KACP,MAAM,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA;KACjC,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO;KACP,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;KACpC,aAAY;KACZ,CAAA;IACE;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,MAAD;IAAI,WAAU;cAA+C;IAExD,CAAA,EACJ,EAAgB,WAAW,IAC1B,kBAAC,GAAD;IACE,cAAa;IACb,OAAM;IACN,aAAY;IACZ,CAAA,GAEF,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAgB,KAAK,MACpB,kBAAC,OAAD;KAA2B,WAAU;eAArC,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAU;OACN,CAAA,EACP,kBAAC,QAAD;OAAM,WAAU;iBAAhB,CACG,EAAU,OAAM,IACZ;SACH;SACN,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD;OACE,WAAW,sBAAsB,EAAU;OAC3C,OAAO,EAAE,OAAO,GAAG,EAAU,MAAM,IAAI;OACvC,CAAA;MACE,CAAA,CACF;OAfI,EAAU,MAed,CACN;IACE,CAAA,CAEJ;KACK"}
|
|
@@ -1,61 +1,65 @@
|
|
|
1
1
|
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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
5
|
import { useCallback as a, useEffect as o, useState as s } from "react";
|
|
6
6
|
import { Settings as c } from "lucide-react";
|
|
7
7
|
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
8
|
+
import { GlassCard as d } from "@burdenoff/fe-libs/ui";
|
|
8
9
|
//#region src/timecampus/pages/focus-score/FocusScoreSettingsPage.tsx
|
|
9
|
-
var
|
|
10
|
+
var f = "timecampus.focus.settings", p = {
|
|
10
11
|
dailyFocusTarget: 4,
|
|
11
12
|
minSessionLength: 25
|
|
12
13
|
};
|
|
13
|
-
function
|
|
14
|
-
let { workspaceId:
|
|
14
|
+
function m() {
|
|
15
|
+
let { workspaceId: m = "" } = e(), { data: h, loading: g, error: _ } = n({
|
|
15
16
|
variables: {
|
|
16
17
|
scope: "WORKSPACE",
|
|
17
18
|
limit: 100
|
|
18
19
|
},
|
|
19
|
-
skip: !
|
|
20
|
-
}), [
|
|
20
|
+
skip: !m
|
|
21
|
+
}), [v, { loading: y }] = r(), [b, x] = s(p);
|
|
21
22
|
o(() => {
|
|
22
|
-
if (
|
|
23
|
-
let e =
|
|
23
|
+
if (h?.configurations) {
|
|
24
|
+
let e = h.configurations.find((e) => e.key === f);
|
|
24
25
|
if (e?.value) {
|
|
25
26
|
let t = e.value;
|
|
26
|
-
|
|
27
|
-
dailyFocusTarget: t.dailyFocusTarget ??
|
|
28
|
-
minSessionLength: t.minSessionLength ??
|
|
27
|
+
x({
|
|
28
|
+
dailyFocusTarget: t.dailyFocusTarget ?? p.dailyFocusTarget,
|
|
29
|
+
minSessionLength: t.minSessionLength ?? p.minSessionLength
|
|
29
30
|
});
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
}, [
|
|
33
|
-
let
|
|
34
|
-
await
|
|
35
|
-
key:
|
|
36
|
-
value:
|
|
33
|
+
}, [h]);
|
|
34
|
+
let S = a(async () => {
|
|
35
|
+
await v({ variables: { input: {
|
|
36
|
+
key: f,
|
|
37
|
+
value: b,
|
|
37
38
|
description: "Focus score settings",
|
|
38
39
|
scope: "WORKSPACE"
|
|
39
40
|
} } });
|
|
40
|
-
}, [
|
|
41
|
-
return
|
|
41
|
+
}, [v, b]);
|
|
42
|
+
return g ? /* @__PURE__ */ l(i, {
|
|
42
43
|
title: "Focus Score Settings",
|
|
43
44
|
description: "Configure focus tracking preferences",
|
|
44
|
-
children: /* @__PURE__ */ l(
|
|
45
|
-
}) :
|
|
45
|
+
children: /* @__PURE__ */ l(t, { variant: "detail" })
|
|
46
|
+
}) : _ ? /* @__PURE__ */ l(i, {
|
|
46
47
|
title: "Focus Score Settings",
|
|
47
48
|
description: "Configure focus tracking preferences",
|
|
48
49
|
children: /* @__PURE__ */ l("div", {
|
|
49
50
|
className: "rounded-xl border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
|
|
50
51
|
children: "Failed to load settings. Please try again later."
|
|
51
52
|
})
|
|
52
|
-
}) : /* @__PURE__ */ l(
|
|
53
|
+
}) : /* @__PURE__ */ l(i, {
|
|
53
54
|
title: "Focus Score Settings",
|
|
54
55
|
description: "Configure focus tracking preferences",
|
|
56
|
+
purpose: "Set what 'a good focus day' means for you — a daily deep-work target and the minimum length that counts as a real focus session — so your focus score reflects your own goals, not generic defaults.",
|
|
55
57
|
children: /* @__PURE__ */ u("div", {
|
|
56
58
|
className: "mx-auto max-w-2xl space-y-6",
|
|
57
|
-
children: [/* @__PURE__ */ u(
|
|
58
|
-
|
|
59
|
+
children: [/* @__PURE__ */ u(d, {
|
|
60
|
+
treatment: "glass",
|
|
61
|
+
glow: !0,
|
|
62
|
+
className: "p-6",
|
|
59
63
|
children: [/* @__PURE__ */ u("h3", {
|
|
60
64
|
className: "mb-4 flex items-center gap-2 text-sm font-semibold text-text-primary",
|
|
61
65
|
children: [/* @__PURE__ */ l(c, { className: "h-4 w-4" }), "Focus Goals"]
|
|
@@ -71,8 +75,8 @@ function p() {
|
|
|
71
75
|
children: "Hours of deep focus per day"
|
|
72
76
|
})] }), /* @__PURE__ */ l("input", {
|
|
73
77
|
type: "number",
|
|
74
|
-
value:
|
|
75
|
-
onChange: (e) =>
|
|
78
|
+
value: b.dailyFocusTarget,
|
|
79
|
+
onChange: (e) => x((t) => ({
|
|
76
80
|
...t,
|
|
77
81
|
dailyFocusTarget: Number(e.target.value)
|
|
78
82
|
})),
|
|
@@ -88,8 +92,8 @@ function p() {
|
|
|
88
92
|
children: "Minimum minutes for a focus session"
|
|
89
93
|
})] }), /* @__PURE__ */ l("input", {
|
|
90
94
|
type: "number",
|
|
91
|
-
value:
|
|
92
|
-
onChange: (e) =>
|
|
95
|
+
value: b.minSessionLength,
|
|
96
|
+
onChange: (e) => x((t) => ({
|
|
93
97
|
...t,
|
|
94
98
|
minSessionLength: Number(e.target.value)
|
|
95
99
|
})),
|
|
@@ -100,16 +104,16 @@ function p() {
|
|
|
100
104
|
}), /* @__PURE__ */ l("div", {
|
|
101
105
|
className: "flex justify-end",
|
|
102
106
|
children: /* @__PURE__ */ l("button", {
|
|
103
|
-
onClick:
|
|
104
|
-
disabled:
|
|
107
|
+
onClick: S,
|
|
108
|
+
disabled: y,
|
|
105
109
|
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",
|
|
106
|
-
children:
|
|
110
|
+
children: y ? "Saving..." : "Save Settings"
|
|
107
111
|
})
|
|
108
112
|
})]
|
|
109
113
|
})
|
|
110
114
|
});
|
|
111
115
|
}
|
|
112
116
|
//#endregion
|
|
113
|
-
export {
|
|
117
|
+
export { m as FocusScoreSettingsPage };
|
|
114
118
|
|
|
115
119
|
//# sourceMappingURL=FocusScoreSettingsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FocusScoreSettingsPage.js","names":[],"sources":["../../../../src/timecampus/pages/focus-score/FocusScoreSettingsPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { Settings } from \"lucide-react\";\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 FOCUS_SETTINGS_KEY = \"timecampus.focus.settings\";\n\ninterface FocusSettings {\n dailyFocusTarget: number;\n minSessionLength: number;\n}\n\nconst DEFAULT_SETTINGS: FocusSettings = {\n dailyFocusTarget: 4,\n minSessionLength: 25,\n};\n\nexport function FocusScoreSettingsPage() {\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] = useState<FocusSettings>(DEFAULT_SETTINGS);\n\n useEffect(() => {\n if (data?.configurations) {\n const config = data.configurations.find(\n (c: ConfigurationFieldsFragment) => c.key === FOCUS_SETTINGS_KEY,\n );\n if (config?.value) {\n const val = config.value as Partial<FocusSettings>;\n setSettings({\n dailyFocusTarget:\n val.dailyFocusTarget ?? DEFAULT_SETTINGS.dailyFocusTarget,\n minSessionLength:\n val.minSessionLength ?? DEFAULT_SETTINGS.minSessionLength,\n });\n }\n }\n }, [data]);\n\n const handleSave = useCallback(async () => {\n await setConfiguration({\n variables: {\n input: {\n key: FOCUS_SETTINGS_KEY,\n value: settings as unknown as Record<string, unknown>,\n description: \"Focus score settings\",\n scope: \"WORKSPACE\" as never,\n },\n },\n });\n }, [setConfiguration, settings]);\n\n if (loading) {\n return (\n <PageLayout\n title=\"Focus Score Settings\"\n description=\"Configure focus tracking preferences\"\n >\n <LoadingSkeleton variant=\"detail\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Focus Score Settings\"\n description=\"Configure focus tracking preferences\"\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=\"Focus Score Settings\"\n description=\"Configure focus tracking preferences\"\n >\n <div className=\"mx-auto max-w-2xl space-y-6\">\n <
|
|
1
|
+
{"version":3,"file":"FocusScoreSettingsPage.js","names":[],"sources":["../../../../src/timecampus/pages/focus-score/FocusScoreSettingsPage.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 FOCUS_SETTINGS_KEY = \"timecampus.focus.settings\";\n\ninterface FocusSettings {\n dailyFocusTarget: number;\n minSessionLength: number;\n}\n\nconst DEFAULT_SETTINGS: FocusSettings = {\n dailyFocusTarget: 4,\n minSessionLength: 25,\n};\n\nexport function FocusScoreSettingsPage() {\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] = useState<FocusSettings>(DEFAULT_SETTINGS);\n\n useEffect(() => {\n if (data?.configurations) {\n const config = data.configurations.find(\n (c: ConfigurationFieldsFragment) => c.key === FOCUS_SETTINGS_KEY,\n );\n if (config?.value) {\n const val = config.value as Partial<FocusSettings>;\n setSettings({\n dailyFocusTarget:\n val.dailyFocusTarget ?? DEFAULT_SETTINGS.dailyFocusTarget,\n minSessionLength:\n val.minSessionLength ?? DEFAULT_SETTINGS.minSessionLength,\n });\n }\n }\n }, [data]);\n\n const handleSave = useCallback(async () => {\n await setConfiguration({\n variables: {\n input: {\n key: FOCUS_SETTINGS_KEY,\n value: settings as unknown as Record<string, unknown>,\n description: \"Focus score settings\",\n scope: \"WORKSPACE\" as never,\n },\n },\n });\n }, [setConfiguration, settings]);\n\n if (loading) {\n return (\n <PageLayout\n title=\"Focus Score Settings\"\n description=\"Configure focus tracking preferences\"\n >\n <LoadingSkeleton variant=\"detail\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Focus Score Settings\"\n description=\"Configure focus tracking preferences\"\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=\"Focus Score Settings\"\n description=\"Configure focus tracking preferences\"\n purpose=\"Set what 'a good focus day' means for you — a daily deep-work target and the minimum length that counts as a real focus session — so your focus score reflects your own goals, not generic defaults.\"\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 Focus Goals\n </h3>\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n Daily focus target\n </p>\n <p className=\"text-xs text-text-secondary\">\n Hours of deep focus per day\n </p>\n </div>\n <input\n type=\"number\"\n value={settings.dailyFocusTarget}\n onChange={(e) =>\n setSettings((s) => ({\n ...s,\n dailyFocusTarget: Number(e.target.value),\n }))\n }\n className=\"w-20 rounded-md border border-border-subtle bg-bg-surface px-3 py-1.5 text-sm text-text-primary text-right\"\n />\n </div>\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n Min. session length\n </p>\n <p className=\"text-xs text-text-secondary\">\n Minimum minutes for a focus session\n </p>\n </div>\n <input\n type=\"number\"\n value={settings.minSessionLength}\n onChange={(e) =>\n setSettings((s) => ({\n ...s,\n minSessionLength: Number(e.target.value),\n }))\n }\n className=\"w-20 rounded-md border border-border-subtle bg-bg-surface px-3 py-1.5 text-sm text-text-primary text-right\"\n />\n </div>\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,IAAqB,6BAOrB,IAAkC;CACtC,kBAAkB;CAClB,kBAAkB;CACnB;AAED,SAAgB,IAAyB;CACvC,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,KAAe,EAAwB,EAAiB;AAEzE,SAAgB;AACd,MAAI,GAAM,gBAAgB;GACxB,IAAM,IAAS,EAAK,eAAe,MAChC,MAAmC,EAAE,QAAQ,EAC/C;AACD,OAAI,GAAQ,OAAO;IACjB,IAAM,IAAM,EAAO;AACnB,MAAY;KACV,kBACE,EAAI,oBAAoB,EAAiB;KAC3C,kBACE,EAAI,oBAAoB,EAAiB;KAC5C,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,cAE7B;QACL,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAwC;OAEjD,CAAA,EACJ,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAEvC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,SAAD;OACE,MAAK;OACL,OAAO,EAAS;OAChB,WAAW,MACT,GAAa,OAAO;QAClB,GAAG;QACH,kBAAkB,OAAO,EAAE,OAAO,MAAM;QACzC,EAAE;OAEL,WAAU;OACV,CAAA,CACE;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAwC;OAEjD,CAAA,EACJ,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAEvC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,SAAD;OACE,MAAK;OACL,OAAO,EAAS;OAChB,WAAW,MACT,GAAa,OAAO;QAClB,GAAG;QACH,kBAAkB,OAAO,EAAE,OAAO,MAAM;QACzC,EAAE;OAEL,WAAU;OACV,CAAA,CACE;QACF;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"}
|
|
@@ -1,49 +1,56 @@
|
|
|
1
1
|
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
2
|
import { getStatusColor as t } from "../../utils/helpers.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
|
|
4
|
+
import { useListGeofencesQuery as r } from "../../../generated/wspace-operations.js";
|
|
5
|
+
import { PageLayout as i } from "../../components/PageLayout.js";
|
|
6
|
+
import { EmptyState as a } from "../../components/EmptyState.js";
|
|
7
|
+
import { MapPin as o, Plus as s } from "lucide-react";
|
|
8
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
8
9
|
//#region src/timecampus/pages/geofencing/GeofencingPage.tsx
|
|
9
|
-
function
|
|
10
|
-
let { workspaceId:
|
|
11
|
-
return
|
|
10
|
+
function u() {
|
|
11
|
+
let { workspaceId: u = "" } = e(), { data: d, loading: f, error: p } = r(), m = d?.geofences?.items ?? [];
|
|
12
|
+
return f ? /* @__PURE__ */ c(i, {
|
|
12
13
|
title: "Geofencing",
|
|
13
14
|
description: "Set up location-based triggers and zones",
|
|
14
|
-
children: /* @__PURE__ */
|
|
15
|
+
children: /* @__PURE__ */ c(n, {
|
|
15
16
|
variant: "card",
|
|
16
17
|
count: 4
|
|
17
18
|
})
|
|
18
|
-
}) :
|
|
19
|
+
}) : p ? /* @__PURE__ */ c(i, {
|
|
19
20
|
title: "Geofencing",
|
|
20
21
|
description: "Set up location-based triggers and zones",
|
|
21
|
-
children: /* @__PURE__ */
|
|
22
|
-
className: "rounded-lg border border-
|
|
22
|
+
children: /* @__PURE__ */ c("div", {
|
|
23
|
+
className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
|
|
23
24
|
children: "Failed to load geofences. Please try again later."
|
|
24
25
|
})
|
|
25
|
-
}) : /* @__PURE__ */
|
|
26
|
+
}) : /* @__PURE__ */ c(i, {
|
|
26
27
|
title: "Geofencing",
|
|
27
28
|
description: "Set up location-based triggers and zones",
|
|
28
|
-
|
|
29
|
+
purpose: "Draw zones around your worksites — offices, client sites, job locations — and have time tracking start and stop automatically as people move in and out, so on-site hours record themselves.",
|
|
30
|
+
actions: /* @__PURE__ */ l("button", {
|
|
29
31
|
className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
30
|
-
children: [/* @__PURE__ */ s
|
|
32
|
+
children: [/* @__PURE__ */ c(s, { className: "h-4 w-4" }), "Create Geofence"]
|
|
31
33
|
}),
|
|
32
|
-
children: /* @__PURE__ */ c(
|
|
34
|
+
children: m.length === 0 ? /* @__PURE__ */ c(a, {
|
|
35
|
+
illustration: "empty-generic",
|
|
36
|
+
title: "No geofences configured yet",
|
|
37
|
+
description: "Create your first zone to trigger automatic time tracking when people arrive or leave a location.",
|
|
38
|
+
action: /* @__PURE__ */ l("button", {
|
|
39
|
+
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",
|
|
40
|
+
children: [/* @__PURE__ */ c(s, { className: "h-4 w-4" }), "Create Geofence"]
|
|
41
|
+
})
|
|
42
|
+
}) : /* @__PURE__ */ c("div", {
|
|
33
43
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
34
|
-
children:
|
|
35
|
-
className: "
|
|
36
|
-
children:
|
|
37
|
-
}), p.map((e) => /* @__PURE__ */ c("div", {
|
|
38
|
-
className: "rounded-xl border border-border-subtle bg-bg-surface p-5 transition-colors hover:bg-bg-sunken/50 cursor-pointer",
|
|
39
|
-
children: [/* @__PURE__ */ c("div", {
|
|
44
|
+
children: m.map((e) => /* @__PURE__ */ l("div", {
|
|
45
|
+
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-5 transition-colors hover:bg-bg-sunken/50 cursor-pointer",
|
|
46
|
+
children: [/* @__PURE__ */ l("div", {
|
|
40
47
|
className: "flex items-start justify-between",
|
|
41
|
-
children: [/* @__PURE__ */
|
|
48
|
+
children: [/* @__PURE__ */ l("div", {
|
|
42
49
|
className: "flex items-center gap-2",
|
|
43
|
-
children: [/* @__PURE__ */
|
|
50
|
+
children: [/* @__PURE__ */ c(o, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("p", {
|
|
44
51
|
className: "text-sm font-semibold text-text-primary",
|
|
45
52
|
children: e.name
|
|
46
|
-
}), /* @__PURE__ */
|
|
53
|
+
}), /* @__PURE__ */ l("p", {
|
|
47
54
|
className: "text-xs text-text-secondary",
|
|
48
55
|
children: [
|
|
49
56
|
e.trigger,
|
|
@@ -52,19 +59,19 @@ function l() {
|
|
|
52
59
|
"m radius"
|
|
53
60
|
]
|
|
54
61
|
})] })]
|
|
55
|
-
}), /* @__PURE__ */
|
|
62
|
+
}), /* @__PURE__ */ c("span", {
|
|
56
63
|
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${t(e.isActive ? "active" : "inactive")}`,
|
|
57
64
|
children: e.isActive ? "Active" : "Inactive"
|
|
58
65
|
})]
|
|
59
|
-
}), /* @__PURE__ */
|
|
66
|
+
}), /* @__PURE__ */ l("div", {
|
|
60
67
|
className: "mt-3 flex items-center justify-between text-xs text-text-secondary",
|
|
61
|
-
children: [/* @__PURE__ */
|
|
68
|
+
children: [/* @__PURE__ */ c("span", { children: e.address ?? "No address" }), /* @__PURE__ */ l("span", { children: [e.events?.length ?? 0, " events"] })]
|
|
62
69
|
})]
|
|
63
|
-
}, e.id))
|
|
70
|
+
}, e.id))
|
|
64
71
|
})
|
|
65
72
|
});
|
|
66
73
|
}
|
|
67
74
|
//#endregion
|
|
68
|
-
export {
|
|
75
|
+
export { u as GeofencingPage };
|
|
69
76
|
|
|
70
77
|
//# sourceMappingURL=GeofencingPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GeofencingPage.js","names":[],"sources":["../../../../src/timecampus/pages/geofencing/GeofencingPage.tsx"],"sourcesContent":["import { MapPin, Plus } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { getStatusColor } from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListGeofencesQuery,\n type ListGeofencesQuery,\n} from \"@/generated/wspace-operations\";\n\ntype GeofenceItem = NonNullable<\n ListGeofencesQuery[\"geofences\"]\n>[\"items\"][number];\n\nexport function GeofencingPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const { data, loading, error } = useListGeofencesQuery();\n\n const geofences = data?.geofences?.items ?? [];\n\n if (loading) {\n return (\n <PageLayout\n title=\"Geofencing\"\n description=\"Set up location-based triggers and zones\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Geofencing\"\n description=\"Set up location-based triggers and zones\"\n >\n <div className=\"rounded-lg border border-
|
|
1
|
+
{"version":3,"file":"GeofencingPage.js","names":[],"sources":["../../../../src/timecampus/pages/geofencing/GeofencingPage.tsx"],"sourcesContent":["import { MapPin, Plus } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { EmptyState } from \"../../components/EmptyState\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { getStatusColor } from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListGeofencesQuery,\n type ListGeofencesQuery,\n} from \"@/generated/wspace-operations\";\n\ntype GeofenceItem = NonNullable<\n ListGeofencesQuery[\"geofences\"]\n>[\"items\"][number];\n\nexport function GeofencingPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const { data, loading, error } = useListGeofencesQuery();\n\n const geofences = data?.geofences?.items ?? [];\n\n if (loading) {\n return (\n <PageLayout\n title=\"Geofencing\"\n description=\"Set up location-based triggers and zones\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Geofencing\"\n description=\"Set up location-based triggers and zones\"\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 geofences. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Geofencing\"\n description=\"Set up location-based triggers and zones\"\n purpose=\"Draw zones around your worksites — offices, client sites, job locations — and have time tracking start and stop automatically as people move in and out, so on-site hours record themselves.\"\n actions={\n <button 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 <Plus className=\"h-4 w-4\" />\n Create Geofence\n </button>\n }\n >\n {geofences.length === 0 ? (\n <EmptyState\n illustration=\"empty-generic\"\n title=\"No geofences configured yet\"\n description=\"Create your first zone to trigger automatic time tracking when people arrive or leave a location.\"\n action={\n <button 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 <Plus className=\"h-4 w-4\" />\n Create Geofence\n </button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {geofences.map((fence: GeofenceItem) => (\n <div\n key={fence.id}\n className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-5 transition-colors hover:bg-bg-sunken/50 cursor-pointer\"\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-2\">\n <MapPin className=\"h-5 w-5 text-text-secondary\" />\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">\n {fence.name}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {fence.trigger} · {fence.radius}m radius\n </p>\n </div>\n </div>\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${getStatusColor(fence.isActive ? \"active\" : \"inactive\")}`}\n >\n {fence.isActive ? \"Active\" : \"Inactive\"}\n </span>\n </div>\n <div className=\"mt-3 flex items-center justify-between text-xs text-text-secondary\">\n <span>{fence.address ?? \"No address\"}</span>\n <span>{fence.events?.length ?? 0} events</span>\n </div>\n </div>\n ))}\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,IAAiB;CAC/B,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EAAE,SAAM,YAAS,aAAU,GAAuB,EAElD,IAAY,GAAM,WAAW,SAAS,EAAE;AA0B9C,QAxBI,IAEA,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA,GAIb,IAEA,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAAoG;GAE7G,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SAAQ;EACR,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,kBAErB;;YAGV,EAAU,WAAW,IACpB,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,UAAD;IAAQ,WAAU;cAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,kBAErB;;GAEX,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAU,KAAK,MACd,kBAAC,OAAD;IAEE,WAAU;cAFZ,CAIE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,+BAAgC,CAAA,EAClD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAM;OACL,CAAA,EACJ,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAM;QAAQ;QAAW,EAAM;QAAO;QACrC;SACA,EAAA,CAAA,CACF;SACN,kBAAC,QAAD;MACE,WAAW,4DAA4D,EAAe,EAAM,WAAW,WAAW,WAAW;gBAE5H,EAAM,WAAW,WAAW;MACxB,CAAA,CACH;QACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD,EAAA,UAAO,EAAM,WAAW,cAAoB,CAAA,EAC5C,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAM,QAAQ,UAAU,GAAE,UAAc,EAAA,CAAA,CAC3C;OACF;MAzBC,EAAM,GAyBP,CACN;GACE,CAAA;EAEG,CAAA"}
|