@burdenoff/microfe-crewfoundry 2026.703.2 → 2026.704.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/crewfoundry/components/forms/FormModal.js.map +1 -1
- package/dist/crewfoundry/pages/AdminAdminPagePage.js +117 -164
- package/dist/crewfoundry/pages/AdminAdminPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +99 -82
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +160 -192
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +238 -231
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +196 -166
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js +45 -147
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsDirectoryPagePage.js +20 -11
- package/dist/crewfoundry/pages/CommunicationsDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js +45 -152
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +50 -138
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js +149 -67
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js +50 -201
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +205 -136
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js +25 -31
- package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js +118 -104
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +117 -58
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js +90 -94
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +210 -191
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js +213 -180
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js +133 -264
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js.map +1 -1
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js +279 -212
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +131 -105
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +167 -148
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +3 -3
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +13 -5
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +151 -152
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +38 -21
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +3 -3
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js +134 -127
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +163 -132
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js +202 -160
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +104 -91
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js +29 -147
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +22 -106
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +74 -74
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +101 -97
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +64 -47
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js +111 -121
- package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.js +131 -110
- package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +65 -64
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +58 -43
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +66 -82
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js +38 -88
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js +59 -65
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js +209 -323
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +175 -220
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +74 -59
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +96 -80
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js +28 -100
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js +27 -20
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +73 -73
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +62 -56
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js +40 -138
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +126 -93
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js +99 -77
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js +73 -74
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js +1 -1
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +122 -122
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +130 -113
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js +68 -59
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +73 -62
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +82 -58
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js +153 -153
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +63 -48
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,194 +1,184 @@
|
|
|
1
1
|
import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { BookOpen as t, GraduationCap as n, Star as r, Users as i } from "lucide-react";
|
|
3
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
4
|
+
import { Badge as s, Card as c, CardContent as l, CardHeader as u, CardTitle as d, GlassCard as f, GradientText as p, IllustratedEmptyState as m, PagePurpose as h, Pagination as g, ResponsiveTable as _ } from "@burdenoff/fe-libs/ui";
|
|
5
|
+
import { usePagination as v } from "@burdenoff/fe-libs/shared/hooks";
|
|
6
6
|
//#region src/crewfoundry/pages/LearningLearningAnalyticsPagePage.tsx
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
month: (/* @__PURE__ */ new Date(_ - (5 - t) * 864e5 * 30)).toLocaleString("en-US", { month: "short" }),
|
|
11
|
-
hours: Math.round((e.completed + Math.max(e.modules, 1)) * 2.2),
|
|
12
|
-
completions: e.completed,
|
|
13
|
-
enrollments: e.enrolled
|
|
14
|
-
})), [v]), C = Math.max(1, ...S.map((e) => e.hours)), w = S.reduce((e, t) => e + t.hours, 0), T = v.reduce((e, t) => (e[t.category] = (e[t.category] || 0) + t.enrolled, e), {});
|
|
15
|
-
return /* @__PURE__ */ s("div", {
|
|
7
|
+
function y() {
|
|
8
|
+
let { courses: y } = e(), { page: b, pageSize: x, offset: S, setPage: C } = v({ initialPageSize: 10 }), w = y.reduce((e, t) => e + t.enrolled, 0), T = y.reduce((e, t) => e + t.completed, 0), E = y.filter((e) => e.status === "active").length, D = (y.reduce((e, t) => e + t.rating, 0) / Math.max(y.length, 1)).toFixed(1), O = y.reduce((e, t) => (e[t.category] = (e[t.category] || 0) + t.enrolled, e), {}), k = Object.entries(O).sort(([, e], [, t]) => t - e), A = y.slice(S, S + x);
|
|
9
|
+
return /* @__PURE__ */ o("div", {
|
|
16
10
|
className: "space-y-6 p-6",
|
|
17
11
|
children: [
|
|
18
|
-
/* @__PURE__ */
|
|
19
|
-
/* @__PURE__ */
|
|
12
|
+
/* @__PURE__ */ o("div", { children: [
|
|
13
|
+
/* @__PURE__ */ a("h1", {
|
|
20
14
|
className: "text-2xl font-semibold",
|
|
21
|
-
children: /* @__PURE__ */
|
|
15
|
+
children: /* @__PURE__ */ a(p, { children: "Learning Analytics" })
|
|
22
16
|
}),
|
|
23
|
-
/* @__PURE__ */
|
|
17
|
+
/* @__PURE__ */ a("p", {
|
|
24
18
|
className: "text-sm text-text-secondary",
|
|
25
19
|
children: "Training metrics and engagement insights"
|
|
26
20
|
}),
|
|
27
|
-
/* @__PURE__ */
|
|
21
|
+
/* @__PURE__ */ a(h, {
|
|
28
22
|
className: "mt-1",
|
|
29
23
|
children: "See how learning is landing across your organization — completion rates, popular courses, and skill growth to guide your L&D strategy."
|
|
30
24
|
})
|
|
31
25
|
] }),
|
|
32
|
-
/* @__PURE__ */
|
|
26
|
+
/* @__PURE__ */ o("div", {
|
|
33
27
|
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4",
|
|
34
28
|
children: [
|
|
35
|
-
/* @__PURE__ */
|
|
29
|
+
/* @__PURE__ */ o(f, {
|
|
36
30
|
treatment: "glass",
|
|
37
31
|
glow: !0,
|
|
38
32
|
className: "border-border-seam",
|
|
39
|
-
children: [/* @__PURE__ */
|
|
33
|
+
children: [/* @__PURE__ */ o(u, {
|
|
40
34
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
41
|
-
children: [/* @__PURE__ */
|
|
35
|
+
children: [/* @__PURE__ */ a(d, {
|
|
42
36
|
className: "text-sm font-medium",
|
|
43
37
|
children: "Total Enrollments"
|
|
44
|
-
}), /* @__PURE__ */
|
|
45
|
-
}), /* @__PURE__ */
|
|
38
|
+
}), /* @__PURE__ */ a(i, { className: "h-4 w-4 text-text-secondary" })]
|
|
39
|
+
}), /* @__PURE__ */ a(l, { children: /* @__PURE__ */ a("div", {
|
|
46
40
|
className: "text-2xl font-bold tabular-nums",
|
|
47
|
-
children:
|
|
41
|
+
children: w
|
|
48
42
|
}) })]
|
|
49
43
|
}),
|
|
50
|
-
/* @__PURE__ */
|
|
44
|
+
/* @__PURE__ */ o(f, {
|
|
51
45
|
treatment: "metric",
|
|
52
46
|
className: "border-border-seam",
|
|
53
|
-
children: [/* @__PURE__ */
|
|
47
|
+
children: [/* @__PURE__ */ o(u, {
|
|
54
48
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
55
|
-
children: [/* @__PURE__ */
|
|
49
|
+
children: [/* @__PURE__ */ a(d, {
|
|
56
50
|
className: "text-sm font-medium",
|
|
57
51
|
children: "Completions"
|
|
58
|
-
}), /* @__PURE__ */
|
|
59
|
-
}), /* @__PURE__ */
|
|
52
|
+
}), /* @__PURE__ */ a(n, { className: "h-4 w-4 text-status-success-text" })]
|
|
53
|
+
}), /* @__PURE__ */ o(l, { children: [/* @__PURE__ */ a("div", {
|
|
60
54
|
className: "text-2xl font-bold tabular-nums",
|
|
61
|
-
children:
|
|
62
|
-
}), /* @__PURE__ */
|
|
55
|
+
children: T
|
|
56
|
+
}), /* @__PURE__ */ o("p", {
|
|
63
57
|
className: "text-xs text-text-secondary",
|
|
64
|
-
children: [Math.round(
|
|
58
|
+
children: [w > 0 ? Math.round(T / w * 100) : 0, "% rate"]
|
|
65
59
|
})] })]
|
|
66
60
|
}),
|
|
67
|
-
/* @__PURE__ */
|
|
61
|
+
/* @__PURE__ */ o(f, {
|
|
68
62
|
treatment: "metric",
|
|
69
63
|
className: "border-border-seam",
|
|
70
|
-
children: [/* @__PURE__ */
|
|
64
|
+
children: [/* @__PURE__ */ o(u, {
|
|
71
65
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
72
|
-
children: [/* @__PURE__ */
|
|
66
|
+
children: [/* @__PURE__ */ a(d, {
|
|
73
67
|
className: "text-sm font-medium",
|
|
74
68
|
children: "Avg Rating"
|
|
75
|
-
}), /* @__PURE__ */
|
|
76
|
-
}), /* @__PURE__ */
|
|
69
|
+
}), /* @__PURE__ */ a(r, { className: "h-4 w-4 text-status-warning-text" })]
|
|
70
|
+
}), /* @__PURE__ */ a(l, { children: /* @__PURE__ */ o("div", {
|
|
77
71
|
className: "text-2xl font-bold tabular-nums",
|
|
78
|
-
children: [
|
|
72
|
+
children: [D, "/5"]
|
|
79
73
|
}) })]
|
|
80
74
|
}),
|
|
81
|
-
/* @__PURE__ */
|
|
75
|
+
/* @__PURE__ */ o(f, {
|
|
82
76
|
treatment: "metric",
|
|
83
77
|
className: "border-border-seam",
|
|
84
|
-
children: [/* @__PURE__ */
|
|
78
|
+
children: [/* @__PURE__ */ o(u, {
|
|
85
79
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
86
|
-
children: [/* @__PURE__ */
|
|
80
|
+
children: [/* @__PURE__ */ a(d, {
|
|
87
81
|
className: "text-sm font-medium",
|
|
88
|
-
children: "
|
|
89
|
-
}), /* @__PURE__ */
|
|
90
|
-
}), /* @__PURE__ */
|
|
82
|
+
children: "Active Courses"
|
|
83
|
+
}), /* @__PURE__ */ a(t, { className: "h-4 w-4 text-text-secondary" })]
|
|
84
|
+
}), /* @__PURE__ */ o(l, { children: [/* @__PURE__ */ a("div", {
|
|
91
85
|
className: "text-2xl font-bold tabular-nums",
|
|
92
|
-
children:
|
|
86
|
+
children: E
|
|
93
87
|
}), /* @__PURE__ */ o("p", {
|
|
94
88
|
className: "text-xs text-text-secondary",
|
|
95
|
-
children:
|
|
89
|
+
children: [
|
|
90
|
+
"of ",
|
|
91
|
+
y.length,
|
|
92
|
+
" total"
|
|
93
|
+
]
|
|
96
94
|
})] })]
|
|
97
95
|
})
|
|
98
96
|
]
|
|
99
97
|
}),
|
|
100
|
-
/* @__PURE__ */
|
|
101
|
-
className: "space-y-3",
|
|
102
|
-
children: S.map((e) => /* @__PURE__ */ s("div", {
|
|
103
|
-
className: "flex items-center gap-3",
|
|
104
|
-
children: [
|
|
105
|
-
/* @__PURE__ */ o("span", {
|
|
106
|
-
className: "w-10 text-sm text-text-secondary",
|
|
107
|
-
children: e.month
|
|
108
|
-
}),
|
|
109
|
-
/* @__PURE__ */ o("div", {
|
|
110
|
-
className: "h-4 flex-1 overflow-hidden rounded bg-bg-sunken",
|
|
111
|
-
children: /* @__PURE__ */ o("div", {
|
|
112
|
-
className: "h-4 rounded bg-action-primary-bg",
|
|
113
|
-
style: { width: `${Math.round(e.hours / C * 100)}%` }
|
|
114
|
-
})
|
|
115
|
-
}),
|
|
116
|
-
/* @__PURE__ */ s("span", {
|
|
117
|
-
className: "w-16 text-right text-sm font-medium",
|
|
118
|
-
children: [e.hours, "h"]
|
|
119
|
-
}),
|
|
120
|
-
/* @__PURE__ */ s(c, {
|
|
121
|
-
variant: "default",
|
|
122
|
-
className: "text-[10px]",
|
|
123
|
-
children: [e.completions, " done"]
|
|
124
|
-
})
|
|
125
|
-
]
|
|
126
|
-
}, `${e.month}-${e.hours}`))
|
|
127
|
-
})] }),
|
|
128
|
-
/* @__PURE__ */ s("div", {
|
|
98
|
+
/* @__PURE__ */ o("div", {
|
|
129
99
|
className: "grid gap-4 md:grid-cols-2",
|
|
130
|
-
children: [/* @__PURE__ */
|
|
100
|
+
children: [/* @__PURE__ */ o(c, { children: [/* @__PURE__ */ a(u, { children: /* @__PURE__ */ a(d, { children: "Category Distribution" }) }), /* @__PURE__ */ a(l, {
|
|
131
101
|
className: "space-y-3",
|
|
132
|
-
children:
|
|
102
|
+
children: k.length === 0 ? /* @__PURE__ */ a("p", {
|
|
103
|
+
className: "text-sm text-text-secondary",
|
|
104
|
+
children: "No enrollment data yet."
|
|
105
|
+
}) : k.map(([e, t]) => /* @__PURE__ */ o("div", {
|
|
133
106
|
className: "flex items-center justify-between",
|
|
134
|
-
children: [/* @__PURE__ */
|
|
107
|
+
children: [/* @__PURE__ */ a("span", {
|
|
135
108
|
className: "text-sm",
|
|
136
109
|
children: e
|
|
137
|
-
}), /* @__PURE__ */
|
|
110
|
+
}), /* @__PURE__ */ o("div", {
|
|
138
111
|
className: "flex items-center gap-2",
|
|
139
|
-
children: [/* @__PURE__ */
|
|
112
|
+
children: [/* @__PURE__ */ a("span", {
|
|
140
113
|
className: "text-sm font-medium",
|
|
141
114
|
children: t
|
|
142
|
-
}), /* @__PURE__ */ s
|
|
115
|
+
}), /* @__PURE__ */ o(s, {
|
|
143
116
|
variant: "outline",
|
|
144
117
|
className: "text-[10px]",
|
|
145
|
-
children: [Math.round(t /
|
|
118
|
+
children: [w > 0 ? Math.round(t / w * 100) : 0, "%"]
|
|
146
119
|
})]
|
|
147
120
|
})]
|
|
148
121
|
}, e))
|
|
149
|
-
})] }), /* @__PURE__ */
|
|
150
|
-
className: "
|
|
151
|
-
children: [
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
122
|
+
})] }), /* @__PURE__ */ o(c, { children: [/* @__PURE__ */ a(u, { children: /* @__PURE__ */ a(d, { children: "Course Performance" }) }), /* @__PURE__ */ o(l, {
|
|
123
|
+
className: "space-y-3",
|
|
124
|
+
children: [/* @__PURE__ */ a(_, {
|
|
125
|
+
columns: [
|
|
126
|
+
{
|
|
127
|
+
key: "title",
|
|
128
|
+
header: "Course",
|
|
129
|
+
priority: "primary",
|
|
130
|
+
cell: (e) => /* @__PURE__ */ a("span", {
|
|
131
|
+
className: "font-medium",
|
|
132
|
+
children: e.title
|
|
133
|
+
})
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
key: "enrolled",
|
|
137
|
+
header: "Enrolled",
|
|
138
|
+
priority: "secondary",
|
|
139
|
+
headerClassName: "text-right",
|
|
140
|
+
cellClassName: "md:text-right",
|
|
141
|
+
cell: (e) => e.enrolled
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
key: "completed",
|
|
145
|
+
header: "Completed",
|
|
146
|
+
priority: "secondary",
|
|
147
|
+
headerClassName: "text-right",
|
|
148
|
+
cellClassName: "md:text-right",
|
|
149
|
+
cell: (e) => e.completed
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
key: "rating",
|
|
153
|
+
header: "Rating",
|
|
154
|
+
priority: "secondary",
|
|
155
|
+
headerClassName: "text-right",
|
|
156
|
+
cellClassName: "md:text-right",
|
|
157
|
+
cell: (e) => /* @__PURE__ */ o("span", {
|
|
158
|
+
className: "inline-flex items-center gap-1 md:justify-end",
|
|
159
|
+
children: [/* @__PURE__ */ a(r, { className: "h-3 w-3 text-status-warning-text" }), e.rating]
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
data: A,
|
|
164
|
+
rowKey: (e) => e.id,
|
|
165
|
+
emptyState: /* @__PURE__ */ a(m, {
|
|
166
|
+
illustration: "empty-generic",
|
|
167
|
+
title: "No courses yet",
|
|
168
|
+
description: "Course performance will appear here once courses are added."
|
|
184
169
|
})
|
|
185
|
-
|
|
186
|
-
|
|
170
|
+
}), y.length > x && /* @__PURE__ */ a(g, {
|
|
171
|
+
page: b,
|
|
172
|
+
pageSize: x,
|
|
173
|
+
totalItems: y.length,
|
|
174
|
+
onPageChange: C
|
|
175
|
+
})]
|
|
176
|
+
})] })]
|
|
187
177
|
})
|
|
188
178
|
]
|
|
189
179
|
});
|
|
190
180
|
}
|
|
191
181
|
//#endregion
|
|
192
|
-
export {
|
|
182
|
+
export { y as LearningLearningAnalyticsPagePage };
|
|
193
183
|
|
|
194
184
|
//# sourceMappingURL=LearningLearningAnalyticsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LearningLearningAnalyticsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/LearningLearningAnalyticsPagePage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { Clock, GraduationCap, Star, Users } from 'lucide-react';\nimport {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\ntype MonthlyLearning = {\n month: string;\n hours: number;\n completions: number;\n enrollments: number;\n};\n\nconst BASE_TS = new Date('2026-03-01T00:00:00Z').getTime();\n\nexport function LearningLearningAnalyticsPagePage() {\n const { courses } = useCrewFoundryStore();\n\n const totalEnrolled = courses.reduce((sum, course) => sum + course.enrolled, 0);\n const totalCompleted = courses.reduce((sum, course) => sum + course.completed, 0);\n const avgRating = (\n courses.reduce((sum, course) => sum + course.rating, 0) / Math.max(courses.length, 1)\n ).toFixed(1);\n\n const monthlyLearning = useMemo<MonthlyLearning[]>(() => {\n return courses.slice(0, 6).map((course, index) => {\n const month = new Date(BASE_TS - (5 - index) * 86400000 * 30).toLocaleString('en-US', {\n month: 'short',\n });\n return {\n month,\n hours: Math.round((course.completed + Math.max(course.modules, 1)) * 2.2),\n completions: course.completed,\n enrollments: course.enrolled,\n };\n });\n }, [courses]);\n\n const maxHours = Math.max(1, ...monthlyLearning.map((item) => item.hours));\n const totalHours = monthlyLearning.reduce((sum, item) => sum + item.hours, 0);\n\n const categoryDistribution = courses.reduce<Record<string, number>>((acc, course) => {\n acc[course.category] = (acc[course.category] || 0) + course.enrolled;\n return acc;\n }, {});\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Learning Analytics</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Training metrics and engagement insights</p>\n <PagePurpose className=\"mt-1\">See how learning is landing across your organization — completion rates, popular courses, and skill growth to guide your L&D strategy.</PagePurpose>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Total Enrollments</CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{totalEnrolled}</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Completions</CardTitle>\n <GraduationCap className=\"h-4 w-4 text-status-success-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{totalCompleted}</div>\n <p className=\"text-xs text-text-secondary\">\n {Math.round((totalCompleted / Math.max(totalEnrolled, 1)) * 100)}% rate\n </p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Avg Rating</CardTitle>\n <Star className=\"h-4 w-4 text-status-warning-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgRating}/5</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Training Hours</CardTitle>\n <Clock className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{totalHours.toLocaleString()}</div>\n <p className=\"text-xs text-text-secondary\">Recent 6-month trend</p>\n </CardContent>\n </GlassCard>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Monthly Training Activity</CardTitle>\n <CardDescription>Hours and completions over time</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {monthlyLearning.map((item) => (\n <div key={`${item.month}-${item.hours}`} className=\"flex items-center gap-3\">\n <span className=\"w-10 text-sm text-text-secondary\">{item.month}</span>\n <div className=\"h-4 flex-1 overflow-hidden rounded bg-bg-sunken\">\n <div\n className=\"h-4 rounded bg-action-primary-bg\"\n style={{ width: `${Math.round((item.hours / maxHours) * 100)}%` }}\n />\n </div>\n <span className=\"w-16 text-right text-sm font-medium\">{item.hours}h</span>\n <Badge variant=\"default\" className=\"text-[10px]\">\n {item.completions} done\n </Badge>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Category Distribution</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {Object.entries(categoryDistribution)\n .sort(([, a], [, b]) => b - a)\n .map(([category, count]) => (\n <div key={category} className=\"flex items-center justify-between\">\n <span className=\"text-sm\">{category}</span>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{count}</span>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {Math.round((count / Math.max(totalEnrolled, 1)) * 100)}%\n </Badge>\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Course Performance</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"mb-2 grid grid-cols-4 gap-2 border-b pb-2 text-xs font-medium text-text-secondary\">\n <span>Course</span>\n <span className=\"text-right\">Enrolled</span>\n <span className=\"text-right\">Completed</span>\n <span className=\"text-right\">Rating</span>\n </div>\n {courses.map((course) => (\n <div\n key={course.id}\n className=\"grid grid-cols-4 gap-2 border-b py-2 text-sm last:border-0\"\n >\n <span className=\"truncate font-medium\">{course.title}</span>\n <span className=\"text-right\">{course.enrolled}</span>\n <span className=\"text-right\">{course.completed}</span>\n <div className=\"flex items-center justify-end gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n {course.rating}\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LearningLearningAnalyticsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/LearningLearningAnalyticsPagePage.tsx"],"sourcesContent":["import { BookOpen, GraduationCap, Star, Users } from 'lucide-react';\nimport {\n Badge,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { useCrewFoundryStore, type LearningCourse } from '../store/crewfoundryStore';\n\nexport function LearningLearningAnalyticsPagePage() {\n const { courses } = useCrewFoundryStore();\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 10 });\n\n const totalEnrolled = courses.reduce((sum, course) => sum + course.enrolled, 0);\n const totalCompleted = courses.reduce((sum, course) => sum + course.completed, 0);\n const activeCourses = courses.filter((course) => course.status === 'active').length;\n const avgRating = (\n courses.reduce((sum, course) => sum + course.rating, 0) / Math.max(courses.length, 1)\n ).toFixed(1);\n\n const categoryDistribution = courses.reduce<Record<string, number>>((acc, course) => {\n acc[course.category] = (acc[course.category] || 0) + course.enrolled;\n return acc;\n }, {});\n const sortedCategories = Object.entries(categoryDistribution).sort(([, a], [, b]) => b - a);\n\n const pagedCourses = courses.slice(offset, offset + pageSize);\n\n const columns: ResponsiveTableColumn<LearningCourse>[] = [\n {\n key: 'title',\n header: 'Course',\n priority: 'primary',\n cell: (course) => <span className=\"font-medium\">{course.title}</span>,\n },\n {\n key: 'enrolled',\n header: 'Enrolled',\n priority: 'secondary',\n headerClassName: 'text-right',\n cellClassName: 'md:text-right',\n cell: (course) => course.enrolled,\n },\n {\n key: 'completed',\n header: 'Completed',\n priority: 'secondary',\n headerClassName: 'text-right',\n cellClassName: 'md:text-right',\n cell: (course) => course.completed,\n },\n {\n key: 'rating',\n header: 'Rating',\n priority: 'secondary',\n headerClassName: 'text-right',\n cellClassName: 'md:text-right',\n cell: (course) => (\n <span className=\"inline-flex items-center gap-1 md:justify-end\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n {course.rating}\n </span>\n ),\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Learning Analytics</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Training metrics and engagement insights</p>\n <PagePurpose className=\"mt-1\">\n See how learning is landing across your organization — completion rates, popular courses,\n and skill growth to guide your L&D strategy.\n </PagePurpose>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Total Enrollments</CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{totalEnrolled}</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Completions</CardTitle>\n <GraduationCap className=\"h-4 w-4 text-status-success-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{totalCompleted}</div>\n <p className=\"text-xs text-text-secondary\">\n {totalEnrolled > 0 ? Math.round((totalCompleted / totalEnrolled) * 100) : 0}% rate\n </p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Avg Rating</CardTitle>\n <Star className=\"h-4 w-4 text-status-warning-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgRating}/5</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Active Courses</CardTitle>\n <BookOpen className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activeCourses}</div>\n <p className=\"text-xs text-text-secondary\">of {courses.length} total</p>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Category Distribution</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {sortedCategories.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">No enrollment data yet.</p>\n ) : (\n sortedCategories.map(([category, count]) => (\n <div key={category} className=\"flex items-center justify-between\">\n <span className=\"text-sm\">{category}</span>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium\">{count}</span>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {totalEnrolled > 0 ? Math.round((count / totalEnrolled) * 100) : 0}%\n </Badge>\n </div>\n </div>\n ))\n )}\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Course Performance</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <ResponsiveTable\n columns={columns}\n data={pagedCourses}\n rowKey={(course) => course.id}\n emptyState={\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No courses yet\"\n description=\"Course performance will appear here once courses are added.\"\n />\n }\n />\n {courses.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={courses.length}\n onPageChange={setPage}\n />\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAkBA,SAAgB,IAAoC;CAClD,IAAM,EAAE,eAAY,GAAqB,EACnC,EAAE,SAAM,aAAU,WAAQ,eAAY,EAAc,EAAE,iBAAiB,IAAI,CAAC,EAE5E,IAAgB,EAAQ,QAAQ,GAAK,MAAW,IAAM,EAAO,UAAU,EAAE,EACzE,IAAiB,EAAQ,QAAQ,GAAK,MAAW,IAAM,EAAO,WAAW,EAAE,EAC3E,IAAgB,EAAQ,QAAQ,MAAW,EAAO,WAAW,SAAS,CAAC,QACvE,KACJ,EAAQ,QAAQ,GAAK,MAAW,IAAM,EAAO,QAAQ,EAAE,GAAG,KAAK,IAAI,EAAQ,QAAQ,EAAE,EACrF,QAAQ,EAAE,EAEN,IAAuB,EAAQ,QAAgC,GAAK,OACxE,EAAI,EAAO,aAAa,EAAI,EAAO,aAAa,KAAK,EAAO,UACrD,IACN,EAAE,CAAC,EACA,IAAmB,OAAO,QAAQ,EAAqB,CAAC,MAAM,GAAG,IAAI,GAAG,OAAO,IAAI,EAAE,EAErF,IAAe,EAAQ,MAAM,GAAQ,IAAS,EAAS;AAwC7D,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,MAAD;KAAI,WAAU;eACZ,kBAAC,GAAD,EAAA,UAAc,sBAAiC,CAAA;KAC5C,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eAA8B;KAA4C,CAAA;IACvF,kBAAC,GAAD;KAAa,WAAU;eAAO;KAGhB,CAAA;IACV,EAAA,CAAA;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAW,WAAU;MAAQ,MAAA;MAAK,WAAU;gBAA5C,CACE,kBAAC,GAAD;OAAY,WAAU;iBAAtB,CACE,kBAAC,GAAD;QAAW,WAAU;kBAAsB;QAA6B,CAAA,EACxE,kBAAC,GAAD,EAAO,WAAU,+BAAgC,CAAA,CACtC;UACb,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;OAAK,WAAU;iBAAmC;OAAoB,CAAA,EAC1D,CAAA,CACJ;;KACZ,kBAAC,GAAD;MAAW,WAAU;MAAS,WAAU;gBAAxC,CACE,kBAAC,GAAD;OAAY,WAAU;iBAAtB,CACE,kBAAC,GAAD;QAAW,WAAU;kBAAsB;QAAuB,CAAA,EAClE,kBAAC,GAAD,EAAe,WAAU,oCAAqC,CAAA,CACnD;UACb,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAmC;OAAqB,CAAA,EACvE,kBAAC,KAAD;OAAG,WAAU;iBAAb,CACG,IAAgB,IAAI,KAAK,MAAO,IAAiB,IAAiB,IAAI,GAAG,GAAE,SAC1E;SACQ,EAAA,CAAA,CACJ;;KACZ,kBAAC,GAAD;MAAW,WAAU;MAAS,WAAU;gBAAxC,CACE,kBAAC,GAAD;OAAY,WAAU;iBAAtB,CACE,kBAAC,GAAD;QAAW,WAAU;kBAAsB;QAAsB,CAAA,EACjE,kBAAC,GAAD,EAAM,WAAU,oCAAqC,CAAA,CAC1C;UACb,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CAAkD,GAAU,KAAQ;UACxD,CAAA,CACJ;;KACZ,kBAAC,GAAD;MAAW,WAAU;MAAS,WAAU;gBAAxC,CACE,kBAAC,GAAD;OAAY,WAAU;iBAAtB,CACE,kBAAC,GAAD;QAAW,WAAU;kBAAsB;QAA0B,CAAA,EACrE,kBAAC,GAAD,EAAU,WAAU,+BAAgC,CAAA,CACzC;UACb,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAmC;OAAoB,CAAA,EACtE,kBAAC,KAAD;OAAG,WAAU;iBAAb;QAA2C;QAAI,EAAQ;QAAO;QAAU;SAC5D,EAAA,CAAA,CACJ;;KACR;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,yBAAiC,CAAA,EACjC,CAAA,EACb,kBAAC,GAAD;KAAa,WAAU;eACpB,EAAiB,WAAW,IAC3B,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAA2B,CAAA,GAEtE,EAAiB,KAAK,CAAC,GAAU,OAC/B,kBAAC,OAAD;MAAoB,WAAU;gBAA9B,CACE,kBAAC,QAAD;OAAM,WAAU;iBAAW;OAAgB,CAAA,EAC3C,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAuB;QAAa,CAAA,EACpD,kBAAC,GAAD;QAAO,SAAQ;QAAU,WAAU;kBAAnC,CACG,IAAgB,IAAI,KAAK,MAAO,IAAQ,IAAiB,IAAI,GAAG,GAAE,IAC7D;UACJ;SACF;QARI,EAQJ,CACN;KAEQ,CAAA,CACT,EAAA,CAAA,EACP,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAW,sBAA8B,CAAA,EAC9B,CAAA,EACb,kBAAC,GAAD;KAAa,WAAU;eAAvB,CACE,kBAAC,GAAD;MACW,SA3HoC;OACvD;QACE,KAAK;QACL,QAAQ;QACR,UAAU;QACV,OAAO,MAAW,kBAAC,QAAD;SAAM,WAAU;mBAAe,EAAO;SAAa,CAAA;QACtE;OACD;QACE,KAAK;QACL,QAAQ;QACR,UAAU;QACV,iBAAiB;QACjB,eAAe;QACf,OAAO,MAAW,EAAO;QAC1B;OACD;QACE,KAAK;QACL,QAAQ;QACR,UAAU;QACV,iBAAiB;QACjB,eAAe;QACf,OAAO,MAAW,EAAO;QAC1B;OACD;QACE,KAAK;QACL,QAAQ;QACR,UAAU;QACV,iBAAiB;QACjB,eAAe;QACf,OAAO,MACL,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CACE,kBAAC,GAAD,EAAM,WAAU,oCAAqC,CAAA,EACpD,EAAO,OACH;;QAEV;OACF;MAwFW,MAAM;MACN,SAAS,MAAW,EAAO;MAC3B,YACE,kBAAC,GAAD;OACE,cAAa;OACb,OAAM;OACN,aAAY;OACZ,CAAA;MAEJ,CAAA,EACD,EAAQ,SAAS,KAChB,kBAAC,GAAD;MACQ;MACI;MACV,YAAY,EAAQ;MACpB,cAAc;MACd,CAAA,CAEQ;OACT,EAAA,CAAA,CACH;;GACF"}
|