@burdenoff/microfe-timecampus 2026.624.1 → 2026.626.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/timecampus/components/EmptyState.js +14 -0
- package/dist/timecampus/components/EmptyState.js.map +1 -0
- package/dist/timecampus/components/ErrorBoundary.js +2 -2
- package/dist/timecampus/components/ErrorBoundary.js.map +1 -1
- package/dist/timecampus/components/LoadingSkeleton.js +1 -1
- package/dist/timecampus/components/LoadingSkeleton.js.map +1 -1
- package/dist/timecampus/components/PageLayout.js +26 -14
- package/dist/timecampus/components/PageLayout.js.map +1 -1
- package/dist/timecampus/components/StatCard.js +19 -16
- package/dist/timecampus/components/StatCard.js.map +1 -1
- package/dist/timecampus/pages/HomePage.js +169 -149
- package/dist/timecampus/pages/HomePage.js.map +1 -1
- package/dist/timecampus/pages/applets/AppletStorePage.js +38 -35
- package/dist/timecampus/pages/applets/AppletStorePage.js.map +1 -1
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js +42 -36
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +57 -53
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js +40 -36
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/channels/ChannelsPage.js +32 -29
- package/dist/timecampus/pages/channels/ChannelsPage.js.map +1 -1
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js +52 -44
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/AnalyticsPage.js +65 -38
- package/dist/timecampus/pages/dashboard/AnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/ReportsPage.js +47 -41
- package/dist/timecampus/pages/dashboard/ReportsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js +16 -14
- package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js +40 -36
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +34 -28
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +49 -41
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScorePage.js +66 -62
- package/dist/timecampus/pages/focus-score/FocusScorePage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js +37 -33
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingPage.js +37 -30
- package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js +35 -31
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +37 -34
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js +35 -31
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +45 -41
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js +17 -15
- package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js +36 -32
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js +120 -102
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingsPage.js +46 -36
- package/dist/timecampus/pages/meetings/MeetingsPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js +19 -17
- package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js +143 -112
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js +55 -51
- package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectCreatePage.js +32 -28
- package/dist/timecampus/pages/projects/ProjectCreatePage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectDetailPage.js +107 -76
- package/dist/timecampus/pages/projects/ProjectDetailPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectsPage.js +21 -17
- package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/TasksPage.js +44 -34
- package/dist/timecampus/pages/projects/TasksPage.js.map +1 -1
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +59 -55
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js +24 -20
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamMembersPage.js +47 -41
- package/dist/timecampus/pages/team/TeamMembersPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamPage.js +89 -59
- package/dist/timecampus/pages/team/TeamPage.js.map +1 -1
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js +47 -43
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js.map +1 -1
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js +39 -35
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js +24 -20
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateDetailPage.js +66 -48
- package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplatesPage.js +39 -36
- package/dist/timecampus/pages/templates/TemplatesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeEntriesPage.js +53 -44
- package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeTrackingPage.js +72 -71
- package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimerPage.js +100 -66
- package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +63 -59
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js +64 -46
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetsPage.js +44 -37
- package/dist/timecampus/pages/widgets/WidgetsPage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +18 -16
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js +40 -36
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/workflows/WorkflowsPage.js +47 -37
- package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,63 +1,67 @@
|
|
|
1
1
|
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { LoadingSkeleton as t } from "../../components/LoadingSkeleton.js";
|
|
3
|
+
import { useListConfigurationsQuery as n, useSetConfigurationMutation as r } from "../../../generated/wspace-operations.js";
|
|
4
|
+
import { PageLayout as i } from "../../components/PageLayout.js";
|
|
5
5
|
import { useCallback as a, useEffect as o, useState as s } from "react";
|
|
6
6
|
import { Settings as c } from "lucide-react";
|
|
7
7
|
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
8
|
+
import { GlassCard as d } from "@burdenoff/fe-libs/ui";
|
|
8
9
|
//#region src/timecampus/pages/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
|
-
children: /* @__PURE__ */ l(
|
|
47
|
-
}) :
|
|
47
|
+
children: /* @__PURE__ */ l(t, { variant: "detail" })
|
|
48
|
+
}) : _ ? /* @__PURE__ */ l(i, {
|
|
48
49
|
title: "Email Settings",
|
|
49
50
|
description: "Configure email tracking preferences",
|
|
50
51
|
children: /* @__PURE__ */ l("div", {
|
|
51
52
|
className: "rounded-xl border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
|
|
52
53
|
children: "Failed to load settings. Please try again later."
|
|
53
54
|
})
|
|
54
|
-
}) : /* @__PURE__ */ l(
|
|
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":"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"}
|
|
@@ -1,44 +1,50 @@
|
|
|
1
1
|
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
2
|
import { formatRelativeTime as t, getPriorityColor as n, getStatusColor as r } from "../../utils/helpers.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { LoadingSkeleton as i } from "../../components/LoadingSkeleton.js";
|
|
4
|
+
import { useListEmailTimeEntriesQuery as a } from "../../../generated/wspace-operations.js";
|
|
5
|
+
import { PageLayout as o } from "../../components/PageLayout.js";
|
|
6
|
+
import { EmptyState as s } from "../../components/EmptyState.js";
|
|
7
|
+
import { Filter as c, Mail as l } from "lucide-react";
|
|
8
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
9
|
+
import { GlassCard as f } from "@burdenoff/fe-libs/ui";
|
|
8
10
|
//#region src/timecampus/pages/email-tracking/EmailTrackingPage.tsx
|
|
9
|
-
function
|
|
10
|
-
let { workspaceId:
|
|
11
|
+
function p() {
|
|
12
|
+
let { workspaceId: p = "" } = e(), { data: m, loading: h, error: g } = a({
|
|
11
13
|
variables: { limit: 50 },
|
|
12
|
-
skip: !
|
|
13
|
-
}),
|
|
14
|
-
return /* @__PURE__ */
|
|
14
|
+
skip: !p
|
|
15
|
+
}), _ = m?.emailTimeEntries ?? [];
|
|
16
|
+
return /* @__PURE__ */ u(o, {
|
|
15
17
|
title: "Email Tracking",
|
|
16
18
|
description: "Track time spent on emails",
|
|
17
|
-
|
|
19
|
+
purpose: "Surface the hidden hours email steals from your day — every message linked to the time it took and the project it belonged to — so inbox work finally shows up in your timesheets and reports.",
|
|
20
|
+
actions: /* @__PURE__ */ d("button", {
|
|
18
21
|
className: "inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
|
|
19
|
-
children: [/* @__PURE__ */
|
|
22
|
+
children: [/* @__PURE__ */ u(c, { className: "h-4 w-4" }), "Filter"]
|
|
20
23
|
}),
|
|
21
|
-
children:
|
|
24
|
+
children: h ? /* @__PURE__ */ u(i, {
|
|
22
25
|
variant: "list",
|
|
23
26
|
count: 4
|
|
24
|
-
}) :
|
|
27
|
+
}) : g ? /* @__PURE__ */ u("div", {
|
|
25
28
|
className: "rounded-xl border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
|
|
26
29
|
children: "Failed to load email entries. Please try again later."
|
|
27
|
-
}) : /* @__PURE__ */
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
}) : _.length === 0 ? /* @__PURE__ */ u(s, {
|
|
31
|
+
illustration: "empty-notifications",
|
|
32
|
+
title: "No email entries found",
|
|
33
|
+
description: "Once email tracking is connected, the time you spend reading and replying shows up here."
|
|
34
|
+
}) : /* @__PURE__ */ u(f, {
|
|
35
|
+
treatment: "glass",
|
|
36
|
+
glow: !0,
|
|
37
|
+
className: "overflow-hidden",
|
|
38
|
+
children: /* @__PURE__ */ u("div", {
|
|
30
39
|
className: "divide-y divide-border",
|
|
31
|
-
children:
|
|
32
|
-
className: "p-8 text-center text-sm text-text-secondary",
|
|
33
|
-
children: "No email entries found."
|
|
34
|
-
}) : h.map((e) => /* @__PURE__ */ u("div", {
|
|
40
|
+
children: _.map((e) => /* @__PURE__ */ d("div", {
|
|
35
41
|
className: "flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors cursor-pointer",
|
|
36
|
-
children: [/* @__PURE__ */
|
|
42
|
+
children: [/* @__PURE__ */ d("div", {
|
|
37
43
|
className: "flex items-center gap-3",
|
|
38
|
-
children: [/* @__PURE__ */ l
|
|
44
|
+
children: [/* @__PURE__ */ u(l, { className: `h-5 w-5 ${e.isImportant ? "text-primary" : "text-text-secondary"}` }), /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("p", {
|
|
39
45
|
className: `text-sm ${e.isImportant ? "font-semibold text-text-primary" : "font-medium text-text-primary"}`,
|
|
40
46
|
children: e.subject ?? "(No subject)"
|
|
41
|
-
}), /* @__PURE__ */
|
|
47
|
+
}), /* @__PURE__ */ d("p", {
|
|
42
48
|
className: "text-xs text-text-secondary",
|
|
43
49
|
children: [
|
|
44
50
|
e.sender ?? "Unknown",
|
|
@@ -50,12 +56,12 @@ function d() {
|
|
|
50
56
|
"min"
|
|
51
57
|
]
|
|
52
58
|
})] })]
|
|
53
|
-
}), /* @__PURE__ */
|
|
59
|
+
}), /* @__PURE__ */ d("div", {
|
|
54
60
|
className: "flex items-center gap-2",
|
|
55
|
-
children: [/* @__PURE__ */
|
|
61
|
+
children: [/* @__PURE__ */ u("span", {
|
|
56
62
|
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${n(e.isImportant ? "high" : "low")}`,
|
|
57
63
|
children: e.isImportant ? "high" : "normal"
|
|
58
|
-
}), /* @__PURE__ */
|
|
64
|
+
}), /* @__PURE__ */ u("span", {
|
|
59
65
|
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${r(e.category ?? "active")}`,
|
|
60
66
|
children: e.category ?? "uncategorized"
|
|
61
67
|
})]
|
|
@@ -66,6 +72,6 @@ function d() {
|
|
|
66
72
|
});
|
|
67
73
|
}
|
|
68
74
|
//#endregion
|
|
69
|
-
export {
|
|
75
|
+
export { p as EmailTrackingPage };
|
|
70
76
|
|
|
71
77
|
//# sourceMappingURL=EmailTrackingPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmailTrackingPage.js","names":[],"sources":["../../../../src/timecampus/pages/email-tracking/EmailTrackingPage.tsx"],"sourcesContent":["import { Mail, Filter } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport {\n getStatusColor,\n getPriorityColor,\n formatRelativeTime,\n} from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListEmailTimeEntriesQuery,\n type EmailTimeEntryFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function EmailTrackingPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const { data, loading, error } = useListEmailTimeEntriesQuery({\n variables: { limit: 50 },\n skip: !workspaceId,\n });\n\n const emails = data?.emailTimeEntries ?? [];\n\n return (\n <PageLayout\n title=\"Email Tracking\"\n description=\"Track time spent on emails\"\n actions={\n <button className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\">\n <Filter className=\"h-4 w-4\" />\n Filter\n </button>\n }\n >\n {loading ? (\n <LoadingSkeleton variant=\"list\" count={4} />\n ) : error ? (\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 entries. Please try again later.\n </div>\n ) : (\n <
|
|
1
|
+
{"version":3,"file":"EmailTrackingPage.js","names":[],"sources":["../../../../src/timecampus/pages/email-tracking/EmailTrackingPage.tsx"],"sourcesContent":["import { Mail, Filter } 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 {\n getStatusColor,\n getPriorityColor,\n formatRelativeTime,\n} from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListEmailTimeEntriesQuery,\n type EmailTimeEntryFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function EmailTrackingPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const { data, loading, error } = useListEmailTimeEntriesQuery({\n variables: { limit: 50 },\n skip: !workspaceId,\n });\n\n const emails = data?.emailTimeEntries ?? [];\n\n return (\n <PageLayout\n title=\"Email Tracking\"\n description=\"Track time spent on emails\"\n purpose=\"Surface the hidden hours email steals from your day — every message linked to the time it took and the project it belonged to — so inbox work finally shows up in your timesheets and reports.\"\n actions={\n <button className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\">\n <Filter className=\"h-4 w-4\" />\n Filter\n </button>\n }\n >\n {loading ? (\n <LoadingSkeleton variant=\"list\" count={4} />\n ) : error ? (\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 entries. Please try again later.\n </div>\n ) : emails.length === 0 ? (\n <EmptyState\n illustration=\"empty-notifications\"\n title=\"No email entries found\"\n description=\"Once email tracking is connected, the time you spend reading and replying shows up here.\"\n />\n ) : (\n <GlassCard treatment=\"glass\" glow className=\"overflow-hidden\">\n <div className=\"divide-y divide-border\">\n {emails.map((email: EmailTimeEntryFieldsFragment) => (\n <div\n key={email.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 <Mail\n className={`h-5 w-5 ${email.isImportant ? \"text-primary\" : \"text-text-secondary\"}`}\n />\n <div>\n <p\n className={`text-sm ${email.isImportant ? \"font-semibold text-text-primary\" : \"font-medium text-text-primary\"}`}\n >\n {email.subject ?? \"(No subject)\"}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {email.sender ?? \"Unknown\"} ·{\" \"}\n {formatRelativeTime(email.date)} · ~\n {email.duration ?? 0}min\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${getPriorityColor(email.isImportant ? \"high\" : \"low\")}`}\n >\n {email.isImportant ? \"high\" : \"normal\"}\n </span>\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${getStatusColor(email.category ?? \"active\")}`}\n >\n {email.category ?? \"uncategorized\"}\n </span>\n </div>\n </div>\n ))}\n </div>\n </GlassCard>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;AAgBA,SAAgB,IAAoB;CAClC,IAAM,EAAE,iBAAc,OAAO,GAAe,EACtC,EAAE,SAAM,YAAS,aAAU,EAA6B;EAC5D,WAAW,EAAE,OAAO,IAAI;EACxB,MAAM,CAAC;EACR,CAAC,EAEI,IAAS,GAAM,oBAAoB,EAAE;AAE3C,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SAAQ;EACR,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA,EAAA,SAEvB;;YAGV,IACC,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA,GAC1C,IACF,kBAAC,OAAD;GAAK,WAAU;aAA2G;GAEpH,CAAA,GACJ,EAAO,WAAW,IACpB,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,EAAO,KAAK,MACX,kBAAC,OAAD;KAEE,WAAU;eAFZ,CAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EACE,WAAW,WAAW,EAAM,cAAc,iBAAiB,yBAC3D,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OACE,WAAW,WAAW,EAAM,cAAc,oCAAoC;iBAE7E,EAAM,WAAW;OAChB,CAAA,EACJ,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAM,UAAU;QAAU;QAAU;QACpC,EAAmB,EAAM,KAAK;QAAC;QAC/B,EAAM,YAAY;QAAE;QACnB;SACA,EAAA,CAAA,CACF;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OACE,WAAW,4DAA4D,EAAiB,EAAM,cAAc,SAAS,MAAM;iBAE1H,EAAM,cAAc,SAAS;OACzB,CAAA,EACP,kBAAC,QAAD;OACE,WAAW,4DAA4D,EAAe,EAAM,YAAY,SAAS;iBAEhH,EAAM,YAAY;OACd,CAAA,CACH;QACF;OAhCC,EAAM,GAgCP,CACN;IACE,CAAA;GACI,CAAA;EAEH,CAAA"}
|
|
@@ -1,75 +1,83 @@
|
|
|
1
1
|
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
2
|
import { formatCurrency as t, formatDate as n, getStatusColor as r } from "../../utils/helpers.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
3
|
+
import { StatCard as i } from "../../components/StatCard.js";
|
|
4
|
+
import { LoadingSkeleton as a } from "../../components/LoadingSkeleton.js";
|
|
5
|
+
import { useGetExpenseStatsQuery as o, useListExpensesQuery as s } from "../../../generated/wspace-operations.js";
|
|
6
|
+
import { PageLayout as c } from "../../components/PageLayout.js";
|
|
7
|
+
import { EmptyState as l } from "../../components/EmptyState.js";
|
|
8
|
+
import { DollarSign as u, Plus as d, Receipt as f } from "lucide-react";
|
|
9
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
9
10
|
//#region src/timecampus/pages/expense-tracking/ExpenseTrackingPage.tsx
|
|
10
|
-
function
|
|
11
|
-
let { workspaceId:
|
|
12
|
-
return
|
|
11
|
+
function h() {
|
|
12
|
+
let { workspaceId: h = "" } = e(), { data: g, loading: _, error: v } = s({ variables: { workspaceId: h } }), { data: y, loading: b, error: x } = o({ variables: { workspaceId: h } }), S = g?.expenses ?? [], C = y?.expenseStats;
|
|
13
|
+
return _ && b ? /* @__PURE__ */ p(c, {
|
|
13
14
|
title: "Expense Tracking",
|
|
14
15
|
description: "Track and manage work expenses",
|
|
15
|
-
children: /* @__PURE__ */
|
|
16
|
+
children: /* @__PURE__ */ p(a, {
|
|
16
17
|
variant: "list",
|
|
17
18
|
count: 4
|
|
18
19
|
})
|
|
19
|
-
}) :
|
|
20
|
+
}) : v && x ? /* @__PURE__ */ p(c, {
|
|
20
21
|
title: "Expense Tracking",
|
|
21
22
|
description: "Track and manage work expenses",
|
|
22
|
-
children: /* @__PURE__ */
|
|
23
|
-
className: "rounded-lg border border-
|
|
23
|
+
children: /* @__PURE__ */ p("div", {
|
|
24
|
+
className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
|
|
24
25
|
children: "Failed to load expense data. Please try again later."
|
|
25
26
|
})
|
|
26
|
-
}) : /* @__PURE__ */
|
|
27
|
+
}) : /* @__PURE__ */ m(c, {
|
|
27
28
|
title: "Expense Tracking",
|
|
28
29
|
description: "Track and manage work expenses",
|
|
29
|
-
|
|
30
|
+
purpose: "Capture project-related costs alongside the hours you log — receipts, categories and approvals in one place — so the bill you send a client reflects the full cost of the work, not just time.",
|
|
31
|
+
actions: /* @__PURE__ */ m("button", {
|
|
30
32
|
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",
|
|
31
|
-
children: [/* @__PURE__ */
|
|
33
|
+
children: [/* @__PURE__ */ p(d, { className: "h-4 w-4" }), "Add Expense"]
|
|
32
34
|
}),
|
|
33
|
-
children: [/* @__PURE__ */
|
|
35
|
+
children: [/* @__PURE__ */ m("div", {
|
|
34
36
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
35
37
|
children: [
|
|
36
|
-
/* @__PURE__ */
|
|
38
|
+
/* @__PURE__ */ p(i, {
|
|
39
|
+
featured: !0,
|
|
37
40
|
title: "Total This Month",
|
|
38
|
-
value: t(
|
|
39
|
-
icon: /* @__PURE__ */
|
|
41
|
+
value: t(C?.totalAmount ?? 0),
|
|
42
|
+
icon: /* @__PURE__ */ p(u, { className: "h-5 w-5" })
|
|
40
43
|
}),
|
|
41
|
-
/* @__PURE__ */
|
|
44
|
+
/* @__PURE__ */ p(i, {
|
|
42
45
|
title: "Pending",
|
|
43
|
-
value: String(
|
|
46
|
+
value: String(C?.pendingCount ?? 0),
|
|
44
47
|
description: "expenses awaiting approval"
|
|
45
48
|
}),
|
|
46
|
-
/* @__PURE__ */
|
|
49
|
+
/* @__PURE__ */ p(i, {
|
|
47
50
|
title: "Approved",
|
|
48
|
-
value: String(
|
|
51
|
+
value: String(C?.approvedCount ?? 0),
|
|
49
52
|
description: "expenses approved"
|
|
50
53
|
}),
|
|
51
|
-
/* @__PURE__ */
|
|
54
|
+
/* @__PURE__ */ p(i, {
|
|
52
55
|
title: "Average",
|
|
53
|
-
value: t(
|
|
54
|
-
icon: /* @__PURE__ */ f
|
|
56
|
+
value: t(C?.averageAmount ?? 0),
|
|
57
|
+
icon: /* @__PURE__ */ p(f, { className: "h-5 w-5" }),
|
|
55
58
|
description: "per expense"
|
|
56
59
|
})
|
|
57
60
|
]
|
|
58
|
-
}), /* @__PURE__ */
|
|
59
|
-
|
|
61
|
+
}), S.length === 0 && !_ ? /* @__PURE__ */ p(l, {
|
|
62
|
+
illustration: "empty-data",
|
|
63
|
+
title: "No expenses recorded yet",
|
|
64
|
+
description: "Add your first expense to track project costs and route them for approval.",
|
|
65
|
+
action: /* @__PURE__ */ m("button", {
|
|
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",
|
|
67
|
+
children: [/* @__PURE__ */ p(d, { className: "h-4 w-4" }), "Add Expense"]
|
|
68
|
+
})
|
|
69
|
+
}) : /* @__PURE__ */ p("div", {
|
|
70
|
+
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop",
|
|
60
71
|
children: /* @__PURE__ */ p("div", {
|
|
61
72
|
className: "divide-y divide-border",
|
|
62
|
-
children:
|
|
63
|
-
className: "p-4 text-center text-sm text-text-secondary",
|
|
64
|
-
children: "No expenses recorded yet."
|
|
65
|
-
}), x.map((e) => /* @__PURE__ */ p("div", {
|
|
73
|
+
children: S.map((e) => /* @__PURE__ */ m("div", {
|
|
66
74
|
className: "flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors",
|
|
67
|
-
children: [/* @__PURE__ */
|
|
75
|
+
children: [/* @__PURE__ */ m("div", {
|
|
68
76
|
className: "flex items-center gap-3",
|
|
69
|
-
children: [/* @__PURE__ */ f
|
|
77
|
+
children: [/* @__PURE__ */ p(f, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
|
|
70
78
|
className: "text-sm font-medium text-text-primary",
|
|
71
79
|
children: e.description ?? "Untitled expense"
|
|
72
|
-
}), /* @__PURE__ */
|
|
80
|
+
}), /* @__PURE__ */ m("p", {
|
|
73
81
|
className: "text-xs text-text-secondary",
|
|
74
82
|
children: [
|
|
75
83
|
e.category,
|
|
@@ -81,22 +89,22 @@ function m() {
|
|
|
81
89
|
n(e.date)
|
|
82
90
|
]
|
|
83
91
|
})] })]
|
|
84
|
-
}), /* @__PURE__ */
|
|
92
|
+
}), /* @__PURE__ */ m("div", {
|
|
85
93
|
className: "flex items-center gap-3",
|
|
86
|
-
children: [/* @__PURE__ */
|
|
94
|
+
children: [/* @__PURE__ */ p("p", {
|
|
87
95
|
className: "text-sm font-medium text-text-primary",
|
|
88
96
|
children: t(e.amount)
|
|
89
|
-
}), /* @__PURE__ */
|
|
97
|
+
}), /* @__PURE__ */ p("span", {
|
|
90
98
|
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${r(e.status)}`,
|
|
91
99
|
children: e.status
|
|
92
100
|
})]
|
|
93
101
|
})]
|
|
94
|
-
}, e.id))
|
|
102
|
+
}, e.id))
|
|
95
103
|
})
|
|
96
104
|
})]
|
|
97
105
|
});
|
|
98
106
|
}
|
|
99
107
|
//#endregion
|
|
100
|
-
export {
|
|
108
|
+
export { h as ExpenseTrackingPage };
|
|
101
109
|
|
|
102
110
|
//# sourceMappingURL=ExpenseTrackingPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpenseTrackingPage.js","names":[],"sources":["../../../../src/timecampus/pages/expense-tracking/ExpenseTrackingPage.tsx"],"sourcesContent":["import { Receipt, Plus, DollarSign } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport {\n getStatusColor,\n formatCurrency,\n formatDate,\n} from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListExpensesQuery,\n useGetExpenseStatsQuery,\n type ExpenseFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function ExpenseTrackingPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const {\n data: expensesData,\n loading: expensesLoading,\n error: expensesError,\n } = useListExpensesQuery({\n variables: { workspaceId },\n });\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetExpenseStatsQuery({\n variables: { workspaceId },\n });\n\n const expenses = expensesData?.expenses ?? [];\n const stats = statsData?.expenseStats;\n\n if (expensesLoading && statsLoading) {\n return (\n <PageLayout\n title=\"Expense Tracking\"\n description=\"Track and manage work expenses\"\n >\n <LoadingSkeleton variant=\"list\" count={4} />\n </PageLayout>\n );\n }\n\n if (expensesError && statsError) {\n return (\n <PageLayout\n title=\"Expense Tracking\"\n description=\"Track and manage work expenses\"\n >\n <div className=\"rounded-lg border border-
|
|
1
|
+
{"version":3,"file":"ExpenseTrackingPage.js","names":[],"sources":["../../../../src/timecampus/pages/expense-tracking/ExpenseTrackingPage.tsx"],"sourcesContent":["import { Receipt, Plus, DollarSign } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { EmptyState } from \"../../components/EmptyState\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport {\n getStatusColor,\n formatCurrency,\n formatDate,\n} from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListExpensesQuery,\n useGetExpenseStatsQuery,\n type ExpenseFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function ExpenseTrackingPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const {\n data: expensesData,\n loading: expensesLoading,\n error: expensesError,\n } = useListExpensesQuery({\n variables: { workspaceId },\n });\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetExpenseStatsQuery({\n variables: { workspaceId },\n });\n\n const expenses = expensesData?.expenses ?? [];\n const stats = statsData?.expenseStats;\n\n if (expensesLoading && statsLoading) {\n return (\n <PageLayout\n title=\"Expense Tracking\"\n description=\"Track and manage work expenses\"\n >\n <LoadingSkeleton variant=\"list\" count={4} />\n </PageLayout>\n );\n }\n\n if (expensesError && statsError) {\n return (\n <PageLayout\n title=\"Expense Tracking\"\n description=\"Track and manage work expenses\"\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 expense data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Expense Tracking\"\n description=\"Track and manage work expenses\"\n purpose=\"Capture project-related costs alongside the hours you log — receipts, categories and approvals in one place — so the bill you send a client reflects the full cost of the work, not just time.\"\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 Add Expense\n </button>\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=\"Total This Month\"\n value={formatCurrency(stats?.totalAmount ?? 0)}\n icon={<DollarSign className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Pending\"\n value={String(stats?.pendingCount ?? 0)}\n description=\"expenses awaiting approval\"\n />\n <StatCard\n title=\"Approved\"\n value={String(stats?.approvedCount ?? 0)}\n description=\"expenses approved\"\n />\n <StatCard\n title=\"Average\"\n value={formatCurrency(stats?.averageAmount ?? 0)}\n icon={<Receipt className=\"h-5 w-5\" />}\n description=\"per expense\"\n />\n </div>\n\n {expenses.length === 0 && !expensesLoading ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No expenses recorded yet\"\n description=\"Add your first expense to track project costs and route them for approval.\"\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 Add Expense\n </button>\n }\n />\n ) : (\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop\">\n <div className=\"divide-y divide-border\">\n {expenses.map((expense: ExpenseFieldsFragment) => (\n <div\n key={expense.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 <Receipt className=\"h-5 w-5 text-text-secondary\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {expense.description ?? \"Untitled expense\"}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {expense.category} ·{\" \"}\n {expense.projectId ?? \"No project\"} ·{\" \"}\n {formatDate(expense.date)}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <p className=\"text-sm font-medium text-text-primary\">\n {formatCurrency(expense.amount)}\n </p>\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${getStatusColor(expense.status)}`}\n >\n {expense.status}\n </span>\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;AAiBA,SAAgB,IAAsB;CACpC,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAAqB,EACvB,WAAW,EAAE,gBAAa,EAC3B,CAAC,EACI,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAAwB,EAC1B,WAAW,EAAE,gBAAa,EAC3B,CAAC,EAEI,IAAW,GAAc,YAAY,EAAE,EACvC,IAAQ,GAAW;AA0BzB,QAxBI,KAAmB,IAEnB,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA,GAIb,KAAiB,IAEjB,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAAoG;GAE7G,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SAAQ;EACR,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,cAErB;;YARb,CAWE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,UAAA;KACA,OAAM;KACN,OAAO,EAAe,GAAO,eAAe,EAAE;KAC9C,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;KACxC,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,OAAO,GAAO,gBAAgB,EAAE;KACvC,aAAY;KACZ,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,OAAO,GAAO,iBAAiB,EAAE;KACxC,aAAY;KACZ,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,EAAe,GAAO,iBAAiB,EAAE;KAChD,MAAM,kBAAC,GAAD,EAAS,WAAU,WAAY,CAAA;KACrC,aAAY;KACZ,CAAA;IACE;MAEL,EAAS,WAAW,KAAK,CAAC,IACzB,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,UAAD;IAAQ,WAAU;cAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,cAErB;;GAEX,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAS,KAAK,MACb,kBAAC,OAAD;KAEE,WAAU;eAFZ,CAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAS,WAAU,+BAAgC,CAAA,EACnD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAQ,eAAe;OACtB,CAAA,EACJ,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAQ;QAAS;QAAU;QAC3B,EAAQ,aAAa;QAAa;QAAU;QAC5C,EAAW,EAAQ,KAAK;QACvB;SACA,EAAA,CAAA,CACF;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAe,EAAQ,OAAO;OAC7B,CAAA,EACJ,kBAAC,QAAD;OACE,WAAW,4DAA4D,EAAe,EAAQ,OAAO;iBAEpG,EAAQ;OACJ,CAAA,CACH;QACF;OA1BC,EAAQ,GA0BT,CACN;IACE,CAAA;GACF,CAAA,CAEG"}
|