@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.
Files changed (109) hide show
  1. package/dist/timecampus/components/EmptyState.js +14 -0
  2. package/dist/timecampus/components/EmptyState.js.map +1 -0
  3. package/dist/timecampus/components/ErrorBoundary.js +2 -2
  4. package/dist/timecampus/components/ErrorBoundary.js.map +1 -1
  5. package/dist/timecampus/components/LoadingSkeleton.js +1 -1
  6. package/dist/timecampus/components/LoadingSkeleton.js.map +1 -1
  7. package/dist/timecampus/components/PageLayout.js +26 -14
  8. package/dist/timecampus/components/PageLayout.js.map +1 -1
  9. package/dist/timecampus/components/StatCard.js +19 -16
  10. package/dist/timecampus/components/StatCard.js.map +1 -1
  11. package/dist/timecampus/pages/HomePage.js +169 -149
  12. package/dist/timecampus/pages/HomePage.js.map +1 -1
  13. package/dist/timecampus/pages/applets/AppletStorePage.js +38 -35
  14. package/dist/timecampus/pages/applets/AppletStorePage.js.map +1 -1
  15. package/dist/timecampus/pages/applets/InstalledAppletsPage.js +42 -36
  16. package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +1 -1
  17. package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +57 -53
  18. package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
  19. package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js +40 -36
  20. package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js.map +1 -1
  21. package/dist/timecampus/pages/channels/ChannelsPage.js +32 -29
  22. package/dist/timecampus/pages/channels/ChannelsPage.js.map +1 -1
  23. package/dist/timecampus/pages/client-portal/ClientPortalPage.js +52 -44
  24. package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
  25. package/dist/timecampus/pages/dashboard/AnalyticsPage.js +65 -38
  26. package/dist/timecampus/pages/dashboard/AnalyticsPage.js.map +1 -1
  27. package/dist/timecampus/pages/dashboard/ReportsPage.js +47 -41
  28. package/dist/timecampus/pages/dashboard/ReportsPage.js.map +1 -1
  29. package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js +16 -14
  30. package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js.map +1 -1
  31. package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js +40 -36
  32. package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js.map +1 -1
  33. package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +34 -28
  34. package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js.map +1 -1
  35. package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +49 -41
  36. package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
  37. package/dist/timecampus/pages/focus-score/FocusScorePage.js +66 -62
  38. package/dist/timecampus/pages/focus-score/FocusScorePage.js.map +1 -1
  39. package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js +37 -33
  40. package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js.map +1 -1
  41. package/dist/timecampus/pages/geofencing/GeofencingPage.js +37 -30
  42. package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
  43. package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js +35 -31
  44. package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js.map +1 -1
  45. package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +37 -34
  46. package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +1 -1
  47. package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js +35 -31
  48. package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js.map +1 -1
  49. package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +45 -41
  50. package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
  51. package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js +17 -15
  52. package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js.map +1 -1
  53. package/dist/timecampus/pages/meetings/MeetingCreatePage.js +36 -32
  54. package/dist/timecampus/pages/meetings/MeetingCreatePage.js.map +1 -1
  55. package/dist/timecampus/pages/meetings/MeetingDetailPage.js +120 -102
  56. package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
  57. package/dist/timecampus/pages/meetings/MeetingsPage.js +46 -36
  58. package/dist/timecampus/pages/meetings/MeetingsPage.js.map +1 -1
  59. package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js +19 -17
  60. package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js.map +1 -1
  61. package/dist/timecampus/pages/pomodoro/PomodoroPage.js +143 -112
  62. package/dist/timecampus/pages/pomodoro/PomodoroPage.js.map +1 -1
  63. package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js +55 -51
  64. package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js.map +1 -1
  65. package/dist/timecampus/pages/projects/ProjectCreatePage.js +32 -28
  66. package/dist/timecampus/pages/projects/ProjectCreatePage.js.map +1 -1
  67. package/dist/timecampus/pages/projects/ProjectDetailPage.js +107 -76
  68. package/dist/timecampus/pages/projects/ProjectDetailPage.js.map +1 -1
  69. package/dist/timecampus/pages/projects/ProjectsPage.js +21 -17
  70. package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
  71. package/dist/timecampus/pages/projects/TasksPage.js +44 -34
  72. package/dist/timecampus/pages/projects/TasksPage.js.map +1 -1
  73. package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +59 -55
  74. package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
  75. package/dist/timecampus/pages/team/TeamAnalyticsPage.js +24 -20
  76. package/dist/timecampus/pages/team/TeamAnalyticsPage.js.map +1 -1
  77. package/dist/timecampus/pages/team/TeamMembersPage.js +47 -41
  78. package/dist/timecampus/pages/team/TeamMembersPage.js.map +1 -1
  79. package/dist/timecampus/pages/team/TeamPage.js +89 -59
  80. package/dist/timecampus/pages/team/TeamPage.js.map +1 -1
  81. package/dist/timecampus/pages/team-activity/TeamActivityPage.js +47 -43
  82. package/dist/timecampus/pages/team-activity/TeamActivityPage.js.map +1 -1
  83. package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js +39 -35
  84. package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js.map +1 -1
  85. package/dist/timecampus/pages/templates/TemplateApplicationPage.js +24 -20
  86. package/dist/timecampus/pages/templates/TemplateApplicationPage.js.map +1 -1
  87. package/dist/timecampus/pages/templates/TemplateDetailPage.js +66 -48
  88. package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +1 -1
  89. package/dist/timecampus/pages/templates/TemplatesPage.js +39 -36
  90. package/dist/timecampus/pages/templates/TemplatesPage.js.map +1 -1
  91. package/dist/timecampus/pages/time/TimeEntriesPage.js +53 -44
  92. package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
  93. package/dist/timecampus/pages/time/TimeTrackingPage.js +72 -71
  94. package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
  95. package/dist/timecampus/pages/time/TimerPage.js +100 -66
  96. package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
  97. package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +63 -59
  98. package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
  99. package/dist/timecampus/pages/widgets/WidgetDetailPage.js +64 -46
  100. package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +1 -1
  101. package/dist/timecampus/pages/widgets/WidgetsPage.js +44 -37
  102. package/dist/timecampus/pages/widgets/WidgetsPage.js.map +1 -1
  103. package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +18 -16
  104. package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
  105. package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js +40 -36
  106. package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js.map +1 -1
  107. package/dist/timecampus/pages/workflows/WorkflowsPage.js +47 -37
  108. package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +1 -1
  109. package/package.json +2 -2
@@ -1,121 +1,125 @@
1
1
  import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
2
- import { PageLayout as t } from "../../components/PageLayout.js";
3
- import { StatCard as n } from "../../components/StatCard.js";
4
- import { LoadingSkeleton as r } from "../../components/LoadingSkeleton.js";
5
- import { useGetFocusScoreSummaryQuery as i, useGetTodayFocusScoreQuery as a, useListFocusScoresQuery as o } from "../../../generated/wspace-operations.js";
6
- import { Brain as s, Shield as c, Target as l, Zap as u } from "lucide-react";
7
- import { jsx as d, jsxs as f } from "react/jsx-runtime";
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 p = {
10
- deepWork: "bg-blue-500",
11
- consistency: "bg-emerald-500",
12
- taskCompletion: "bg-violet-500",
13
- distractionResistance: "bg-amber-500",
14
- energyManagement: "bg-rose-500"
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 m() {
17
- let { workspaceId: m = "" } = e(), { data: h, loading: g, error: _ } = o({
17
+ function h() {
18
+ let { workspaceId: h = "" } = e(), { data: g, loading: _, error: v } = a({
18
19
  variables: { limit: 30 },
19
- skip: !m
20
- }), { data: v, loading: y, error: b } = i({ skip: !m }), { data: x, loading: S, error: C } = a({ skip: !m }), w = g || y || S, T = _ || b || C, E = x?.todayFocusScore, D = v?.focusScoreSummary, O = h?.focusScores ?? [], k = E ? [
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: E.deepWorkScore ?? 0,
24
- color: p.deepWork
24
+ score: D.deepWorkScore ?? 0,
25
+ color: m.deepWork
25
26
  },
26
27
  {
27
28
  label: "Consistency",
28
- score: E.consistencyScore ?? 0,
29
- color: p.consistency
29
+ score: D.consistencyScore ?? 0,
30
+ color: m.consistency
30
31
  },
31
32
  {
32
33
  label: "Task Completion",
33
- score: E.taskCompletionScore ?? 0,
34
- color: p.taskCompletion
34
+ score: D.taskCompletionScore ?? 0,
35
+ color: m.taskCompletion
35
36
  },
36
37
  {
37
38
  label: "Distraction Resistance",
38
- score: E.distractionResistanceScore ?? 0,
39
- color: p.distractionResistance
39
+ score: D.distractionResistanceScore ?? 0,
40
+ color: m.distractionResistance
40
41
  },
41
42
  {
42
43
  label: "Energy Management",
43
- score: E.energyManagementScore ?? 0,
44
- color: p.energyManagement
44
+ score: D.energyManagementScore ?? 0,
45
+ color: m.energyManagement
45
46
  }
46
- ] : [], A = E?.overallScore == null ? "--" : `${E.overallScore}/100`, j = O.filter((e) => e.overallScore >= 70).length, M = O.reduce((e, t) => e + (t.overallScore ?? 0), 0), N = Math.floor(M / 60), P = M % 60, F = N > 0 ? `${N}h ${P}m` : `${P}m`, I = D?.trend === "up" ? 7 : D?.trend === "down" ? -5 : 0, L = D?.highestScore == null ? "--" : `${D.highestScore}`;
47
- return w ? /* @__PURE__ */ d(t, {
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__ */ d(r, {
51
+ children: /* @__PURE__ */ f(n, {
51
52
  variant: "card",
52
53
  count: 4
53
54
  })
54
- }) : T ? /* @__PURE__ */ d(t, {
55
+ }) : E ? /* @__PURE__ */ f(o, {
55
56
  title: "Focus Score",
56
57
  description: "Measure and improve your focus",
57
- children: /* @__PURE__ */ d("div", {
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__ */ f(t, {
62
+ }) : /* @__PURE__ */ p(o, {
62
63
  title: "Focus Score",
63
64
  description: "Measure and improve your focus",
64
- children: [/* @__PURE__ */ f("div", {
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__ */ d(n, {
69
+ /* @__PURE__ */ f(t, {
70
+ featured: !0,
68
71
  title: "Overall Score",
69
- value: A,
70
- icon: /* @__PURE__ */ d(s, { className: "h-5 w-5" }),
71
- trend: I === 0 ? void 0 : {
72
- value: I,
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-violet-100 text-violet-600 dark:bg-violet-900/30 dark:text-violet-400"
78
+ iconBgColor: "bg-status-info-bg text-status-info-text"
76
79
  }),
77
- /* @__PURE__ */ d(n, {
80
+ /* @__PURE__ */ f(t, {
78
81
  title: "Focus Sessions",
79
- value: String(j),
80
- icon: /* @__PURE__ */ d(l, { className: "h-5 w-5" }),
82
+ value: String(M),
83
+ icon: /* @__PURE__ */ f(u, { className: "h-5 w-5" }),
81
84
  description: "Completed today"
82
85
  }),
83
- /* @__PURE__ */ d(n, {
86
+ /* @__PURE__ */ f(t, {
84
87
  title: "Total Focus Time",
85
- value: F,
86
- icon: /* @__PURE__ */ d(u, { className: "h-5 w-5" })
88
+ value: I,
89
+ icon: /* @__PURE__ */ f(d, { className: "h-5 w-5" })
87
90
  }),
88
- /* @__PURE__ */ d(n, {
91
+ /* @__PURE__ */ f(t, {
89
92
  title: "Highest Score",
90
- value: L,
91
- icon: /* @__PURE__ */ d(c, { className: "h-5 w-5" }),
93
+ value: R,
94
+ icon: /* @__PURE__ */ f(l, { className: "h-5 w-5" }),
92
95
  description: "Personal best"
93
96
  })
94
97
  ]
95
- }), /* @__PURE__ */ f("div", {
96
- className: "rounded-xl border border-border-subtle bg-bg-surface p-6",
97
- children: [/* @__PURE__ */ d("h3", {
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
- }), k.length === 0 ? /* @__PURE__ */ d("div", {
101
- className: "flex h-32 items-center justify-center text-sm text-text-secondary",
102
- children: "No focus score recorded today."
103
- }) : /* @__PURE__ */ d("div", {
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: k.map((e) => /* @__PURE__ */ f("div", {
109
+ children: A.map((e) => /* @__PURE__ */ p("div", {
106
110
  className: "space-y-1",
107
- children: [/* @__PURE__ */ f("div", {
111
+ children: [/* @__PURE__ */ p("div", {
108
112
  className: "flex items-center justify-between text-sm",
109
- children: [/* @__PURE__ */ d("span", {
113
+ children: [/* @__PURE__ */ f("span", {
110
114
  className: "font-medium text-text-primary",
111
115
  children: e.label
112
- }), /* @__PURE__ */ f("span", {
116
+ }), /* @__PURE__ */ p("span", {
113
117
  className: "text-text-secondary",
114
118
  children: [e.score, "%"]
115
119
  })]
116
- }), /* @__PURE__ */ d("div", {
120
+ }), /* @__PURE__ */ f("div", {
117
121
  className: "h-2.5 w-full rounded-full bg-bg-sunken",
118
- children: /* @__PURE__ */ d("div", {
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 { m as FocusScorePage };
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-500\",\n consistency: \"bg-emerald-500\",\n taskCompletion: \"bg-violet-500\",\n distractionResistance: \"bg-amber-500\",\n energyManagement: \"bg-rose-500\",\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 >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\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-violet-100 text-violet-600 dark:bg-violet-900/30 dark:text-violet-400\"\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-subtle bg-bg-surface p-6\">\n <h3 className=\"mb-4 text-sm font-semibold text-text-primary\">\n Focus Components\n </h3>\n {focusComponents.length === 0 ? (\n <div className=\"flex h-32 items-center justify-center text-sm text-text-secondary\">\n No focus score recorded today.\n </div>\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":"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"}
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":"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"}
@@ -1,61 +1,65 @@
1
1
  import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
2
- import { PageLayout as t } from "../../components/PageLayout.js";
3
- import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
4
- import { useListConfigurationsQuery as r, useSetConfigurationMutation as i } from "../../../generated/wspace-operations.js";
2
+ import { LoadingSkeleton as t } from "../../components/LoadingSkeleton.js";
3
+ import { useListConfigurationsQuery as n, useSetConfigurationMutation as r } from "../../../generated/wspace-operations.js";
4
+ import { PageLayout as i } from "../../components/PageLayout.js";
5
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 d = "timecampus.focus.settings", f = {
10
+ var f = "timecampus.focus.settings", p = {
10
11
  dailyFocusTarget: 4,
11
12
  minSessionLength: 25
12
13
  };
13
- function p() {
14
- let { workspaceId: p = "" } = e(), { data: m, loading: h, error: g } = r({
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: !p
20
- }), [_, { loading: v }] = i(), [y, b] = s(f);
20
+ skip: !m
21
+ }), [v, { loading: y }] = r(), [b, x] = s(p);
21
22
  o(() => {
22
- if (m?.configurations) {
23
- let e = m.configurations.find((e) => e.key === d);
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
- b({
27
- dailyFocusTarget: t.dailyFocusTarget ?? f.dailyFocusTarget,
28
- minSessionLength: t.minSessionLength ?? f.minSessionLength
27
+ x({
28
+ dailyFocusTarget: t.dailyFocusTarget ?? p.dailyFocusTarget,
29
+ minSessionLength: t.minSessionLength ?? p.minSessionLength
29
30
  });
30
31
  }
31
32
  }
32
- }, [m]);
33
- let x = a(async () => {
34
- await _({ variables: { input: {
35
- key: d,
36
- value: y,
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
- }, [_, y]);
41
- return h ? /* @__PURE__ */ l(t, {
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(n, { variant: "detail" })
45
- }) : g ? /* @__PURE__ */ l(t, {
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(t, {
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("div", {
58
- className: "rounded-xl border border-border-subtle bg-bg-surface p-6",
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: y.dailyFocusTarget,
75
- onChange: (e) => b((t) => ({
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: y.minSessionLength,
92
- onChange: (e) => b((t) => ({
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: x,
104
- disabled: v,
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: v ? "Saving..." : "Save Settings"
110
+ children: y ? "Saving..." : "Save Settings"
107
111
  })
108
112
  })]
109
113
  })
110
114
  });
111
115
  }
112
116
  //#endregion
113
- export { p as FocusScoreSettingsPage };
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 <div className=\"rounded-xl border border-border-subtle bg-bg-surface 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 </div>\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":";;;;;;;;AAWA,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;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,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;OACF;OACN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,UAAD;KACE,SAAS;KACT,UAAU;KACV,WAAU;eAET,IAAS,cAAc;KACjB,CAAA;IACL,CAAA,CACF;;EACK,CAAA"}
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 { PageLayout as n } from "../../components/PageLayout.js";
4
- import { LoadingSkeleton as r } from "../../components/LoadingSkeleton.js";
5
- import { useListGeofencesQuery as i } from "../../../generated/wspace-operations.js";
6
- import { MapPin as a, Plus as o } from "lucide-react";
7
- import { jsx as s, jsxs as c } from "react/jsx-runtime";
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 l() {
10
- let { workspaceId: l = "" } = e(), { data: u, loading: d, error: f } = i(), p = u?.geofences?.items ?? [];
11
- return d ? /* @__PURE__ */ s(n, {
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__ */ s(r, {
15
+ children: /* @__PURE__ */ c(n, {
15
16
  variant: "card",
16
17
  count: 4
17
18
  })
18
- }) : f ? /* @__PURE__ */ s(n, {
19
+ }) : p ? /* @__PURE__ */ c(i, {
19
20
  title: "Geofencing",
20
21
  description: "Set up location-based triggers and zones",
21
- children: /* @__PURE__ */ s("div", {
22
- className: "rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-600 dark:border-red-800 dark:bg-red-900/20 dark:text-red-400",
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__ */ s(n, {
26
+ }) : /* @__PURE__ */ c(i, {
26
27
  title: "Geofencing",
27
28
  description: "Set up location-based triggers and zones",
28
- actions: /* @__PURE__ */ c("button", {
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(o, { className: "h-4 w-4" }), "Create Geofence"]
32
+ children: [/* @__PURE__ */ c(s, { className: "h-4 w-4" }), "Create Geofence"]
31
33
  }),
32
- children: /* @__PURE__ */ c("div", {
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: [p.length === 0 && /* @__PURE__ */ s("div", {
35
- className: "col-span-full p-4 text-center text-sm text-text-secondary",
36
- children: "No geofences configured yet."
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__ */ c("div", {
48
+ children: [/* @__PURE__ */ l("div", {
42
49
  className: "flex items-center gap-2",
43
- children: [/* @__PURE__ */ s(a, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("p", {
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__ */ c("p", {
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__ */ s("span", {
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__ */ c("div", {
66
+ }), /* @__PURE__ */ l("div", {
60
67
  className: "mt-3 flex items-center justify-between text-xs text-text-secondary",
61
- children: [/* @__PURE__ */ s("span", { children: e.address ?? "No address" }), /* @__PURE__ */ c("span", { children: [e.events?.length ?? 0, " events"] })]
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 { l as GeofencingPage };
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-red-200 bg-red-50 p-4 text-sm text-red-600 dark:border-red-800 dark:bg-red-900/20 dark:text-red-400\">\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 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 <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {geofences.length === 0 && (\n <div className=\"col-span-full p-4 text-center text-sm text-text-secondary\">\n No geofences configured yet.\n </div>\n )}\n {geofences.map((fence: GeofenceItem) => (\n <div\n key={fence.id}\n className=\"rounded-xl border border-border-subtle bg-bg-surface 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} &middot; {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 </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAcA,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;aAA+H;GAExI,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,kBAErB;;YAGX,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAU,WAAW,KACpB,kBAAC,OAAD;IAAK,WAAU;cAA4D;IAErE,CAAA,EAEP,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,CACE;;EACK,CAAA"}
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} &middot; {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"}