@burdenoff/microfe-timecampus 2026.624.1 → 2026.626.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/dist/timecampus/components/EmptyState.js +14 -0
  2. package/dist/timecampus/components/EmptyState.js.map +1 -0
  3. package/dist/timecampus/components/ErrorBoundary.js +2 -2
  4. package/dist/timecampus/components/ErrorBoundary.js.map +1 -1
  5. package/dist/timecampus/components/LoadingSkeleton.js +1 -1
  6. package/dist/timecampus/components/LoadingSkeleton.js.map +1 -1
  7. package/dist/timecampus/components/PageLayout.js +26 -14
  8. package/dist/timecampus/components/PageLayout.js.map +1 -1
  9. package/dist/timecampus/components/StatCard.js +19 -16
  10. package/dist/timecampus/components/StatCard.js.map +1 -1
  11. package/dist/timecampus/pages/HomePage.js +169 -149
  12. package/dist/timecampus/pages/HomePage.js.map +1 -1
  13. package/dist/timecampus/pages/applets/AppletStorePage.js +38 -35
  14. package/dist/timecampus/pages/applets/AppletStorePage.js.map +1 -1
  15. package/dist/timecampus/pages/applets/InstalledAppletsPage.js +42 -36
  16. package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +1 -1
  17. package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +57 -53
  18. package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
  19. package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js +40 -36
  20. package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js.map +1 -1
  21. package/dist/timecampus/pages/channels/ChannelsPage.js +32 -29
  22. package/dist/timecampus/pages/channels/ChannelsPage.js.map +1 -1
  23. package/dist/timecampus/pages/client-portal/ClientPortalPage.js +52 -44
  24. package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
  25. package/dist/timecampus/pages/dashboard/AnalyticsPage.js +65 -38
  26. package/dist/timecampus/pages/dashboard/AnalyticsPage.js.map +1 -1
  27. package/dist/timecampus/pages/dashboard/ReportsPage.js +47 -41
  28. package/dist/timecampus/pages/dashboard/ReportsPage.js.map +1 -1
  29. package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js +16 -14
  30. package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js.map +1 -1
  31. package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js +40 -36
  32. package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js.map +1 -1
  33. package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +34 -28
  34. package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js.map +1 -1
  35. package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +49 -41
  36. package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
  37. package/dist/timecampus/pages/focus-score/FocusScorePage.js +66 -62
  38. package/dist/timecampus/pages/focus-score/FocusScorePage.js.map +1 -1
  39. package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js +37 -33
  40. package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js.map +1 -1
  41. package/dist/timecampus/pages/geofencing/GeofencingPage.js +37 -30
  42. package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
  43. package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js +35 -31
  44. package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js.map +1 -1
  45. package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +37 -34
  46. package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +1 -1
  47. package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js +35 -31
  48. package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js.map +1 -1
  49. package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +45 -41
  50. package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
  51. package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js +17 -15
  52. package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js.map +1 -1
  53. package/dist/timecampus/pages/meetings/MeetingCreatePage.js +36 -32
  54. package/dist/timecampus/pages/meetings/MeetingCreatePage.js.map +1 -1
  55. package/dist/timecampus/pages/meetings/MeetingDetailPage.js +120 -102
  56. package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
  57. package/dist/timecampus/pages/meetings/MeetingsPage.js +46 -36
  58. package/dist/timecampus/pages/meetings/MeetingsPage.js.map +1 -1
  59. package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js +19 -17
  60. package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js.map +1 -1
  61. package/dist/timecampus/pages/pomodoro/PomodoroPage.js +143 -112
  62. package/dist/timecampus/pages/pomodoro/PomodoroPage.js.map +1 -1
  63. package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js +55 -51
  64. package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js.map +1 -1
  65. package/dist/timecampus/pages/projects/ProjectCreatePage.js +32 -28
  66. package/dist/timecampus/pages/projects/ProjectCreatePage.js.map +1 -1
  67. package/dist/timecampus/pages/projects/ProjectDetailPage.js +107 -76
  68. package/dist/timecampus/pages/projects/ProjectDetailPage.js.map +1 -1
  69. package/dist/timecampus/pages/projects/ProjectsPage.js +21 -17
  70. package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
  71. package/dist/timecampus/pages/projects/TasksPage.js +44 -34
  72. package/dist/timecampus/pages/projects/TasksPage.js.map +1 -1
  73. package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +59 -55
  74. package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
  75. package/dist/timecampus/pages/team/TeamAnalyticsPage.js +24 -20
  76. package/dist/timecampus/pages/team/TeamAnalyticsPage.js.map +1 -1
  77. package/dist/timecampus/pages/team/TeamMembersPage.js +47 -41
  78. package/dist/timecampus/pages/team/TeamMembersPage.js.map +1 -1
  79. package/dist/timecampus/pages/team/TeamPage.js +89 -59
  80. package/dist/timecampus/pages/team/TeamPage.js.map +1 -1
  81. package/dist/timecampus/pages/team-activity/TeamActivityPage.js +47 -43
  82. package/dist/timecampus/pages/team-activity/TeamActivityPage.js.map +1 -1
  83. package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js +39 -35
  84. package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js.map +1 -1
  85. package/dist/timecampus/pages/templates/TemplateApplicationPage.js +24 -20
  86. package/dist/timecampus/pages/templates/TemplateApplicationPage.js.map +1 -1
  87. package/dist/timecampus/pages/templates/TemplateDetailPage.js +66 -48
  88. package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +1 -1
  89. package/dist/timecampus/pages/templates/TemplatesPage.js +39 -36
  90. package/dist/timecampus/pages/templates/TemplatesPage.js.map +1 -1
  91. package/dist/timecampus/pages/time/TimeEntriesPage.js +53 -44
  92. package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
  93. package/dist/timecampus/pages/time/TimeTrackingPage.js +72 -71
  94. package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
  95. package/dist/timecampus/pages/time/TimerPage.js +100 -66
  96. package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
  97. package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +63 -59
  98. package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
  99. package/dist/timecampus/pages/widgets/WidgetDetailPage.js +64 -46
  100. package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +1 -1
  101. package/dist/timecampus/pages/widgets/WidgetsPage.js +44 -37
  102. package/dist/timecampus/pages/widgets/WidgetsPage.js.map +1 -1
  103. package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +18 -16
  104. package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
  105. package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js +40 -36
  106. package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js.map +1 -1
  107. package/dist/timecampus/pages/workflows/WorkflowsPage.js +47 -37
  108. package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +1 -1
  109. package/package.json +2 -2
@@ -1,63 +1,67 @@
1
1
  import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
2
- import { PageLayout as t } from "../../components/PageLayout.js";
3
- import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
4
- import { useListConfigurationsQuery as r, useSetConfigurationMutation as i } from "../../../generated/wspace-operations.js";
2
+ import { LoadingSkeleton as t } from "../../components/LoadingSkeleton.js";
3
+ import { useListConfigurationsQuery as n, useSetConfigurationMutation as r } from "../../../generated/wspace-operations.js";
4
+ import { PageLayout as i } from "../../components/PageLayout.js";
5
5
  import { useCallback as a, useEffect as o, useState as s } from "react";
6
6
  import { Settings as c } from "lucide-react";
7
7
  import { jsx as l, jsxs as u } from "react/jsx-runtime";
8
+ import { GlassCard as d } from "@burdenoff/fe-libs/ui";
8
9
  //#region src/timecampus/pages/email-tracking/EmailSettingsPage.tsx
9
- var d = "timecampus.email.settings", f = {
10
+ var f = "timecampus.email.settings", p = {
10
11
  autoTrack: !0,
11
12
  categorizeByProject: !0,
12
13
  responseTimeAlerts: !1
13
14
  };
14
- function p() {
15
- let { workspaceId: p = "" } = e(), { data: m, loading: h, error: g } = r({
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: !p
21
- }), [_, { loading: v }] = i(), [y, b] = s(f);
21
+ skip: !m
22
+ }), [v, { loading: y }] = r(), [b, x] = s(p);
22
23
  o(() => {
23
- if (m?.configurations) {
24
- let e = m.configurations.find((e) => e.key === d);
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
- b({
28
- autoTrack: t.autoTrack ?? f.autoTrack,
29
- categorizeByProject: t.categorizeByProject ?? f.categorizeByProject,
30
- responseTimeAlerts: t.responseTimeAlerts ?? f.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
- }, [m]);
35
- let x = a(async () => {
36
- await _({ variables: { input: {
37
- key: d,
38
- value: y,
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
- }, [_, y]);
43
- return h ? /* @__PURE__ */ l(t, {
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(n, { variant: "detail" })
47
- }) : g ? /* @__PURE__ */ l(t, {
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(t, {
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("div", {
60
- className: "rounded-xl border border-border-subtle bg-bg-surface p-6",
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: y.autoTrack,
78
- onChange: (e) => b((t) => ({
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: y.categorizeByProject,
96
- onChange: (e) => b((t) => ({
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: y.responseTimeAlerts,
114
- onChange: (e) => b((t) => ({
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: x,
127
- disabled: v,
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: v ? "Saving..." : "Save Settings"
133
+ children: y ? "Saving..." : "Save Settings"
130
134
  })
131
135
  })]
132
136
  })
133
137
  });
134
138
  }
135
139
  //#endregion
136
- export { p as EmailSettingsPage };
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 <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-6\">\n <h3 className=\"mb-4 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <Settings className=\"h-4 w-4\" />\n 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 </div>\n <div className=\"flex justify-end\">\n <button\n onClick={handleSave}\n disabled={saving}\n className=\"rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {saving ? \"Saving...\" : \"Save Settings\"}\n </button>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
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 { PageLayout as i } from "../../components/PageLayout.js";
4
- import { LoadingSkeleton as a } from "../../components/LoadingSkeleton.js";
5
- import { useListEmailTimeEntriesQuery as o } from "../../../generated/wspace-operations.js";
6
- import { Filter as s, Mail as c } from "lucide-react";
7
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
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 d() {
10
- let { workspaceId: d = "" } = e(), { data: f, loading: p, error: m } = o({
11
+ function p() {
12
+ let { workspaceId: p = "" } = e(), { data: m, loading: h, error: g } = a({
11
13
  variables: { limit: 50 },
12
- skip: !d
13
- }), h = f?.emailTimeEntries ?? [];
14
- return /* @__PURE__ */ l(i, {
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
- actions: /* @__PURE__ */ u("button", {
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__ */ l(s, { className: "h-4 w-4" }), "Filter"]
22
+ children: [/* @__PURE__ */ u(c, { className: "h-4 w-4" }), "Filter"]
20
23
  }),
21
- children: p ? /* @__PURE__ */ l(a, {
24
+ children: h ? /* @__PURE__ */ u(i, {
22
25
  variant: "list",
23
26
  count: 4
24
- }) : m ? /* @__PURE__ */ l("div", {
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__ */ l("div", {
28
- className: "rounded-xl border border-border-subtle bg-bg-surface",
29
- children: /* @__PURE__ */ l("div", {
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: h.length === 0 ? /* @__PURE__ */ l("div", {
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__ */ u("div", {
42
+ children: [/* @__PURE__ */ d("div", {
37
43
  className: "flex items-center gap-3",
38
- children: [/* @__PURE__ */ l(c, { className: `h-5 w-5 ${e.isImportant ? "text-primary" : "text-text-secondary"}` }), /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("p", {
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__ */ u("p", {
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__ */ u("div", {
59
+ }), /* @__PURE__ */ d("div", {
54
60
  className: "flex items-center gap-2",
55
- children: [/* @__PURE__ */ l("span", {
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__ */ l("span", {
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 { d as EmailTrackingPage };
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 <div className=\"rounded-xl border border-border-subtle bg-bg-surface\">\n <div className=\"divide-y divide-border\">\n {emails.length === 0 ? (\n <div className=\"p-8 text-center text-sm text-text-secondary\">\n No email entries found.\n </div>\n ) : (\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\"} &middot;{\" \"}\n {formatRelativeTime(email.date)} &middot; ~\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 )}\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAcA,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,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,GAEN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAO,WAAW,IACjB,kBAAC,OAAD;KAAK,WAAU;eAA8C;KAEvD,CAAA,GAEN,EAAO,KAAK,MACV,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;IAEA,CAAA;GACF,CAAA;EAEG,CAAA"}
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\"} &middot;{\" \"}\n {formatRelativeTime(email.date)} &middot; ~\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 { PageLayout as i } from "../../components/PageLayout.js";
4
- import { StatCard as a } from "../../components/StatCard.js";
5
- import { LoadingSkeleton as o } from "../../components/LoadingSkeleton.js";
6
- import { useGetExpenseStatsQuery as s, useListExpensesQuery as c } from "../../../generated/wspace-operations.js";
7
- import { DollarSign as l, Plus as u, Receipt as d } from "lucide-react";
8
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
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 m() {
11
- let { workspaceId: m = "" } = e(), { data: h, loading: g, error: _ } = c({ variables: { workspaceId: m } }), { data: v, loading: y, error: b } = s({ variables: { workspaceId: m } }), x = h?.expenses ?? [], S = v?.expenseStats;
12
- return g && y ? /* @__PURE__ */ f(i, {
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__ */ f(o, {
16
+ children: /* @__PURE__ */ p(a, {
16
17
  variant: "list",
17
18
  count: 4
18
19
  })
19
- }) : _ && b ? /* @__PURE__ */ f(i, {
20
+ }) : v && x ? /* @__PURE__ */ p(c, {
20
21
  title: "Expense Tracking",
21
22
  description: "Track and manage work expenses",
22
- children: /* @__PURE__ */ f("div", {
23
- className: "rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-600 dark:border-red-800 dark:bg-red-900/20 dark:text-red-400",
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__ */ p(i, {
27
+ }) : /* @__PURE__ */ m(c, {
27
28
  title: "Expense Tracking",
28
29
  description: "Track and manage work expenses",
29
- actions: /* @__PURE__ */ p("button", {
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__ */ f(u, { className: "h-4 w-4" }), "Add Expense"]
33
+ children: [/* @__PURE__ */ p(d, { className: "h-4 w-4" }), "Add Expense"]
32
34
  }),
33
- children: [/* @__PURE__ */ p("div", {
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__ */ f(a, {
38
+ /* @__PURE__ */ p(i, {
39
+ featured: !0,
37
40
  title: "Total This Month",
38
- value: t(S?.totalAmount ?? 0),
39
- icon: /* @__PURE__ */ f(l, { className: "h-5 w-5" })
41
+ value: t(C?.totalAmount ?? 0),
42
+ icon: /* @__PURE__ */ p(u, { className: "h-5 w-5" })
40
43
  }),
41
- /* @__PURE__ */ f(a, {
44
+ /* @__PURE__ */ p(i, {
42
45
  title: "Pending",
43
- value: String(S?.pendingCount ?? 0),
46
+ value: String(C?.pendingCount ?? 0),
44
47
  description: "expenses awaiting approval"
45
48
  }),
46
- /* @__PURE__ */ f(a, {
49
+ /* @__PURE__ */ p(i, {
47
50
  title: "Approved",
48
- value: String(S?.approvedCount ?? 0),
51
+ value: String(C?.approvedCount ?? 0),
49
52
  description: "expenses approved"
50
53
  }),
51
- /* @__PURE__ */ f(a, {
54
+ /* @__PURE__ */ p(i, {
52
55
  title: "Average",
53
- value: t(S?.averageAmount ?? 0),
54
- icon: /* @__PURE__ */ f(d, { className: "h-5 w-5" }),
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__ */ f("div", {
59
- className: "rounded-xl border border-border-subtle bg-bg-surface",
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: [x.length === 0 && !g && /* @__PURE__ */ f("div", {
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__ */ p("div", {
75
+ children: [/* @__PURE__ */ m("div", {
68
76
  className: "flex items-center gap-3",
69
- children: [/* @__PURE__ */ f(d, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
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__ */ p("p", {
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__ */ p("div", {
92
+ }), /* @__PURE__ */ m("div", {
85
93
  className: "flex items-center gap-3",
86
- children: [/* @__PURE__ */ f("p", {
94
+ children: [/* @__PURE__ */ p("p", {
87
95
  className: "text-sm font-medium text-text-primary",
88
96
  children: t(e.amount)
89
- }), /* @__PURE__ */ f("span", {
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 { m as ExpenseTrackingPage };
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-red-200 bg-red-50 p-4 text-sm text-red-600 dark:border-red-800 dark:bg-red-900/20 dark:text-red-400\">\n Failed to load 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 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 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 <div className=\"rounded-xl border border-border-subtle bg-bg-surface\">\n <div className=\"divide-y divide-border\">\n {expenses.length === 0 && !expensesLoading && (\n <div className=\"p-4 text-center text-sm text-text-secondary\">\n No expenses recorded yet.\n </div>\n )}\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} &middot;{\" \"}\n {expense.projectId ?? \"No project\"} &middot;{\" \"}\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 </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;AAgBA,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;aAA+H;GAExI,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,cAErB;;YAPb,CAUE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,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;MAEN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAS,WAAW,KAAK,CAAC,KACzB,kBAAC,OAAD;KAAK,WAAU;eAA8C;KAEvD,CAAA,EAEP,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,CACE;;GACF,CAAA,CACK"}
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} &middot;{\" \"}\n {expense.projectId ?? \"No project\"} &middot;{\" \"}\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"}