@burdenoff/microfe-timecampus 2026.608.1 → 2026.625.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/timecampus/components/ErrorBoundary.js +4 -4
- package/dist/timecampus/components/ErrorBoundary.js.map +1 -1
- package/dist/timecampus/components/LoadingSkeleton.js +8 -8
- package/dist/timecampus/components/LoadingSkeleton.js.map +1 -1
- package/dist/timecampus/components/PageLayout.js +17 -13
- package/dist/timecampus/components/PageLayout.js.map +1 -1
- package/dist/timecampus/components/StatCard.js +22 -19
- package/dist/timecampus/components/StatCard.js.map +1 -1
- package/dist/timecampus/pages/HomePage.js +183 -163
- package/dist/timecampus/pages/HomePage.js.map +1 -1
- package/dist/timecampus/pages/applets/AppletStorePage.js +17 -17
- package/dist/timecampus/pages/applets/AppletStorePage.js.map +1 -1
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js +18 -18
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +28 -28
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js +19 -19
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/channels/ChannelsPage.js +15 -15
- package/dist/timecampus/pages/channels/ChannelsPage.js.map +1 -1
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js +22 -22
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/AnalyticsPage.js +20 -20
- package/dist/timecampus/pages/dashboard/AnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/ReportsPage.js +20 -20
- package/dist/timecampus/pages/dashboard/ReportsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js +18 -18
- package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js +22 -22
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +14 -14
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +22 -22
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScorePage.js +27 -27
- package/dist/timecampus/pages/focus-score/FocusScorePage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js +19 -19
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingPage.js +16 -16
- package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js +18 -18
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +16 -16
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js +21 -21
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +22 -22
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js +18 -18
- package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js +16 -16
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js +29 -29
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingsPage.js +20 -20
- package/dist/timecampus/pages/meetings/MeetingsPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js +23 -23
- package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js +23 -23
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js +30 -30
- package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectCreatePage.js +19 -19
- package/dist/timecampus/pages/projects/ProjectCreatePage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectDetailPage.js +23 -23
- package/dist/timecampus/pages/projects/ProjectDetailPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectsPage.js +20 -20
- package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/TasksPage.js +15 -15
- package/dist/timecampus/pages/projects/TasksPage.js.map +1 -1
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +25 -25
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js +19 -19
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamMembersPage.js +21 -21
- package/dist/timecampus/pages/team/TeamMembersPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamPage.js +19 -19
- package/dist/timecampus/pages/team/TeamPage.js.map +1 -1
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js +21 -21
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js.map +1 -1
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js +20 -20
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js +16 -16
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateDetailPage.js +21 -21
- package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplatesPage.js +16 -16
- package/dist/timecampus/pages/templates/TemplatesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeEntriesPage.js +25 -25
- package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeTrackingPage.js +24 -24
- package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimerPage.js +20 -20
- package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +27 -27
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js +20 -20
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetsPage.js +18 -18
- package/dist/timecampus/pages/widgets/WidgetsPage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +23 -23
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js +19 -19
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/workflows/WorkflowsPage.js +17 -17
- package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,69 +1,69 @@
|
|
|
1
1
|
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { LoadingSkeleton as t } from "../../components/LoadingSkeleton.js";
|
|
3
|
+
import { 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
7
|
//#region src/timecampus/pages/team/TeamAnalyticsPage.tsx
|
|
8
8
|
function l() {
|
|
9
|
-
let { workspaceId: l = "" } = e(), { data: u, loading: d, error: f } =
|
|
10
|
-
return d || m ? /* @__PURE__ */ s(
|
|
9
|
+
let { workspaceId: l = "" } = e(), { data: u, loading: d, error: f } = n({ skip: !l }), { data: p, loading: m } = r({ skip: !l }), h = u?.timeEntryStats, g = p?.workPatternSummary;
|
|
10
|
+
return d || m ? /* @__PURE__ */ s(i, {
|
|
11
11
|
title: "Team Analytics",
|
|
12
12
|
description: "Team performance insights and metrics",
|
|
13
|
-
children: /* @__PURE__ */ s(
|
|
13
|
+
children: /* @__PURE__ */ s(t, {
|
|
14
14
|
variant: "card",
|
|
15
15
|
count: 4
|
|
16
16
|
})
|
|
17
|
-
}) : f ? /* @__PURE__ */ s(
|
|
17
|
+
}) : f ? /* @__PURE__ */ s(i, {
|
|
18
18
|
title: "Team Analytics",
|
|
19
19
|
description: "Team performance insights and metrics",
|
|
20
20
|
children: /* @__PURE__ */ s("div", {
|
|
21
|
-
className: "rounded-lg border border-
|
|
21
|
+
className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
|
|
22
22
|
children: "Failed to load team analytics. Please try again later."
|
|
23
23
|
})
|
|
24
|
-
}) : /* @__PURE__ */ s(
|
|
24
|
+
}) : /* @__PURE__ */ s(i, {
|
|
25
25
|
title: "Team Analytics",
|
|
26
26
|
description: "Team performance insights and metrics",
|
|
27
27
|
children: /* @__PURE__ */ c("div", {
|
|
28
28
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
|
|
29
29
|
children: [/* @__PURE__ */ c("div", {
|
|
30
|
-
className: "rounded-xl border border-border bg-card p-6",
|
|
30
|
+
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6",
|
|
31
31
|
children: [/* @__PURE__ */ c("div", {
|
|
32
32
|
className: "mb-4 flex items-center gap-2",
|
|
33
33
|
children: [/* @__PURE__ */ s(o, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ s("h3", {
|
|
34
|
-
className: "text-sm font-semibold text-
|
|
34
|
+
className: "text-sm font-semibold text-text-primary",
|
|
35
35
|
children: "Hours by Member"
|
|
36
36
|
})]
|
|
37
37
|
}), /* @__PURE__ */ s("div", {
|
|
38
|
-
className: "flex h-48 items-center justify-center rounded-lg border border-dashed border-border",
|
|
38
|
+
className: "flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle",
|
|
39
39
|
children: /* @__PURE__ */ c("div", {
|
|
40
40
|
className: "text-center",
|
|
41
41
|
children: [/* @__PURE__ */ s("p", {
|
|
42
|
-
className: "text-sm text-
|
|
42
|
+
className: "text-sm text-text-secondary",
|
|
43
43
|
children: h ? `${Math.round(h.totalHours)}h total · ${Math.round(h.billableHours)}h billable` : "No data available"
|
|
44
44
|
}), g?.mostProductiveDay && /* @__PURE__ */ c("p", {
|
|
45
|
-
className: "mt-1 text-xs text-
|
|
45
|
+
className: "mt-1 text-xs text-text-secondary",
|
|
46
46
|
children: ["Most productive: ", g.mostProductiveDay]
|
|
47
47
|
})]
|
|
48
48
|
})
|
|
49
49
|
})]
|
|
50
50
|
}), /* @__PURE__ */ c("div", {
|
|
51
|
-
className: "rounded-xl border border-border bg-card p-6",
|
|
51
|
+
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6",
|
|
52
52
|
children: [/* @__PURE__ */ c("div", {
|
|
53
53
|
className: "mb-4 flex items-center gap-2",
|
|
54
54
|
children: [/* @__PURE__ */ s(a, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ s("h3", {
|
|
55
|
-
className: "text-sm font-semibold text-
|
|
55
|
+
className: "text-sm font-semibold text-text-primary",
|
|
56
56
|
children: "Productivity Trends"
|
|
57
57
|
})]
|
|
58
58
|
}), /* @__PURE__ */ s("div", {
|
|
59
|
-
className: "flex h-48 items-center justify-center rounded-lg border border-dashed border-border",
|
|
59
|
+
className: "flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle",
|
|
60
60
|
children: /* @__PURE__ */ c("div", {
|
|
61
61
|
className: "text-center",
|
|
62
62
|
children: [/* @__PURE__ */ s("p", {
|
|
63
|
-
className: "text-sm text-
|
|
63
|
+
className: "text-sm text-text-secondary",
|
|
64
64
|
children: g ? `${Math.round(g.averageProductivity)}% avg productivity · ${g.averageFocusHours.toFixed(1)}h avg focus` : "No data available"
|
|
65
65
|
}), g?.insights && g.insights.length > 0 && /* @__PURE__ */ s("p", {
|
|
66
|
-
className: "mt-1 text-xs text-
|
|
66
|
+
className: "mt-1 text-xs text-text-secondary",
|
|
67
67
|
children: g.insights[0].title
|
|
68
68
|
})]
|
|
69
69
|
})
|
|
@@ -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-
|
|
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-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 >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <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-seam bg-gloss-card shadow-pop p-6\">\n <div className=\"mb-4 flex items-center gap-2\">\n <BarChart3 className=\"h-5 w-5 text-primary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n 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;aAAoG;GAE7G,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,13 +1,13 @@
|
|
|
1
1
|
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
2
|
import { formatHours as t } from "../../utils/helpers.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
|
|
4
|
+
import { useListTimeEntriesQuery as r } from "../../../generated/wspace-operations.js";
|
|
5
|
+
import { PageLayout as i } from "../../components/PageLayout.js";
|
|
6
6
|
import { Plus as a, Users as o } from "lucide-react";
|
|
7
7
|
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
8
8
|
//#region src/timecampus/pages/team/TeamMembersPage.tsx
|
|
9
9
|
function l() {
|
|
10
|
-
let { workspaceId: l = "" } = e(), { data: u, loading: d, error: f } =
|
|
10
|
+
let { workspaceId: l = "" } = e(), { data: u, loading: d, error: f } = r({
|
|
11
11
|
variables: { limit: 100 },
|
|
12
12
|
skip: !l
|
|
13
13
|
}), p = (u?.timeEntries?.items ?? []).reduce((e, t) => {
|
|
@@ -21,53 +21,53 @@ function l() {
|
|
|
21
21
|
id: e,
|
|
22
22
|
...t
|
|
23
23
|
})).sort((e, t) => t.totalHours - e.totalHours);
|
|
24
|
-
return d ? /* @__PURE__ */ s(
|
|
24
|
+
return d ? /* @__PURE__ */ s(i, {
|
|
25
25
|
title: "Team Members",
|
|
26
26
|
description: "Manage team members and roles",
|
|
27
27
|
actions: /* @__PURE__ */ c("button", {
|
|
28
|
-
className: "inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-
|
|
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",
|
|
29
29
|
children: [/* @__PURE__ */ s(a, { className: "h-4 w-4" }), "Invite Member"]
|
|
30
30
|
}),
|
|
31
|
-
children: /* @__PURE__ */ s(
|
|
31
|
+
children: /* @__PURE__ */ s(n, {
|
|
32
32
|
variant: "list",
|
|
33
33
|
count: 5
|
|
34
34
|
})
|
|
35
|
-
}) : f ? /* @__PURE__ */ s(
|
|
35
|
+
}) : f ? /* @__PURE__ */ s(i, {
|
|
36
36
|
title: "Team Members",
|
|
37
37
|
description: "Manage team members and roles",
|
|
38
38
|
children: /* @__PURE__ */ s("div", {
|
|
39
|
-
className: "rounded-lg border border-
|
|
39
|
+
className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
|
|
40
40
|
children: "Failed to load team data. Please try again later."
|
|
41
41
|
})
|
|
42
|
-
}) : /* @__PURE__ */ c(
|
|
42
|
+
}) : /* @__PURE__ */ c(i, {
|
|
43
43
|
title: "Team Members",
|
|
44
44
|
description: "Manage team members and roles",
|
|
45
45
|
actions: /* @__PURE__ */ c("button", {
|
|
46
|
-
className: "inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-
|
|
46
|
+
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",
|
|
47
47
|
children: [/* @__PURE__ */ s(a, { className: "h-4 w-4" }), "Invite Member"]
|
|
48
48
|
}),
|
|
49
49
|
children: [/* @__PURE__ */ s("div", {
|
|
50
|
-
className: "mb-4 rounded-lg border border-
|
|
50
|
+
className: "mb-4 rounded-lg border border-status-warning-bg/40 bg-status-warning-bg p-3 text-xs text-status-warning-text",
|
|
51
51
|
children: "Team member data is managed by the groups module. Showing time entry activity by project."
|
|
52
52
|
}), /* @__PURE__ */ s("div", {
|
|
53
|
-
className: "rounded-xl border border-border bg-card",
|
|
53
|
+
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop",
|
|
54
54
|
children: /* @__PURE__ */ s("div", {
|
|
55
55
|
className: "divide-y divide-border",
|
|
56
56
|
children: m.length === 0 ? /* @__PURE__ */ s("div", {
|
|
57
|
-
className: "p-8 text-center text-sm text-
|
|
57
|
+
className: "p-8 text-center text-sm text-text-secondary",
|
|
58
58
|
children: "No time entry data available."
|
|
59
59
|
}) : m.map((e) => /* @__PURE__ */ c("div", {
|
|
60
|
-
className: "flex items-center justify-between p-4 hover:bg-
|
|
60
|
+
className: "flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors",
|
|
61
61
|
children: [/* @__PURE__ */ c("div", {
|
|
62
62
|
className: "flex items-center gap-3",
|
|
63
63
|
children: [/* @__PURE__ */ s("div", {
|
|
64
|
-
className: "flex h-9 w-9 items-center justify-center rounded-full bg-primary/10 text-sm font-medium text-primary",
|
|
64
|
+
className: "flex h-9 w-9 items-center justify-center rounded-full bg-action-primary-bg/10 text-sm font-medium text-primary",
|
|
65
65
|
children: /* @__PURE__ */ s(o, { className: "h-4 w-4" })
|
|
66
66
|
}), /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("p", {
|
|
67
|
-
className: "text-sm font-medium text-
|
|
67
|
+
className: "text-sm font-medium text-text-primary",
|
|
68
68
|
children: e.name
|
|
69
69
|
}), /* @__PURE__ */ c("p", {
|
|
70
|
-
className: "text-xs text-
|
|
70
|
+
className: "text-xs text-text-secondary",
|
|
71
71
|
children: [e.entries, " time entries"]
|
|
72
72
|
})] })]
|
|
73
73
|
}), /* @__PURE__ */ c("div", {
|
|
@@ -75,14 +75,14 @@ function l() {
|
|
|
75
75
|
children: [/* @__PURE__ */ c("div", {
|
|
76
76
|
className: "text-right",
|
|
77
77
|
children: [/* @__PURE__ */ s("p", {
|
|
78
|
-
className: "text-sm font-medium text-
|
|
78
|
+
className: "text-sm font-medium text-text-primary",
|
|
79
79
|
children: t(e.totalHours)
|
|
80
80
|
}), /* @__PURE__ */ s("p", {
|
|
81
|
-
className: "text-xs text-
|
|
81
|
+
className: "text-xs text-text-secondary",
|
|
82
82
|
children: "total tracked"
|
|
83
83
|
})]
|
|
84
84
|
}), /* @__PURE__ */ s("span", {
|
|
85
|
-
className: "inline-flex rounded-full bg-
|
|
85
|
+
className: "inline-flex rounded-full bg-status-success-bg px-2 py-0.5 text-xs font-medium text-status-success-text",
|
|
86
86
|
children: "active"
|
|
87
87
|
})]
|
|
88
88
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamMembersPage.js","names":[],"sources":["../../../../src/timecampus/pages/team/TeamMembersPage.tsx"],"sourcesContent":["import { Users, Plus } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { formatHours } from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListTimeEntriesQuery,\n type TimeEntryFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function TeamMembersPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const { data, loading, error } = useListTimeEntriesQuery({\n variables: { limit: 100 },\n skip: !workspaceId,\n });\n\n const entries = data?.timeEntries?.items ?? [];\n\n // Group time entries by project to show team activity (member data comes from groups module)\n const projectSummary = entries.reduce<\n Record<string, { name: string; totalHours: number; entries: number }>\n >(\n (\n acc: Record<\n string,\n { name: string; totalHours: number; entries: number }\n >,\n entry: TimeEntryFieldsFragment,\n ) => {\n const projectName = entry.project?.name ?? \"Unassigned\";\n const projectId = entry.projectId ?? \"unassigned\";\n if (!acc[projectId]) {\n acc[projectId] = { name: projectName, totalHours: 0, entries: 0 };\n }\n acc[projectId].totalHours += (entry.duration ?? 0) / 3600;\n acc[projectId].entries += 1;\n return acc;\n },\n {},\n );\n\n const summaryList = Object.entries(projectSummary)\n .map(([id, info]) => ({\n id,\n ...(info as { name: string; totalHours: number; entries: number }),\n }))\n .sort((a, b) => b.totalHours - a.totalHours);\n\n if (loading) {\n return (\n <PageLayout\n title=\"Team Members\"\n description=\"Manage team members and roles\"\n actions={\n <button className=\"inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-
|
|
1
|
+
{"version":3,"file":"TeamMembersPage.js","names":[],"sources":["../../../../src/timecampus/pages/team/TeamMembersPage.tsx"],"sourcesContent":["import { Users, Plus } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { formatHours } from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListTimeEntriesQuery,\n type TimeEntryFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function TeamMembersPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const { data, loading, error } = useListTimeEntriesQuery({\n variables: { limit: 100 },\n skip: !workspaceId,\n });\n\n const entries = data?.timeEntries?.items ?? [];\n\n // Group time entries by project to show team activity (member data comes from groups module)\n const projectSummary = entries.reduce<\n Record<string, { name: string; totalHours: number; entries: number }>\n >(\n (\n acc: Record<\n string,\n { name: string; totalHours: number; entries: number }\n >,\n entry: TimeEntryFieldsFragment,\n ) => {\n const projectName = entry.project?.name ?? \"Unassigned\";\n const projectId = entry.projectId ?? \"unassigned\";\n if (!acc[projectId]) {\n acc[projectId] = { name: projectName, totalHours: 0, entries: 0 };\n }\n acc[projectId].totalHours += (entry.duration ?? 0) / 3600;\n acc[projectId].entries += 1;\n return acc;\n },\n {},\n );\n\n const summaryList = Object.entries(projectSummary)\n .map(([id, info]) => ({\n id,\n ...(info as { name: string; totalHours: number; entries: number }),\n }))\n .sort((a, b) => b.totalHours - a.totalHours);\n\n if (loading) {\n return (\n <PageLayout\n title=\"Team Members\"\n description=\"Manage team members and roles\"\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 Invite Member\n </button>\n }\n >\n <LoadingSkeleton variant=\"list\" count={5} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Team Members\"\n description=\"Manage team members and roles\"\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 data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Team Members\"\n description=\"Manage team members and roles\"\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 Invite Member\n </button>\n }\n >\n <div className=\"mb-4 rounded-lg border border-status-warning-bg/40 bg-status-warning-bg p-3 text-xs text-status-warning-text\">\n Team member data is managed by the groups module. Showing time entry\n activity by project.\n </div>\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop\">\n <div className=\"divide-y divide-border\">\n {summaryList.length === 0 ? (\n <div className=\"p-8 text-center text-sm text-text-secondary\">\n No time entry data available.\n </div>\n ) : (\n summaryList.map((project) => (\n <div\n key={project.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 <Users className=\"h-4 w-4\" />\n </div>\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {project.name}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {project.entries} time entries\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 {formatHours(project.totalHours)}\n </p>\n <p className=\"text-xs text-text-secondary\">total tracked</p>\n </div>\n <span className=\"inline-flex rounded-full bg-status-success-bg px-2 py-0.5 text-xs font-medium text-status-success-text\">\n active\n </span>\n </div>\n </div>\n ))\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAUA,SAAgB,IAAkB;CAChC,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EAAE,SAAM,YAAS,aAAU,EAAwB;EACvD,WAAW,EAAE,OAAO,KAAK;EACzB,MAAM,CAAC;EACR,CAAC,EAKI,KAHU,GAAM,aAAa,SAAS,EAAE,EAGf,QAI3B,GAIA,MACG;EACH,IAAM,IAAc,EAAM,SAAS,QAAQ,cACrC,IAAY,EAAM,aAAa;AAMrC,SALK,EAAI,OACP,EAAI,KAAa;GAAE,MAAM;GAAa,YAAY;GAAG,SAAS;GAAG,GAEnE,EAAI,GAAW,eAAe,EAAM,YAAY,KAAK,MACrD,EAAI,GAAW,WAAW,GACnB;IAET,EAAE,CACH,EAEK,IAAc,OAAO,QAAQ,EAAe,CAC/C,KAAK,CAAC,GAAI,QAAW;EACpB;EACA,GAAI;EACL,EAAE,CACF,MAAM,GAAG,MAAM,EAAE,aAAa,EAAE,WAAW;AAgC9C,QA9BI,IAEA,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,gBAErB;;YAGX,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,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,gBAErB;;YAPb,CAUE,kBAAC,OAAD;GAAK,WAAU;aAA+G;GAGxH,CAAA,EACN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAY,WAAW,IACtB,kBAAC,OAAD;KAAK,WAAU;eAA8C;KAEvD,CAAA,GAEN,EAAY,KAAK,MACf,kBAAC,OAAD;KAEE,WAAU;eAFZ,CAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;OACzB,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAQ;OACP,CAAA,EACJ,kBAAC,KAAD;OAAG,WAAU;iBAAb,CACG,EAAQ,SAAQ,gBACf;SACA,EAAA,CAAA,CACF;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAY,EAAQ,WAAW;QAC9B,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBAA8B;QAAiB,CAAA,CACxD;UACN,kBAAC,QAAD;OAAM,WAAU;iBAAyG;OAElH,CAAA,CACH;QACF;OA3BC,EAAQ,GA2BT,CACN;IAEA,CAAA;GACF,CAAA,CACK"}
|
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { StatCard as t } from "../../components/StatCard.js";
|
|
3
|
+
import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
|
|
4
|
+
import { useGetTimeEntryStatsQuery as r } from "../../../generated/wspace-operations.js";
|
|
5
|
+
import { PageLayout as i } from "../../components/PageLayout.js";
|
|
6
6
|
import { Clock as a, TrendingUp as o, Users as s } from "lucide-react";
|
|
7
7
|
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
8
8
|
//#region src/timecampus/pages/team/TeamPage.tsx
|
|
9
9
|
function u() {
|
|
10
|
-
let { workspaceId: u = "" } = e(), { data: d, loading: f, error: p } =
|
|
11
|
-
if (f) return /* @__PURE__ */ c(
|
|
10
|
+
let { workspaceId: u = "" } = e(), { data: d, loading: f, error: p } = r({ skip: !u }), m = d?.timeEntryStats;
|
|
11
|
+
if (f) return /* @__PURE__ */ c(i, {
|
|
12
12
|
title: "Team Overview",
|
|
13
13
|
description: "Monitor team performance and activity",
|
|
14
|
-
children: /* @__PURE__ */ c(
|
|
14
|
+
children: /* @__PURE__ */ c(n, {
|
|
15
15
|
variant: "card",
|
|
16
16
|
count: 4
|
|
17
17
|
})
|
|
18
18
|
});
|
|
19
|
-
if (p) return /* @__PURE__ */ c(
|
|
19
|
+
if (p) return /* @__PURE__ */ c(i, {
|
|
20
20
|
title: "Team Overview",
|
|
21
21
|
description: "Monitor team performance and activity",
|
|
22
22
|
children: /* @__PURE__ */ c("div", {
|
|
23
|
-
className: "rounded-lg border border-
|
|
23
|
+
className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
|
|
24
24
|
children: "Failed to load team data. Please try again later."
|
|
25
25
|
})
|
|
26
26
|
});
|
|
27
27
|
let h = Math.floor(m?.totalHours ?? 0), g = Math.round(((m?.totalHours ?? 0) - h) * 60), _ = m?.totalHours ? Math.round((m.billableHours ?? 0) / m.totalHours * 100) : 0;
|
|
28
|
-
return /* @__PURE__ */ l(
|
|
28
|
+
return /* @__PURE__ */ l(i, {
|
|
29
29
|
title: "Team Overview",
|
|
30
30
|
description: "Monitor team performance and activity",
|
|
31
31
|
children: [/* @__PURE__ */ l("div", {
|
|
32
32
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
33
33
|
children: [
|
|
34
|
-
/* @__PURE__ */ c(
|
|
34
|
+
/* @__PURE__ */ c(t, {
|
|
35
35
|
title: "Total Entries",
|
|
36
36
|
value: String(m?.totalEntries ?? 0),
|
|
37
37
|
icon: /* @__PURE__ */ c(s, { className: "h-5 w-5" })
|
|
38
38
|
}),
|
|
39
|
-
/* @__PURE__ */ c(
|
|
39
|
+
/* @__PURE__ */ c(t, {
|
|
40
40
|
title: "Active Timers",
|
|
41
41
|
value: String(m?.activeTimers ?? 0),
|
|
42
42
|
icon: /* @__PURE__ */ c(s, { className: "h-5 w-5" }),
|
|
43
|
-
iconBgColor: "bg-
|
|
43
|
+
iconBgColor: "bg-status-success-bg text-status-success-text"
|
|
44
44
|
}),
|
|
45
|
-
/* @__PURE__ */ c(
|
|
45
|
+
/* @__PURE__ */ c(t, {
|
|
46
46
|
title: "Total Hours",
|
|
47
47
|
value: `${h}h ${g}m`,
|
|
48
48
|
icon: /* @__PURE__ */ c(a, { className: "h-5 w-5" }),
|
|
@@ -51,7 +51,7 @@ function u() {
|
|
|
51
51
|
label: "billable hours"
|
|
52
52
|
}
|
|
53
53
|
}),
|
|
54
|
-
/* @__PURE__ */ c(
|
|
54
|
+
/* @__PURE__ */ c(t, {
|
|
55
55
|
title: "Billable Rate",
|
|
56
56
|
value: `${_}%`,
|
|
57
57
|
icon: /* @__PURE__ */ c(o, { className: "h-5 w-5" }),
|
|
@@ -62,14 +62,14 @@ function u() {
|
|
|
62
62
|
})
|
|
63
63
|
]
|
|
64
64
|
}), /* @__PURE__ */ l("div", {
|
|
65
|
-
className: "rounded-xl border border-border bg-card p-6",
|
|
65
|
+
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6",
|
|
66
66
|
children: [/* @__PURE__ */ c("h3", {
|
|
67
|
-
className: "mb-4 text-sm font-semibold text-
|
|
67
|
+
className: "mb-4 text-sm font-semibold text-text-primary",
|
|
68
68
|
children: "Team Activity Feed"
|
|
69
69
|
}), /* @__PURE__ */ c("div", {
|
|
70
|
-
className: "flex h-48 items-center justify-center rounded-lg border border-dashed border-border",
|
|
70
|
+
className: "flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle",
|
|
71
71
|
children: /* @__PURE__ */ c("p", {
|
|
72
|
-
className: "text-sm text-
|
|
72
|
+
className: "text-sm text-text-secondary",
|
|
73
73
|
children: "Team activity timeline will render here"
|
|
74
74
|
})
|
|
75
75
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamPage.js","names":[],"sources":["../../../../src/timecampus/pages/team/TeamPage.tsx"],"sourcesContent":["import { Users, Clock, TrendingUp } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport { useGetTimeEntryStatsQuery } from \"@/generated/wspace-operations\";\n\nexport function TeamPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const { data, loading, error } = useGetTimeEntryStatsQuery({\n skip: !workspaceId,\n });\n\n const stats = data?.timeEntryStats;\n\n if (loading) {\n return (\n <PageLayout\n title=\"Team Overview\"\n description=\"Monitor team performance and activity\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Team Overview\"\n description=\"Monitor team performance and activity\"\n >\n <div className=\"rounded-lg border border-
|
|
1
|
+
{"version":3,"file":"TeamPage.js","names":[],"sources":["../../../../src/timecampus/pages/team/TeamPage.tsx"],"sourcesContent":["import { Users, Clock, TrendingUp } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport { useGetTimeEntryStatsQuery } from \"@/generated/wspace-operations\";\n\nexport function TeamPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const { data, loading, error } = useGetTimeEntryStatsQuery({\n skip: !workspaceId,\n });\n\n const stats = data?.timeEntryStats;\n\n if (loading) {\n return (\n <PageLayout\n title=\"Team Overview\"\n description=\"Monitor team performance and activity\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Team Overview\"\n description=\"Monitor team performance and activity\"\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 data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n const totalH = Math.floor(stats?.totalHours ?? 0);\n const totalM = Math.round(((stats?.totalHours ?? 0) - totalH) * 60);\n const billablePercent = stats?.totalHours\n ? Math.round(((stats.billableHours ?? 0) / stats.totalHours) * 100)\n : 0;\n\n return (\n <PageLayout\n title=\"Team Overview\"\n description=\"Monitor team performance and activity\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n title=\"Total Entries\"\n value={String(stats?.totalEntries ?? 0)}\n icon={<Users className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Active Timers\"\n value={String(stats?.activeTimers ?? 0)}\n icon={<Users className=\"h-5 w-5\" />}\n iconBgColor=\"bg-status-success-bg text-status-success-text\"\n />\n <StatCard\n title=\"Total Hours\"\n value={`${totalH}h ${totalM}m`}\n icon={<Clock className=\"h-5 w-5\" />}\n trend={{ value: stats?.billableHours ?? 0, label: \"billable hours\" }}\n />\n <StatCard\n title=\"Billable Rate\"\n value={`${billablePercent}%`}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n trend={{ value: billablePercent, label: \"of total hours\" }}\n />\n </div>\n\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6\">\n <h3 className=\"mb-4 text-sm font-semibold text-text-primary\">\n Team Activity Feed\n </h3>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <p className=\"text-sm text-text-secondary\">\n Team activity timeline will render here\n </p>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,IAAW;CACzB,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EAAE,SAAM,YAAS,aAAU,EAA0B,EACzD,MAAM,CAAC,GACR,CAAC,EAEI,IAAQ,GAAM;AAEpB,KAAI,EACF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA;AAIjB,KAAI,EACF,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAAoG;GAE7G,CAAA;EACK,CAAA;CAIjB,IAAM,IAAS,KAAK,MAAM,GAAO,cAAc,EAAE,EAC3C,IAAS,KAAK,QAAQ,GAAO,cAAc,KAAK,KAAU,GAAG,EAC7D,IAAkB,GAAO,aAC3B,KAAK,OAAQ,EAAM,iBAAiB,KAAK,EAAM,aAAc,IAAI,GACjE;AAEJ,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAFd,CAIE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,OAAO,GAAO,gBAAgB,EAAE;KACvC,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,OAAO,GAAO,gBAAgB,EAAE;KACvC,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,aAAY;KACZ,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,GAAG,EAAO,IAAI,EAAO;KAC5B,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,OAAO;MAAE,OAAO,GAAO,iBAAiB;MAAG,OAAO;MAAkB;KACpE,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,GAAG,EAAgB;KAC1B,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;KACxC,OAAO;MAAE,OAAO;MAAiB,OAAO;MAAkB;KAC1D,CAAA;IACE;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,MAAD;IAAI,WAAU;cAA+C;IAExD,CAAA,EACL,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,KAAD;KAAG,WAAU;eAA8B;KAEvC,CAAA;IACA,CAAA,CACF;KACK"}
|
|
@@ -1,77 +1,77 @@
|
|
|
1
1
|
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
2
|
import { formatRelativeTime as t } from "../../utils/helpers.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { StatCard as n } from "../../components/StatCard.js";
|
|
4
|
+
import { LoadingSkeleton as r } from "../../components/LoadingSkeleton.js";
|
|
5
|
+
import { useGetTimeEntryStatsQuery as i, useListWorkPatternsQuery as a } from "../../../generated/wspace-operations.js";
|
|
6
|
+
import { PageLayout as o } from "../../components/PageLayout.js";
|
|
7
7
|
import { Activity as s, CheckCircle as c, Clock as l, Users as u } from "lucide-react";
|
|
8
8
|
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
9
9
|
//#region src/timecampus/pages/team-activity/TeamActivityPage.tsx
|
|
10
10
|
function p() {
|
|
11
|
-
let { workspaceId: p = "" } = e(), { data: m, loading: h, error: g } =
|
|
12
|
-
return h && v ? /* @__PURE__ */ d(
|
|
11
|
+
let { workspaceId: p = "" } = e(), { data: m, loading: h, error: g } = i(), { data: _, loading: v, error: y } = a({ variables: { limit: 10 } }), b = m?.timeEntryStats, x = _?.workPatterns ?? [];
|
|
12
|
+
return h && v ? /* @__PURE__ */ d(o, {
|
|
13
13
|
title: "Team Activity",
|
|
14
14
|
description: "Real-time team activity feed",
|
|
15
|
-
children: /* @__PURE__ */ d(
|
|
15
|
+
children: /* @__PURE__ */ d(r, {
|
|
16
16
|
variant: "list",
|
|
17
17
|
count: 5
|
|
18
18
|
})
|
|
19
|
-
}) : g && y ? /* @__PURE__ */ d(
|
|
19
|
+
}) : g && y ? /* @__PURE__ */ d(o, {
|
|
20
20
|
title: "Team Activity",
|
|
21
21
|
description: "Real-time team activity feed",
|
|
22
22
|
children: /* @__PURE__ */ d("div", {
|
|
23
|
-
className: "rounded-lg border border-
|
|
23
|
+
className: "rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text",
|
|
24
24
|
children: "Failed to load team activity data. Please try again later."
|
|
25
25
|
})
|
|
26
|
-
}) : /* @__PURE__ */ f(
|
|
26
|
+
}) : /* @__PURE__ */ f(o, {
|
|
27
27
|
title: "Team Activity",
|
|
28
28
|
description: "Real-time team activity feed",
|
|
29
29
|
children: [/* @__PURE__ */ f("div", {
|
|
30
30
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
31
31
|
children: [
|
|
32
|
-
/* @__PURE__ */ d(
|
|
32
|
+
/* @__PURE__ */ d(n, {
|
|
33
33
|
title: "Active Timers",
|
|
34
34
|
value: String(b?.activeTimers ?? 0),
|
|
35
35
|
icon: /* @__PURE__ */ d(u, { className: "h-5 w-5" })
|
|
36
36
|
}),
|
|
37
|
-
/* @__PURE__ */ d(
|
|
37
|
+
/* @__PURE__ */ d(n, {
|
|
38
38
|
title: "Total Entries",
|
|
39
39
|
value: String(b?.totalEntries ?? 0),
|
|
40
40
|
icon: /* @__PURE__ */ d(c, { className: "h-5 w-5" }),
|
|
41
41
|
description: "Today"
|
|
42
42
|
}),
|
|
43
|
-
/* @__PURE__ */ d(
|
|
43
|
+
/* @__PURE__ */ d(n, {
|
|
44
44
|
title: "Team Hours",
|
|
45
45
|
value: `${Math.round(b?.totalHours ?? 0)}h`,
|
|
46
46
|
icon: /* @__PURE__ */ d(l, { className: "h-5 w-5" }),
|
|
47
47
|
description: "Total tracked"
|
|
48
48
|
}),
|
|
49
|
-
/* @__PURE__ */ d(
|
|
49
|
+
/* @__PURE__ */ d(n, {
|
|
50
50
|
title: "Billable Hours",
|
|
51
51
|
value: `${Math.round(b?.billableHours ?? 0)}h`,
|
|
52
52
|
icon: /* @__PURE__ */ d(s, { className: "h-5 w-5" }),
|
|
53
|
-
iconBgColor: "bg-
|
|
53
|
+
iconBgColor: "bg-status-success-bg text-status-success-text"
|
|
54
54
|
})
|
|
55
55
|
]
|
|
56
56
|
}), /* @__PURE__ */ f("div", {
|
|
57
|
-
className: "rounded-xl border border-border bg-card p-6",
|
|
57
|
+
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6",
|
|
58
58
|
children: [/* @__PURE__ */ d("h3", {
|
|
59
|
-
className: "mb-4 text-sm font-semibold text-
|
|
59
|
+
className: "mb-4 text-sm font-semibold text-text-primary",
|
|
60
60
|
children: "Activity Feed"
|
|
61
61
|
}), /* @__PURE__ */ f("div", {
|
|
62
62
|
className: "space-y-4",
|
|
63
63
|
children: [x.length === 0 && !v && /* @__PURE__ */ d("div", {
|
|
64
|
-
className: "text-center text-sm text-
|
|
64
|
+
className: "text-center text-sm text-text-secondary",
|
|
65
65
|
children: "No recent activity data available."
|
|
66
66
|
}), x.map((e) => /* @__PURE__ */ f("div", {
|
|
67
67
|
className: "flex items-start gap-3",
|
|
68
68
|
children: [/* @__PURE__ */ d("div", {
|
|
69
|
-
className: "mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-primary/10",
|
|
69
|
+
className: "mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-action-primary-bg/10",
|
|
70
70
|
children: /* @__PURE__ */ d(s, { className: "h-4 w-4 text-primary" })
|
|
71
71
|
}), /* @__PURE__ */ f("div", {
|
|
72
72
|
className: "flex-1",
|
|
73
73
|
children: [/* @__PURE__ */ f("p", {
|
|
74
|
-
className: "text-sm text-
|
|
74
|
+
className: "text-sm text-text-primary",
|
|
75
75
|
children: [
|
|
76
76
|
/* @__PURE__ */ d("span", {
|
|
77
77
|
className: "font-medium",
|
|
@@ -81,7 +81,7 @@ function p() {
|
|
|
81
81
|
e.deepWorkSessions > 0 ? "Completed deep work session" : "Logged work pattern"
|
|
82
82
|
]
|
|
83
83
|
}), /* @__PURE__ */ f("p", {
|
|
84
|
-
className: "text-xs text-
|
|
84
|
+
className: "text-xs text-text-secondary",
|
|
85
85
|
children: [
|
|
86
86
|
e.focusHours.toFixed(1),
|
|
87
87
|
"h focus ·",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamActivityPage.js","names":[],"sources":["../../../../src/timecampus/pages/team-activity/TeamActivityPage.tsx"],"sourcesContent":["import { Activity, Users, Clock, CheckCircle } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { formatRelativeTime } from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useGetTimeEntryStatsQuery,\n useListWorkPatternsQuery,\n type WorkPatternFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function TeamActivityPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetTimeEntryStatsQuery();\n const {\n data: patternsData,\n loading: patternsLoading,\n error: patternsError,\n } = useListWorkPatternsQuery({ variables: { limit: 10 } });\n\n const stats = statsData?.timeEntryStats;\n const patterns = patternsData?.workPatterns ?? [];\n\n if (statsLoading && patternsLoading) {\n return (\n <PageLayout\n title=\"Team Activity\"\n description=\"Real-time team activity feed\"\n >\n <LoadingSkeleton variant=\"list\" count={5} />\n </PageLayout>\n );\n }\n\n if (statsError && patternsError) {\n return (\n <PageLayout\n title=\"Team Activity\"\n description=\"Real-time team activity feed\"\n >\n <div className=\"rounded-lg border border-
|
|
1
|
+
{"version":3,"file":"TeamActivityPage.js","names":[],"sources":["../../../../src/timecampus/pages/team-activity/TeamActivityPage.tsx"],"sourcesContent":["import { Activity, Users, Clock, CheckCircle } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { formatRelativeTime } from \"../../utils/helpers\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useGetTimeEntryStatsQuery,\n useListWorkPatternsQuery,\n type WorkPatternFieldsFragment,\n} from \"@/generated/wspace-operations\";\n\nexport function TeamActivityPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n } = useGetTimeEntryStatsQuery();\n const {\n data: patternsData,\n loading: patternsLoading,\n error: patternsError,\n } = useListWorkPatternsQuery({ variables: { limit: 10 } });\n\n const stats = statsData?.timeEntryStats;\n const patterns = patternsData?.workPatterns ?? [];\n\n if (statsLoading && patternsLoading) {\n return (\n <PageLayout\n title=\"Team Activity\"\n description=\"Real-time team activity feed\"\n >\n <LoadingSkeleton variant=\"list\" count={5} />\n </PageLayout>\n );\n }\n\n if (statsError && patternsError) {\n return (\n <PageLayout\n title=\"Team Activity\"\n description=\"Real-time team activity feed\"\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 activity data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Team Activity\"\n description=\"Real-time team activity feed\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n title=\"Active Timers\"\n value={String(stats?.activeTimers ?? 0)}\n icon={<Users className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Total Entries\"\n value={String(stats?.totalEntries ?? 0)}\n icon={<CheckCircle className=\"h-5 w-5\" />}\n description=\"Today\"\n />\n <StatCard\n title=\"Team Hours\"\n value={`${Math.round(stats?.totalHours ?? 0)}h`}\n icon={<Clock className=\"h-5 w-5\" />}\n description=\"Total tracked\"\n />\n <StatCard\n title=\"Billable Hours\"\n value={`${Math.round(stats?.billableHours ?? 0)}h`}\n icon={<Activity className=\"h-5 w-5\" />}\n iconBgColor=\"bg-status-success-bg text-status-success-text\"\n />\n </div>\n\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6\">\n <h3 className=\"mb-4 text-sm font-semibold text-text-primary\">\n Activity Feed\n </h3>\n <div className=\"space-y-4\">\n {patterns.length === 0 && !patternsLoading && (\n <div className=\"text-center text-sm text-text-secondary\">\n No recent activity data available.\n </div>\n )}\n {patterns.map((pattern: WorkPatternFieldsFragment) => (\n <div key={pattern.id} className=\"flex items-start gap-3\">\n <div className=\"mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-action-primary-bg/10\">\n <Activity className=\"h-4 w-4 text-primary\" />\n </div>\n <div className=\"flex-1\">\n <p className=\"text-sm text-text-primary\">\n <span className=\"font-medium\">{pattern.userId}</span>{\" \"}\n {pattern.deepWorkSessions > 0\n ? \"Completed deep work session\"\n : \"Logged work pattern\"}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {pattern.focusHours.toFixed(1)}h focus ·{\" \"}\n {pattern.meetingHours.toFixed(1)}h meetings ·{\" \"}\n {pattern.productivityScore\n ? `${pattern.productivityScore}% productivity`\n : pattern.date}{\" \"}\n · {formatRelativeTime(pattern.createdAt)}\n </p>\n </div>\n </div>\n ))}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;AAYA,SAAgB,IAAmB;CACjC,IAAM,EAAE,iBAAc,OAAO,GAAe,EAEtC,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,GAA2B,EACzB,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAAyB,EAAE,WAAW,EAAE,OAAO,IAAI,EAAE,CAAC,EAEpD,IAAQ,GAAW,gBACnB,IAAW,GAAc,gBAAgB,EAAE;AA0BjD,QAxBI,KAAgB,IAEhB,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA;EACjC,CAAA,GAIb,KAAc,IAEd,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAAoG;GAE7G,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAFd,CAIE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,OAAO,GAAO,gBAAgB,EAAE;KACvC,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,OAAO,GAAO,gBAAgB,EAAE;KACvC,MAAM,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;KACzC,aAAY;KACZ,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,GAAG,KAAK,MAAM,GAAO,cAAc,EAAE,CAAC;KAC7C,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,aAAY;KACZ,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,GAAG,KAAK,MAAM,GAAO,iBAAiB,EAAE,CAAC;KAChD,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;KACtC,aAAY;KACZ,CAAA;IACE;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,MAAD;IAAI,WAAU;cAA+C;IAExD,CAAA,EACL,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAS,WAAW,KAAK,CAAC,KACzB,kBAAC,OAAD;KAAK,WAAU;eAA0C;KAEnD,CAAA,EAEP,EAAS,KAAK,MACb,kBAAC,OAAD;KAAsB,WAAU;eAAhC,CACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD,EAAU,WAAU,wBAAyB,CAAA;MACzC,CAAA,EACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACE,kBAAC,QAAD;SAAM,WAAU;mBAAe,EAAQ;SAAc,CAAA;QAAC;QACrD,EAAQ,mBAAmB,IACxB,gCACA;QACF;UACJ,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAQ,WAAW,QAAQ,EAAE;QAAC;QAAiB;QAC/C,EAAQ,aAAa,QAAQ,EAAE;QAAC;QAAoB;QACpD,EAAQ,oBACL,GAAG,EAAQ,kBAAkB,kBAC7B,EAAQ;QAAM;QAAI;QACZ,EAAmB,EAAQ,UAAU;QAC7C;SACA;QACF;OApBI,EAAQ,GAoBZ,CACN,CACE;MACF;KACK"}
|