@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,45 +1,58 @@
1
1
  import { getPriorityColor as e, getStatusColor as t } from "../../utils/helpers.js";
2
- import { PageLayout as n } from "../../components/PageLayout.js";
3
- import { LoadingSkeleton as r } from "../../components/LoadingSkeleton.js";
4
- import { useListTasksQuery as i } from "../../../generated/wspace-operations.js";
5
- import { CheckSquare as a, Plus as o } from "lucide-react";
6
- import { useParams as s } from "react-router-dom";
7
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
2
+ import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
3
+ import { useListTasksQuery as r } from "../../../generated/wspace-operations.js";
4
+ import { PageLayout as i } from "../../components/PageLayout.js";
5
+ import { EmptyState as a } from "../../components/EmptyState.js";
6
+ import { CheckSquare as o, Plus as s } from "lucide-react";
7
+ import { useParams as c } from "react-router-dom";
8
+ import { jsx as l, jsxs as u } from "react/jsx-runtime";
9
+ import { GlassCard as d } from "@burdenoff/fe-libs/ui";
8
10
  //#region src/timecampus/pages/projects/TasksPage.tsx
9
- function u() {
10
- let { projectId: u } = s(), { data: d, loading: f, error: p } = i({
11
- variables: { projectId: u },
12
- skip: !u
13
- }), m = d?.tasks?.items ?? [];
14
- return p ? /* @__PURE__ */ c(n, {
11
+ function f() {
12
+ let { projectId: f } = c(), { data: p, loading: m, error: h } = r({
13
+ variables: { projectId: f },
14
+ skip: !f
15
+ }), g = p?.tasks?.items ?? [];
16
+ return h ? /* @__PURE__ */ l(i, {
15
17
  title: "Tasks",
16
- description: `Tasks for project ${u}`,
17
- children: /* @__PURE__ */ c("div", {
18
- className: "rounded-xl border border-red-200 bg-red-50 p-6 text-sm text-red-700 dark:border-red-900 dark:bg-red-950/50 dark:text-red-400",
18
+ description: `Tasks for project ${f}`,
19
+ children: /* @__PURE__ */ l("div", {
20
+ className: "rounded-xl border border-status-error-bg/40 bg-status-error-bg p-6 text-sm text-status-error-text",
19
21
  children: "Failed to load tasks. Please try again later."
20
22
  })
21
- }) : /* @__PURE__ */ c(n, {
23
+ }) : /* @__PURE__ */ l(i, {
22
24
  title: "Tasks",
23
- description: `Tasks for project ${u}`,
24
- actions: /* @__PURE__ */ l("button", {
25
+ description: `Tasks for project ${f}`,
26
+ purpose: "Break a project down into the concrete pieces of work that need doing, then track hours against each one — so you can see what's done, what's blocking, and where effort is actually being spent.",
27
+ actions: /* @__PURE__ */ u("button", {
25
28
  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",
26
- children: [/* @__PURE__ */ c(o, { className: "h-4 w-4" }), "Add Task"]
29
+ children: [/* @__PURE__ */ l(s, { className: "h-4 w-4" }), "Add Task"]
27
30
  }),
28
- children: f ? /* @__PURE__ */ c(r, {
31
+ children: m ? /* @__PURE__ */ l(n, {
29
32
  variant: "list",
30
33
  count: 5
31
- }) : /* @__PURE__ */ c("div", {
32
- className: "rounded-xl border border-border-subtle bg-bg-surface",
34
+ }) : g.length === 0 ? /* @__PURE__ */ l(a, {
35
+ illustration: "empty-generic",
36
+ title: "No tasks yet",
37
+ description: "Add a task to break this project into trackable work.",
38
+ action: /* @__PURE__ */ u("button", {
39
+ className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
40
+ children: [/* @__PURE__ */ l(s, { className: "h-4 w-4" }), "Add Task"]
41
+ })
42
+ }) : /* @__PURE__ */ l(d, {
43
+ treatment: "glass",
44
+ glow: !0,
45
+ className: "overflow-hidden",
33
46
  children: /* @__PURE__ */ l("div", {
34
47
  className: "divide-y divide-border",
35
- children: [m.map((n) => /* @__PURE__ */ l("div", {
48
+ children: g.map((n) => /* @__PURE__ */ u("div", {
36
49
  className: "flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors",
37
- children: [/* @__PURE__ */ l("div", {
50
+ children: [/* @__PURE__ */ u("div", {
38
51
  className: "flex items-center gap-3",
39
- children: [/* @__PURE__ */ c(a, { className: `h-5 w-5 ${n.status === "done" ? "text-emerald-500" : "text-text-secondary"}` }), /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("p", {
52
+ children: [/* @__PURE__ */ l(o, { className: `h-5 w-5 ${n.status === "done" ? "text-status-success-text" : "text-text-secondary"}` }), /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("p", {
40
53
  className: `text-sm font-medium ${n.status === "done" ? "text-text-secondary line-through" : "text-text-primary"}`,
41
54
  children: n.title
42
- }), /* @__PURE__ */ l("p", {
55
+ }), /* @__PURE__ */ u("p", {
43
56
  className: "text-xs text-text-secondary",
44
57
  children: [
45
58
  n.assigneeId ?? "Unassigned",
@@ -49,25 +62,22 @@ function u() {
49
62
  "h tracked"
50
63
  ]
51
64
  })] })]
52
- }), /* @__PURE__ */ l("div", {
65
+ }), /* @__PURE__ */ u("div", {
53
66
  className: "flex items-center gap-2",
54
- children: [/* @__PURE__ */ c("span", {
67
+ children: [/* @__PURE__ */ l("span", {
55
68
  className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${e(n.priority)}`,
56
69
  children: n.priority
57
- }), /* @__PURE__ */ c("span", {
70
+ }), /* @__PURE__ */ l("span", {
58
71
  className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${t(n.status)}`,
59
72
  children: n.status
60
73
  })]
61
74
  })]
62
- }, n.id)), m.length === 0 && /* @__PURE__ */ c("div", {
63
- className: "p-8 text-center text-sm text-text-secondary",
64
- children: "No tasks yet. Add a task to get started."
65
- })]
75
+ }, n.id))
66
76
  })
67
77
  })
68
78
  });
69
79
  }
70
80
  //#endregion
71
- export { u as TasksPage };
81
+ export { f as TasksPage };
72
82
 
73
83
  //# sourceMappingURL=TasksPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TasksPage.js","names":[],"sources":["../../../../src/timecampus/pages/projects/TasksPage.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\";\nimport { Plus, CheckSquare } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { getStatusColor, getPriorityColor } from \"../../utils/helpers\";\nimport {\n useListTasksQuery,\n type TaskFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function TasksPage() {\n const { projectId } = useParams<{ projectId: string }>();\n\n const { data, loading, error } = useListTasksQuery({\n variables: { projectId: projectId! },\n skip: !projectId,\n });\n\n const tasks = data?.tasks?.items ?? [];\n\n if (error) {\n return (\n <PageLayout title=\"Tasks\" description={`Tasks for project ${projectId}`}>\n <div className=\"rounded-xl border border-red-200 bg-red-50 p-6 text-sm text-red-700 dark:border-red-900 dark:bg-red-950/50 dark:text-red-400\">\n Failed to load tasks. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Tasks\"\n description={`Tasks for project ${projectId}`}\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 Task\n </button>\n }\n >\n {loading ? (\n <LoadingSkeleton variant=\"list\" count={5} />\n ) : (\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface\">\n <div className=\"divide-y divide-border\">\n {tasks.map((task: TaskFieldsFragment) => (\n <div\n key={task.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 <CheckSquare\n className={`h-5 w-5 ${task.status === \"done\" ? \"text-emerald-500\" : \"text-text-secondary\"}`}\n />\n <div>\n <p\n className={`text-sm font-medium ${task.status === \"done\" ? \"text-text-secondary line-through\" : \"text-text-primary\"}`}\n >\n {task.title}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {task.assigneeId ?? \"Unassigned\"} &middot;{\" \"}\n {task.trackedHours}h tracked\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(task.priority)}`}\n >\n {task.priority}\n </span>\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${getStatusColor(task.status)}`}\n >\n {task.status}\n </span>\n </div>\n </div>\n ))}\n {tasks.length === 0 && (\n <div className=\"p-8 text-center text-sm text-text-secondary\">\n No tasks yet. Add a task to get started.\n </div>\n )}\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAUA,SAAgB,IAAY;CAC1B,IAAM,EAAE,iBAAc,GAAkC,EAElD,EAAE,SAAM,YAAS,aAAU,EAAkB;EACjD,WAAW,EAAa,cAAY;EACpC,MAAM,CAAC;EACR,CAAC,EAEI,IAAQ,GAAM,OAAO,SAAS,EAAE;AAYtC,QAVI,IAEA,kBAAC,GAAD;EAAY,OAAM;EAAQ,aAAa,qBAAqB;YAC1D,kBAAC,OAAD;GAAK,WAAU;aAA+H;GAExI,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAa,qBAAqB;EAClC,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,WAErB;;YAGV,IACC,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA,GAE5C,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAM,KAAK,MACV,kBAAC,OAAD;KAEE,WAAU;eAFZ,CAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EACE,WAAW,WAAW,EAAK,WAAW,SAAS,qBAAqB,yBACpE,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OACE,WAAW,uBAAuB,EAAK,WAAW,SAAS,qCAAqC;iBAE/F,EAAK;OACJ,CAAA,EACJ,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAK,cAAc;QAAa;QAAU;QAC1C,EAAK;QAAa;QACjB;SACA,EAAA,CAAA,CACF;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OACE,WAAW,4DAA4D,EAAiB,EAAK,SAAS;iBAErG,EAAK;OACD,CAAA,EACP,kBAAC,QAAD;OACE,WAAW,4DAA4D,EAAe,EAAK,OAAO;iBAEjG,EAAK;OACD,CAAA,CACH;QACF;OA/BC,EAAK,GA+BN,CACN,EACD,EAAM,WAAW,KAChB,kBAAC,OAAD;KAAK,WAAU;eAA8C;KAEvD,CAAA,CAEJ;;GACF,CAAA;EAEG,CAAA"}
1
+ {"version":3,"file":"TasksPage.js","names":[],"sources":["../../../../src/timecampus/pages/projects/TasksPage.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\";\nimport { Plus, CheckSquare } 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 { getStatusColor, getPriorityColor } from \"../../utils/helpers\";\nimport {\n useListTasksQuery,\n type TaskFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function TasksPage() {\n const { projectId } = useParams<{ projectId: string }>();\n\n const { data, loading, error } = useListTasksQuery({\n variables: { projectId: projectId! },\n skip: !projectId,\n });\n\n const tasks = data?.tasks?.items ?? [];\n\n if (error) {\n return (\n <PageLayout title=\"Tasks\" description={`Tasks for project ${projectId}`}>\n <div className=\"rounded-xl border border-status-error-bg/40 bg-status-error-bg p-6 text-sm text-status-error-text\">\n Failed to load tasks. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Tasks\"\n description={`Tasks for project ${projectId}`}\n purpose=\"Break a project down into the concrete pieces of work that need doing, then track hours against each one — so you can see what's done, what's blocking, and where effort is actually being spent.\"\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 Task\n </button>\n }\n >\n {loading ? (\n <LoadingSkeleton variant=\"list\" count={5} />\n ) : tasks.length === 0 ? (\n <EmptyState\n illustration=\"empty-generic\"\n title=\"No tasks yet\"\n description=\"Add a task to break this project into trackable work.\"\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 Task\n </button>\n }\n />\n ) : (\n <GlassCard treatment=\"glass\" glow className=\"overflow-hidden\">\n <div className=\"divide-y divide-border\">\n {tasks.map((task: TaskFieldsFragment) => (\n <div\n key={task.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 <CheckSquare\n className={`h-5 w-5 ${task.status === \"done\" ? \"text-status-success-text\" : \"text-text-secondary\"}`}\n />\n <div>\n <p\n className={`text-sm font-medium ${task.status === \"done\" ? \"text-text-secondary line-through\" : \"text-text-primary\"}`}\n >\n {task.title}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {task.assigneeId ?? \"Unassigned\"} &middot;{\" \"}\n {task.trackedHours}h tracked\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(task.priority)}`}\n >\n {task.priority}\n </span>\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${getStatusColor(task.status)}`}\n >\n {task.status}\n </span>\n </div>\n </div>\n ))}\n </div>\n </GlassCard>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;AAYA,SAAgB,IAAY;CAC1B,IAAM,EAAE,iBAAc,GAAkC,EAElD,EAAE,SAAM,YAAS,aAAU,EAAkB;EACjD,WAAW,EAAa,cAAY;EACpC,MAAM,CAAC;EACR,CAAC,EAEI,IAAQ,GAAM,OAAO,SAAS,EAAE;AAYtC,QAVI,IAEA,kBAAC,GAAD;EAAY,OAAM;EAAQ,aAAa,qBAAqB;YAC1D,kBAAC,OAAD;GAAK,WAAU;aAAoG;GAE7G,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAa,qBAAqB;EAClC,SAAQ;EACR,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,WAErB;;YAGV,IACC,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA,GAC1C,EAAM,WAAW,IACnB,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,UAAD;IAAQ,WAAU;cAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,WAErB;;GAEX,CAAA,GAEF,kBAAC,GAAD;GAAW,WAAU;GAAQ,MAAA;GAAK,WAAU;aAC1C,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAM,KAAK,MACV,kBAAC,OAAD;KAEE,WAAU;eAFZ,CAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EACE,WAAW,WAAW,EAAK,WAAW,SAAS,6BAA6B,yBAC5E,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OACE,WAAW,uBAAuB,EAAK,WAAW,SAAS,qCAAqC;iBAE/F,EAAK;OACJ,CAAA,EACJ,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAK,cAAc;QAAa;QAAU;QAC1C,EAAK;QAAa;QACjB;SACA,EAAA,CAAA,CACF;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OACE,WAAW,4DAA4D,EAAiB,EAAK,SAAS;iBAErG,EAAK;OACD,CAAA,EACP,kBAAC,QAAD;OACE,WAAW,4DAA4D,EAAe,EAAK,OAAO;iBAEjG,EAAK;OACD,CAAA,CACH;QACF;OA/BC,EAAK,GA+BN,CACN;IACE,CAAA;GACI,CAAA;EAEH,CAAA"}
@@ -1,86 +1,90 @@
1
1
  import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
2
2
  import { getInitials as t } from "../../utils/helpers.js";
3
- import { PageLayout as n } from "../../components/PageLayout.js";
4
- import { StatCard as r } from "../../components/StatCard.js";
5
- import { LoadingSkeleton as i } from "../../components/LoadingSkeleton.js";
6
- import { useGetCapacityOverviewQuery as a, useListResourcePlansQuery as o } from "../../../generated/wspace-operations.js";
7
- import { CalendarRange as s, TrendingUp as c, Users as l } from "lucide-react";
8
- import { jsx as u, jsxs as d } from "react/jsx-runtime";
3
+ import { StatCard as n } from "../../components/StatCard.js";
4
+ import { LoadingSkeleton as r } from "../../components/LoadingSkeleton.js";
5
+ import { useGetCapacityOverviewQuery as i, useListResourcePlansQuery as a } from "../../../generated/wspace-operations.js";
6
+ import { PageLayout as o } from "../../components/PageLayout.js";
7
+ import { EmptyState as s } from "../../components/EmptyState.js";
8
+ import { CalendarRange as c, TrendingUp as l, Users as u } from "lucide-react";
9
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
9
10
  //#region src/timecampus/pages/resource-planning/ResourcePlanningPage.tsx
10
- function f() {
11
- let { workspaceId: f = "" } = e(), p = /* @__PURE__ */ new Date(), m = new Date(p.getFullYear(), p.getMonth(), p.getDate()).toISOString(), h = new Date(p.getFullYear(), p.getMonth(), p.getDate() + 7).toISOString(), { data: g, loading: _, error: v } = o(), { data: y } = a({ variables: {
12
- startDate: m,
13
- endDate: h
14
- } }), b = g?.resourcePlans?.items ?? [], x = y?.capacityOverview, S = b.flatMap((e) => e.allocations.map((t) => ({
11
+ function p() {
12
+ let { workspaceId: p = "" } = e(), m = /* @__PURE__ */ new Date(), h = new Date(m.getFullYear(), m.getMonth(), m.getDate()).toISOString(), g = new Date(m.getFullYear(), m.getMonth(), m.getDate() + 7).toISOString(), { data: _, loading: v, error: y } = a(), { data: b } = i({ variables: {
13
+ startDate: h,
14
+ endDate: g
15
+ } }), x = _?.resourcePlans?.items ?? [], S = b?.capacityOverview, C = x.flatMap((e) => e.allocations.map((t) => ({
15
16
  ...t,
16
17
  planName: e.name
17
18
  })));
18
- if (_) return /* @__PURE__ */ u(n, {
19
+ if (v) return /* @__PURE__ */ d(o, {
19
20
  title: "Resource Planning",
20
21
  description: "Plan and optimize team resource allocation",
21
- children: /* @__PURE__ */ u(i, {
22
+ children: /* @__PURE__ */ d(r, {
22
23
  variant: "list",
23
24
  count: 5
24
25
  })
25
26
  });
26
- if (v) return /* @__PURE__ */ u(n, {
27
+ if (y) return /* @__PURE__ */ d(o, {
27
28
  title: "Resource Planning",
28
29
  description: "Plan and optimize team resource allocation",
29
- children: /* @__PURE__ */ u("div", {
30
- className: "rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-700 dark:border-red-800 dark:bg-red-900/20 dark:text-red-400",
30
+ children: /* @__PURE__ */ d("div", {
31
+ className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
31
32
  children: "Failed to load resource planning data. Please try again later."
32
33
  })
33
34
  });
34
- let C = x?.utilizationRate ?? 0, w = x?.overallocatedUsers?.length ?? 0, T = x?.availableCapacity ?? 0;
35
- return /* @__PURE__ */ d(n, {
35
+ let w = S?.utilizationRate ?? 0, T = S?.overallocatedUsers?.length ?? 0, E = S?.availableCapacity ?? 0;
36
+ return /* @__PURE__ */ f(o, {
36
37
  title: "Resource Planning",
37
38
  description: "Plan and optimize team resource allocation",
38
- children: [/* @__PURE__ */ d("div", {
39
+ purpose: "Match the work ahead to the people you have — see who's over- or under-booked and how much capacity is free this week — so you can commit to deadlines you can actually hit without burning anyone out.",
40
+ children: [/* @__PURE__ */ f("div", {
39
41
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
40
42
  children: [
41
- /* @__PURE__ */ u(r, {
43
+ /* @__PURE__ */ d(n, {
44
+ featured: !0,
42
45
  title: "Team Utilization",
43
- value: `${Math.round(C)}%`,
44
- icon: /* @__PURE__ */ u(c, { className: "h-5 w-5" })
46
+ value: `${Math.round(w)}%`,
47
+ icon: /* @__PURE__ */ d(l, { className: "h-5 w-5" })
45
48
  }),
46
- /* @__PURE__ */ u(r, {
49
+ /* @__PURE__ */ d(n, {
47
50
  title: "Over-allocated",
48
- value: String(w),
49
- icon: /* @__PURE__ */ u(l, { className: "h-5 w-5" }),
50
- iconBgColor: "bg-red-100 text-red-600 dark:bg-red-900/30 dark:text-red-400"
51
+ value: String(T),
52
+ icon: /* @__PURE__ */ d(u, { className: "h-5 w-5" }),
53
+ iconBgColor: "bg-status-error-bg text-status-error-text"
51
54
  }),
52
- /* @__PURE__ */ u(r, {
55
+ /* @__PURE__ */ d(n, {
53
56
  title: "Active Plans",
54
- value: String(b.length),
55
- icon: /* @__PURE__ */ u(l, { className: "h-5 w-5" })
57
+ value: String(x.length),
58
+ icon: /* @__PURE__ */ d(u, { className: "h-5 w-5" })
56
59
  }),
57
- /* @__PURE__ */ u(r, {
60
+ /* @__PURE__ */ d(n, {
58
61
  title: "Available Capacity",
59
- value: `${Math.round(T)}h`,
60
- icon: /* @__PURE__ */ u(s, { className: "h-5 w-5" }),
62
+ value: `${Math.round(E)}h`,
63
+ icon: /* @__PURE__ */ d(c, { className: "h-5 w-5" }),
61
64
  description: "This week"
62
65
  })
63
66
  ]
64
- }), /* @__PURE__ */ u("div", {
65
- className: "rounded-xl border border-border-subtle bg-bg-surface",
66
- children: /* @__PURE__ */ u("div", {
67
+ }), C.length === 0 ? /* @__PURE__ */ d(s, {
68
+ illustration: "empty-people",
69
+ title: "No resource allocations found",
70
+ description: "Create a resource plan to start allocating team members and balancing workload across the week."
71
+ }) : /* @__PURE__ */ d("div", {
72
+ className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop",
73
+ children: /* @__PURE__ */ d("div", {
67
74
  className: "divide-y divide-border",
68
- children: S.length === 0 ? /* @__PURE__ */ u("div", {
69
- className: "p-8 text-center text-sm text-text-secondary",
70
- children: "No resource allocations found. Create a resource plan to start allocating team members."
71
- }) : S.map((e) => {
75
+ children: C.map((e) => {
72
76
  let n = e.utilizationRate ?? (e.allocatedHours > 0 ? Math.round(e.actualHours / e.allocatedHours * 100) : 0);
73
- return /* @__PURE__ */ d("div", {
77
+ return /* @__PURE__ */ f("div", {
74
78
  className: "flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors",
75
- children: [/* @__PURE__ */ d("div", {
79
+ children: [/* @__PURE__ */ f("div", {
76
80
  className: "flex items-center gap-3",
77
- children: [/* @__PURE__ */ u("div", {
81
+ children: [/* @__PURE__ */ d("div", {
78
82
  className: "flex h-9 w-9 items-center justify-center rounded-full bg-action-primary-bg/10 text-sm font-medium text-primary",
79
83
  children: t(e.userId)
80
- }), /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("p", {
84
+ }), /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("p", {
81
85
  className: "text-sm font-medium text-text-primary",
82
86
  children: e.userId
83
- }), /* @__PURE__ */ d("p", {
87
+ }), /* @__PURE__ */ f("p", {
84
88
  className: "text-xs text-text-secondary",
85
89
  children: [
86
90
  e.planName,
@@ -92,26 +96,26 @@ function f() {
92
96
  e.endDate.slice(0, 10)
93
97
  ]
94
98
  })] })]
95
- }), /* @__PURE__ */ d("div", {
99
+ }), /* @__PURE__ */ f("div", {
96
100
  className: "flex items-center gap-4",
97
- children: [/* @__PURE__ */ u("div", {
101
+ children: [/* @__PURE__ */ d("div", {
98
102
  className: "text-right",
99
- children: /* @__PURE__ */ d("p", {
103
+ children: /* @__PURE__ */ f("p", {
100
104
  className: "text-sm font-medium text-text-primary",
101
105
  children: [e.allocatedHours, "h allocated"]
102
106
  })
103
- }), /* @__PURE__ */ d("div", {
107
+ }), /* @__PURE__ */ f("div", {
104
108
  className: "w-24",
105
- children: [/* @__PURE__ */ u("div", {
109
+ children: [/* @__PURE__ */ d("div", {
106
110
  className: "flex items-center justify-between text-xs mb-0.5",
107
- children: /* @__PURE__ */ d("span", {
108
- className: `font-medium ${n > 100 ? "text-red-500" : n < 70 ? "text-amber-500" : "text-emerald-500"}`,
111
+ children: /* @__PURE__ */ f("span", {
112
+ className: `font-medium ${n > 100 ? "text-status-error-text" : n < 70 ? "text-status-warning-text" : "text-status-success-text"}`,
109
113
  children: [n, "%"]
110
114
  })
111
- }), /* @__PURE__ */ u("div", {
115
+ }), /* @__PURE__ */ d("div", {
112
116
  className: "h-2 rounded-full bg-bg-sunken",
113
- children: /* @__PURE__ */ u("div", {
114
- className: `h-2 rounded-full ${n > 100 ? "bg-red-500" : n < 70 ? "bg-amber-500" : "bg-emerald-500"}`,
117
+ children: /* @__PURE__ */ d("div", {
118
+ className: `h-2 rounded-full ${n > 100 ? "bg-status-error-text" : n < 70 ? "bg-status-warning-text" : "bg-status-success-text"}`,
115
119
  style: { width: `${Math.min(n, 100)}%` }
116
120
  })
117
121
  })]
@@ -124,6 +128,6 @@ function f() {
124
128
  });
125
129
  }
126
130
  //#endregion
127
- export { f as ResourcePlanningPage };
131
+ export { p as ResourcePlanningPage };
128
132
 
129
133
  //# sourceMappingURL=ResourcePlanningPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ResourcePlanningPage.js","names":[],"sources":["../../../../src/timecampus/pages/resource-planning/ResourcePlanningPage.tsx"],"sourcesContent":["import { CalendarRange, Users, TrendingUp } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { getStatusColor, getInitials } from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListResourcePlansQuery,\n useGetCapacityOverviewQuery,\n type ResourcePlanFieldsFragment,\n type ResourceAllocationFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function ResourcePlanningPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const now = new Date();\n const startDate = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate(),\n ).toISOString();\n const endDate = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate() + 7,\n ).toISOString();\n\n const {\n data: plansData,\n loading: plansLoading,\n error: plansError,\n } = useListResourcePlansQuery();\n const { data: capacityData } = useGetCapacityOverviewQuery({\n variables: { startDate, endDate },\n });\n\n const plans = plansData?.resourcePlans?.items ?? [];\n const capacity = capacityData?.capacityOverview;\n\n // Flatten all allocations across plans for display\n const allocations = plans.flatMap((plan: ResourcePlanFieldsFragment) =>\n plan.allocations.map((alloc: ResourceAllocationFieldsFragment) => ({\n ...alloc,\n planName: plan.name,\n })),\n );\n\n if (plansLoading) {\n return (\n <PageLayout\n title=\"Resource Planning\"\n description=\"Plan and optimize team resource allocation\"\n >\n <LoadingSkeleton variant=\"list\" count={5} />\n </PageLayout>\n );\n }\n\n if (plansError) {\n return (\n <PageLayout\n title=\"Resource Planning\"\n description=\"Plan and optimize team resource allocation\"\n >\n <div className=\"rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-700 dark:border-red-800 dark:bg-red-900/20 dark:text-red-400\">\n Failed to load resource planning data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n const utilizationRate = capacity?.utilizationRate ?? 0;\n const overallocatedCount = capacity?.overallocatedUsers?.length ?? 0;\n const availableHours = capacity?.availableCapacity ?? 0;\n\n return (\n <PageLayout\n title=\"Resource Planning\"\n description=\"Plan and optimize team resource allocation\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n title=\"Team Utilization\"\n value={`${Math.round(utilizationRate)}%`}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Over-allocated\"\n value={String(overallocatedCount)}\n icon={<Users className=\"h-5 w-5\" />}\n iconBgColor=\"bg-red-100 text-red-600 dark:bg-red-900/30 dark:text-red-400\"\n />\n <StatCard\n title=\"Active Plans\"\n value={String(plans.length)}\n icon={<Users className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Available Capacity\"\n value={`${Math.round(availableHours)}h`}\n icon={<CalendarRange className=\"h-5 w-5\" />}\n description=\"This week\"\n />\n </div>\n\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface\">\n <div className=\"divide-y divide-border\">\n {allocations.length === 0 ? (\n <div className=\"p-8 text-center text-sm text-text-secondary\">\n No resource allocations found. Create a resource plan to start\n allocating team members.\n </div>\n ) : (\n allocations.map(\n (\n alloc: ResourceAllocationFieldsFragment & { planName: string },\n ) => {\n const utilization =\n alloc.utilizationRate ??\n (alloc.allocatedHours > 0\n ? Math.round(\n (alloc.actualHours / alloc.allocatedHours) * 100,\n )\n : 0);\n return (\n <div\n key={alloc.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 <div className=\"flex h-9 w-9 items-center justify-center rounded-full bg-action-primary-bg/10 text-sm font-medium text-primary\">\n {getInitials(alloc.userId)}\n </div>\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {alloc.userId}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {alloc.planName} &middot;{\" \"}\n {alloc.startDate.slice(0, 10)} to{\" \"}\n {alloc.endDate.slice(0, 10)}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-4\">\n <div className=\"text-right\">\n <p className=\"text-sm font-medium text-text-primary\">\n {alloc.allocatedHours}h allocated\n </p>\n </div>\n <div className=\"w-24\">\n <div className=\"flex items-center justify-between text-xs mb-0.5\">\n <span\n className={`font-medium ${utilization > 100 ? \"text-red-500\" : utilization < 70 ? \"text-amber-500\" : \"text-emerald-500\"}`}\n >\n {utilization}%\n </span>\n </div>\n <div className=\"h-2 rounded-full bg-bg-sunken\">\n <div\n className={`h-2 rounded-full ${utilization > 100 ? \"bg-red-500\" : utilization < 70 ? \"bg-amber-500\" : \"bg-emerald-500\"}`}\n style={{ width: `${Math.min(utilization, 100)}%` }}\n />\n </div>\n </div>\n </div>\n </div>\n );\n },\n )\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ResourcePlanningPage.js","names":[],"sources":["../../../../src/timecampus/pages/resource-planning/ResourcePlanningPage.tsx"],"sourcesContent":["import { CalendarRange, Users, TrendingUp } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { EmptyState } from \"../../components/EmptyState\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { getStatusColor, getInitials } from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListResourcePlansQuery,\n useGetCapacityOverviewQuery,\n type ResourcePlanFieldsFragment,\n type ResourceAllocationFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function ResourcePlanningPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const now = new Date();\n const startDate = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate(),\n ).toISOString();\n const endDate = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate() + 7,\n ).toISOString();\n\n const {\n data: plansData,\n loading: plansLoading,\n error: plansError,\n } = useListResourcePlansQuery();\n const { data: capacityData } = useGetCapacityOverviewQuery({\n variables: { startDate, endDate },\n });\n\n const plans = plansData?.resourcePlans?.items ?? [];\n const capacity = capacityData?.capacityOverview;\n\n // Flatten all allocations across plans for display\n const allocations = plans.flatMap((plan: ResourcePlanFieldsFragment) =>\n plan.allocations.map((alloc: ResourceAllocationFieldsFragment) => ({\n ...alloc,\n planName: plan.name,\n })),\n );\n\n if (plansLoading) {\n return (\n <PageLayout\n title=\"Resource Planning\"\n description=\"Plan and optimize team resource allocation\"\n >\n <LoadingSkeleton variant=\"list\" count={5} />\n </PageLayout>\n );\n }\n\n if (plansError) {\n return (\n <PageLayout\n title=\"Resource Planning\"\n description=\"Plan and optimize team resource allocation\"\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 resource planning data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n const utilizationRate = capacity?.utilizationRate ?? 0;\n const overallocatedCount = capacity?.overallocatedUsers?.length ?? 0;\n const availableHours = capacity?.availableCapacity ?? 0;\n\n return (\n <PageLayout\n title=\"Resource Planning\"\n description=\"Plan and optimize team resource allocation\"\n purpose=\"Match the work ahead to the people you have — see who's over- or under-booked and how much capacity is free this week — so you can commit to deadlines you can actually hit without burning anyone out.\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n featured\n title=\"Team Utilization\"\n value={`${Math.round(utilizationRate)}%`}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Over-allocated\"\n value={String(overallocatedCount)}\n icon={<Users className=\"h-5 w-5\" />}\n iconBgColor=\"bg-status-error-bg text-status-error-text\"\n />\n <StatCard\n title=\"Active Plans\"\n value={String(plans.length)}\n icon={<Users className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Available Capacity\"\n value={`${Math.round(availableHours)}h`}\n icon={<CalendarRange className=\"h-5 w-5\" />}\n description=\"This week\"\n />\n </div>\n\n {allocations.length === 0 ? (\n <EmptyState\n illustration=\"empty-people\"\n title=\"No resource allocations found\"\n description=\"Create a resource plan to start allocating team members and balancing workload across the week.\"\n />\n ) : (\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop\">\n <div className=\"divide-y divide-border\">\n {allocations.map(\n (\n alloc: ResourceAllocationFieldsFragment & { planName: string },\n ) => {\n const utilization =\n alloc.utilizationRate ??\n (alloc.allocatedHours > 0\n ? Math.round(\n (alloc.actualHours / alloc.allocatedHours) * 100,\n )\n : 0);\n return (\n <div\n key={alloc.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 <div className=\"flex h-9 w-9 items-center justify-center rounded-full bg-action-primary-bg/10 text-sm font-medium text-primary\">\n {getInitials(alloc.userId)}\n </div>\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {alloc.userId}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {alloc.planName} &middot;{\" \"}\n {alloc.startDate.slice(0, 10)} to{\" \"}\n {alloc.endDate.slice(0, 10)}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-4\">\n <div className=\"text-right\">\n <p className=\"text-sm font-medium text-text-primary\">\n {alloc.allocatedHours}h allocated\n </p>\n </div>\n <div className=\"w-24\">\n <div className=\"flex items-center justify-between text-xs mb-0.5\">\n <span\n className={`font-medium ${utilization > 100 ? \"text-status-error-text\" : utilization < 70 ? \"text-status-warning-text\" : \"text-status-success-text\"}`}\n >\n {utilization}%\n </span>\n </div>\n <div className=\"h-2 rounded-full bg-bg-sunken\">\n <div\n className={`h-2 rounded-full ${utilization > 100 ? \"bg-status-error-text\" : utilization < 70 ? \"bg-status-warning-text\" : \"bg-status-success-text\"}`}\n style={{ width: `${Math.min(utilization, 100)}%` }}\n />\n </div>\n </div>\n </div>\n </div>\n );\n },\n )}\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1,33 +1,37 @@
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 { useGetTimeEntryStatsQuery as r, useGetWorkPatternSummaryQuery as i } from "../../../generated/wspace-operations.js";
2
+ import { LoadingSkeleton as t } from "../../components/LoadingSkeleton.js";
3
+ import { useGetTimeEntryStatsQuery as n, useGetWorkPatternSummaryQuery as r } from "../../../generated/wspace-operations.js";
4
+ import { PageLayout as i } from "../../components/PageLayout.js";
5
5
  import { BarChart3 as a, Users as o } from "lucide-react";
6
6
  import { jsx as s, jsxs as c } from "react/jsx-runtime";
7
+ import { GlassCard as l } from "@burdenoff/fe-libs/ui";
7
8
  //#region src/timecampus/pages/team/TeamAnalyticsPage.tsx
8
- function l() {
9
- let { workspaceId: l = "" } = e(), { data: u, loading: d, error: f } = r({ skip: !l }), { data: p, loading: m } = i({ skip: !l }), h = u?.timeEntryStats, g = p?.workPatternSummary;
10
- return d || m ? /* @__PURE__ */ s(t, {
9
+ function u() {
10
+ let { workspaceId: u = "" } = e(), { data: d, loading: f, error: p } = n({ skip: !u }), { data: m, loading: h } = r({ skip: !u }), g = d?.timeEntryStats, _ = m?.workPatternSummary;
11
+ return f || h ? /* @__PURE__ */ s(i, {
11
12
  title: "Team Analytics",
12
13
  description: "Team performance insights and metrics",
13
- children: /* @__PURE__ */ s(n, {
14
+ children: /* @__PURE__ */ s(t, {
14
15
  variant: "card",
15
16
  count: 4
16
17
  })
17
- }) : f ? /* @__PURE__ */ s(t, {
18
+ }) : p ? /* @__PURE__ */ s(i, {
18
19
  title: "Team Analytics",
19
20
  description: "Team performance insights and metrics",
20
21
  children: /* @__PURE__ */ s("div", {
21
- className: "rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-600 dark:border-red-800 dark:bg-red-900/20 dark:text-red-400",
22
+ className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
22
23
  children: "Failed to load team analytics. Please try again later."
23
24
  })
24
- }) : /* @__PURE__ */ s(t, {
25
+ }) : /* @__PURE__ */ s(i, {
25
26
  title: "Team Analytics",
26
27
  description: "Team performance insights and metrics",
28
+ purpose: "Compare how your team works — hours by member, productive days, focus versus meeting time — so you can rebalance workload, recognise top contributors, and fix the patterns that slow everyone down.",
27
29
  children: /* @__PURE__ */ c("div", {
28
30
  className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
29
- children: [/* @__PURE__ */ c("div", {
30
- className: "rounded-xl border border-border-subtle bg-bg-surface p-6",
31
+ children: [/* @__PURE__ */ c(l, {
32
+ treatment: "glass",
33
+ glow: !0,
34
+ className: "p-6",
31
35
  children: [/* @__PURE__ */ c("div", {
32
36
  className: "mb-4 flex items-center gap-2",
33
37
  children: [/* @__PURE__ */ s(o, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ s("h3", {
@@ -40,15 +44,15 @@ function l() {
40
44
  className: "text-center",
41
45
  children: [/* @__PURE__ */ s("p", {
42
46
  className: "text-sm text-text-secondary",
43
- children: h ? `${Math.round(h.totalHours)}h total · ${Math.round(h.billableHours)}h billable` : "No data available"
44
- }), g?.mostProductiveDay && /* @__PURE__ */ c("p", {
47
+ children: g ? `${Math.round(g.totalHours)}h total · ${Math.round(g.billableHours)}h billable` : "No data available"
48
+ }), _?.mostProductiveDay && /* @__PURE__ */ c("p", {
45
49
  className: "mt-1 text-xs text-text-secondary",
46
- children: ["Most productive: ", g.mostProductiveDay]
50
+ children: ["Most productive: ", _.mostProductiveDay]
47
51
  })]
48
52
  })
49
53
  })]
50
54
  }), /* @__PURE__ */ c("div", {
51
- className: "rounded-xl border border-border-subtle bg-bg-surface p-6",
55
+ className: "rounded-xl border border-border-seam bg-bg-surface shadow-elevation-1 p-6",
52
56
  children: [/* @__PURE__ */ c("div", {
53
57
  className: "mb-4 flex items-center gap-2",
54
58
  children: [/* @__PURE__ */ s(a, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ s("h3", {
@@ -61,10 +65,10 @@ function l() {
61
65
  className: "text-center",
62
66
  children: [/* @__PURE__ */ s("p", {
63
67
  className: "text-sm text-text-secondary",
64
- children: g ? `${Math.round(g.averageProductivity)}% avg productivity · ${g.averageFocusHours.toFixed(1)}h avg focus` : "No data available"
65
- }), g?.insights && g.insights.length > 0 && /* @__PURE__ */ s("p", {
68
+ children: _ ? `${Math.round(_.averageProductivity)}% avg productivity · ${_.averageFocusHours.toFixed(1)}h avg focus` : "No data available"
69
+ }), _?.insights && _.insights.length > 0 && /* @__PURE__ */ s("p", {
66
70
  className: "mt-1 text-xs text-text-secondary",
67
- children: g.insights[0].title
71
+ children: _.insights[0].title
68
72
  })]
69
73
  })
70
74
  })]
@@ -73,6 +77,6 @@ function l() {
73
77
  });
74
78
  }
75
79
  //#endregion
76
- export { l as TeamAnalyticsPage };
80
+ export { u as TeamAnalyticsPage };
77
81
 
78
82
  //# sourceMappingURL=TeamAnalyticsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TeamAnalyticsPage.js","names":[],"sources":["../../../../src/timecampus/pages/team/TeamAnalyticsPage.tsx"],"sourcesContent":["import { BarChart3, Users } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useGetTimeEntryStatsQuery,\n useGetWorkPatternSummaryQuery,\n} from \"@/generated/wspace-operations\";\n\nexport function TeamAnalyticsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetTimeEntryStatsQuery({\n skip: !workspaceId,\n });\n\n const { data: patternData, loading: patternLoading } =\n useGetWorkPatternSummaryQuery({\n skip: !workspaceId,\n });\n\n const stats = statsData?.timeEntryStats;\n const pattern = patternData?.workPatternSummary;\n\n if (statsLoading || patternLoading) {\n return (\n <PageLayout\n title=\"Team Analytics\"\n description=\"Team performance insights and metrics\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (statsError) {\n return (\n <PageLayout\n title=\"Team Analytics\"\n description=\"Team performance insights and metrics\"\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 team analytics. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Team Analytics\"\n description=\"Team performance insights and metrics\"\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <Users className=\"h-5 w-5 text-primary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n Hours by Member\n </h3>\n </div>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <div className=\"text-center\">\n <p className=\"text-sm text-text-secondary\">\n {stats\n ? `${Math.round(stats.totalHours)}h total · ${Math.round(stats.billableHours)}h billable`\n : \"No data available\"}\n </p>\n {pattern?.mostProductiveDay && (\n <p className=\"mt-1 text-xs text-text-secondary\">\n Most productive: {pattern.mostProductiveDay}\n </p>\n )}\n </div>\n </div>\n </div>\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <BarChart3 className=\"h-5 w-5 text-primary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n Productivity Trends\n </h3>\n </div>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <div className=\"text-center\">\n <p className=\"text-sm text-text-secondary\">\n {pattern\n ? `${Math.round(pattern.averageProductivity)}% avg productivity · ${pattern.averageFocusHours.toFixed(1)}h avg focus`\n : \"No data available\"}\n </p>\n {pattern?.insights && pattern.insights.length > 0 && (\n <p className=\"mt-1 text-xs text-text-secondary\">\n {pattern.insights[0].title}\n </p>\n )}\n </div>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;AASA,SAAgB,IAAoB;CAClC,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAA0B,EAC5B,MAAM,CAAC,GACR,CAAC,EAEI,EAAE,MAAM,GAAa,SAAS,MAClC,EAA8B,EAC5B,MAAM,CAAC,GACR,CAAC,EAEE,IAAQ,GAAW,gBACnB,IAAU,GAAa;AA0B7B,QAxBI,KAAgB,IAEhB,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA,GAIb,IAEA,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAA+H;GAExI,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAO,WAAU,wBAAyB,CAAA,EAC1C,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAEnD,CAAA,CACD;QACN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBACV,IACG,GAAG,KAAK,MAAM,EAAM,WAAW,CAAC,YAAY,KAAK,MAAM,EAAM,cAAc,CAAC,cAC5E;OACF,CAAA,EACH,GAAS,qBACR,kBAAC,KAAD;OAAG,WAAU;iBAAb,CAAgD,qBAC5B,EAAQ,kBACxB;SAEF;;KACF,CAAA,CACF;OACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAW,WAAU,wBAAyB,CAAA,EAC9C,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAEnD,CAAA,CACD;QACN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBACV,IACG,GAAG,KAAK,MAAM,EAAQ,oBAAoB,CAAC,uBAAuB,EAAQ,kBAAkB,QAAQ,EAAE,CAAC,eACvG;OACF,CAAA,EACH,GAAS,YAAY,EAAQ,SAAS,SAAS,KAC9C,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAQ,SAAS,GAAG;OACnB,CAAA,CAEF;;KACF,CAAA,CACF;MACF;;EACK,CAAA"}
1
+ {"version":3,"file":"TeamAnalyticsPage.js","names":[],"sources":["../../../../src/timecampus/pages/team/TeamAnalyticsPage.tsx"],"sourcesContent":["import { BarChart3, Users } 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 useGetTimeEntryStatsQuery,\n useGetWorkPatternSummaryQuery,\n} from \"@/generated/wspace-operations\";\n\nexport function TeamAnalyticsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetTimeEntryStatsQuery({\n skip: !workspaceId,\n });\n\n const { data: patternData, loading: patternLoading } =\n useGetWorkPatternSummaryQuery({\n skip: !workspaceId,\n });\n\n const stats = statsData?.timeEntryStats;\n const pattern = patternData?.workPatternSummary;\n\n if (statsLoading || patternLoading) {\n return (\n <PageLayout\n title=\"Team Analytics\"\n description=\"Team performance insights and metrics\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (statsError) {\n return (\n <PageLayout\n title=\"Team Analytics\"\n description=\"Team performance insights and metrics\"\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 team analytics. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Team Analytics\"\n description=\"Team performance insights and metrics\"\n purpose=\"Compare how your team works — hours by member, productive days, focus versus meeting time — so you can rebalance workload, recognise top contributors, and fix the patterns that slow everyone down.\"\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <Users className=\"h-5 w-5 text-primary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n Hours by Member\n </h3>\n </div>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <div className=\"text-center\">\n <p className=\"text-sm text-text-secondary\">\n {stats\n ? `${Math.round(stats.totalHours)}h total · ${Math.round(stats.billableHours)}h billable`\n : \"No data available\"}\n </p>\n {pattern?.mostProductiveDay && (\n <p className=\"mt-1 text-xs text-text-secondary\">\n Most productive: {pattern.mostProductiveDay}\n </p>\n )}\n </div>\n </div>\n </GlassCard>\n <div className=\"rounded-xl border border-border-seam bg-bg-surface shadow-elevation-1 p-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <BarChart3 className=\"h-5 w-5 text-primary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n Productivity Trends\n </h3>\n </div>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <div className=\"text-center\">\n <p className=\"text-sm text-text-secondary\">\n {pattern\n ? `${Math.round(pattern.averageProductivity)}% avg productivity · ${pattern.averageFocusHours.toFixed(1)}h avg focus`\n : \"No data available\"}\n </p>\n {pattern?.insights && pattern.insights.length > 0 && (\n <p className=\"mt-1 text-xs text-text-secondary\">\n {pattern.insights[0].title}\n </p>\n )}\n </div>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAUA,SAAgB,IAAoB;CAClC,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAA0B,EAC5B,MAAM,CAAC,GACR,CAAC,EAEI,EAAE,MAAM,GAAa,SAAS,MAClC,EAA8B,EAC5B,MAAM,CAAC,GACR,CAAC,EAEE,IAAQ,GAAW,gBACnB,IAAU,GAAa;AA0B7B,QAxBI,KAAgB,IAEhB,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA,GAIb,IAEA,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAAoG;GAE7G,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SAAQ;YAER,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IAAW,WAAU;IAAQ,MAAA;IAAK,WAAU;cAA5C,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAO,WAAU,wBAAyB,CAAA,EAC1C,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAEnD,CAAA,CACD;QACN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBACV,IACG,GAAG,KAAK,MAAM,EAAM,WAAW,CAAC,YAAY,KAAK,MAAM,EAAM,cAAc,CAAC,cAC5E;OACF,CAAA,EACH,GAAS,qBACR,kBAAC,KAAD;OAAG,WAAU;iBAAb,CAAgD,qBAC5B,EAAQ,kBACxB;SAEF;;KACF,CAAA,CACI;OACZ,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAW,WAAU,wBAAyB,CAAA,EAC9C,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAEnD,CAAA,CACD;QACN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBACV,IACG,GAAG,KAAK,MAAM,EAAQ,oBAAoB,CAAC,uBAAuB,EAAQ,kBAAkB,QAAQ,EAAE,CAAC,eACvG;OACF,CAAA,EACH,GAAS,YAAY,EAAQ,SAAS,SAAS,KAC9C,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAQ,SAAS,GAAG;OACnB,CAAA,CAEF;;KACF,CAAA,CACF;MACF;;EACK,CAAA"}