@burdenoff/microfe-timecampus 2026.625.1 → 2026.626.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/timecampus/components/EmptyState.js +14 -0
- package/dist/timecampus/components/EmptyState.js.map +1 -0
- package/dist/timecampus/components/PageLayout.js +23 -15
- package/dist/timecampus/components/PageLayout.js.map +1 -1
- package/dist/timecampus/pages/applets/AppletStorePage.js +33 -30
- package/dist/timecampus/pages/applets/AppletStorePage.js.map +1 -1
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js +37 -31
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +48 -44
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js +35 -31
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/channels/ChannelsPage.js +27 -24
- package/dist/timecampus/pages/channels/ChannelsPage.js.map +1 -1
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js +46 -38
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/AnalyticsPage.js +66 -39
- package/dist/timecampus/pages/dashboard/AnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/ReportsPage.js +42 -36
- package/dist/timecampus/pages/dashboard/ReportsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js +2 -0
- package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js +35 -31
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +31 -25
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +43 -35
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScorePage.js +55 -51
- package/dist/timecampus/pages/focus-score/FocusScorePage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js +32 -28
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingPage.js +32 -25
- package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js +29 -25
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +32 -29
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js +29 -25
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +39 -35
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js +2 -0
- package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js +33 -29
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js +122 -104
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingsPage.js +42 -32
- package/dist/timecampus/pages/meetings/MeetingsPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js +2 -0
- package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js +145 -114
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js +49 -45
- package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectCreatePage.js +28 -24
- package/dist/timecampus/pages/projects/ProjectCreatePage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectDetailPage.js +109 -78
- package/dist/timecampus/pages/projects/ProjectDetailPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectsPage.js +11 -7
- package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/TasksPage.js +40 -30
- package/dist/timecampus/pages/projects/TasksPage.js.map +1 -1
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +50 -46
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js +18 -14
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamMembersPage.js +41 -35
- package/dist/timecampus/pages/team/TeamMembersPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamPage.js +91 -61
- package/dist/timecampus/pages/team/TeamPage.js.map +1 -1
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js +40 -36
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js.map +1 -1
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js +33 -29
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js +17 -13
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateDetailPage.js +67 -49
- package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplatesPage.js +34 -31
- package/dist/timecampus/pages/templates/TemplatesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeEntriesPage.js +48 -39
- package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeTrackingPage.js +65 -64
- package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimerPage.js +103 -69
- package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +53 -49
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js +65 -47
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetsPage.js +38 -31
- package/dist/timecampus/pages/widgets/WidgetsPage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +2 -0
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js +35 -31
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/workflows/WorkflowsPage.js +43 -33
- package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,91 +1,118 @@
|
|
|
1
|
-
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
|
-
import { LoadingSkeleton as
|
|
3
|
-
import { useGetFocusScoreSummaryQuery as
|
|
4
|
-
import { PageLayout as
|
|
5
|
-
import { BarChart3 as
|
|
6
|
-
import { jsx as
|
|
1
|
+
import { useTimeCampus as e, useTimeCampusNavigate as t } from "../../providers/TimeCampusProvider.js";
|
|
2
|
+
import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
|
|
3
|
+
import { useGetFocusScoreSummaryQuery as r, useGetTimeEntryStatsQuery as i, useGetWorkPatternSummaryQuery as a } from "../../../generated/wspace-operations.js";
|
|
4
|
+
import { PageLayout as o } from "../../components/PageLayout.js";
|
|
5
|
+
import { BarChart3 as s } from "lucide-react";
|
|
6
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
7
|
+
import { GlassCard as u, NextSteps as d } from "@burdenoff/fe-libs/ui";
|
|
7
8
|
//#region src/timecampus/pages/dashboard/AnalyticsPage.tsx
|
|
8
|
-
function
|
|
9
|
-
let { workspaceId:
|
|
10
|
-
return
|
|
9
|
+
function f() {
|
|
10
|
+
let { workspaceId: f = "" } = e(), p = t(), { data: m, loading: h, error: g } = i({ skip: !f }), { data: _, loading: v } = r({ skip: !f }), { data: y, loading: b } = a({ skip: !f }), x = m?.timeEntryStats, S = _?.focusScoreSummary, C = y?.workPatternSummary;
|
|
11
|
+
return h || v || b ? /* @__PURE__ */ c(o, {
|
|
11
12
|
title: "Analytics",
|
|
12
13
|
description: "Insights into your time tracking and productivity",
|
|
13
|
-
children: /* @__PURE__ */
|
|
14
|
+
children: /* @__PURE__ */ c(n, {
|
|
14
15
|
variant: "card",
|
|
15
16
|
count: 4
|
|
16
17
|
})
|
|
17
|
-
}) :
|
|
18
|
+
}) : g ? /* @__PURE__ */ c(o, {
|
|
18
19
|
title: "Analytics",
|
|
19
20
|
description: "Insights into your time tracking and productivity",
|
|
20
|
-
children: /* @__PURE__ */
|
|
21
|
+
children: /* @__PURE__ */ c("div", {
|
|
21
22
|
className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
|
|
22
23
|
children: "Failed to load analytics. Please try again later."
|
|
23
24
|
})
|
|
24
|
-
}) : /* @__PURE__ */
|
|
25
|
+
}) : /* @__PURE__ */ l(o, {
|
|
25
26
|
title: "Analytics",
|
|
26
27
|
description: "Insights into your time tracking and productivity",
|
|
27
|
-
|
|
28
|
+
purpose: "Turn the raw hours you track into answers — spot whether your focus is improving, where billable time is going, and which habits to change to get more done with less burnout.",
|
|
29
|
+
children: [/* @__PURE__ */ c(d, {
|
|
30
|
+
storageKey: "timecampus-analytics",
|
|
31
|
+
className: "mb-6",
|
|
32
|
+
steps: [
|
|
33
|
+
{
|
|
34
|
+
id: "reports",
|
|
35
|
+
label: "Build a detailed report",
|
|
36
|
+
description: "Slice time by project, client or person.",
|
|
37
|
+
onClick: () => p("/reports")
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "focus",
|
|
41
|
+
label: "Dig into your focus score",
|
|
42
|
+
description: "Understand what's helping or hurting deep work.",
|
|
43
|
+
onClick: () => p("/focus-score")
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "patterns",
|
|
47
|
+
label: "Review your work patterns",
|
|
48
|
+
description: "See how your week actually breaks down.",
|
|
49
|
+
onClick: () => p("/work-patterns")
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}), /* @__PURE__ */ l("div", {
|
|
28
53
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
|
|
29
|
-
children: [/* @__PURE__ */
|
|
30
|
-
|
|
31
|
-
|
|
54
|
+
children: [/* @__PURE__ */ l(u, {
|
|
55
|
+
treatment: "glass",
|
|
56
|
+
glow: !0,
|
|
57
|
+
className: "p-6",
|
|
58
|
+
children: [/* @__PURE__ */ l("div", {
|
|
32
59
|
className: "mb-4 flex items-center gap-2",
|
|
33
|
-
children: [/* @__PURE__ */ s
|
|
60
|
+
children: [/* @__PURE__ */ c(s, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ c("h3", {
|
|
34
61
|
className: "text-sm font-semibold text-text-primary",
|
|
35
62
|
children: "Productivity Trends"
|
|
36
63
|
})]
|
|
37
|
-
}), /* @__PURE__ */
|
|
64
|
+
}), /* @__PURE__ */ c("div", {
|
|
38
65
|
className: "flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle",
|
|
39
|
-
children: /* @__PURE__ */
|
|
66
|
+
children: /* @__PURE__ */ l("div", {
|
|
40
67
|
className: "text-center",
|
|
41
68
|
children: [
|
|
42
|
-
/* @__PURE__ */
|
|
69
|
+
/* @__PURE__ */ c("p", {
|
|
43
70
|
className: "text-sm text-text-secondary",
|
|
44
|
-
children:
|
|
71
|
+
children: S ? `Focus Score: ${Math.round(S.averageScore)}/100 (${S.trend ?? "stable"})` : "No focus score data"
|
|
45
72
|
}),
|
|
46
|
-
|
|
73
|
+
C && /* @__PURE__ */ l("p", {
|
|
47
74
|
className: "mt-1 text-xs text-text-secondary",
|
|
48
75
|
children: [
|
|
49
|
-
|
|
76
|
+
C.averageFocusHours.toFixed(1),
|
|
50
77
|
"h avg focus ·",
|
|
51
78
|
" ",
|
|
52
|
-
|
|
79
|
+
C.averageMeetingHours.toFixed(1),
|
|
53
80
|
"h avg meetings"
|
|
54
81
|
]
|
|
55
82
|
}),
|
|
56
|
-
|
|
83
|
+
S?.improvementArea && /* @__PURE__ */ l("p", {
|
|
57
84
|
className: "mt-1 text-xs text-text-secondary",
|
|
58
|
-
children: ["Improve: ",
|
|
85
|
+
children: ["Improve: ", S.improvementArea]
|
|
59
86
|
})
|
|
60
87
|
]
|
|
61
88
|
})
|
|
62
89
|
})]
|
|
63
|
-
}), /* @__PURE__ */
|
|
64
|
-
className: "rounded-xl border border-border-seam bg-
|
|
65
|
-
children: [/* @__PURE__ */
|
|
90
|
+
}), /* @__PURE__ */ l("div", {
|
|
91
|
+
className: "rounded-xl border border-border-seam bg-bg-surface shadow-elevation-1 p-6",
|
|
92
|
+
children: [/* @__PURE__ */ l("div", {
|
|
66
93
|
className: "mb-4 flex items-center gap-2",
|
|
67
|
-
children: [/* @__PURE__ */ s
|
|
94
|
+
children: [/* @__PURE__ */ c(s, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ c("h3", {
|
|
68
95
|
className: "text-sm font-semibold text-text-primary",
|
|
69
96
|
children: "Time Distribution"
|
|
70
97
|
})]
|
|
71
|
-
}), /* @__PURE__ */
|
|
98
|
+
}), /* @__PURE__ */ c("div", {
|
|
72
99
|
className: "flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle",
|
|
73
|
-
children: /* @__PURE__ */
|
|
100
|
+
children: /* @__PURE__ */ l("div", {
|
|
74
101
|
className: "text-center",
|
|
75
|
-
children: [/* @__PURE__ */
|
|
102
|
+
children: [/* @__PURE__ */ c("p", {
|
|
76
103
|
className: "text-sm text-text-secondary",
|
|
77
|
-
children:
|
|
78
|
-
}),
|
|
104
|
+
children: x ? `${Math.round(x.totalHours)}h total · ${Math.round(x.billableHours)}h billable · ${x.totalEntries} entries` : "No time entry data"
|
|
105
|
+
}), x && x.activeTimers > 0 && /* @__PURE__ */ l("p", {
|
|
79
106
|
className: "mt-1 text-xs text-text-secondary",
|
|
80
|
-
children: [
|
|
107
|
+
children: [x.activeTimers, " timer(s) running"]
|
|
81
108
|
})]
|
|
82
109
|
})
|
|
83
110
|
})]
|
|
84
111
|
})]
|
|
85
|
-
})
|
|
112
|
+
})]
|
|
86
113
|
});
|
|
87
114
|
}
|
|
88
115
|
//#endregion
|
|
89
|
-
export {
|
|
116
|
+
export { f as AnalyticsPage };
|
|
90
117
|
|
|
91
118
|
//# sourceMappingURL=AnalyticsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsPage.js","names":[],"sources":["../../../../src/timecampus/pages/dashboard/AnalyticsPage.tsx"],"sourcesContent":["import { BarChart3 } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport {
|
|
1
|
+
{"version":3,"file":"AnalyticsPage.js","names":[],"sources":["../../../../src/timecampus/pages/dashboard/AnalyticsPage.tsx"],"sourcesContent":["import { BarChart3 } from \"lucide-react\";\nimport { GlassCard, NextSteps } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport {\n useTimeCampus,\n useTimeCampusNavigate,\n} from \"../../providers/TimeCampusProvider\";\nimport {\n useGetTimeEntryStatsQuery,\n useGetFocusScoreSummaryQuery,\n useGetWorkPatternSummaryQuery,\n} from \"@/generated/wspace-operations\";\n\nexport function AnalyticsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const navigate = useTimeCampusNavigate();\n\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetTimeEntryStatsQuery({\n skip: !workspaceId,\n });\n\n const { data: focusData, loading: focusLoading } =\n useGetFocusScoreSummaryQuery({\n skip: !workspaceId,\n });\n\n const { data: patternData, loading: patternLoading } =\n useGetWorkPatternSummaryQuery({\n skip: !workspaceId,\n });\n\n const stats = statsData?.timeEntryStats;\n const focus = focusData?.focusScoreSummary;\n const pattern = patternData?.workPatternSummary;\n\n if (statsLoading || focusLoading || patternLoading) {\n return (\n <PageLayout\n title=\"Analytics\"\n description=\"Insights into your time tracking and productivity\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (statsError) {\n return (\n <PageLayout\n title=\"Analytics\"\n description=\"Insights into your time tracking 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 analytics. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Analytics\"\n description=\"Insights into your time tracking and productivity\"\n purpose=\"Turn the raw hours you track into answers — spot whether your focus is improving, where billable time is going, and which habits to change to get more done with less burnout.\"\n >\n <NextSteps\n storageKey=\"timecampus-analytics\"\n className=\"mb-6\"\n steps={[\n {\n id: \"reports\",\n label: \"Build a detailed report\",\n description: \"Slice time by project, client or person.\",\n onClick: () => navigate(\"/reports\"),\n },\n {\n id: \"focus\",\n label: \"Dig into your focus score\",\n description: \"Understand what's helping or hurting deep work.\",\n onClick: () => navigate(\"/focus-score\"),\n },\n {\n id: \"patterns\",\n label: \"Review your work patterns\",\n description: \"See how your week actually breaks down.\",\n onClick: () => navigate(\"/work-patterns\"),\n },\n ]}\n />\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <GlassCard treatment=\"glass\" glow className=\"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 Productivity Trends\n </h3>\n </div>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <div className=\"text-center\">\n <p className=\"text-sm text-text-secondary\">\n {focus\n ? `Focus Score: ${Math.round(focus.averageScore)}/100 (${focus.trend ?? \"stable\"})`\n : \"No focus score data\"}\n </p>\n {pattern && (\n <p className=\"mt-1 text-xs text-text-secondary\">\n {pattern.averageFocusHours.toFixed(1)}h avg focus ·{\" \"}\n {pattern.averageMeetingHours.toFixed(1)}h avg meetings\n </p>\n )}\n {focus?.improvementArea && (\n <p className=\"mt-1 text-xs text-text-secondary\">\n Improve: {focus.improvementArea}\n </p>\n )}\n </div>\n </div>\n </GlassCard>\n <div className=\"rounded-xl border border-border-seam bg-bg-surface shadow-elevation-1 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 Time Distribution\n </h3>\n </div>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <div className=\"text-center\">\n <p className=\"text-sm text-text-secondary\">\n {stats\n ? `${Math.round(stats.totalHours)}h total · ${Math.round(stats.billableHours)}h billable · ${stats.totalEntries} entries`\n : \"No time entry data\"}\n </p>\n {stats && stats.activeTimers > 0 && (\n <p className=\"mt-1 text-xs text-text-secondary\">\n {stats.activeTimers} timer(s) running\n </p>\n )}\n </div>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAcA,SAAgB,IAAgB;CAC9B,IAAM,EAAE,iBAAc,OAAO,GAAe,EACtC,IAAW,GAAuB,EAElC,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAA0B,EAC5B,MAAM,CAAC,GACR,CAAC,EAEI,EAAE,MAAM,GAAW,SAAS,MAChC,EAA6B,EAC3B,MAAM,CAAC,GACR,CAAC,EAEE,EAAE,MAAM,GAAa,SAAS,MAClC,EAA8B,EAC5B,MAAM,CAAC,GACR,CAAC,EAEE,IAAQ,GAAW,gBACnB,IAAQ,GAAW,mBACnB,IAAU,GAAa;AA0B7B,QAxBI,KAAgB,KAAgB,IAEhC,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;YAHV,CAKE,kBAAC,GAAD;GACE,YAAW;GACX,WAAU;GACV,OAAO;IACL;KACE,IAAI;KACJ,OAAO;KACP,aAAa;KACb,eAAe,EAAS,WAAW;KACpC;IACD;KACE,IAAI;KACJ,OAAO;KACP,aAAa;KACb,eAAe,EAAS,eAAe;KACxC;IACD;KACE,IAAI;KACJ,OAAO;KACP,aAAa;KACb,eAAe,EAAS,iBAAiB;KAC1C;IACF;GACD,CAAA,EACF,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IAAW,WAAU;IAAQ,MAAA;IAAK,WAAU;cAA5C,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,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,KAAD;QAAG,WAAU;kBACV,IACG,gBAAgB,KAAK,MAAM,EAAM,aAAa,CAAC,QAAQ,EAAM,SAAS,SAAS,KAC/E;QACF,CAAA;OACH,KACC,kBAAC,KAAD;QAAG,WAAU;kBAAb;SACG,EAAQ,kBAAkB,QAAQ,EAAE;SAAC;SAAc;SACnD,EAAQ,oBAAoB,QAAQ,EAAE;SAAC;SACtC;;OAEL,GAAO,mBACN,kBAAC,KAAD;QAAG,WAAU;kBAAb,CAAgD,aACpC,EAAM,gBACd;;OAEF;;KACF,CAAA,CACI;OACZ,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,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBACV,IACG,GAAG,KAAK,MAAM,EAAM,WAAW,CAAC,YAAY,KAAK,MAAM,EAAM,cAAc,CAAC,eAAe,EAAM,aAAa,YAC9G;OACF,CAAA,EACH,KAAS,EAAM,eAAe,KAC7B,kBAAC,KAAD;OAAG,WAAU;iBAAb,CACG,EAAM,cAAa,oBAClB;SAEF;;KACF,CAAA,CACF;MACF;KACK"}
|
|
@@ -2,93 +2,99 @@ import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
|
2
2
|
import { LoadingSkeleton as t } from "../../components/LoadingSkeleton.js";
|
|
3
3
|
import { useGetFocusScoreSummaryQuery as n, useGetTimeEntryStatsQuery as r, useGetWorkPatternSummaryQuery as i } from "../../../generated/wspace-operations.js";
|
|
4
4
|
import { PageLayout as a } from "../../components/PageLayout.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { EmptyState as o } from "../../components/EmptyState.js";
|
|
6
|
+
import { Download as s, FileText as c, Plus as l } from "lucide-react";
|
|
7
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
8
|
+
import { GlassCard as f } from "@burdenoff/fe-libs/ui";
|
|
7
9
|
//#region src/timecampus/pages/dashboard/ReportsPage.tsx
|
|
8
|
-
function
|
|
9
|
-
let { workspaceId:
|
|
10
|
-
if (
|
|
10
|
+
function p() {
|
|
11
|
+
let { workspaceId: p = "" } = e(), { data: m, loading: h, error: g } = r({ skip: !p }), { data: _, loading: v } = i({ skip: !p }), { data: y, loading: b } = n({ skip: !p }), x = m?.timeEntryStats, S = _?.workPatternSummary, C = y?.focusScoreSummary;
|
|
12
|
+
if (h || v || b) return /* @__PURE__ */ u(a, {
|
|
11
13
|
title: "Reports",
|
|
12
14
|
description: "Generate and view time tracking reports",
|
|
13
|
-
actions: /* @__PURE__ */
|
|
15
|
+
actions: /* @__PURE__ */ d("button", {
|
|
14
16
|
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",
|
|
15
|
-
children: [/* @__PURE__ */ l
|
|
17
|
+
children: [/* @__PURE__ */ u(l, { className: "h-4 w-4" }), "Generate Report"]
|
|
16
18
|
}),
|
|
17
|
-
children: /* @__PURE__ */
|
|
19
|
+
children: /* @__PURE__ */ u(t, {
|
|
18
20
|
variant: "list",
|
|
19
21
|
count: 4
|
|
20
22
|
})
|
|
21
23
|
});
|
|
22
|
-
if (
|
|
24
|
+
if (g) return /* @__PURE__ */ u(a, {
|
|
23
25
|
title: "Reports",
|
|
24
26
|
description: "Generate and view time tracking reports",
|
|
25
|
-
children: /* @__PURE__ */
|
|
27
|
+
children: /* @__PURE__ */ u("div", {
|
|
26
28
|
className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
|
|
27
29
|
children: "Failed to load reports data. Please try again later."
|
|
28
30
|
})
|
|
29
31
|
});
|
|
30
|
-
let
|
|
31
|
-
...
|
|
32
|
+
let w = [
|
|
33
|
+
...x ? [{
|
|
32
34
|
id: "time-summary",
|
|
33
35
|
name: "Time Tracking Summary",
|
|
34
36
|
type: "time",
|
|
35
|
-
period: `${Math.round(
|
|
37
|
+
period: `${Math.round(x.totalHours)}h total · ${x.totalEntries} entries`,
|
|
36
38
|
status: "ready"
|
|
37
39
|
}, {
|
|
38
40
|
id: "billable-summary",
|
|
39
41
|
name: "Billable Hours Report",
|
|
40
42
|
type: "billing",
|
|
41
|
-
period: `${Math.round(
|
|
43
|
+
period: `${Math.round(x.billableHours)}h billable · ${x.activeTimers} active`,
|
|
42
44
|
status: "ready"
|
|
43
45
|
}] : [],
|
|
44
|
-
...
|
|
46
|
+
...S ? [{
|
|
45
47
|
id: "work-pattern",
|
|
46
48
|
name: "Work Pattern Analysis",
|
|
47
49
|
type: "team",
|
|
48
|
-
period: `${
|
|
50
|
+
period: `${S.averageFocusHours.toFixed(1)}h avg focus · ${Math.round(S.averageProductivity)}% productivity`,
|
|
49
51
|
status: "ready"
|
|
50
52
|
}] : [],
|
|
51
|
-
...
|
|
53
|
+
...C ? [{
|
|
52
54
|
id: "focus-score",
|
|
53
55
|
name: "Focus Score Report",
|
|
54
56
|
type: "productivity",
|
|
55
|
-
period: `Avg: ${Math.round(
|
|
57
|
+
period: `Avg: ${Math.round(C.averageScore)} · High: ${Math.round(C.highestScore)} · Low: ${Math.round(C.lowestScore)}`,
|
|
56
58
|
status: "ready"
|
|
57
59
|
}] : []
|
|
58
60
|
];
|
|
59
|
-
return /* @__PURE__ */
|
|
61
|
+
return /* @__PURE__ */ u(a, {
|
|
60
62
|
title: "Reports",
|
|
61
63
|
description: "Generate and view time tracking reports",
|
|
62
|
-
|
|
64
|
+
purpose: "Package your tracked time into shareable, exportable reports — the deliverables you hand to clients for billing or to leadership for capacity and utilisation decisions.",
|
|
65
|
+
actions: /* @__PURE__ */ d("button", {
|
|
63
66
|
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",
|
|
64
|
-
children: [/* @__PURE__ */ l
|
|
67
|
+
children: [/* @__PURE__ */ u(l, { className: "h-4 w-4" }), "Generate Report"]
|
|
65
68
|
}),
|
|
66
|
-
children: /* @__PURE__ */
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
children: w.length === 0 ? /* @__PURE__ */ u(o, {
|
|
70
|
+
illustration: "empty-data",
|
|
71
|
+
title: "No report data available yet",
|
|
72
|
+
description: "Track some time first — once you have entries, focus scores or work patterns, ready-to-export reports appear here."
|
|
73
|
+
}) : /* @__PURE__ */ u(f, {
|
|
74
|
+
treatment: "glass",
|
|
75
|
+
glow: !0,
|
|
76
|
+
className: "overflow-hidden",
|
|
77
|
+
children: /* @__PURE__ */ u("div", {
|
|
69
78
|
className: "divide-y divide-border",
|
|
70
|
-
children:
|
|
71
|
-
className: "p-8 text-center text-sm text-text-secondary",
|
|
72
|
-
children: "No report data available yet."
|
|
73
|
-
}) : S.map((e) => /* @__PURE__ */ u("div", {
|
|
79
|
+
children: w.map((e) => /* @__PURE__ */ d("div", {
|
|
74
80
|
className: "flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors",
|
|
75
|
-
children: [/* @__PURE__ */
|
|
81
|
+
children: [/* @__PURE__ */ d("div", {
|
|
76
82
|
className: "flex items-center gap-3",
|
|
77
|
-
children: [/* @__PURE__ */
|
|
83
|
+
children: [/* @__PURE__ */ u(c, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("p", {
|
|
78
84
|
className: "text-sm font-medium text-text-primary",
|
|
79
85
|
children: e.name
|
|
80
|
-
}), /* @__PURE__ */
|
|
86
|
+
}), /* @__PURE__ */ u("p", {
|
|
81
87
|
className: "text-xs text-text-secondary",
|
|
82
88
|
children: e.period
|
|
83
89
|
})] })]
|
|
84
|
-
}), /* @__PURE__ */
|
|
90
|
+
}), /* @__PURE__ */ d("div", {
|
|
85
91
|
className: "flex items-center gap-3",
|
|
86
|
-
children: [/* @__PURE__ */
|
|
92
|
+
children: [/* @__PURE__ */ u("span", {
|
|
87
93
|
className: "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium bg-status-success-bg text-status-success-text",
|
|
88
94
|
children: e.status
|
|
89
|
-
}), /* @__PURE__ */
|
|
95
|
+
}), /* @__PURE__ */ u("button", {
|
|
90
96
|
className: "rounded-md p-1.5 hover:bg-bg-sunken",
|
|
91
|
-
children: /* @__PURE__ */
|
|
97
|
+
children: /* @__PURE__ */ u(s, { className: "h-4 w-4 text-text-secondary" })
|
|
92
98
|
})]
|
|
93
99
|
})]
|
|
94
100
|
}, e.id))
|
|
@@ -97,6 +103,6 @@ function d() {
|
|
|
97
103
|
});
|
|
98
104
|
}
|
|
99
105
|
//#endregion
|
|
100
|
-
export {
|
|
106
|
+
export { p as ReportsPage };
|
|
101
107
|
|
|
102
108
|
//# sourceMappingURL=ReportsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsPage.js","names":[],"sources":["../../../../src/timecampus/pages/dashboard/ReportsPage.tsx"],"sourcesContent":["import { FileText, Plus, Download } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useGetTimeEntryStatsQuery,\n useGetWorkPatternSummaryQuery,\n useGetFocusScoreSummaryQuery,\n} from \"@/generated/wspace-operations\";\n\nexport function ReportsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetTimeEntryStatsQuery({\n skip: !workspaceId,\n });\n\n const { data: patternData, loading: patternLoading } =\n useGetWorkPatternSummaryQuery({\n skip: !workspaceId,\n });\n\n const { data: focusData, loading: focusLoading } =\n useGetFocusScoreSummaryQuery({\n skip: !workspaceId,\n });\n\n const stats = statsData?.timeEntryStats;\n const pattern = patternData?.workPatternSummary;\n const focus = focusData?.focusScoreSummary;\n\n const isLoading = statsLoading || patternLoading || focusLoading;\n\n if (isLoading) {\n return (\n <PageLayout\n title=\"Reports\"\n description=\"Generate and view time tracking reports\"\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 Generate Report\n </button>\n }\n >\n <LoadingSkeleton variant=\"list\" count={4} />\n </PageLayout>\n );\n }\n\n if (statsError) {\n return (\n <PageLayout\n title=\"Reports\"\n description=\"Generate and view time tracking reports\"\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 reports data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n // Build dynamic reports from available analytics data\n const reports = [\n ...(stats\n ? [\n {\n id: \"time-summary\",\n name: \"Time Tracking Summary\",\n type: \"time\",\n period: `${Math.round(stats.totalHours)}h total · ${stats.totalEntries} entries`,\n status: \"ready\" as const,\n },\n {\n id: \"billable-summary\",\n name: \"Billable Hours Report\",\n type: \"billing\",\n period: `${Math.round(stats.billableHours)}h billable · ${stats.activeTimers} active`,\n status: \"ready\" as const,\n },\n ]\n : []),\n ...(pattern\n ? [\n {\n id: \"work-pattern\",\n name: \"Work Pattern Analysis\",\n type: \"team\",\n period: `${pattern.averageFocusHours.toFixed(1)}h avg focus · ${Math.round(pattern.averageProductivity)}% productivity`,\n status: \"ready\" as const,\n },\n ]\n : []),\n ...(focus\n ? [\n {\n id: \"focus-score\",\n name: \"Focus Score Report\",\n type: \"productivity\",\n period: `Avg: ${Math.round(focus.averageScore)} · High: ${Math.round(focus.highestScore)} · Low: ${Math.round(focus.lowestScore)}`,\n status: \"ready\" as const,\n },\n ]\n : []),\n ];\n\n return (\n <PageLayout\n title=\"Reports\"\n description=\"Generate and view time tracking reports\"\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 Generate Report\n </button>\n }\n >\n
|
|
1
|
+
{"version":3,"file":"ReportsPage.js","names":[],"sources":["../../../../src/timecampus/pages/dashboard/ReportsPage.tsx"],"sourcesContent":["import { FileText, Plus, Download } 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 { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useGetTimeEntryStatsQuery,\n useGetWorkPatternSummaryQuery,\n useGetFocusScoreSummaryQuery,\n} from \"@/generated/wspace-operations\";\n\nexport function ReportsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetTimeEntryStatsQuery({\n skip: !workspaceId,\n });\n\n const { data: patternData, loading: patternLoading } =\n useGetWorkPatternSummaryQuery({\n skip: !workspaceId,\n });\n\n const { data: focusData, loading: focusLoading } =\n useGetFocusScoreSummaryQuery({\n skip: !workspaceId,\n });\n\n const stats = statsData?.timeEntryStats;\n const pattern = patternData?.workPatternSummary;\n const focus = focusData?.focusScoreSummary;\n\n const isLoading = statsLoading || patternLoading || focusLoading;\n\n if (isLoading) {\n return (\n <PageLayout\n title=\"Reports\"\n description=\"Generate and view time tracking reports\"\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 Generate Report\n </button>\n }\n >\n <LoadingSkeleton variant=\"list\" count={4} />\n </PageLayout>\n );\n }\n\n if (statsError) {\n return (\n <PageLayout\n title=\"Reports\"\n description=\"Generate and view time tracking reports\"\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 reports data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n // Build dynamic reports from available analytics data\n const reports = [\n ...(stats\n ? [\n {\n id: \"time-summary\",\n name: \"Time Tracking Summary\",\n type: \"time\",\n period: `${Math.round(stats.totalHours)}h total · ${stats.totalEntries} entries`,\n status: \"ready\" as const,\n },\n {\n id: \"billable-summary\",\n name: \"Billable Hours Report\",\n type: \"billing\",\n period: `${Math.round(stats.billableHours)}h billable · ${stats.activeTimers} active`,\n status: \"ready\" as const,\n },\n ]\n : []),\n ...(pattern\n ? [\n {\n id: \"work-pattern\",\n name: \"Work Pattern Analysis\",\n type: \"team\",\n period: `${pattern.averageFocusHours.toFixed(1)}h avg focus · ${Math.round(pattern.averageProductivity)}% productivity`,\n status: \"ready\" as const,\n },\n ]\n : []),\n ...(focus\n ? [\n {\n id: \"focus-score\",\n name: \"Focus Score Report\",\n type: \"productivity\",\n period: `Avg: ${Math.round(focus.averageScore)} · High: ${Math.round(focus.highestScore)} · Low: ${Math.round(focus.lowestScore)}`,\n status: \"ready\" as const,\n },\n ]\n : []),\n ];\n\n return (\n <PageLayout\n title=\"Reports\"\n description=\"Generate and view time tracking reports\"\n purpose=\"Package your tracked time into shareable, exportable reports — the deliverables you hand to clients for billing or to leadership for capacity and utilisation decisions.\"\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 Generate Report\n </button>\n }\n >\n {reports.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No report data available yet\"\n description=\"Track some time first — once you have entries, focus scores or work patterns, ready-to-export reports appear here.\"\n />\n ) : (\n <GlassCard treatment=\"glass\" glow className=\"overflow-hidden\">\n <div className=\"divide-y divide-border\">\n {reports.map((report) => (\n <div\n key={report.id}\n className=\"flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <FileText className=\"h-5 w-5 text-text-secondary\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {report.name}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {report.period}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <span className=\"inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium bg-status-success-bg text-status-success-text\">\n {report.status}\n </span>\n <button className=\"rounded-md p-1.5 hover:bg-bg-sunken\">\n <Download className=\"h-4 w-4 text-text-secondary\" />\n </button>\n </div>\n </div>\n ))}\n </div>\n </GlassCard>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;AAYA,SAAgB,IAAc;CAC5B,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAA0B,EAC5B,MAAM,CAAC,GACR,CAAC,EAEI,EAAE,MAAM,GAAa,SAAS,MAClC,EAA8B,EAC5B,MAAM,CAAC,GACR,CAAC,EAEE,EAAE,MAAM,GAAW,SAAS,MAChC,EAA6B,EAC3B,MAAM,CAAC,GACR,CAAC,EAEE,IAAQ,GAAW,gBACnB,IAAU,GAAa,oBACvB,IAAQ,GAAW;AAIzB,KAFkB,KAAgB,KAAkB,EAGlD,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,kBAErB;;YAGX,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;CAKjB,IAAM,IAAU;EACd,GAAI,IACA,CACE;GACE,IAAI;GACJ,MAAM;GACN,MAAM;GACN,QAAQ,GAAG,KAAK,MAAM,EAAM,WAAW,CAAC,YAAY,EAAM,aAAa;GACvE,QAAQ;GACT,EACD;GACE,IAAI;GACJ,MAAM;GACN,MAAM;GACN,QAAQ,GAAG,KAAK,MAAM,EAAM,cAAc,CAAC,eAAe,EAAM,aAAa;GAC7E,QAAQ;GACT,CACF,GACD,EAAE;EACN,GAAI,IACA,CACE;GACE,IAAI;GACJ,MAAM;GACN,MAAM;GACN,QAAQ,GAAG,EAAQ,kBAAkB,QAAQ,EAAE,CAAC,gBAAgB,KAAK,MAAM,EAAQ,oBAAoB,CAAC;GACxG,QAAQ;GACT,CACF,GACD,EAAE;EACN,GAAI,IACA,CACE;GACE,IAAI;GACJ,MAAM;GACN,MAAM;GACN,QAAQ,QAAQ,KAAK,MAAM,EAAM,aAAa,CAAC,WAAW,KAAK,MAAM,EAAM,aAAa,CAAC,UAAU,KAAK,MAAM,EAAM,YAAY;GAChI,QAAQ;GACT,CACF,GACD,EAAE;EACP;AAED,QACE,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,EAAQ,WAAW,IAClB,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,CAAA,GAEF,kBAAC,GAAD;GAAW,WAAU;GAAQ,MAAA;GAAK,WAAU;aAC1C,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAQ,KAAK,MACZ,kBAAC,OAAD;KAEE,WAAU;eAFZ,CAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,+BAAgC,CAAA,EACpD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAO;OACN,CAAA,EACJ,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAO;OACN,CAAA,CACA,EAAA,CAAA,CACF;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAO;OACH,CAAA,EACP,kBAAC,UAAD;OAAQ,WAAU;iBAChB,kBAAC,GAAD,EAAU,WAAU,+BAAgC,CAAA;OAC7C,CAAA,CACL;QACF;OAtBC,EAAO,GAsBR,CACN;IACE,CAAA;GACI,CAAA;EAEH,CAAA"}
|
|
@@ -28,10 +28,12 @@ function u() {
|
|
|
28
28
|
return /* @__PURE__ */ l(i, {
|
|
29
29
|
title: "Email Analytics",
|
|
30
30
|
description: "Insights into email time management",
|
|
31
|
+
purpose: "Know exactly how much of your day email consumes and how fast you respond — so you can set realistic response targets, batch your inbox, and stop email from quietly running your schedule.",
|
|
31
32
|
children: [/* @__PURE__ */ l("div", {
|
|
32
33
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
33
34
|
children: [
|
|
34
35
|
/* @__PURE__ */ c(t, {
|
|
36
|
+
featured: !0,
|
|
35
37
|
title: "Emails Today",
|
|
36
38
|
value: b,
|
|
37
39
|
icon: /* @__PURE__ */ c(s, { className: "h-5 w-5" })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmailAnalyticsPage.js","names":[],"sources":["../../../../src/timecampus/pages/email-tracking/EmailAnalyticsPage.tsx"],"sourcesContent":["import { BarChart3, Mail, Clock } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport { useGetEmailTrackingStatsQuery } from \"@/generated/wspace-operations\";\n\nexport function EmailAnalyticsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const { data, loading, error } = useGetEmailTrackingStatsQuery({\n skip: !workspaceId,\n });\n\n const stats = data?.emailTrackingStats;\n\n if (loading) {\n return (\n <PageLayout\n title=\"Email Analytics\"\n description=\"Insights into email time management\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Email Analytics\"\n description=\"Insights into email time management\"\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 email analytics. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n const totalMinutes = Math.round((stats?.totalDuration ?? 0) / 60);\n const hours = Math.floor(totalMinutes / 60);\n const minutes = totalMinutes % 60;\n const timeOnEmail = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;\n const avgResponse =\n stats?.averageResponseTime != null\n ? `${Math.round(stats.averageResponseTime)} min`\n : \"--\";\n const totalEmails = String(stats?.totalEmails ?? 0);\n const importantRatio = stats?.totalEmails\n ? Math.round((stats.importantCount / stats.totalEmails) * 100)\n : 0;\n\n return (\n <PageLayout\n title=\"Email Analytics\"\n description=\"Insights into email time management\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n title=\"Emails Today\"\n value={totalEmails}\n icon={<Mail className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Time on Email\"\n value={timeOnEmail}\n icon={<Clock className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Avg. Response\"\n value={avgResponse}\n description=\"Target: 15 min\"\n />\n <StatCard\n title=\"Email Score\"\n value={`${importantRatio}%`}\n icon={<BarChart3 className=\"h-5 w-5\" />}\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 Email Volume & Response Time\n </h3>\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\">Chart will render here</p>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,IAAqB;CACnC,IAAM,EAAE,iBAAc,OAAO,GAAe,EACtC,EAAE,SAAM,YAAS,aAAU,EAA8B,EAC7D,MAAM,CAAC,GACR,CAAC,EAEI,IAAQ,GAAM;AAEpB,KAAI,EACF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA;AAIjB,KAAI,EACF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAA2G;GAEpH,CAAA;EACK,CAAA;CAIjB,IAAM,IAAe,KAAK,OAAO,GAAO,iBAAiB,KAAK,GAAG,EAC3D,IAAQ,KAAK,MAAM,IAAe,GAAG,EACrC,IAAU,IAAe,IACzB,IAAc,IAAQ,IAAI,GAAG,EAAM,IAAI,EAAQ,KAAK,GAAG,EAAQ,IAC/D,IACJ,GAAO,uBAAuB,OAE1B,OADA,GAAG,KAAK,MAAM,EAAM,oBAAoB,CAAC,OAEzC,IAAc,OAAO,GAAO,eAAe,EAAE,EAC7C,IAAiB,GAAO,cAC1B,KAAK,MAAO,EAAM,iBAAiB,EAAM,cAAe,IAAI,GAC5D;AAEJ,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;
|
|
1
|
+
{"version":3,"file":"EmailAnalyticsPage.js","names":[],"sources":["../../../../src/timecampus/pages/email-tracking/EmailAnalyticsPage.tsx"],"sourcesContent":["import { BarChart3, Mail, Clock } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport { useGetEmailTrackingStatsQuery } from \"@/generated/wspace-operations\";\n\nexport function EmailAnalyticsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const { data, loading, error } = useGetEmailTrackingStatsQuery({\n skip: !workspaceId,\n });\n\n const stats = data?.emailTrackingStats;\n\n if (loading) {\n return (\n <PageLayout\n title=\"Email Analytics\"\n description=\"Insights into email time management\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Email Analytics\"\n description=\"Insights into email time management\"\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 email analytics. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n const totalMinutes = Math.round((stats?.totalDuration ?? 0) / 60);\n const hours = Math.floor(totalMinutes / 60);\n const minutes = totalMinutes % 60;\n const timeOnEmail = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;\n const avgResponse =\n stats?.averageResponseTime != null\n ? `${Math.round(stats.averageResponseTime)} min`\n : \"--\";\n const totalEmails = String(stats?.totalEmails ?? 0);\n const importantRatio = stats?.totalEmails\n ? Math.round((stats.importantCount / stats.totalEmails) * 100)\n : 0;\n\n return (\n <PageLayout\n title=\"Email Analytics\"\n description=\"Insights into email time management\"\n purpose=\"Know exactly how much of your day email consumes and how fast you respond — so you can set realistic response targets, batch your inbox, and stop email from quietly running your schedule.\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n featured\n title=\"Emails Today\"\n value={totalEmails}\n icon={<Mail className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Time on Email\"\n value={timeOnEmail}\n icon={<Clock className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Avg. Response\"\n value={avgResponse}\n description=\"Target: 15 min\"\n />\n <StatCard\n title=\"Email Score\"\n value={`${importantRatio}%`}\n icon={<BarChart3 className=\"h-5 w-5\" />}\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 Email Volume & Response Time\n </h3>\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\">Chart will render here</p>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,IAAqB;CACnC,IAAM,EAAE,iBAAc,OAAO,GAAe,EACtC,EAAE,SAAM,YAAS,aAAU,EAA8B,EAC7D,MAAM,CAAC,GACR,CAAC,EAEI,IAAQ,GAAM;AAEpB,KAAI,EACF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA;AAIjB,KAAI,EACF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAA2G;GAEpH,CAAA;EACK,CAAA;CAIjB,IAAM,IAAe,KAAK,OAAO,GAAO,iBAAiB,KAAK,GAAG,EAC3D,IAAQ,KAAK,MAAM,IAAe,GAAG,EACrC,IAAU,IAAe,IACzB,IAAc,IAAQ,IAAI,GAAG,EAAM,IAAI,EAAQ,KAAK,GAAG,EAAQ,IAC/D,IACJ,GAAO,uBAAuB,OAE1B,OADA,GAAG,KAAK,MAAM,EAAM,oBAAoB,CAAC,OAEzC,IAAc,OAAO,GAAO,eAAe,EAAE,EAC7C,IAAiB,GAAO,cAC1B,KAAK,MAAO,EAAM,iBAAiB,EAAM,cAAe,IAAI,GAC5D;AAEJ,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;KACP,MAAM,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA;KAClC,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO;KACP,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO;KACP,aAAY;KACZ,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,GAAG,EAAe;KACzB,MAAM,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;KACvC,CAAA;IACE;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,MAAD;IAAI,WAAU;cAA+C;IAExD,CAAA,EACL,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,KAAD;KAAG,WAAU;eAA8B;KAA0B,CAAA;IACjE,CAAA,CACF;KACK"}
|
|
@@ -5,46 +5,47 @@ 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/email-tracking/EmailSettingsPage.tsx
|
|
9
|
-
var
|
|
10
|
+
var f = "timecampus.email.settings", p = {
|
|
10
11
|
autoTrack: !0,
|
|
11
12
|
categorizeByProject: !0,
|
|
12
13
|
responseTimeAlerts: !1
|
|
13
14
|
};
|
|
14
|
-
function
|
|
15
|
-
let { workspaceId:
|
|
15
|
+
function m() {
|
|
16
|
+
let { workspaceId: m = "" } = e(), { data: h, loading: g, error: _ } = n({
|
|
16
17
|
variables: {
|
|
17
18
|
scope: "WORKSPACE",
|
|
18
19
|
limit: 100
|
|
19
20
|
},
|
|
20
|
-
skip: !
|
|
21
|
-
}), [
|
|
21
|
+
skip: !m
|
|
22
|
+
}), [v, { loading: y }] = r(), [b, x] = s(p);
|
|
22
23
|
o(() => {
|
|
23
|
-
if (
|
|
24
|
-
let e =
|
|
24
|
+
if (h?.configurations) {
|
|
25
|
+
let e = h.configurations.find((e) => e.key === f);
|
|
25
26
|
if (e?.value) {
|
|
26
27
|
let t = e.value;
|
|
27
|
-
|
|
28
|
-
autoTrack: t.autoTrack ??
|
|
29
|
-
categorizeByProject: t.categorizeByProject ??
|
|
30
|
-
responseTimeAlerts: t.responseTimeAlerts ??
|
|
28
|
+
x({
|
|
29
|
+
autoTrack: t.autoTrack ?? p.autoTrack,
|
|
30
|
+
categorizeByProject: t.categorizeByProject ?? p.categorizeByProject,
|
|
31
|
+
responseTimeAlerts: t.responseTimeAlerts ?? p.responseTimeAlerts
|
|
31
32
|
});
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
|
-
}, [
|
|
35
|
-
let
|
|
36
|
-
await
|
|
37
|
-
key:
|
|
38
|
-
value:
|
|
35
|
+
}, [h]);
|
|
36
|
+
let S = a(async () => {
|
|
37
|
+
await v({ variables: { input: {
|
|
38
|
+
key: f,
|
|
39
|
+
value: b,
|
|
39
40
|
description: "Email tracking settings",
|
|
40
41
|
scope: "WORKSPACE"
|
|
41
42
|
} } });
|
|
42
|
-
}, [
|
|
43
|
-
return
|
|
43
|
+
}, [v, b]);
|
|
44
|
+
return g ? /* @__PURE__ */ l(i, {
|
|
44
45
|
title: "Email Settings",
|
|
45
46
|
description: "Configure email tracking preferences",
|
|
46
47
|
children: /* @__PURE__ */ l(t, { variant: "detail" })
|
|
47
|
-
}) :
|
|
48
|
+
}) : _ ? /* @__PURE__ */ l(i, {
|
|
48
49
|
title: "Email Settings",
|
|
49
50
|
description: "Configure email tracking preferences",
|
|
50
51
|
children: /* @__PURE__ */ l("div", {
|
|
@@ -54,10 +55,13 @@ function p() {
|
|
|
54
55
|
}) : /* @__PURE__ */ l(i, {
|
|
55
56
|
title: "Email Settings",
|
|
56
57
|
description: "Configure email tracking preferences",
|
|
58
|
+
purpose: "Control how email time is captured and attributed — auto-track reading and replies, tie messages to the right project, and get nudged about slow responses — so email effort shows up in your reports.",
|
|
57
59
|
children: /* @__PURE__ */ u("div", {
|
|
58
60
|
className: "mx-auto max-w-2xl space-y-6",
|
|
59
|
-
children: [/* @__PURE__ */ u(
|
|
60
|
-
|
|
61
|
+
children: [/* @__PURE__ */ u(d, {
|
|
62
|
+
treatment: "glass",
|
|
63
|
+
glow: !0,
|
|
64
|
+
className: "p-6",
|
|
61
65
|
children: [/* @__PURE__ */ u("h3", {
|
|
62
66
|
className: "mb-4 flex items-center gap-2 text-sm font-semibold text-text-primary",
|
|
63
67
|
children: [/* @__PURE__ */ l(c, { className: "h-4 w-4" }), "Tracking Configuration"]
|
|
@@ -74,8 +78,8 @@ function p() {
|
|
|
74
78
|
children: "Automatically track time spent reading and responding"
|
|
75
79
|
})] }), /* @__PURE__ */ l("input", {
|
|
76
80
|
type: "checkbox",
|
|
77
|
-
checked:
|
|
78
|
-
onChange: (e) =>
|
|
81
|
+
checked: b.autoTrack,
|
|
82
|
+
onChange: (e) => x((t) => ({
|
|
79
83
|
...t,
|
|
80
84
|
autoTrack: e.target.checked
|
|
81
85
|
})),
|
|
@@ -92,8 +96,8 @@ function p() {
|
|
|
92
96
|
children: "Link emails to projects automatically"
|
|
93
97
|
})] }), /* @__PURE__ */ l("input", {
|
|
94
98
|
type: "checkbox",
|
|
95
|
-
checked:
|
|
96
|
-
onChange: (e) =>
|
|
99
|
+
checked: b.categorizeByProject,
|
|
100
|
+
onChange: (e) => x((t) => ({
|
|
97
101
|
...t,
|
|
98
102
|
categorizeByProject: e.target.checked
|
|
99
103
|
})),
|
|
@@ -110,8 +114,8 @@ function p() {
|
|
|
110
114
|
children: "Notify when response time exceeds threshold"
|
|
111
115
|
})] }), /* @__PURE__ */ l("input", {
|
|
112
116
|
type: "checkbox",
|
|
113
|
-
checked:
|
|
114
|
-
onChange: (e) =>
|
|
117
|
+
checked: b.responseTimeAlerts,
|
|
118
|
+
onChange: (e) => x((t) => ({
|
|
115
119
|
...t,
|
|
116
120
|
responseTimeAlerts: e.target.checked
|
|
117
121
|
})),
|
|
@@ -123,16 +127,16 @@ function p() {
|
|
|
123
127
|
}), /* @__PURE__ */ l("div", {
|
|
124
128
|
className: "flex justify-end",
|
|
125
129
|
children: /* @__PURE__ */ l("button", {
|
|
126
|
-
onClick:
|
|
127
|
-
disabled:
|
|
130
|
+
onClick: S,
|
|
131
|
+
disabled: y,
|
|
128
132
|
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",
|
|
129
|
-
children:
|
|
133
|
+
children: y ? "Saving..." : "Save Settings"
|
|
130
134
|
})
|
|
131
135
|
})]
|
|
132
136
|
})
|
|
133
137
|
});
|
|
134
138
|
}
|
|
135
139
|
//#endregion
|
|
136
|
-
export {
|
|
140
|
+
export { m as EmailSettingsPage };
|
|
137
141
|
|
|
138
142
|
//# sourceMappingURL=EmailSettingsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmailSettingsPage.js","names":[],"sources":["../../../../src/timecampus/pages/email-tracking/EmailSettingsPage.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 EMAIL_SETTINGS_KEY = \"timecampus.email.settings\";\n\ninterface EmailSettings {\n autoTrack: boolean;\n categorizeByProject: boolean;\n responseTimeAlerts: boolean;\n}\n\nconst DEFAULT_SETTINGS: EmailSettings = {\n autoTrack: true,\n categorizeByProject: true,\n responseTimeAlerts: false,\n};\n\nexport function EmailSettingsPage() {\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<EmailSettings>(DEFAULT_SETTINGS);\n\n useEffect(() => {\n if (data?.configurations) {\n const emailConfig = data.configurations.find(\n (c: ConfigurationFieldsFragment) => c.key === EMAIL_SETTINGS_KEY,\n );\n if (emailConfig?.value) {\n const val = emailConfig.value as Partial<EmailSettings>;\n setSettings({\n autoTrack: val.autoTrack ?? DEFAULT_SETTINGS.autoTrack,\n categorizeByProject:\n val.categorizeByProject ?? DEFAULT_SETTINGS.categorizeByProject,\n responseTimeAlerts:\n val.responseTimeAlerts ?? DEFAULT_SETTINGS.responseTimeAlerts,\n });\n }\n }\n }, [data]);\n\n const handleSave = useCallback(async () => {\n await setConfiguration({\n variables: {\n input: {\n key: EMAIL_SETTINGS_KEY,\n value: settings as unknown as Record<string, unknown>,\n description: \"Email tracking settings\",\n scope: \"WORKSPACE\" as never,\n },\n },\n });\n }, [setConfiguration, settings]);\n\n if (loading) {\n return (\n <PageLayout\n title=\"Email Settings\"\n description=\"Configure email tracking preferences\"\n >\n <LoadingSkeleton variant=\"detail\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Email Settings\"\n description=\"Configure email 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=\"Email Settings\"\n description=\"Configure email tracking preferences\"\n >\n <div className=\"mx-auto max-w-2xl space-y-6\">\n <
|
|
1
|
+
{"version":3,"file":"EmailSettingsPage.js","names":[],"sources":["../../../../src/timecampus/pages/email-tracking/EmailSettingsPage.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 EMAIL_SETTINGS_KEY = \"timecampus.email.settings\";\n\ninterface EmailSettings {\n autoTrack: boolean;\n categorizeByProject: boolean;\n responseTimeAlerts: boolean;\n}\n\nconst DEFAULT_SETTINGS: EmailSettings = {\n autoTrack: true,\n categorizeByProject: true,\n responseTimeAlerts: false,\n};\n\nexport function EmailSettingsPage() {\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<EmailSettings>(DEFAULT_SETTINGS);\n\n useEffect(() => {\n if (data?.configurations) {\n const emailConfig = data.configurations.find(\n (c: ConfigurationFieldsFragment) => c.key === EMAIL_SETTINGS_KEY,\n );\n if (emailConfig?.value) {\n const val = emailConfig.value as Partial<EmailSettings>;\n setSettings({\n autoTrack: val.autoTrack ?? DEFAULT_SETTINGS.autoTrack,\n categorizeByProject:\n val.categorizeByProject ?? DEFAULT_SETTINGS.categorizeByProject,\n responseTimeAlerts:\n val.responseTimeAlerts ?? DEFAULT_SETTINGS.responseTimeAlerts,\n });\n }\n }\n }, [data]);\n\n const handleSave = useCallback(async () => {\n await setConfiguration({\n variables: {\n input: {\n key: EMAIL_SETTINGS_KEY,\n value: settings as unknown as Record<string, unknown>,\n description: \"Email tracking settings\",\n scope: \"WORKSPACE\" as never,\n },\n },\n });\n }, [setConfiguration, settings]);\n\n if (loading) {\n return (\n <PageLayout\n title=\"Email Settings\"\n description=\"Configure email tracking preferences\"\n >\n <LoadingSkeleton variant=\"detail\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Email Settings\"\n description=\"Configure email 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=\"Email Settings\"\n description=\"Configure email tracking preferences\"\n purpose=\"Control how email time is captured and attributed — auto-track reading and replies, tie messages to the right project, and get nudged about slow responses — so email effort shows up in your reports.\"\n >\n <div className=\"mx-auto max-w-2xl space-y-6\">\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <h3 className=\"mb-4 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <Settings className=\"h-4 w-4\" />\n Tracking Configuration\n </h3>\n <div className=\"space-y-3\">\n <label className=\"flex items-center justify-between\">\n <div>\n <span className=\"text-sm font-medium text-text-primary\">\n Auto-track emails\n </span>\n <p className=\"text-xs text-text-secondary\">\n Automatically track time spent reading and responding\n </p>\n </div>\n <input\n type=\"checkbox\"\n checked={settings.autoTrack}\n onChange={(e) =>\n setSettings((s) => ({ ...s, autoTrack: e.target.checked }))\n }\n className=\"h-4 w-4 rounded border-border-subtle\"\n />\n </label>\n <label className=\"flex items-center justify-between\">\n <div>\n <span className=\"text-sm font-medium text-text-primary\">\n Categorize by project\n </span>\n <p className=\"text-xs text-text-secondary\">\n Link emails to projects automatically\n </p>\n </div>\n <input\n type=\"checkbox\"\n checked={settings.categorizeByProject}\n onChange={(e) =>\n setSettings((s) => ({\n ...s,\n categorizeByProject: e.target.checked,\n }))\n }\n className=\"h-4 w-4 rounded border-border-subtle\"\n />\n </label>\n <label className=\"flex items-center justify-between\">\n <div>\n <span className=\"text-sm font-medium text-text-primary\">\n Response time alerts\n </span>\n <p className=\"text-xs text-text-secondary\">\n Notify when response time exceeds threshold\n </p>\n </div>\n <input\n type=\"checkbox\"\n checked={settings.responseTimeAlerts}\n onChange={(e) =>\n setSettings((s) => ({\n ...s,\n responseTimeAlerts: e.target.checked,\n }))\n }\n className=\"h-4 w-4 rounded border-border-subtle\"\n />\n </label>\n </div>\n </GlassCard>\n <div className=\"flex justify-end\">\n <button\n onClick={handleSave}\n disabled={saving}\n className=\"rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {saving ? \"Saving...\" : \"Save Settings\"}\n </button>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;AAYA,IAAM,IAAqB,6BAQrB,IAAkC;CACtC,WAAW;CACX,qBAAqB;CACrB,oBAAoB;CACrB;AAED,SAAgB,IAAoB;CAClC,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,IAAc,EAAK,eAAe,MACrC,MAAmC,EAAE,QAAQ,EAC/C;AACD,OAAI,GAAa,OAAO;IACtB,IAAM,IAAM,EAAY;AACxB,MAAY;KACV,WAAW,EAAI,aAAa,EAAiB;KAC7C,qBACE,EAAI,uBAAuB,EAAiB;KAC9C,oBACE,EAAI,sBAAsB,EAAiB;KAC9C,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,yBAE7B;QACL,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwC;QAEjD,CAAA,EACP,kBAAC,KAAD;QAAG,WAAU;kBAA8B;QAEvC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,SAAD;QACE,MAAK;QACL,SAAS,EAAS;QAClB,WAAW,MACT,GAAa,OAAO;SAAE,GAAG;SAAG,WAAW,EAAE,OAAO;SAAS,EAAE;QAE7D,WAAU;QACV,CAAA,CACI;;MACR,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwC;QAEjD,CAAA,EACP,kBAAC,KAAD;QAAG,WAAU;kBAA8B;QAEvC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,SAAD;QACE,MAAK;QACL,SAAS,EAAS;QAClB,WAAW,MACT,GAAa,OAAO;SAClB,GAAG;SACH,qBAAqB,EAAE,OAAO;SAC/B,EAAE;QAEL,WAAU;QACV,CAAA,CACI;;MACR,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAwC;QAEjD,CAAA,EACP,kBAAC,KAAD;QAAG,WAAU;kBAA8B;QAEvC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,SAAD;QACE,MAAK;QACL,SAAS,EAAS;QAClB,WAAW,MACT,GAAa,OAAO;SAClB,GAAG;SACH,oBAAoB,EAAE,OAAO;SAC9B,EAAE;QAEL,WAAU;QACV,CAAA,CACI;;MACJ;OACI;OACZ,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,UAAD;KACE,SAAS;KACT,UAAU;KACV,WAAU;eAET,IAAS,cAAc;KACjB,CAAA;IACL,CAAA,CACF;;EACK,CAAA"}
|