@burdenoff/microfe-crewfoundry 2026.703.2 → 2026.704.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/dist/crewfoundry/pages/AdminAdminPagePage.js +117 -164
  2. package/dist/crewfoundry/pages/AdminAdminPagePage.js.map +1 -1
  3. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +99 -82
  4. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  5. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +160 -192
  6. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
  7. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +238 -231
  8. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
  9. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +196 -166
  10. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
  11. package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js +45 -147
  12. package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js.map +1 -1
  13. package/dist/crewfoundry/pages/CommunicationsDirectoryPagePage.js +20 -11
  14. package/dist/crewfoundry/pages/CommunicationsDirectoryPagePage.js.map +1 -1
  15. package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js +45 -152
  16. package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js.map +1 -1
  17. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +50 -138
  18. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
  19. package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js +149 -67
  20. package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js.map +1 -1
  21. package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js +50 -201
  22. package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js.map +1 -1
  23. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +205 -136
  24. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
  25. package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js +25 -31
  26. package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js.map +1 -1
  27. package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js +118 -104
  28. package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js.map +1 -1
  29. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +117 -58
  30. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
  31. package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js +90 -94
  32. package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js.map +1 -1
  33. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +210 -191
  34. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
  35. package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js +213 -180
  36. package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js.map +1 -1
  37. package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js +133 -264
  38. package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js.map +1 -1
  39. package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js +279 -212
  40. package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js.map +1 -1
  41. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +131 -105
  42. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
  43. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +167 -148
  44. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
  45. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +3 -3
  46. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
  47. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +13 -5
  48. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
  49. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +151 -152
  50. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
  51. package/dist/crewfoundry/pages/HiringJobsPagePage.js +38 -21
  52. package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
  53. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +3 -3
  54. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
  55. package/dist/crewfoundry/pages/HrEmployeesPagePage.js +134 -127
  56. package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
  57. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +163 -132
  58. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
  59. package/dist/crewfoundry/pages/HrPayrollPagePage.js +202 -160
  60. package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
  61. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +104 -91
  62. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
  63. package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js +29 -147
  64. package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js.map +1 -1
  65. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +22 -106
  66. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
  67. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +74 -74
  68. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
  69. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +101 -97
  70. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
  71. package/dist/crewfoundry/pages/LearningCoursesPagePage.js +64 -47
  72. package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
  73. package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js +111 -121
  74. package/dist/crewfoundry/pages/LearningLearningAnalyticsPagePage.js.map +1 -1
  75. package/dist/crewfoundry/pages/LearningLearningPagePage.js +131 -110
  76. package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +1 -1
  77. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +65 -64
  78. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
  79. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +58 -43
  80. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
  81. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +66 -82
  82. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
  83. package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js +38 -88
  84. package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js.map +1 -1
  85. package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js +59 -65
  86. package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js.map +1 -1
  87. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js +209 -323
  88. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
  89. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +175 -220
  90. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
  91. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +74 -59
  92. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
  93. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +96 -80
  94. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
  95. package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js +28 -100
  96. package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js.map +1 -1
  97. package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js +27 -20
  98. package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
  99. package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +73 -73
  100. package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
  101. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +62 -56
  102. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
  103. package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js +40 -138
  104. package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js.map +1 -1
  105. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +126 -93
  106. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
  107. package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js +99 -77
  108. package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
  109. package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js +73 -74
  110. package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js.map +1 -1
  111. package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js +1 -1
  112. package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js.map +1 -1
  113. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +122 -122
  114. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
  115. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +130 -113
  116. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
  117. package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js +68 -59
  118. package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js.map +1 -1
  119. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +73 -62
  120. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
  121. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +82 -58
  122. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
  123. package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js +153 -153
  124. package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
  125. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +63 -48
  126. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
  127. package/package.json +1 -1
@@ -1,194 +1,184 @@
1
1
  import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
2
- import { useMemo as t } from "react";
3
- import { Clock as n, GraduationCap as r, Star as i, Users as a } from "lucide-react";
4
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
5
- import { Badge as c, Card as l, CardContent as u, CardDescription as d, CardHeader as f, CardTitle as p, GlassCard as m, GradientText as h, PagePurpose as g } from "@burdenoff/fe-libs/ui";
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
- var _ = (/* @__PURE__ */ new Date("2026-03-01T00:00:00Z")).getTime();
8
- function v() {
9
- let { courses: v } = e(), y = v.reduce((e, t) => e + t.enrolled, 0), b = v.reduce((e, t) => e + t.completed, 0), x = (v.reduce((e, t) => e + t.rating, 0) / Math.max(v.length, 1)).toFixed(1), S = t(() => v.slice(0, 6).map((e, t) => ({
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__ */ s("div", { children: [
19
- /* @__PURE__ */ o("h1", {
12
+ /* @__PURE__ */ o("div", { children: [
13
+ /* @__PURE__ */ a("h1", {
20
14
  className: "text-2xl font-semibold",
21
- children: /* @__PURE__ */ o(h, { children: "Learning Analytics" })
15
+ children: /* @__PURE__ */ a(p, { children: "Learning Analytics" })
22
16
  }),
23
- /* @__PURE__ */ o("p", {
17
+ /* @__PURE__ */ a("p", {
24
18
  className: "text-sm text-text-secondary",
25
19
  children: "Training metrics and engagement insights"
26
20
  }),
27
- /* @__PURE__ */ o(g, {
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__ */ s("div", {
26
+ /* @__PURE__ */ o("div", {
33
27
  className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4",
34
28
  children: [
35
- /* @__PURE__ */ s(m, {
29
+ /* @__PURE__ */ o(f, {
36
30
  treatment: "glass",
37
31
  glow: !0,
38
32
  className: "border-border-seam",
39
- children: [/* @__PURE__ */ s(f, {
33
+ children: [/* @__PURE__ */ o(u, {
40
34
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
41
- children: [/* @__PURE__ */ o(p, {
35
+ children: [/* @__PURE__ */ a(d, {
42
36
  className: "text-sm font-medium",
43
37
  children: "Total Enrollments"
44
- }), /* @__PURE__ */ o(a, { className: "h-4 w-4 text-text-secondary" })]
45
- }), /* @__PURE__ */ o(u, { children: /* @__PURE__ */ o("div", {
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: y
41
+ children: w
48
42
  }) })]
49
43
  }),
50
- /* @__PURE__ */ s(m, {
44
+ /* @__PURE__ */ o(f, {
51
45
  treatment: "metric",
52
46
  className: "border-border-seam",
53
- children: [/* @__PURE__ */ s(f, {
47
+ children: [/* @__PURE__ */ o(u, {
54
48
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
55
- children: [/* @__PURE__ */ o(p, {
49
+ children: [/* @__PURE__ */ a(d, {
56
50
  className: "text-sm font-medium",
57
51
  children: "Completions"
58
- }), /* @__PURE__ */ o(r, { className: "h-4 w-4 text-status-success-text" })]
59
- }), /* @__PURE__ */ s(u, { children: [/* @__PURE__ */ o("div", {
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: b
62
- }), /* @__PURE__ */ s("p", {
55
+ children: T
56
+ }), /* @__PURE__ */ o("p", {
63
57
  className: "text-xs text-text-secondary",
64
- children: [Math.round(b / Math.max(y, 1) * 100), "% rate"]
58
+ children: [w > 0 ? Math.round(T / w * 100) : 0, "% rate"]
65
59
  })] })]
66
60
  }),
67
- /* @__PURE__ */ s(m, {
61
+ /* @__PURE__ */ o(f, {
68
62
  treatment: "metric",
69
63
  className: "border-border-seam",
70
- children: [/* @__PURE__ */ s(f, {
64
+ children: [/* @__PURE__ */ o(u, {
71
65
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
72
- children: [/* @__PURE__ */ o(p, {
66
+ children: [/* @__PURE__ */ a(d, {
73
67
  className: "text-sm font-medium",
74
68
  children: "Avg Rating"
75
- }), /* @__PURE__ */ o(i, { className: "h-4 w-4 text-status-warning-text" })]
76
- }), /* @__PURE__ */ o(u, { children: /* @__PURE__ */ s("div", {
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: [x, "/5"]
72
+ children: [D, "/5"]
79
73
  }) })]
80
74
  }),
81
- /* @__PURE__ */ s(m, {
75
+ /* @__PURE__ */ o(f, {
82
76
  treatment: "metric",
83
77
  className: "border-border-seam",
84
- children: [/* @__PURE__ */ s(f, {
78
+ children: [/* @__PURE__ */ o(u, {
85
79
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
86
- children: [/* @__PURE__ */ o(p, {
80
+ children: [/* @__PURE__ */ a(d, {
87
81
  className: "text-sm font-medium",
88
- children: "Training Hours"
89
- }), /* @__PURE__ */ o(n, { className: "h-4 w-4 text-text-secondary" })]
90
- }), /* @__PURE__ */ s(u, { children: [/* @__PURE__ */ o("div", {
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: w.toLocaleString()
86
+ children: E
93
87
  }), /* @__PURE__ */ o("p", {
94
88
  className: "text-xs text-text-secondary",
95
- children: "Recent 6-month trend"
89
+ children: [
90
+ "of ",
91
+ y.length,
92
+ " total"
93
+ ]
96
94
  })] })]
97
95
  })
98
96
  ]
99
97
  }),
100
- /* @__PURE__ */ s(l, { children: [/* @__PURE__ */ s(f, { children: [/* @__PURE__ */ o(p, { children: "Monthly Training Activity" }), /* @__PURE__ */ o(d, { children: "Hours and completions over time" })] }), /* @__PURE__ */ o(u, {
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__ */ s(l, { children: [/* @__PURE__ */ o(f, { children: /* @__PURE__ */ o(p, { children: "Category Distribution" }) }), /* @__PURE__ */ o(u, {
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: Object.entries(T).sort(([, e], [, t]) => t - e).map(([e, t]) => /* @__PURE__ */ s("div", {
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__ */ o("span", {
107
+ children: [/* @__PURE__ */ a("span", {
135
108
  className: "text-sm",
136
109
  children: e
137
- }), /* @__PURE__ */ s("div", {
110
+ }), /* @__PURE__ */ o("div", {
138
111
  className: "flex items-center gap-2",
139
- children: [/* @__PURE__ */ o("span", {
112
+ children: [/* @__PURE__ */ a("span", {
140
113
  className: "text-sm font-medium",
141
114
  children: t
142
- }), /* @__PURE__ */ s(c, {
115
+ }), /* @__PURE__ */ o(s, {
143
116
  variant: "outline",
144
117
  className: "text-[10px]",
145
- children: [Math.round(t / Math.max(y, 1) * 100), "%"]
118
+ children: [w > 0 ? Math.round(t / w * 100) : 0, "%"]
146
119
  })]
147
120
  })]
148
121
  }, e))
149
- })] }), /* @__PURE__ */ s(l, { children: [/* @__PURE__ */ o(f, { children: /* @__PURE__ */ o(p, { children: "Course Performance" }) }), /* @__PURE__ */ s(u, { children: [/* @__PURE__ */ s("div", {
150
- className: "mb-2 grid grid-cols-4 gap-2 border-b pb-2 text-xs font-medium text-text-secondary",
151
- children: [
152
- /* @__PURE__ */ o("span", { children: "Course" }),
153
- /* @__PURE__ */ o("span", {
154
- className: "text-right",
155
- children: "Enrolled"
156
- }),
157
- /* @__PURE__ */ o("span", {
158
- className: "text-right",
159
- children: "Completed"
160
- }),
161
- /* @__PURE__ */ o("span", {
162
- className: "text-right",
163
- children: "Rating"
164
- })
165
- ]
166
- }), v.map((e) => /* @__PURE__ */ s("div", {
167
- className: "grid grid-cols-4 gap-2 border-b py-2 text-sm last:border-0",
168
- children: [
169
- /* @__PURE__ */ o("span", {
170
- className: "truncate font-medium",
171
- children: e.title
172
- }),
173
- /* @__PURE__ */ o("span", {
174
- className: "text-right",
175
- children: e.enrolled
176
- }),
177
- /* @__PURE__ */ o("span", {
178
- className: "text-right",
179
- children: e.completed
180
- }),
181
- /* @__PURE__ */ s("div", {
182
- className: "flex items-center justify-end gap-1",
183
- children: [/* @__PURE__ */ o(i, { className: "h-3 w-3 text-status-warning-text" }), e.rating]
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
- }, e.id))] })] })]
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 { v as LearningLearningAnalyticsPagePage };
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&amp;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":"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"}