@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,123 +1,141 @@
1
- import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
2
- import { formatCurrency as t } from "../../utils/helpers.js";
3
- import { PageLayout as n } from "../../components/PageLayout.js";
1
+ import { useTimeCampus as e, useTimeCampusNavigate as t } from "../../providers/TimeCampusProvider.js";
2
+ import { formatCurrency as n } from "../../utils/helpers.js";
4
3
  import { StatCard as r } from "../../components/StatCard.js";
5
4
  import { LoadingSkeleton as i } from "../../components/LoadingSkeleton.js";
6
5
  import { useGetMeetingQuery as a } from "../../../generated/wspace-operations.js";
7
- import { Clock as o, Users as s } from "lucide-react";
8
- import { useParams as c } from "react-router-dom";
9
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
6
+ import { PageLayout as o } from "../../components/PageLayout.js";
7
+ import { EmptyState as s } from "../../components/EmptyState.js";
8
+ import { Clock as c, Users as l } from "lucide-react";
9
+ import { useParams as u } from "react-router-dom";
10
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
11
+ import { NextSteps as p } from "@burdenoff/fe-libs/ui";
10
12
  //#region src/timecampus/pages/meetings/MeetingDetailPage.tsx
11
- function d() {
12
- let { id: d } = c(), { workspaceId: f = "" } = e(), { data: p, loading: m, error: h } = a({
13
+ function m() {
14
+ let { id: m } = u(), { workspaceId: h = "" } = e(), g = t(), { data: _, loading: v, error: y } = a({
13
15
  variables: {
14
- id: d ?? "",
15
- workspaceId: f
16
+ id: m ?? "",
17
+ workspaceId: h
16
18
  },
17
- skip: !f || !d
18
- }), g = p?.meeting;
19
- if (m) return /* @__PURE__ */ l(n, {
19
+ skip: !h || !m
20
+ }), b = _?.meeting;
21
+ if (v) return /* @__PURE__ */ d(o, {
20
22
  title: "Meeting Details",
21
- description: `Meeting ID: ${d}`,
22
- children: /* @__PURE__ */ l(i, { variant: "detail" })
23
+ description: `Meeting ID: ${m}`,
24
+ children: /* @__PURE__ */ d(i, { variant: "detail" })
23
25
  });
24
- if (h || !g) return /* @__PURE__ */ l(n, {
26
+ if (y || !b) return /* @__PURE__ */ d(o, {
25
27
  title: "Meeting Details",
26
- description: `Meeting ID: ${d}`,
27
- children: /* @__PURE__ */ l("div", {
28
- 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",
29
- children: h ? "Failed to load meeting details. Please try again later." : "Meeting not found."
28
+ description: `Meeting ID: ${m}`,
29
+ children: /* @__PURE__ */ d("div", {
30
+ className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
31
+ children: y ? "Failed to load meeting details. Please try again later." : "Meeting not found."
30
32
  })
31
33
  });
32
- let _ = g.actionItems.filter((e) => e.status !== "COMPLETED").length;
33
- return /* @__PURE__ */ u(n, {
34
+ let x = b.actionItems.filter((e) => e.status !== "COMPLETED").length;
35
+ return /* @__PURE__ */ f(o, {
34
36
  title: "Meeting Details",
35
- description: g.title,
36
- children: [/* @__PURE__ */ u("div", {
37
- className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
38
- children: [
39
- /* @__PURE__ */ l(r, {
40
- title: "Duration",
41
- value: `${g.duration ?? 0} min`,
42
- icon: /* @__PURE__ */ l(o, { className: "h-5 w-5" })
43
- }),
44
- /* @__PURE__ */ l(r, {
45
- title: "Participants",
46
- value: String(g.participants.length),
47
- icon: /* @__PURE__ */ l(s, { className: "h-5 w-5" })
48
- }),
49
- /* @__PURE__ */ l(r, {
50
- title: "Cost",
51
- value: g.cost == null ? "N/A" : t(g.cost),
52
- description: "Based on participant rates"
53
- }),
54
- /* @__PURE__ */ l(r, {
55
- title: "Action Items",
56
- value: String(g.actionItems.length),
57
- description: `${_} pending`
58
- })
59
- ]
60
- }), /* @__PURE__ */ u("div", {
61
- className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
62
- children: [/* @__PURE__ */ u("div", {
63
- className: "rounded-xl border border-border-subtle bg-bg-surface p-6",
64
- children: [/* @__PURE__ */ l("h3", {
65
- className: "mb-4 text-sm font-semibold text-text-primary",
66
- children: "Participants"
67
- }), g.participants.length > 0 ? /* @__PURE__ */ l("div", {
68
- className: "space-y-2",
69
- children: g.participants.map((e) => /* @__PURE__ */ u("div", {
70
- className: "flex items-center justify-between rounded-lg border border-border-subtle px-3 py-2",
71
- children: [/* @__PURE__ */ l("span", {
72
- className: "text-sm text-text-primary",
73
- children: e.userId
74
- }), /* @__PURE__ */ u("div", {
75
- className: "flex items-center gap-2",
76
- children: [/* @__PURE__ */ l("span", {
77
- className: "text-xs text-text-secondary",
78
- children: e.role
79
- }), /* @__PURE__ */ l("span", {
37
+ description: b.title,
38
+ purpose: "The full record of one meeting — who attended, what it cost in people's time, and the action items it produced — so you can follow up on commitments and judge whether the meeting was worth it.",
39
+ children: [
40
+ /* @__PURE__ */ d(p, {
41
+ storageKey: "timecampus-meeting-detail",
42
+ className: "mb-6",
43
+ steps: [{
44
+ id: "all-meetings",
45
+ label: "Back to all meetings",
46
+ description: "Browse and schedule other meetings.",
47
+ onClick: () => g("/meetings")
48
+ }, {
49
+ id: "analytics",
50
+ label: "See meeting analytics",
51
+ description: "Understand your overall meeting load and cost.",
52
+ onClick: () => g("/meetings/analytics")
53
+ }]
54
+ }),
55
+ /* @__PURE__ */ f("div", {
56
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
57
+ children: [
58
+ /* @__PURE__ */ d(r, {
59
+ featured: !0,
60
+ title: "Duration",
61
+ value: `${b.duration ?? 0} min`,
62
+ icon: /* @__PURE__ */ d(c, { className: "h-5 w-5" })
63
+ }),
64
+ /* @__PURE__ */ d(r, {
65
+ title: "Participants",
66
+ value: String(b.participants.length),
67
+ icon: /* @__PURE__ */ d(l, { className: "h-5 w-5" })
68
+ }),
69
+ /* @__PURE__ */ d(r, {
70
+ title: "Cost",
71
+ value: b.cost == null ? "N/A" : n(b.cost),
72
+ description: "Based on participant rates"
73
+ }),
74
+ /* @__PURE__ */ d(r, {
75
+ title: "Action Items",
76
+ value: String(b.actionItems.length),
77
+ description: `${x} pending`
78
+ })
79
+ ]
80
+ }),
81
+ /* @__PURE__ */ f("div", {
82
+ className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
83
+ children: [/* @__PURE__ */ f("div", {
84
+ className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6",
85
+ children: [/* @__PURE__ */ d("h3", {
86
+ className: "mb-4 text-sm font-semibold text-text-primary",
87
+ children: "Participants"
88
+ }), b.participants.length > 0 ? /* @__PURE__ */ d("div", {
89
+ className: "space-y-2",
90
+ children: b.participants.map((e) => /* @__PURE__ */ f("div", {
91
+ className: "flex items-center justify-between rounded-lg border border-border-subtle px-3 py-2",
92
+ children: [/* @__PURE__ */ d("span", {
93
+ className: "text-sm text-text-primary",
94
+ children: e.userId
95
+ }), /* @__PURE__ */ f("div", {
96
+ className: "flex items-center gap-2",
97
+ children: [/* @__PURE__ */ d("span", {
98
+ className: "text-xs text-text-secondary",
99
+ children: e.role
100
+ }), /* @__PURE__ */ d("span", {
101
+ className: "inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
102
+ children: e.status
103
+ })]
104
+ })]
105
+ }, e.id))
106
+ }) : /* @__PURE__ */ d(s, {
107
+ illustration: "empty-people",
108
+ title: "No participants added",
109
+ description: "Add attendees to capture who was in the room and what it cost."
110
+ })]
111
+ }), /* @__PURE__ */ f("div", {
112
+ className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6",
113
+ children: [/* @__PURE__ */ d("h3", {
114
+ className: "mb-4 text-sm font-semibold text-text-primary",
115
+ children: "Action Items"
116
+ }), b.actionItems.length > 0 ? /* @__PURE__ */ d("div", {
117
+ className: "space-y-2",
118
+ children: b.actionItems.map((e) => /* @__PURE__ */ f("div", {
119
+ className: "flex items-center justify-between rounded-lg border border-border-subtle px-3 py-2",
120
+ children: [/* @__PURE__ */ d("span", {
121
+ className: "text-sm text-text-primary",
122
+ children: e.title
123
+ }), /* @__PURE__ */ d("span", {
80
124
  className: "inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
81
125
  children: e.status
82
126
  })]
83
- })]
84
- }, e.id))
85
- }) : /* @__PURE__ */ l("div", {
86
- className: "flex h-32 items-center justify-center rounded-lg border border-dashed border-border-subtle",
87
- children: /* @__PURE__ */ l("p", {
88
- className: "text-sm text-text-secondary",
89
- children: "No participants added"
90
- })
91
- })]
92
- }), /* @__PURE__ */ u("div", {
93
- className: "rounded-xl border border-border-subtle bg-bg-surface p-6",
94
- children: [/* @__PURE__ */ l("h3", {
95
- className: "mb-4 text-sm font-semibold text-text-primary",
96
- children: "Action Items"
97
- }), g.actionItems.length > 0 ? /* @__PURE__ */ l("div", {
98
- className: "space-y-2",
99
- children: g.actionItems.map((e) => /* @__PURE__ */ u("div", {
100
- className: "flex items-center justify-between rounded-lg border border-border-subtle px-3 py-2",
101
- children: [/* @__PURE__ */ l("span", {
102
- className: "text-sm text-text-primary",
103
- children: e.title
104
- }), /* @__PURE__ */ l("span", {
105
- className: "inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
106
- children: e.status
107
- })]
108
- }, e.id))
109
- }) : /* @__PURE__ */ l("div", {
110
- className: "flex h-32 items-center justify-center rounded-lg border border-dashed border-border-subtle",
111
- children: /* @__PURE__ */ l("p", {
112
- className: "text-sm text-text-secondary",
113
- children: "No action items"
114
- })
127
+ }, e.id))
128
+ }) : /* @__PURE__ */ d(s, {
129
+ illustration: "empty-generic",
130
+ title: "No action items",
131
+ description: "Capture follow-ups here so commitments from the meeting don't get lost."
132
+ })]
115
133
  })]
116
- })]
117
- })]
134
+ })
135
+ ]
118
136
  });
119
137
  }
120
138
  //#endregion
121
- export { d as MeetingDetailPage };
139
+ export { m as MeetingDetailPage };
122
140
 
123
141
  //# sourceMappingURL=MeetingDetailPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MeetingDetailPage.js","names":[],"sources":["../../../../src/timecampus/pages/meetings/MeetingDetailPage.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\";\nimport { CalendarDays, Users, Clock, Video } 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 useGetMeetingQuery,\n type MeetingParticipantFieldsFragment,\n type MeetingActionItemFieldsFragment,\n} from \"@/generated/wspace-operations\";\nimport { formatCurrency } from \"../../utils/helpers\";\n\nexport function MeetingDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { workspaceId = \"\" } = useTimeCampus();\n\n const { data, loading, error } = useGetMeetingQuery({\n variables: { id: id ?? \"\", workspaceId },\n skip: !workspaceId || !id,\n });\n\n const meeting = data?.meeting;\n\n if (loading) {\n return (\n <PageLayout title=\"Meeting Details\" description={`Meeting ID: ${id}`}>\n <LoadingSkeleton variant=\"detail\" />\n </PageLayout>\n );\n }\n\n if (error || !meeting) {\n return (\n <PageLayout title=\"Meeting Details\" description={`Meeting ID: ${id}`}>\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 {error\n ? \"Failed to load meeting details. Please try again later.\"\n : \"Meeting not found.\"}\n </div>\n </PageLayout>\n );\n }\n\n const pendingActions = meeting.actionItems.filter(\n (a: MeetingActionItemFieldsFragment) => a.status !== \"COMPLETED\",\n ).length;\n\n return (\n <PageLayout title=\"Meeting Details\" description={meeting.title}>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n title=\"Duration\"\n value={`${meeting.duration ?? 0} min`}\n icon={<Clock className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Participants\"\n value={String(meeting.participants.length)}\n icon={<Users className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Cost\"\n value={meeting.cost != null ? formatCurrency(meeting.cost) : \"N/A\"}\n description=\"Based on participant rates\"\n />\n <StatCard\n title=\"Action Items\"\n value={String(meeting.actionItems.length)}\n description={`${pendingActions} pending`}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\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 Participants\n </h3>\n {meeting.participants.length > 0 ? (\n <div className=\"space-y-2\">\n {meeting.participants.map(\n (p: MeetingParticipantFieldsFragment) => (\n <div\n key={p.id}\n className=\"flex items-center justify-between rounded-lg border border-border-subtle px-3 py-2\"\n >\n <span className=\"text-sm text-text-primary\">{p.userId}</span>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-text-secondary\">\n {p.role}\n </span>\n <span className=\"inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {p.status}\n </span>\n </div>\n </div>\n ),\n )}\n </div>\n ) : (\n <div className=\"flex h-32 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <p className=\"text-sm text-text-secondary\">\n No participants added\n </p>\n </div>\n )}\n </div>\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 Action Items\n </h3>\n {meeting.actionItems.length > 0 ? (\n <div className=\"space-y-2\">\n {meeting.actionItems.map(\n (item: MeetingActionItemFieldsFragment) => (\n <div\n key={item.id}\n className=\"flex items-center justify-between rounded-lg border border-border-subtle px-3 py-2\"\n >\n <span className=\"text-sm text-text-primary\">\n {item.title}\n </span>\n <span className=\"inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {item.status}\n </span>\n </div>\n ),\n )}\n </div>\n ) : (\n <div className=\"flex h-32 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <p className=\"text-sm text-text-secondary\">No action items</p>\n </div>\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;AAaA,SAAgB,IAAoB;CAClC,IAAM,EAAE,UAAO,GAA2B,EACpC,EAAE,iBAAc,OAAO,GAAe,EAEtC,EAAE,SAAM,YAAS,aAAU,EAAmB;EAClD,WAAW;GAAE,IAAI,KAAM;GAAI;GAAa;EACxC,MAAM,CAAC,KAAe,CAAC;EACxB,CAAC,EAEI,IAAU,GAAM;AAEtB,KAAI,EACF,QACE,kBAAC,GAAD;EAAY,OAAM;EAAkB,aAAa,eAAe;YAC9D,kBAAC,GAAD,EAAiB,SAAQ,UAAW,CAAA;EACzB,CAAA;AAIjB,KAAI,KAAS,CAAC,EACZ,QACE,kBAAC,GAAD;EAAY,OAAM;EAAkB,aAAa,eAAe;YAC9D,kBAAC,OAAD;GAAK,WAAU;aACZ,IACG,4DACA;GACA,CAAA;EACK,CAAA;CAIjB,IAAM,IAAiB,EAAQ,YAAY,QACxC,MAAuC,EAAE,WAAW,YACtD,CAAC;AAEF,QACE,kBAAC,GAAD;EAAY,OAAM;EAAkB,aAAa,EAAQ;YAAzD,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,GAAG,EAAQ,YAAY,EAAE;KAChC,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,OAAO,EAAQ,aAAa,OAAO;KAC1C,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,EAAQ,QAAQ,OAAsC,QAA/B,EAAe,EAAQ,KAAK;KAC1D,aAAY;KACZ,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,OAAO,EAAQ,YAAY,OAAO;KACzC,aAAa,GAAG,EAAe;KAC/B,CAAA;IACE;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAA+C;KAExD,CAAA,EACJ,EAAQ,aAAa,SAAS,IAC7B,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAQ,aAAa,KACnB,MACC,kBAAC,OAAD;MAEE,WAAU;gBAFZ,CAIE,kBAAC,QAAD;OAAM,WAAU;iBAA6B,EAAE;OAAc,CAAA,EAC7D,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAE;QACE,CAAA,EACP,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAE;QACE,CAAA,CACH;SACF;QAZC,EAAE,GAYH,CAET;KACG,CAAA,GAEN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAEvC,CAAA;KACA,CAAA,CAEJ;OACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAA+C;KAExD,CAAA,EACJ,EAAQ,YAAY,SAAS,IAC5B,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAQ,YAAY,KAClB,MACC,kBAAC,OAAD;MAEE,WAAU;gBAFZ,CAIE,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAK;OACD,CAAA,EACP,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAK;OACD,CAAA,CACH;QATC,EAAK,GASN,CAET;KACG,CAAA,GAEN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAAmB,CAAA;KAC1D,CAAA,CAEJ;MACF;KACK"}
1
+ {"version":3,"file":"MeetingDetailPage.js","names":[],"sources":["../../../../src/timecampus/pages/meetings/MeetingDetailPage.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\";\nimport { Users, Clock } from \"lucide-react\";\nimport { NextSteps } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { EmptyState } from \"../../components/EmptyState\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport {\n useTimeCampus,\n useTimeCampusNavigate,\n} from \"../../providers/TimeCampusProvider\";\nimport {\n useGetMeetingQuery,\n type MeetingParticipantFieldsFragment,\n type MeetingActionItemFieldsFragment,\n} from \"@/generated/wspace-operations\";\nimport { formatCurrency } from \"../../utils/helpers\";\n\nexport function MeetingDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { workspaceId = \"\" } = useTimeCampus();\n const navigate = useTimeCampusNavigate();\n\n const { data, loading, error } = useGetMeetingQuery({\n variables: { id: id ?? \"\", workspaceId },\n skip: !workspaceId || !id,\n });\n\n const meeting = data?.meeting;\n\n if (loading) {\n return (\n <PageLayout title=\"Meeting Details\" description={`Meeting ID: ${id}`}>\n <LoadingSkeleton variant=\"detail\" />\n </PageLayout>\n );\n }\n\n if (error || !meeting) {\n return (\n <PageLayout title=\"Meeting Details\" description={`Meeting ID: ${id}`}>\n <div className=\"rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text\">\n {error\n ? \"Failed to load meeting details. Please try again later.\"\n : \"Meeting not found.\"}\n </div>\n </PageLayout>\n );\n }\n\n const pendingActions = meeting.actionItems.filter(\n (a: MeetingActionItemFieldsFragment) => a.status !== \"COMPLETED\",\n ).length;\n\n return (\n <PageLayout\n title=\"Meeting Details\"\n description={meeting.title}\n purpose=\"The full record of one meeting — who attended, what it cost in people's time, and the action items it produced — so you can follow up on commitments and judge whether the meeting was worth it.\"\n >\n <NextSteps\n storageKey=\"timecampus-meeting-detail\"\n className=\"mb-6\"\n steps={[\n {\n id: \"all-meetings\",\n label: \"Back to all meetings\",\n description: \"Browse and schedule other meetings.\",\n onClick: () => navigate(\"/meetings\"),\n },\n {\n id: \"analytics\",\n label: \"See meeting analytics\",\n description: \"Understand your overall meeting load and cost.\",\n onClick: () => navigate(\"/meetings/analytics\"),\n },\n ]}\n />\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n featured\n title=\"Duration\"\n value={`${meeting.duration ?? 0} min`}\n icon={<Clock className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Participants\"\n value={String(meeting.participants.length)}\n icon={<Users className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Cost\"\n value={meeting.cost != null ? formatCurrency(meeting.cost) : \"N/A\"}\n description=\"Based on participant rates\"\n />\n <StatCard\n title=\"Action Items\"\n value={String(meeting.actionItems.length)}\n description={`${pendingActions} pending`}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\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 Participants\n </h3>\n {meeting.participants.length > 0 ? (\n <div className=\"space-y-2\">\n {meeting.participants.map(\n (p: MeetingParticipantFieldsFragment) => (\n <div\n key={p.id}\n className=\"flex items-center justify-between rounded-lg border border-border-subtle px-3 py-2\"\n >\n <span className=\"text-sm text-text-primary\">\n {p.userId}\n </span>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-text-secondary\">\n {p.role}\n </span>\n <span className=\"inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {p.status}\n </span>\n </div>\n </div>\n ),\n )}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-people\"\n title=\"No participants added\"\n description=\"Add attendees to capture who was in the room and what it cost.\"\n />\n )}\n </div>\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 Action Items\n </h3>\n {meeting.actionItems.length > 0 ? (\n <div className=\"space-y-2\">\n {meeting.actionItems.map(\n (item: MeetingActionItemFieldsFragment) => (\n <div\n key={item.id}\n className=\"flex items-center justify-between rounded-lg border border-border-subtle px-3 py-2\"\n >\n <span className=\"text-sm text-text-primary\">\n {item.title}\n </span>\n <span className=\"inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {item.status}\n </span>\n </div>\n ),\n )}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n title=\"No action items\"\n description=\"Capture follow-ups here so commitments from the meeting don't get lost.\"\n />\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAkBA,SAAgB,IAAoB;CAClC,IAAM,EAAE,UAAO,GAA2B,EACpC,EAAE,iBAAc,OAAO,GAAe,EACtC,IAAW,GAAuB,EAElC,EAAE,SAAM,YAAS,aAAU,EAAmB;EAClD,WAAW;GAAE,IAAI,KAAM;GAAI;GAAa;EACxC,MAAM,CAAC,KAAe,CAAC;EACxB,CAAC,EAEI,IAAU,GAAM;AAEtB,KAAI,EACF,QACE,kBAAC,GAAD;EAAY,OAAM;EAAkB,aAAa,eAAe;YAC9D,kBAAC,GAAD,EAAiB,SAAQ,UAAW,CAAA;EACzB,CAAA;AAIjB,KAAI,KAAS,CAAC,EACZ,QACE,kBAAC,GAAD;EAAY,OAAM;EAAkB,aAAa,eAAe;YAC9D,kBAAC,OAAD;GAAK,WAAU;aACZ,IACG,4DACA;GACA,CAAA;EACK,CAAA;CAIjB,IAAM,IAAiB,EAAQ,YAAY,QACxC,MAAuC,EAAE,WAAW,YACtD,CAAC;AAEF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAa,EAAQ;EACrB,SAAQ;YAHV;GAKE,kBAAC,GAAD;IACE,YAAW;IACX,WAAU;IACV,OAAO,CACL;KACE,IAAI;KACJ,OAAO;KACP,aAAa;KACb,eAAe,EAAS,YAAY;KACrC,EACD;KACE,IAAI;KACJ,OAAO;KACP,aAAa;KACb,eAAe,EAAS,sBAAsB;KAC/C,CACF;IACD,CAAA;GACF,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,UAAA;MACA,OAAM;MACN,OAAO,GAAG,EAAQ,YAAY,EAAE;MAChC,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;MACnC,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,OAAO,EAAQ,aAAa,OAAO;MAC1C,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;MACnC,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,EAAQ,QAAQ,OAAsC,QAA/B,EAAe,EAAQ,KAAK;MAC1D,aAAY;MACZ,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,OAAO,EAAQ,YAAY,OAAO;MACzC,aAAa,GAAG,EAAe;MAC/B,CAAA;KACE;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA+C;MAExD,CAAA,EACJ,EAAQ,aAAa,SAAS,IAC7B,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAQ,aAAa,KACnB,MACC,kBAAC,OAAD;OAEE,WAAU;iBAFZ,CAIE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAE;QACE,CAAA,EACP,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAE;SACE,CAAA,EACP,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAE;SACE,CAAA,CACH;UACF;SAdC,EAAE,GAcH,CAET;MACG,CAAA,GAEN,kBAAC,GAAD;MACE,cAAa;MACb,OAAM;MACN,aAAY;MACZ,CAAA,CAEA;QACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA+C;MAExD,CAAA,EACJ,EAAQ,YAAY,SAAS,IAC5B,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAQ,YAAY,KAClB,MACC,kBAAC,OAAD;OAEE,WAAU;iBAFZ,CAIE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAK;QACD,CAAA,EACP,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAK;QACD,CAAA,CACH;SATC,EAAK,GASN,CAET;MACG,CAAA,GAEN,kBAAC,GAAD;MACE,cAAa;MACb,OAAM;MACN,aAAY;MACZ,CAAA,CAEA;OACF;;GACK"}
@@ -1,62 +1,72 @@
1
1
  import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
2
2
  import { formatDate 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 { useListMeetingsQuery as i } from "../../../generated/wspace-operations.js";
6
- import { CalendarDays as a, Plus as o, Video as s } from "lucide-react";
7
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
3
+ import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
4
+ import { useListMeetingsQuery 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 { CalendarDays as o, Plus as s, Video as c } from "lucide-react";
8
+ import { jsx as l, jsxs as u } from "react/jsx-runtime";
9
+ import { GlassCard as d } from "@burdenoff/fe-libs/ui";
8
10
  //#region src/timecampus/pages/meetings/MeetingsPage.tsx
9
- function u() {
10
- let { workspaceId: u = "" } = e(), { data: d, loading: f, error: p } = i({
11
+ function f() {
12
+ let { workspaceId: f = "" } = e(), { data: p, loading: m, error: h } = r({
11
13
  variables: {
12
- workspaceId: u,
14
+ workspaceId: f,
13
15
  limit: 20
14
16
  },
15
- skip: !u
16
- }), m = d?.meetings ?? [];
17
- return f ? /* @__PURE__ */ c(n, {
17
+ skip: !f
18
+ }), g = p?.meetings ?? [];
19
+ return m ? /* @__PURE__ */ l(i, {
18
20
  title: "Meetings",
19
21
  description: "Schedule and track meetings",
20
- actions: /* @__PURE__ */ l("button", {
22
+ actions: /* @__PURE__ */ u("button", {
21
23
  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",
22
- children: [/* @__PURE__ */ c(o, { className: "h-4 w-4" }), "Schedule Meeting"]
24
+ children: [/* @__PURE__ */ l(s, { className: "h-4 w-4" }), "Schedule Meeting"]
23
25
  }),
24
- children: /* @__PURE__ */ c(r, {
26
+ children: /* @__PURE__ */ l(n, {
25
27
  variant: "list",
26
28
  count: 5
27
29
  })
28
- }) : p ? /* @__PURE__ */ c(n, {
30
+ }) : h ? /* @__PURE__ */ l(i, {
29
31
  title: "Meetings",
30
32
  description: "Schedule and track meetings",
31
- children: /* @__PURE__ */ c("div", {
32
- 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",
33
+ children: /* @__PURE__ */ l("div", {
34
+ className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
33
35
  children: "Failed to load meetings. Please try again later."
34
36
  })
35
- }) : /* @__PURE__ */ c(n, {
37
+ }) : /* @__PURE__ */ l(i, {
36
38
  title: "Meetings",
37
39
  description: "Schedule and track meetings",
38
- actions: /* @__PURE__ */ l("button", {
40
+ purpose: "Keep every meeting and its recording in one place and see how much of your week goes to them — so you can protect focus time, trim low-value calls, and account for meeting hours in your tracking.",
41
+ actions: /* @__PURE__ */ u("button", {
39
42
  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(o, { className: "h-4 w-4" }), "Schedule Meeting"]
43
+ children: [/* @__PURE__ */ l(s, { className: "h-4 w-4" }), "Schedule Meeting"]
41
44
  }),
42
- children: /* @__PURE__ */ c("div", {
43
- className: "rounded-xl border border-border-subtle bg-bg-surface",
44
- children: /* @__PURE__ */ c("div", {
45
+ children: g.length === 0 ? /* @__PURE__ */ l(a, {
46
+ illustration: "empty-data",
47
+ title: "No meetings found",
48
+ description: "Schedule your first meeting to start tracking calls and their time impact.",
49
+ action: /* @__PURE__ */ u("button", {
50
+ 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",
51
+ children: [/* @__PURE__ */ l(s, { className: "h-4 w-4" }), "Schedule Meeting"]
52
+ })
53
+ }) : /* @__PURE__ */ l(d, {
54
+ treatment: "glass",
55
+ glow: !0,
56
+ className: "overflow-hidden",
57
+ children: /* @__PURE__ */ l("div", {
45
58
  className: "divide-y divide-border",
46
- children: m.length === 0 ? /* @__PURE__ */ c("div", {
47
- className: "p-8 text-center text-sm text-text-secondary",
48
- children: "No meetings found."
49
- }) : m.map((e) => /* @__PURE__ */ l("div", {
59
+ children: g.map((e) => /* @__PURE__ */ u("div", {
50
60
  className: "flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors cursor-pointer",
51
- children: [/* @__PURE__ */ l("div", {
61
+ children: [/* @__PURE__ */ u("div", {
52
62
  className: "flex items-center gap-3",
53
- children: [/* @__PURE__ */ c(a, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ l("div", {
63
+ children: [/* @__PURE__ */ l(o, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ u("div", {
54
64
  className: "flex items-center gap-2",
55
- children: [/* @__PURE__ */ c("p", {
65
+ children: [/* @__PURE__ */ l("p", {
56
66
  className: "text-sm font-medium text-text-primary",
57
67
  children: e.title
58
- }), e.recordingUrl && /* @__PURE__ */ c(s, { className: "h-3.5 w-3.5 text-text-secondary" })]
59
- }), /* @__PURE__ */ l("p", {
68
+ }), e.recordingUrl && /* @__PURE__ */ l(c, { className: "h-3.5 w-3.5 text-text-secondary" })]
69
+ }), /* @__PURE__ */ u("p", {
60
70
  className: "text-xs text-text-secondary",
61
71
  children: [
62
72
  t(e.startTime),
@@ -69,12 +79,12 @@ function u() {
69
79
  " participants"
70
80
  ]
71
81
  })] })]
72
- }), /* @__PURE__ */ l("div", {
82
+ }), /* @__PURE__ */ u("div", {
73
83
  className: "flex items-center gap-2",
74
- children: [/* @__PURE__ */ c("span", {
84
+ children: [/* @__PURE__ */ l("span", {
75
85
  className: "inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
76
86
  children: e.meetingType
77
- }), /* @__PURE__ */ c("span", {
87
+ }), /* @__PURE__ */ l("span", {
78
88
  className: "inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
79
89
  children: e.endTime ? "completed" : "scheduled"
80
90
  })]
@@ -85,6 +95,6 @@ function u() {
85
95
  });
86
96
  }
87
97
  //#endregion
88
- export { u as MeetingsPage };
98
+ export { f as MeetingsPage };
89
99
 
90
100
  //# sourceMappingURL=MeetingsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MeetingsPage.js","names":[],"sources":["../../../../src/timecampus/pages/meetings/MeetingsPage.tsx"],"sourcesContent":["import { CalendarDays, Plus, Video } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { formatDate } from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListMeetingsQuery,\n type MeetingFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function MeetingsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const { data, loading, error } = useListMeetingsQuery({\n variables: { workspaceId, limit: 20 },\n skip: !workspaceId,\n });\n\n const meetings = data?.meetings ?? [];\n\n if (loading) {\n return (\n <PageLayout\n title=\"Meetings\"\n description=\"Schedule and track meetings\"\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 Schedule Meeting\n </button>\n }\n >\n <LoadingSkeleton variant=\"list\" count={5} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout title=\"Meetings\" description=\"Schedule and track meetings\">\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 meetings. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Meetings\"\n description=\"Schedule and track meetings\"\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 Schedule Meeting\n </button>\n }\n >\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface\">\n <div className=\"divide-y divide-border\">\n {meetings.length === 0 ? (\n <div className=\"p-8 text-center text-sm text-text-secondary\">\n No meetings found.\n </div>\n ) : (\n meetings.map((meeting: MeetingFieldsFragment) => (\n <div\n key={meeting.id}\n className=\"flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors cursor-pointer\"\n >\n <div className=\"flex items-center gap-3\">\n <CalendarDays className=\"h-5 w-5 text-text-secondary\" />\n <div>\n <div className=\"flex items-center gap-2\">\n <p className=\"text-sm font-medium text-text-primary\">\n {meeting.title}\n </p>\n {meeting.recordingUrl && (\n <Video className=\"h-3.5 w-3.5 text-text-secondary\" />\n )}\n </div>\n <p className=\"text-xs text-text-secondary\">\n {formatDate(meeting.startTime)} &middot;{\" \"}\n {meeting.duration ?? 0}min &middot;{\" \"}\n {meeting.participants.length} participants\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {meeting.meetingType}\n </span>\n <span className=\"inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {meeting.endTime ? \"completed\" : \"scheduled\"}\n </span>\n </div>\n </div>\n ))\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAUA,SAAgB,IAAe;CAC7B,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EAAE,SAAM,YAAS,aAAU,EAAqB;EACpD,WAAW;GAAE;GAAa,OAAO;GAAI;EACrC,MAAM,CAAC;EACR,CAAC,EAEI,IAAW,GAAM,YAAY,EAAE;AA6BrC,QA3BI,IAEA,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,mBAErB;;YAGX,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA,GAIb,IAEA,kBAAC,GAAD;EAAY,OAAM;EAAW,aAAY;YACvC,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,mBAErB;;YAGX,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAS,WAAW,IACnB,kBAAC,OAAD;KAAK,WAAU;eAA8C;KAEvD,CAAA,GAEN,EAAS,KAAK,MACZ,kBAAC,OAAD;KAEE,WAAU;eAFZ,CAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAc,WAAU,+BAAgC,CAAA,EACxD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAQ;QACP,CAAA,EACH,EAAQ,gBACP,kBAAC,GAAD,EAAO,WAAU,mCAAoC,CAAA,CAEnD;UACN,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAW,EAAQ,UAAU;QAAC;QAAU;QACxC,EAAQ,YAAY;QAAE;QAAa;QACnC,EAAQ,aAAa;QAAO;QAC3B;SACA,EAAA,CAAA,CACF;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAQ;OACJ,CAAA,EACP,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAQ,UAAU,cAAc;OAC5B,CAAA,CACH;QACF;OA7BC,EAAQ,GA6BT,CACN;IAEA,CAAA;GACF,CAAA;EACK,CAAA"}
1
+ {"version":3,"file":"MeetingsPage.js","names":[],"sources":["../../../../src/timecampus/pages/meetings/MeetingsPage.tsx"],"sourcesContent":["import { CalendarDays, Plus, Video } from \"lucide-react\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { EmptyState } from \"../../components/EmptyState\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { formatDate } from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListMeetingsQuery,\n type MeetingFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function MeetingsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const { data, loading, error } = useListMeetingsQuery({\n variables: { workspaceId, limit: 20 },\n skip: !workspaceId,\n });\n\n const meetings = data?.meetings ?? [];\n\n if (loading) {\n return (\n <PageLayout\n title=\"Meetings\"\n description=\"Schedule and track meetings\"\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 Schedule Meeting\n </button>\n }\n >\n <LoadingSkeleton variant=\"list\" count={5} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout title=\"Meetings\" description=\"Schedule and track meetings\">\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 meetings. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Meetings\"\n description=\"Schedule and track meetings\"\n purpose=\"Keep every meeting and its recording in one place and see how much of your week goes to them — so you can protect focus time, trim low-value calls, and account for meeting hours in your tracking.\"\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 Schedule Meeting\n </button>\n }\n >\n {meetings.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No meetings found\"\n description=\"Schedule your first meeting to start tracking calls and their time impact.\"\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 Schedule Meeting\n </button>\n }\n />\n ) : (\n <GlassCard treatment=\"glass\" glow className=\"overflow-hidden\">\n <div className=\"divide-y divide-border\">\n {meetings.map((meeting: MeetingFieldsFragment) => (\n <div\n key={meeting.id}\n className=\"flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors cursor-pointer\"\n >\n <div className=\"flex items-center gap-3\">\n <CalendarDays className=\"h-5 w-5 text-text-secondary\" />\n <div>\n <div className=\"flex items-center gap-2\">\n <p className=\"text-sm font-medium text-text-primary\">\n {meeting.title}\n </p>\n {meeting.recordingUrl && (\n <Video className=\"h-3.5 w-3.5 text-text-secondary\" />\n )}\n </div>\n <p className=\"text-xs text-text-secondary\">\n {formatDate(meeting.startTime)} &middot;{\" \"}\n {meeting.duration ?? 0}min &middot;{\" \"}\n {meeting.participants.length} participants\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {meeting.meetingType}\n </span>\n <span className=\"inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {meeting.endTime ? \"completed\" : \"scheduled\"}\n </span>\n </div>\n </div>\n ))}\n </div>\n </GlassCard>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;AAYA,SAAgB,IAAe;CAC7B,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EAAE,SAAM,YAAS,aAAU,EAAqB;EACpD,WAAW;GAAE;GAAa,OAAO;GAAI;EACrC,MAAM,CAAC;EACR,CAAC,EAEI,IAAW,GAAM,YAAY,EAAE;AA6BrC,QA3BI,IAEA,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,mBAErB;;YAGX,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA,GAIb,IAEA,kBAAC,GAAD;EAAY,OAAM;EAAW,aAAY;YACvC,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,mBAErB;;YAGV,EAAS,WAAW,IACnB,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,UAAD;IAAQ,WAAU;cAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,mBAErB;;GAEX,CAAA,GAEF,kBAAC,GAAD;GAAW,WAAU;GAAQ,MAAA;GAAK,WAAU;aAC1C,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAS,KAAK,MACb,kBAAC,OAAD;KAEE,WAAU;eAFZ,CAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAc,WAAU,+BAAgC,CAAA,EACxD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAQ;QACP,CAAA,EACH,EAAQ,gBACP,kBAAC,GAAD,EAAO,WAAU,mCAAoC,CAAA,CAEnD;UACN,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAW,EAAQ,UAAU;QAAC;QAAU;QACxC,EAAQ,YAAY;QAAE;QAAa;QACnC,EAAQ,aAAa;QAAO;QAC3B;SACA,EAAA,CAAA,CACF;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAQ;OACJ,CAAA,EACP,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAQ,UAAU,cAAc;OAC5B,CAAA,CACH;QACF;OA7BC,EAAQ,GA6BT,CACN;IACE,CAAA;GACI,CAAA;EAEH,CAAA"}
@@ -1,46 +1,48 @@
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 { useGetPomodoroStatsQuery as i, useListPomodoroSessionsQuery as a } from "../../../generated/wspace-operations.js";
2
+ import { StatCard as t } from "../../components/StatCard.js";
3
+ import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
4
+ import { useGetPomodoroStatsQuery as r, useListPomodoroSessionsQuery as i } from "../../../generated/wspace-operations.js";
5
+ import { PageLayout as a } from "../../components/PageLayout.js";
6
6
  import { BarChart3 as o, Target as s } from "lucide-react";
7
7
  import { jsx as c, jsxs as l } from "react/jsx-runtime";
8
8
  //#region src/timecampus/pages/pomodoro/PomodoroAnalyticsPage.tsx
9
9
  function u() {
10
- let { workspaceId: u = "" } = e(), { data: d, loading: f, error: p } = i({
10
+ let { workspaceId: u = "" } = e(), { data: d, loading: f, error: p } = r({
11
11
  variables: { workspaceId: u },
12
12
  skip: !u
13
- }), { data: m, loading: h } = a({
13
+ }), { data: m, loading: h } = i({
14
14
  variables: {
15
15
  workspaceId: u,
16
16
  limit: 50
17
17
  },
18
18
  skip: !u
19
19
  }), g = d?.pomodoroStats, _ = m?.pomodoroSessions ?? [];
20
- if (f || h) return /* @__PURE__ */ c(t, {
20
+ if (f || h) return /* @__PURE__ */ c(a, {
21
21
  title: "Pomodoro Analytics",
22
22
  description: "Track your focus sessions and productivity",
23
- children: /* @__PURE__ */ c(r, {
23
+ children: /* @__PURE__ */ c(n, {
24
24
  variant: "card",
25
25
  count: 4
26
26
  })
27
27
  });
28
- if (p) return /* @__PURE__ */ c(t, {
28
+ if (p) return /* @__PURE__ */ c(a, {
29
29
  title: "Pomodoro Analytics",
30
30
  description: "Track your focus sessions and productivity",
31
31
  children: /* @__PURE__ */ c("div", {
32
- 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",
32
+ className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
33
33
  children: "Failed to load pomodoro analytics. Please try again later."
34
34
  })
35
35
  });
36
36
  let v = Math.floor((g?.totalFocusMinutes ?? 0) / 60), y = (g?.totalFocusMinutes ?? 0) % 60, b = g?.totalSessions ? (g.totalSessions / 30).toFixed(1) : "0", x = _.filter((e) => e.completed).length;
37
- return /* @__PURE__ */ l(t, {
37
+ return /* @__PURE__ */ l(a, {
38
38
  title: "Pomodoro Analytics",
39
39
  description: "Track your focus sessions and productivity",
40
+ purpose: "See whether your focus habit is sticking — completion rate, streaks and focus minutes over time — so you can tell good-focus days from distracted ones and keep your momentum going.",
40
41
  children: [/* @__PURE__ */ l("div", {
41
42
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
42
43
  children: [
43
- /* @__PURE__ */ c(n, {
44
+ /* @__PURE__ */ c(t, {
45
+ featured: !0,
44
46
  title: "Total Sessions",
45
47
  value: String(g?.totalSessions ?? 0),
46
48
  trend: {
@@ -48,7 +50,7 @@ function u() {
48
50
  label: "completion rate"
49
51
  }
50
52
  }),
51
- /* @__PURE__ */ c(n, {
53
+ /* @__PURE__ */ c(t, {
52
54
  title: "Total Focus Time",
53
55
  value: `${v}h ${y}m`,
54
56
  trend: {
@@ -56,12 +58,12 @@ function u() {
56
58
  label: "avg min/session"
57
59
  }
58
60
  }),
59
- /* @__PURE__ */ c(n, {
61
+ /* @__PURE__ */ c(t, {
60
62
  title: "Avg. Sessions/Day",
61
63
  value: b,
62
64
  description: `Target: ${g?.totalSessions ?? 0} total`
63
65
  }),
64
- /* @__PURE__ */ c(n, {
66
+ /* @__PURE__ */ c(t, {
65
67
  title: "Completion Rate",
66
68
  value: `${g?.completionRate ?? 0}%`,
67
69
  icon: /* @__PURE__ */ c(s, { className: "h-5 w-5" }),
@@ -74,7 +76,7 @@ function u() {
74
76
  }), /* @__PURE__ */ l("div", {
75
77
  className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
76
78
  children: [/* @__PURE__ */ l("div", {
77
- className: "rounded-xl border border-border-subtle bg-bg-surface p-6",
79
+ className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6",
78
80
  children: [/* @__PURE__ */ l("div", {
79
81
  className: "mb-4 flex items-center gap-2",
80
82
  children: [/* @__PURE__ */ c(o, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ c("h3", {
@@ -89,7 +91,7 @@ function u() {
89
91
  })
90
92
  })]
91
93
  }), /* @__PURE__ */ l("div", {
92
- className: "rounded-xl border border-border-subtle bg-bg-surface p-6",
94
+ className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6",
93
95
  children: [/* @__PURE__ */ l("div", {
94
96
  className: "mb-4 flex items-center gap-2",
95
97
  children: [/* @__PURE__ */ c(o, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ c("h3", {
@@ -1 +1 @@
1
- {"version":3,"file":"PomodoroAnalyticsPage.js","names":[],"sources":["../../../../src/timecampus/pages/pomodoro/PomodoroAnalyticsPage.tsx"],"sourcesContent":["import { BarChart3, Target } 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 useGetPomodoroStatsQuery,\n useListPomodoroSessionsQuery,\n type PomodoroSessionFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function PomodoroAnalyticsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetPomodoroStatsQuery({\n variables: { workspaceId },\n skip: !workspaceId,\n });\n\n const { data: sessionsData, loading: sessionsLoading } =\n useListPomodoroSessionsQuery({\n variables: { workspaceId, limit: 50 },\n skip: !workspaceId,\n });\n\n const stats = statsData?.pomodoroStats;\n const sessions = sessionsData?.pomodoroSessions ?? [];\n\n if (statsLoading || sessionsLoading) {\n return (\n <PageLayout\n title=\"Pomodoro Analytics\"\n description=\"Track your focus sessions and productivity\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (statsError) {\n return (\n <PageLayout\n title=\"Pomodoro Analytics\"\n description=\"Track your focus sessions and productivity\"\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 pomodoro analytics. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n const totalFocusH = Math.floor((stats?.totalFocusMinutes ?? 0) / 60);\n const totalFocusM = (stats?.totalFocusMinutes ?? 0) % 60;\n const avgSessions = stats?.totalSessions\n ? (stats.totalSessions / 30).toFixed(1)\n : \"0\";\n const completedCount = sessions.filter(\n (s: PomodoroSessionFieldsFragment) => s.completed,\n ).length;\n\n return (\n <PageLayout\n title=\"Pomodoro Analytics\"\n description=\"Track your focus sessions and productivity\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n title=\"Total Sessions\"\n value={String(stats?.totalSessions ?? 0)}\n trend={{\n value: stats?.completionRate ?? 0,\n label: \"completion rate\",\n }}\n />\n <StatCard\n title=\"Total Focus Time\"\n value={`${totalFocusH}h ${totalFocusM}m`}\n trend={{\n value: stats?.averageSessionMinutes ?? 0,\n label: \"avg min/session\",\n }}\n />\n <StatCard\n title=\"Avg. Sessions/Day\"\n value={avgSessions}\n description={`Target: ${stats?.totalSessions ?? 0} total`}\n />\n <StatCard\n title=\"Completion Rate\"\n value={`${stats?.completionRate ?? 0}%`}\n icon={<Target className=\"h-5 w-5\" />}\n trend={{ value: stats?.streakDays ?? 0, label: \"day streak\" }}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <BarChart3 className=\"h-5 w-5 text-primary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n Sessions per Day\n </h3>\n </div>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <p className=\"text-sm text-text-secondary\">\n {sessions.length > 0\n ? `${completedCount} completed out of ${sessions.length} sessions`\n : \"No session data available\"}\n </p>\n </div>\n </div>\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <BarChart3 className=\"h-5 w-5 text-primary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n Focus Distribution\n </h3>\n </div>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <p className=\"text-sm text-text-secondary\">\n {stats\n ? `${stats.streakDays} day streak · ${stats.averageSessionMinutes}m avg session`\n : \"No data available\"}\n </p>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAWA,SAAgB,IAAwB;CACtC,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAAyB;EAC3B,WAAW,EAAE,gBAAa;EAC1B,MAAM,CAAC;EACR,CAAC,EAEI,EAAE,MAAM,GAAc,SAAS,MACnC,EAA6B;EAC3B,WAAW;GAAE;GAAa,OAAO;GAAI;EACrC,MAAM,CAAC;EACR,CAAC,EAEE,IAAQ,GAAW,eACnB,IAAW,GAAc,oBAAoB,EAAE;AAErD,KAAI,KAAgB,EAClB,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA;AAIjB,KAAI,EACF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAA+H;GAExI,CAAA;EACK,CAAA;CAIjB,IAAM,IAAc,KAAK,OAAO,GAAO,qBAAqB,KAAK,GAAG,EAC9D,KAAe,GAAO,qBAAqB,KAAK,IAChD,IAAc,GAAO,iBACtB,EAAM,gBAAgB,IAAI,QAAQ,EAAE,GACrC,KACE,IAAiB,EAAS,QAC7B,MAAqC,EAAE,UACzC,CAAC;AAEF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAFd,CAIE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,OAAO,GAAO,iBAAiB,EAAE;KACxC,OAAO;MACL,OAAO,GAAO,kBAAkB;MAChC,OAAO;MACR;KACD,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,GAAG,EAAY,IAAI,EAAY;KACtC,OAAO;MACL,OAAO,GAAO,yBAAyB;MACvC,OAAO;MACR;KACD,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO;KACP,aAAa,WAAW,GAAO,iBAAiB,EAAE;KAClD,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,GAAG,GAAO,kBAAkB,EAAE;KACrC,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;KACpC,OAAO;MAAE,OAAO,GAAO,cAAc;MAAG,OAAO;MAAc;KAC7D,CAAA;IACE;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAW,WAAU,wBAAyB,CAAA,EAC9C,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAEnD,CAAA,CACD;QACN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAS,SAAS,IACf,GAAG,EAAe,oBAAoB,EAAS,OAAO,aACtD;MACF,CAAA;KACA,CAAA,CACF;OACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAW,WAAU,wBAAyB,CAAA,EAC9C,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAEnD,CAAA,CACD;QACN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,KAAD;MAAG,WAAU;gBACV,IACG,GAAG,EAAM,WAAW,gBAAgB,EAAM,sBAAsB,iBAChE;MACF,CAAA;KACA,CAAA,CACF;MACF;KACK"}
1
+ {"version":3,"file":"PomodoroAnalyticsPage.js","names":[],"sources":["../../../../src/timecampus/pages/pomodoro/PomodoroAnalyticsPage.tsx"],"sourcesContent":["import { BarChart3, Target } 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 useGetPomodoroStatsQuery,\n useListPomodoroSessionsQuery,\n type PomodoroSessionFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function PomodoroAnalyticsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetPomodoroStatsQuery({\n variables: { workspaceId },\n skip: !workspaceId,\n });\n\n const { data: sessionsData, loading: sessionsLoading } =\n useListPomodoroSessionsQuery({\n variables: { workspaceId, limit: 50 },\n skip: !workspaceId,\n });\n\n const stats = statsData?.pomodoroStats;\n const sessions = sessionsData?.pomodoroSessions ?? [];\n\n if (statsLoading || sessionsLoading) {\n return (\n <PageLayout\n title=\"Pomodoro Analytics\"\n description=\"Track your focus sessions and productivity\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (statsError) {\n return (\n <PageLayout\n title=\"Pomodoro Analytics\"\n description=\"Track your focus sessions and productivity\"\n >\n <div className=\"rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text\">\n Failed to load pomodoro analytics. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n const totalFocusH = Math.floor((stats?.totalFocusMinutes ?? 0) / 60);\n const totalFocusM = (stats?.totalFocusMinutes ?? 0) % 60;\n const avgSessions = stats?.totalSessions\n ? (stats.totalSessions / 30).toFixed(1)\n : \"0\";\n const completedCount = sessions.filter(\n (s: PomodoroSessionFieldsFragment) => s.completed,\n ).length;\n\n return (\n <PageLayout\n title=\"Pomodoro Analytics\"\n description=\"Track your focus sessions and productivity\"\n purpose=\"See whether your focus habit is sticking — completion rate, streaks and focus minutes over time — so you can tell good-focus days from distracted ones and keep your momentum going.\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n featured\n title=\"Total Sessions\"\n value={String(stats?.totalSessions ?? 0)}\n trend={{\n value: stats?.completionRate ?? 0,\n label: \"completion rate\",\n }}\n />\n <StatCard\n title=\"Total Focus Time\"\n value={`${totalFocusH}h ${totalFocusM}m`}\n trend={{\n value: stats?.averageSessionMinutes ?? 0,\n label: \"avg min/session\",\n }}\n />\n <StatCard\n title=\"Avg. Sessions/Day\"\n value={avgSessions}\n description={`Target: ${stats?.totalSessions ?? 0} total`}\n />\n <StatCard\n title=\"Completion Rate\"\n value={`${stats?.completionRate ?? 0}%`}\n icon={<Target className=\"h-5 w-5\" />}\n trend={{ value: stats?.streakDays ?? 0, label: \"day streak\" }}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <BarChart3 className=\"h-5 w-5 text-primary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n Sessions per Day\n </h3>\n </div>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <p className=\"text-sm text-text-secondary\">\n {sessions.length > 0\n ? `${completedCount} completed out of ${sessions.length} sessions`\n : \"No session data available\"}\n </p>\n </div>\n </div>\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <BarChart3 className=\"h-5 w-5 text-primary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n Focus Distribution\n </h3>\n </div>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <p className=\"text-sm text-text-secondary\">\n {stats\n ? `${stats.streakDays} day streak · ${stats.averageSessionMinutes}m avg session`\n : \"No data available\"}\n </p>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAWA,SAAgB,IAAwB;CACtC,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAAyB;EAC3B,WAAW,EAAE,gBAAa;EAC1B,MAAM,CAAC;EACR,CAAC,EAEI,EAAE,MAAM,GAAc,SAAS,MACnC,EAA6B;EAC3B,WAAW;GAAE;GAAa,OAAO;GAAI;EACrC,MAAM,CAAC;EACR,CAAC,EAEE,IAAQ,GAAW,eACnB,IAAW,GAAc,oBAAoB,EAAE;AAErD,KAAI,KAAgB,EAClB,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA;AAIjB,KAAI,EACF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAAoG;GAE7G,CAAA;EACK,CAAA;CAIjB,IAAM,IAAc,KAAK,OAAO,GAAO,qBAAqB,KAAK,GAAG,EAC9D,KAAe,GAAO,qBAAqB,KAAK,IAChD,IAAc,GAAO,iBACtB,EAAM,gBAAgB,IAAI,QAAQ,EAAE,GACrC,KACE,IAAiB,EAAS,QAC7B,MAAqC,EAAE,UACzC,CAAC;AAEF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SAAQ;YAHV,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,UAAA;KACA,OAAM;KACN,OAAO,OAAO,GAAO,iBAAiB,EAAE;KACxC,OAAO;MACL,OAAO,GAAO,kBAAkB;MAChC,OAAO;MACR;KACD,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,GAAG,EAAY,IAAI,EAAY;KACtC,OAAO;MACL,OAAO,GAAO,yBAAyB;MACvC,OAAO;MACR;KACD,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO;KACP,aAAa,WAAW,GAAO,iBAAiB,EAAE;KAClD,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,GAAG,GAAO,kBAAkB,EAAE;KACrC,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;KACpC,OAAO;MAAE,OAAO,GAAO,cAAc;MAAG,OAAO;MAAc;KAC7D,CAAA;IACE;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAW,WAAU,wBAAyB,CAAA,EAC9C,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAEnD,CAAA,CACD;QACN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAS,SAAS,IACf,GAAG,EAAe,oBAAoB,EAAS,OAAO,aACtD;MACF,CAAA;KACA,CAAA,CACF;OACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAW,WAAU,wBAAyB,CAAA,EAC9C,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAEnD,CAAA,CACD;QACN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,KAAD;MAAG,WAAU;gBACV,IACG,GAAG,EAAM,WAAW,gBAAgB,EAAM,sBAAsB,iBAChE;MACF,CAAA;KACA,CAAA,CACF;MACF;KACK"}