@burdenoff/microfe-crewfoundry 2026.704.6 → 2026.704.7

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 (148) hide show
  1. package/dist/crewfoundry/CrewFoundryRoutes.js +51 -43
  2. package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
  3. package/dist/crewfoundry/components/forms/formValues.js +5 -2
  4. package/dist/crewfoundry/components/forms/formValues.js.map +1 -1
  5. package/dist/crewfoundry/components/viz/AllocationBar.js +68 -0
  6. package/dist/crewfoundry/components/viz/AllocationBar.js.map +1 -0
  7. package/dist/crewfoundry/components/viz/AreaChart.js +102 -0
  8. package/dist/crewfoundry/components/viz/AreaChart.js.map +1 -0
  9. package/dist/crewfoundry/components/viz/AvatarStack.js +36 -0
  10. package/dist/crewfoundry/components/viz/AvatarStack.js.map +1 -0
  11. package/dist/crewfoundry/components/viz/BarChart.js +83 -0
  12. package/dist/crewfoundry/components/viz/BarChart.js.map +1 -0
  13. package/dist/crewfoundry/components/viz/CertificateCard.js +118 -0
  14. package/dist/crewfoundry/components/viz/CertificateCard.js.map +1 -0
  15. package/dist/crewfoundry/components/viz/DonutChart.js +109 -0
  16. package/dist/crewfoundry/components/viz/DonutChart.js.map +1 -0
  17. package/dist/crewfoundry/components/viz/HBarFunnel.js +54 -0
  18. package/dist/crewfoundry/components/viz/HBarFunnel.js.map +1 -0
  19. package/dist/crewfoundry/components/viz/Heatmap.js +91 -0
  20. package/dist/crewfoundry/components/viz/Heatmap.js.map +1 -0
  21. package/dist/crewfoundry/components/viz/KanbanBoard.js +50 -0
  22. package/dist/crewfoundry/components/viz/KanbanBoard.js.map +1 -0
  23. package/dist/crewfoundry/components/viz/LineChart.js +123 -0
  24. package/dist/crewfoundry/components/viz/LineChart.js.map +1 -0
  25. package/dist/crewfoundry/components/viz/OrgTree.js +83 -0
  26. package/dist/crewfoundry/components/viz/OrgTree.js.map +1 -0
  27. package/dist/crewfoundry/components/viz/PathSteps.js +68 -0
  28. package/dist/crewfoundry/components/viz/PathSteps.js.map +1 -0
  29. package/dist/crewfoundry/components/viz/ProgressRing.js +68 -0
  30. package/dist/crewfoundry/components/viz/ProgressRing.js.map +1 -0
  31. package/dist/crewfoundry/components/viz/RatingStars.js +51 -0
  32. package/dist/crewfoundry/components/viz/RatingStars.js.map +1 -0
  33. package/dist/crewfoundry/components/viz/SegmentedTabs.js +69 -0
  34. package/dist/crewfoundry/components/viz/SegmentedTabs.js.map +1 -0
  35. package/dist/crewfoundry/components/viz/SkillBar.js +3 -0
  36. package/dist/crewfoundry/components/viz/Sparkline.js +74 -0
  37. package/dist/crewfoundry/components/viz/Sparkline.js.map +1 -0
  38. package/dist/crewfoundry/components/viz/StatCard.js +60 -0
  39. package/dist/crewfoundry/components/viz/StatCard.js.map +1 -0
  40. package/dist/crewfoundry/components/viz/StepProgress.js +3 -0
  41. package/dist/crewfoundry/components/viz/Timeline.js +66 -0
  42. package/dist/crewfoundry/components/viz/Timeline.js.map +1 -0
  43. package/dist/crewfoundry/components/viz/index.js +23 -0
  44. package/dist/crewfoundry/components/viz/lib/Avatar.js +30 -0
  45. package/dist/crewfoundry/components/viz/lib/Avatar.js.map +1 -0
  46. package/dist/crewfoundry/components/viz/lib/CartesianFrame.js +119 -0
  47. package/dist/crewfoundry/components/viz/lib/CartesianFrame.js.map +1 -0
  48. package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js +35 -0
  49. package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js.map +1 -0
  50. package/dist/crewfoundry/components/viz/lib/format.js +21 -0
  51. package/dist/crewfoundry/components/viz/lib/format.js.map +1 -0
  52. package/dist/crewfoundry/components/viz/lib/geometry.js +69 -0
  53. package/dist/crewfoundry/components/viz/lib/geometry.js.map +1 -0
  54. package/dist/crewfoundry/components/viz/lib/hooks.js +39 -0
  55. package/dist/crewfoundry/components/viz/lib/hooks.js.map +1 -0
  56. package/dist/crewfoundry/components/viz/lib/palette.js +27 -0
  57. package/dist/crewfoundry/components/viz/lib/palette.js.map +1 -0
  58. package/dist/crewfoundry/lib/analytics.js +323 -0
  59. package/dist/crewfoundry/lib/analytics.js.map +1 -0
  60. package/dist/crewfoundry/lib/companyFinance.js +16 -0
  61. package/dist/crewfoundry/lib/companyFinance.js.map +1 -0
  62. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +226 -283
  63. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  64. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +107 -120
  65. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
  66. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +122 -162
  67. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
  68. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +121 -158
  69. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
  70. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +316 -211
  71. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
  72. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +75 -27
  73. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
  74. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +167 -165
  75. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
  76. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +168 -109
  77. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
  78. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +401 -290
  79. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
  80. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +84 -75
  81. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
  82. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +368 -174
  83. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
  84. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +236 -201
  85. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
  86. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +369 -196
  87. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
  88. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +269 -270
  89. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
  90. package/dist/crewfoundry/pages/HiringJobsPagePage.js +210 -110
  91. package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
  92. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +216 -178
  93. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
  94. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +385 -0
  95. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js.map +1 -0
  96. package/dist/crewfoundry/pages/HrEmployeesPagePage.js +189 -130
  97. package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
  98. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +397 -241
  99. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
  100. package/dist/crewfoundry/pages/HrPayrollPagePage.js +262 -147
  101. package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
  102. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +345 -167
  103. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
  104. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +98 -24
  105. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
  106. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +1 -1
  107. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
  108. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +289 -108
  109. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
  110. package/dist/crewfoundry/pages/LearningCoursesPagePage.js +221 -114
  111. package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
  112. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +134 -135
  113. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
  114. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +148 -97
  115. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
  116. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +264 -157
  117. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
  118. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +85 -93
  119. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
  120. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
  121. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
  122. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
  123. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
  124. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +289 -140
  125. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
  126. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
  127. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
  128. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
  129. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
  130. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
  131. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
  132. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +140 -78
  133. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
  134. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
  135. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
  136. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
  137. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
  138. package/dist/crewfoundry/store/crewfoundryStore.js +1 -1
  139. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  140. package/dist/crewfoundry/utils/cn.js +10 -0
  141. package/dist/crewfoundry/utils/cn.js.map +1 -0
  142. package/dist/crewfoundry/utils/courseProgress.js +46 -0
  143. package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
  144. package/dist/node_modules/clsx/dist/clsx.js +18 -0
  145. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  146. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
  147. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  148. package/package.json +1 -1
@@ -1,14 +1,19 @@
1
1
  import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
2
2
  import { formatEnumLabel as t } from "../utils/formatEnumLabel.js";
3
- import { FormModal as n, useFormModal as r } from "../components/forms/FormModal.js";
4
- import { useState as i } from "react";
5
- import { Plus as a, Search as o, Star as s, Users as c } from "lucide-react";
6
- import { useNavigate as l } from "react-router-dom";
7
- import { jsx as u, jsxs as d } from "react/jsx-runtime";
8
- import { Badge as f, Button as p, CardContent as m, CardDescription as h, CardHeader as g, CardTitle as _, GlassCard as v, GradientText as y, IllustratedEmptyState as b, Input as x, PagePurpose as S, Pagination as C } from "@burdenoff/fe-libs/ui";
9
- import { usePagination as w } from "@burdenoff/fe-libs/shared/hooks";
3
+ import { chartPalette as n } from "../components/viz/lib/palette.js";
4
+ import { RatingStars as r } from "../components/viz/RatingStars.js";
5
+ import "../components/viz/index.js";
6
+ import { FormModal as i, useFormModal as a } from "../components/forms/FormModal.js";
7
+ import { readCourseProgress as o } from "../utils/courseProgress.js";
8
+ import { useMemo as s, useState as c } from "react";
9
+ import { BarChart3 as l, Briefcase as u, Code2 as d, GraduationCap as f, Megaphone as p, Palette as m, Play as h, Plus as g, Search as _, ShieldCheck as v, Users as y } from "lucide-react";
10
+ import { useNavigate as b } from "react-router-dom";
11
+ import { jsx as x, jsxs as S } from "react/jsx-runtime";
12
+ import { Badge as C, Button as w, CardContent as T, CardHeader as E, GlassCard as D, GradientText as O, IllustratedEmptyState as k, Input as A, PagePurpose as j, Pagination as M } from "@burdenoff/fe-libs/ui";
13
+ import { usePagination as N } from "@burdenoff/fe-libs/shared/hooks";
14
+ import { useGlobalUi as P } from "@burdenoff/fe-libs/shared/providers/shell";
10
15
  //#region src/crewfoundry/pages/LearningCoursesPagePage.tsx
11
- var T = [
16
+ var F = [
12
17
  {
13
18
  name: "title",
14
19
  label: "Course Title",
@@ -97,136 +102,238 @@ var T = [
97
102
  colSpan: 2
98
103
  }
99
104
  ];
100
- function E() {
101
- let { courses: E, addCourse: D } = e(), O = l(), [k, A] = i(""), j = r(), { page: M, pageSize: N, offset: P, setPage: F } = w({ initialPageSize: 12 }), I = E.filter((e) => `${e.title} ${e.category} ${e.instructor}`.toLowerCase().includes(k.toLowerCase())), L = I.slice(P, P + N), R = (e) => O(`../learning/course-details-page?id=${encodeURIComponent(e)}`);
102
- return /* @__PURE__ */ d("div", {
105
+ function I(e) {
106
+ let t = n(8), r = 0;
107
+ for (let t = 0; t < e.length; t += 1) r = r * 31 + e.charCodeAt(t) >>> 0;
108
+ return t[r % t.length];
109
+ }
110
+ function L(e) {
111
+ let t = e.toLowerCase();
112
+ return t.includes("engineer") || t.includes("develop") || t.includes("program") || t.includes("tech") ? d : t.includes("design") || t.includes("ux") || t.includes("ui") ? m : t.includes("lead") || t.includes("manage") || t.includes("people") || t.includes("hr") ? y : t.includes("compliance") || t.includes("security") || t.includes("legal") ? v : t.includes("data") || t.includes("analyt") ? l : t.includes("market") || t.includes("sales") ? p : t.includes("business") || t.includes("finance") || t.includes("operations") ? u : f;
113
+ }
114
+ function R(e) {
115
+ return e === "beginner" ? "secondary" : e === "intermediate" ? "default" : "destructive";
116
+ }
117
+ function z() {
118
+ let { courses: n, addCourse: l, enrollCourse: u } = e(), { showToast: d } = P(), f = b(), [p, m] = c(""), [v, z] = c("all"), [B, V] = c(null), H = a(), { page: U, pageSize: W, offset: G, setPage: K } = N({ initialPageSize: 12 }), q = s(() => {
119
+ let e = /* @__PURE__ */ new Map();
120
+ for (let t of n) {
121
+ let n = t.category.trim() || "Uncategorized";
122
+ e.set(n, (e.get(n) ?? 0) + 1);
123
+ }
124
+ return [...e.entries()].sort((e, t) => t[1] - e[1]);
125
+ }, [n]), J = n.filter((e) => {
126
+ let t = v === "all" || (e.category.trim() || "Uncategorized") === v, n = `${e.title} ${e.category} ${e.instructor} ${e.skills.join(" ")}`.toLowerCase().includes(p.toLowerCase());
127
+ return t && n;
128
+ }), Y = J.slice(G, G + W), X = (e) => f(`../learning/course-details-page?id=${encodeURIComponent(e)}`), Z = (e) => f(`../learning/course-learning-page?id=${encodeURIComponent(e)}`), Q = async (e) => {
129
+ V(e.id);
130
+ try {
131
+ await u(e.id), d(`Enrolled in ${e.title}`, "success"), Z(e.id);
132
+ } catch (e) {
133
+ d(e instanceof Error ? e.message : "Unable to enroll in course", "error");
134
+ } finally {
135
+ V(null);
136
+ }
137
+ };
138
+ return /* @__PURE__ */ S("div", {
103
139
  className: "space-y-6 p-6",
104
140
  children: [
105
- /* @__PURE__ */ d("div", {
141
+ /* @__PURE__ */ S("div", {
106
142
  className: "flex flex-wrap items-start justify-between gap-3",
107
- children: [/* @__PURE__ */ d("div", { children: [
108
- /* @__PURE__ */ u("h1", {
143
+ children: [/* @__PURE__ */ S("div", { children: [
144
+ /* @__PURE__ */ x("h1", {
109
145
  className: "text-2xl font-semibold",
110
- children: /* @__PURE__ */ u(y, { children: "Course Catalog" })
146
+ children: /* @__PURE__ */ x(O, { children: "Course Catalog" })
111
147
  }),
112
- /* @__PURE__ */ d("p", {
148
+ /* @__PURE__ */ S("p", {
113
149
  className: "text-sm text-text-secondary",
114
- children: [E.length, " courses available"]
150
+ children: [
151
+ n.length,
152
+ " courses · ",
153
+ q.length,
154
+ " categories"
155
+ ]
115
156
  }),
116
- /* @__PURE__ */ u(S, {
157
+ /* @__PURE__ */ x(j, {
117
158
  className: "mt-1",
118
159
  children: "Browse the course catalog — find training to grow your team's skills and enroll in the programs that fit your goals."
119
160
  })
120
- ] }), /* @__PURE__ */ d(p, {
121
- onClick: () => j.openModal(),
122
- children: [/* @__PURE__ */ u(a, { className: "mr-1 h-4 w-4" }), "Create Course"]
161
+ ] }), /* @__PURE__ */ S(w, {
162
+ onClick: () => H.openModal(),
163
+ children: [/* @__PURE__ */ x(g, { className: "mr-1 h-4 w-4" }), "Create Course"]
123
164
  })]
124
165
  }),
125
- /* @__PURE__ */ d("div", {
126
- className: "relative max-w-sm",
127
- children: [/* @__PURE__ */ u(o, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ u(x, {
128
- placeholder: "Search courses...",
129
- className: "pl-9",
130
- value: k,
131
- onChange: (e) => {
132
- A(e.target.value), F(1);
133
- }
166
+ /* @__PURE__ */ S("div", {
167
+ className: "flex flex-col gap-3",
168
+ children: [/* @__PURE__ */ S("div", {
169
+ className: "relative max-w-md",
170
+ children: [/* @__PURE__ */ x(_, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ x(A, {
171
+ placeholder: "Search courses, skills, or instructors...",
172
+ className: "pl-9",
173
+ value: p,
174
+ onChange: (e) => {
175
+ m(e.target.value), K(1);
176
+ }
177
+ })]
178
+ }), /* @__PURE__ */ S("div", {
179
+ className: "flex flex-wrap gap-2",
180
+ children: [/* @__PURE__ */ x("button", {
181
+ type: "button",
182
+ onClick: () => {
183
+ z("all"), K(1);
184
+ },
185
+ className: `rounded-full border px-3 py-1 text-xs font-medium transition-colors ${v === "all" ? "border-transparent bg-action-primary-bg text-action-primary-text" : "border-border-subtle bg-bg-surface text-text-secondary hover:text-text-primary"}`,
186
+ children: "All"
187
+ }), q.map(([e, t]) => /* @__PURE__ */ S("button", {
188
+ type: "button",
189
+ onClick: () => {
190
+ z(e), K(1);
191
+ },
192
+ className: `inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-medium transition-colors ${v === e ? "border-transparent bg-action-primary-bg text-action-primary-text" : "border-border-subtle bg-bg-surface text-text-secondary hover:text-text-primary"}`,
193
+ children: [e, /* @__PURE__ */ x("span", {
194
+ className: "tabular-nums opacity-70",
195
+ children: t
196
+ })]
197
+ }, e))]
134
198
  })]
135
199
  }),
136
- /* @__PURE__ */ u("div", {
200
+ /* @__PURE__ */ x("div", {
137
201
  className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
138
- children: I.length === 0 ? /* @__PURE__ */ u("div", {
202
+ children: J.length === 0 ? /* @__PURE__ */ x("div", {
139
203
  className: "col-span-full",
140
- children: /* @__PURE__ */ u(b, {
204
+ children: /* @__PURE__ */ x(k, {
141
205
  illustration: "empty-search",
142
206
  title: "No courses found",
143
- description: "Try a different search term to find training."
207
+ description: "Try a different search term or category to find training."
144
208
  })
145
- }) : L.map((e, n) => /* @__PURE__ */ d(v, {
146
- treatment: n === 0 ? "glass" : "plain",
147
- glow: n === 0,
148
- role: "button",
149
- tabIndex: 0,
150
- "aria-label": `View ${e.title}`,
151
- onClick: () => R(e.id),
152
- onKeyDown: (t) => {
153
- (t.key === "Enter" || t.key === " ") && (t.preventDefault(), R(e.id));
154
- },
155
- className: "hover:shadow-md transition-shadow cursor-pointer focus-visible:outline-none focus-visible:shadow-[var(--shadow-focus)]",
156
- children: [/* @__PURE__ */ d(g, { children: [
157
- /* @__PURE__ */ d("div", {
158
- className: "flex items-center justify-between",
159
- children: [/* @__PURE__ */ u(f, {
160
- variant: "outline",
161
- className: "text-[10px]",
162
- children: e.category
163
- }), /* @__PURE__ */ u(f, {
164
- variant: e.level === "beginner" ? "secondary" : e.level === "intermediate" ? "default" : "destructive",
165
- className: "text-[10px]",
166
- children: t(e.level)
167
- })]
168
- }),
169
- /* @__PURE__ */ u(_, {
170
- className: "text-base mt-2",
171
- children: e.title
172
- }),
173
- /* @__PURE__ */ d(h, { children: [
174
- e.instructor,
175
- " · ",
176
- e.duration,
177
- " · ",
178
- e.modules,
179
- " modules"
180
- ] })
181
- ] }), /* @__PURE__ */ d(m, { children: [
182
- /* @__PURE__ */ u("p", {
183
- className: "text-sm text-text-secondary mb-3",
184
- children: e.description
185
- }),
186
- /* @__PURE__ */ u("div", {
187
- className: "flex flex-wrap gap-1 mb-3",
188
- children: e.skills.map((e) => /* @__PURE__ */ u(f, {
189
- variant: "outline",
190
- className: "text-[9px]",
191
- children: e
192
- }, e))
193
- }),
194
- /* @__PURE__ */ d("div", {
195
- className: "flex items-center justify-between text-xs text-text-secondary",
196
- children: [
197
- /* @__PURE__ */ d("span", {
198
- className: "flex items-center gap-1",
199
- children: [/* @__PURE__ */ u(s, { className: "h-3 w-3 text-status-warning-text" }), e.rating]
200
- }),
201
- /* @__PURE__ */ d("span", {
202
- className: "flex items-center gap-1",
203
- children: [
204
- /* @__PURE__ */ u(c, { className: "h-3 w-3" }),
205
- e.enrolled,
206
- " enrolled"
207
- ]
208
- }),
209
- /* @__PURE__ */ d("span", { children: [e.enrolled > 0 ? Math.round(e.completed / e.enrolled * 100) : 0, "% completion"] })
210
- ]
211
- })
212
- ] })]
213
- }, e.id))
209
+ }) : Y.map((e) => {
210
+ let n = I(e.category), i = L(e.category), a = o(e.id), s = Math.max(e.modules, 1), c = a.completed.length > 0 ? Math.min(100, Math.round(a.completed.length / s * 100)) : 0, l = c > 0;
211
+ return /* @__PURE__ */ S(D, {
212
+ treatment: "plain",
213
+ className: "group flex flex-col overflow-hidden transition-shadow hover:shadow-md",
214
+ children: [
215
+ /* @__PURE__ */ S("button", {
216
+ type: "button",
217
+ "aria-label": `View ${e.title}`,
218
+ onClick: () => X(e.id),
219
+ className: "relative flex h-24 w-full items-center justify-between px-5 text-left outline-none focus-visible:shadow-[var(--shadow-focus)]",
220
+ style: { background: `linear-gradient(135deg, color-mix(in srgb, ${n} 28%, var(--color-bg-surface)), color-mix(in srgb, ${n} 8%, var(--color-bg-surface)))` },
221
+ children: [/* @__PURE__ */ x("span", {
222
+ className: "flex h-11 w-11 items-center justify-center rounded-xl bg-bg-surface/70 shadow-elevation-1",
223
+ style: { color: n },
224
+ children: /* @__PURE__ */ x(i, { className: "h-6 w-6" })
225
+ }), /* @__PURE__ */ x(C, {
226
+ variant: R(e.level),
227
+ className: "text-[10px]",
228
+ children: t(e.level)
229
+ })]
230
+ }),
231
+ /* @__PURE__ */ S(E, {
232
+ className: "pb-2",
233
+ children: [
234
+ /* @__PURE__ */ x(C, {
235
+ variant: "outline",
236
+ className: "w-fit text-[10px]",
237
+ children: e.category
238
+ }),
239
+ /* @__PURE__ */ x("button", {
240
+ type: "button",
241
+ onClick: () => X(e.id),
242
+ className: "mt-2 text-left text-base font-semibold outline-none hover:text-action-primary-bg focus-visible:text-action-primary-bg",
243
+ children: e.title
244
+ }),
245
+ /* @__PURE__ */ S("p", {
246
+ className: "text-xs text-text-secondary",
247
+ children: [
248
+ e.instructor,
249
+ " · ",
250
+ e.duration,
251
+ " · ",
252
+ e.modules,
253
+ " modules"
254
+ ]
255
+ })
256
+ ]
257
+ }),
258
+ /* @__PURE__ */ S(T, {
259
+ className: "flex flex-1 flex-col gap-3",
260
+ children: [
261
+ /* @__PURE__ */ x("p", {
262
+ className: "line-clamp-2 text-sm text-text-secondary",
263
+ children: e.description
264
+ }),
265
+ e.skills.length > 0 && /* @__PURE__ */ x("div", {
266
+ className: "flex flex-wrap gap-1",
267
+ children: e.skills.slice(0, 3).map((e) => /* @__PURE__ */ x(C, {
268
+ variant: "outline",
269
+ className: "text-[9px]",
270
+ children: e
271
+ }, e))
272
+ }),
273
+ /* @__PURE__ */ S("div", {
274
+ className: "mt-auto space-y-3",
275
+ children: [
276
+ /* @__PURE__ */ S("div", {
277
+ className: "flex items-center justify-between text-xs text-text-secondary",
278
+ children: [/* @__PURE__ */ x(r, {
279
+ value: e.rating,
280
+ size: 13,
281
+ showValue: !0
282
+ }), /* @__PURE__ */ S("span", {
283
+ className: "flex items-center gap-1",
284
+ children: [
285
+ /* @__PURE__ */ x(y, { className: "h-3 w-3" }),
286
+ e.enrolled,
287
+ " enrolled"
288
+ ]
289
+ })]
290
+ }),
291
+ l && /* @__PURE__ */ S("div", {
292
+ className: "space-y-1",
293
+ children: [/* @__PURE__ */ x("div", {
294
+ className: "flex justify-between text-[11px] font-medium",
295
+ children: /* @__PURE__ */ S("span", {
296
+ className: "text-text-secondary",
297
+ children: [c, "% complete"]
298
+ })
299
+ }), /* @__PURE__ */ x("div", {
300
+ className: "h-1.5 overflow-hidden rounded-full bg-bg-sunken",
301
+ children: /* @__PURE__ */ x("div", {
302
+ className: "h-full rounded-full bg-action-primary-bg",
303
+ style: { width: `${c}%` }
304
+ })
305
+ })]
306
+ }),
307
+ /* @__PURE__ */ S(w, {
308
+ className: "w-full",
309
+ variant: l ? "outline" : "default",
310
+ disabled: B === e.id,
311
+ onClick: () => l ? Z(e.id) : void Q(e),
312
+ children: [/* @__PURE__ */ x(h, { className: "mr-1 h-4 w-4" }), B === e.id ? "Enrolling…" : l ? "Continue" : "Enroll"]
313
+ })
314
+ ]
315
+ })
316
+ ]
317
+ })
318
+ ]
319
+ }, e.id);
320
+ })
214
321
  }),
215
- I.length > N && /* @__PURE__ */ u(C, {
216
- page: M,
217
- pageSize: N,
218
- totalItems: I.length,
219
- onPageChange: F
322
+ J.length > W && /* @__PURE__ */ x(M, {
323
+ page: U,
324
+ pageSize: W,
325
+ totalItems: J.length,
326
+ onPageChange: K
220
327
  }),
221
- /* @__PURE__ */ u(n, {
222
- open: j.open,
223
- onOpenChange: j.onOpenChange,
328
+ /* @__PURE__ */ x(i, {
329
+ open: H.open,
330
+ onOpenChange: H.onOpenChange,
224
331
  title: "Create Course",
225
332
  description: "Add a new course to the catalog.",
226
- fields: T,
333
+ fields: F,
227
334
  submitLabel: "Create Course",
228
335
  onSubmit: async (e) => {
229
- await D({
336
+ await l({
230
337
  id: `course-${Date.now()}`,
231
338
  title: String(e.title ?? ""),
232
339
  category: String(e.category ?? ""),
@@ -247,6 +354,6 @@ function E() {
247
354
  });
248
355
  }
249
356
  //#endregion
250
- export { E as LearningCoursesPagePage };
357
+ export { z as LearningCoursesPagePage };
251
358
 
252
359
  //# sourceMappingURL=LearningCoursesPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LearningCoursesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/LearningCoursesPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Badge,\n Button,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { Plus, Search, Star, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore, type LearningCourse } from '../store/crewfoundryStore';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\nconst COURSE_FIELDS: FieldConfig[] = [\n { name: 'title', label: 'Course Title', type: 'text', required: true, colSpan: 2 },\n { name: 'category', label: 'Category', type: 'text', required: true },\n { name: 'instructor', label: 'Instructor', type: 'text', required: true },\n {\n name: 'duration',\n label: 'Duration',\n type: 'text',\n required: true,\n placeholder: 'e.g. 6 weeks',\n },\n { name: 'modules', label: 'Modules', type: 'number', required: true, placeholder: 'e.g. 8' },\n {\n name: 'level',\n label: 'Level',\n type: 'select',\n required: true,\n options: [\n { label: 'Beginner', value: 'beginner' },\n { label: 'Intermediate', value: 'intermediate' },\n { label: 'Advanced', value: 'advanced' },\n ],\n },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n required: true,\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Draft', value: 'draft' },\n { label: 'Archived', value: 'archived' },\n ],\n },\n { name: 'description', label: 'Description', type: 'textarea', required: true, colSpan: 2 },\n {\n name: 'skills',\n label: 'Skills',\n type: 'tags',\n placeholder: 'Add a skill and press Enter',\n colSpan: 2,\n },\n];\n\nexport function LearningCoursesPagePage() {\n const { courses, addCourse } = useCrewFoundryStore();\n const navigate = useNavigate();\n const [search, setSearch] = useState('');\n const createModal = useFormModal();\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 12 });\n const filtered = courses.filter((c) =>\n `${c.title} ${c.category} ${c.instructor}`.toLowerCase().includes(search.toLowerCase())\n );\n const paged = filtered.slice(offset, offset + pageSize);\n const openCourse = (id: string) =>\n navigate(`../learning/course-details-page?id=${encodeURIComponent(id)}`);\n\n const handleCreate = async (values: FormValues) => {\n await addCourse({\n id: `course-${Date.now()}`,\n title: String(values.title ?? ''),\n category: String(values.category ?? ''),\n instructor: String(values.instructor ?? ''),\n duration: String(values.duration ?? ''),\n level: String(values.level ?? 'beginner') as LearningCourse['level'],\n enrolled: 0,\n completed: 0,\n rating: 0,\n status: String(values.status ?? 'draft') as LearningCourse['status'],\n description: String(values.description ?? ''),\n modules: typeof values.modules === 'number' ? values.modules : Number(values.modules) || 0,\n skills: Array.isArray(values.skills) ? values.skills : [],\n });\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Course Catalog</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{courses.length} courses available</p>\n <PagePurpose className=\"mt-1\">\n Browse the course catalog — find training to grow your team&apos;s skills and enroll in\n the programs that fit your goals.\n </PagePurpose>\n </div>\n <Button onClick={() => createModal.openModal()}>\n <Plus className=\"mr-1 h-4 w-4\" />\n Create Course\n </Button>\n </div>\n <div className=\"relative max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder=\"Search courses...\"\n className=\"pl-9\"\n value={search}\n onChange={(e) => {\n setSearch(e.target.value);\n setPage(1);\n }}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {filtered.length === 0 ? (\n <div className=\"col-span-full\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No courses found\"\n description=\"Try a different search term to find training.\"\n />\n </div>\n ) : (\n paged.map((course, _idx) => (\n <GlassCard\n key={course.id}\n treatment={_idx === 0 ? 'glass' : 'plain'}\n glow={_idx === 0}\n role=\"button\"\n tabIndex={0}\n aria-label={`View ${course.title}`}\n onClick={() => openCourse(course.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n openCourse(course.id);\n }\n }}\n className=\"hover:shadow-md transition-shadow cursor-pointer focus-visible:outline-none focus-visible:shadow-[var(--shadow-focus)]\"\n >\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {course.category}\n </Badge>\n <Badge\n variant={\n course.level === 'beginner'\n ? 'secondary'\n : course.level === 'intermediate'\n ? 'default'\n : 'destructive'\n }\n className=\"text-[10px]\"\n >\n {formatEnumLabel(course.level)}\n </Badge>\n </div>\n <CardTitle className=\"text-base mt-2\">{course.title}</CardTitle>\n <CardDescription>\n {course.instructor} · {course.duration} · {course.modules} modules\n </CardDescription>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-text-secondary mb-3\">{course.description}</p>\n <div className=\"flex flex-wrap gap-1 mb-3\">\n {course.skills.map((s) => (\n <Badge key={s} variant=\"outline\" className=\"text-[9px]\">\n {s}\n </Badge>\n ))}\n </div>\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n {course.rating}\n </span>\n <span className=\"flex items-center gap-1\">\n <Users className=\"h-3 w-3\" />\n {course.enrolled} enrolled\n </span>\n <span>\n {course.enrolled > 0\n ? Math.round((course.completed / course.enrolled) * 100)\n : 0}\n % completion\n </span>\n </div>\n </CardContent>\n </GlassCard>\n ))\n )}\n </div>\n\n {filtered.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={filtered.length}\n onPageChange={setPage}\n />\n )}\n\n <FormModal\n open={createModal.open}\n onOpenChange={createModal.onOpenChange}\n title=\"Create Course\"\n description=\"Add a new course to the catalog.\"\n fields={COURSE_FIELDS}\n submitLabel=\"Create Course\"\n onSubmit={handleCreate}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"LearningCoursesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/LearningCoursesPagePage.tsx"],"sourcesContent":["import { useMemo, useState, type ComponentType } from 'react';\nimport {\n Badge,\n Button,\n CardContent,\n CardHeader,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n BarChart3,\n Briefcase,\n Code2,\n GraduationCap,\n Megaphone,\n Palette,\n Play,\n Plus,\n Search,\n ShieldCheck,\n Users,\n} from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore, type LearningCourse } from '../store/crewfoundryStore';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { chartPalette, RatingStars } from '../components/viz';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\nimport { readCourseProgress } from '../utils/courseProgress';\n\nconst COURSE_FIELDS: FieldConfig[] = [\n { name: 'title', label: 'Course Title', type: 'text', required: true, colSpan: 2 },\n { name: 'category', label: 'Category', type: 'text', required: true },\n { name: 'instructor', label: 'Instructor', type: 'text', required: true },\n {\n name: 'duration',\n label: 'Duration',\n type: 'text',\n required: true,\n placeholder: 'e.g. 6 weeks',\n },\n { name: 'modules', label: 'Modules', type: 'number', required: true, placeholder: 'e.g. 8' },\n {\n name: 'level',\n label: 'Level',\n type: 'select',\n required: true,\n options: [\n { label: 'Beginner', value: 'beginner' },\n { label: 'Intermediate', value: 'intermediate' },\n { label: 'Advanced', value: 'advanced' },\n ],\n },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n required: true,\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Draft', value: 'draft' },\n { label: 'Archived', value: 'archived' },\n ],\n },\n { name: 'description', label: 'Description', type: 'textarea', required: true, colSpan: 2 },\n {\n name: 'skills',\n label: 'Skills',\n type: 'tags',\n placeholder: 'Add a skill and press Enter',\n colSpan: 2,\n },\n];\n\ntype IconType = ComponentType<{ className?: string }>;\n\n/** Deterministic tokenized accent for a category (never a raw color). */\nfunction categoryAccent(category: string): string {\n const palette = chartPalette(8);\n let hash = 0;\n for (let i = 0; i < category.length; i += 1) {\n hash = (hash * 31 + category.charCodeAt(i)) >>> 0;\n }\n return palette[hash % palette.length];\n}\n\nfunction categoryIcon(category: string): IconType {\n const c = category.toLowerCase();\n if (c.includes('engineer') || c.includes('develop') || c.includes('program') || c.includes('tech'))\n return Code2;\n if (c.includes('design') || c.includes('ux') || c.includes('ui')) return Palette;\n if (c.includes('lead') || c.includes('manage') || c.includes('people') || c.includes('hr'))\n return Users;\n if (c.includes('compliance') || c.includes('security') || c.includes('legal')) return ShieldCheck;\n if (c.includes('data') || c.includes('analyt')) return BarChart3;\n if (c.includes('market') || c.includes('sales')) return Megaphone;\n if (c.includes('business') || c.includes('finance') || c.includes('operations')) return Briefcase;\n return GraduationCap;\n}\n\nfunction levelVariant(level: LearningCourse['level']): 'secondary' | 'default' | 'destructive' {\n return level === 'beginner' ? 'secondary' : level === 'intermediate' ? 'default' : 'destructive';\n}\n\nexport function LearningCoursesPagePage() {\n const { courses, addCourse, enrollCourse } = useCrewFoundryStore();\n const { showToast } = useGlobalUi();\n const navigate = useNavigate();\n const [search, setSearch] = useState('');\n const [category, setCategory] = useState('all');\n const [enrollingId, setEnrollingId] = useState<string | null>(null);\n const createModal = useFormModal();\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 12 });\n\n const categories = useMemo(() => {\n const seen = new Map<string, number>();\n for (const course of courses) {\n const key = course.category.trim() || 'Uncategorized';\n seen.set(key, (seen.get(key) ?? 0) + 1);\n }\n return [...seen.entries()].sort((a, b) => b[1] - a[1]);\n }, [courses]);\n\n const filtered = courses.filter((c) => {\n const matchesCategory = category === 'all' || (c.category.trim() || 'Uncategorized') === category;\n const matchesSearch = `${c.title} ${c.category} ${c.instructor} ${c.skills.join(' ')}`\n .toLowerCase()\n .includes(search.toLowerCase());\n return matchesCategory && matchesSearch;\n });\n const paged = filtered.slice(offset, offset + pageSize);\n\n const openCourse = (id: string) =>\n navigate(`../learning/course-details-page?id=${encodeURIComponent(id)}`);\n const openPlayer = (id: string) =>\n navigate(`../learning/course-learning-page?id=${encodeURIComponent(id)}`);\n\n const handleEnroll = async (course: LearningCourse) => {\n setEnrollingId(course.id);\n try {\n await enrollCourse(course.id);\n showToast(`Enrolled in ${course.title}`, 'success');\n openPlayer(course.id);\n } catch (error) {\n showToast(error instanceof Error ? error.message : 'Unable to enroll in course', 'error');\n } finally {\n setEnrollingId(null);\n }\n };\n\n const handleCreate = async (values: FormValues) => {\n await addCourse({\n id: `course-${Date.now()}`,\n title: String(values.title ?? ''),\n category: String(values.category ?? ''),\n instructor: String(values.instructor ?? ''),\n duration: String(values.duration ?? ''),\n level: String(values.level ?? 'beginner') as LearningCourse['level'],\n enrolled: 0,\n completed: 0,\n rating: 0,\n status: String(values.status ?? 'draft') as LearningCourse['status'],\n description: String(values.description ?? ''),\n modules: typeof values.modules === 'number' ? values.modules : Number(values.modules) || 0,\n skills: Array.isArray(values.skills) ? values.skills : [],\n });\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Course Catalog</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {courses.length} courses · {categories.length} categories\n </p>\n <PagePurpose className=\"mt-1\">\n Browse the course catalog — find training to grow your team&apos;s skills and enroll in\n the programs that fit your goals.\n </PagePurpose>\n </div>\n <Button onClick={() => createModal.openModal()}>\n <Plus className=\"mr-1 h-4 w-4\" />\n Create Course\n </Button>\n </div>\n\n <div className=\"flex flex-col gap-3\">\n <div className=\"relative max-w-md\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder=\"Search courses, skills, or instructors...\"\n className=\"pl-9\"\n value={search}\n onChange={(e) => {\n setSearch(e.target.value);\n setPage(1);\n }}\n />\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n setCategory('all');\n setPage(1);\n }}\n className={`rounded-full border px-3 py-1 text-xs font-medium transition-colors ${\n category === 'all'\n ? 'border-transparent bg-action-primary-bg text-action-primary-text'\n : 'border-border-subtle bg-bg-surface text-text-secondary hover:text-text-primary'\n }`}\n >\n All\n </button>\n {categories.map(([name, count]) => (\n <button\n key={name}\n type=\"button\"\n onClick={() => {\n setCategory(name);\n setPage(1);\n }}\n className={`inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-medium transition-colors ${\n category === name\n ? 'border-transparent bg-action-primary-bg text-action-primary-text'\n : 'border-border-subtle bg-bg-surface text-text-secondary hover:text-text-primary'\n }`}\n >\n {name}\n <span className=\"tabular-nums opacity-70\">{count}</span>\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {filtered.length === 0 ? (\n <div className=\"col-span-full\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No courses found\"\n description=\"Try a different search term or category to find training.\"\n />\n </div>\n ) : (\n paged.map((course) => {\n const accent = categoryAccent(course.category);\n const Icon = categoryIcon(course.category);\n const progress = readCourseProgress(course.id);\n const totalModules = Math.max(course.modules, 1);\n const pct =\n progress.completed.length > 0\n ? Math.min(100, Math.round((progress.completed.length / totalModules) * 100))\n : 0;\n const started = pct > 0;\n return (\n <GlassCard\n key={course.id}\n treatment=\"plain\"\n className=\"group flex flex-col overflow-hidden transition-shadow hover:shadow-md\"\n >\n <button\n type=\"button\"\n aria-label={`View ${course.title}`}\n onClick={() => openCourse(course.id)}\n className=\"relative flex h-24 w-full items-center justify-between px-5 text-left outline-none focus-visible:shadow-[var(--shadow-focus)]\"\n style={{\n background: `linear-gradient(135deg, color-mix(in srgb, ${accent} 28%, var(--color-bg-surface)), color-mix(in srgb, ${accent} 8%, var(--color-bg-surface)))`,\n }}\n >\n <span\n className=\"flex h-11 w-11 items-center justify-center rounded-xl bg-bg-surface/70 shadow-elevation-1\"\n style={{ color: accent }}\n >\n <Icon className=\"h-6 w-6\" />\n </span>\n <Badge variant={levelVariant(course.level)} className=\"text-[10px]\">\n {formatEnumLabel(course.level)}\n </Badge>\n </button>\n <CardHeader className=\"pb-2\">\n <Badge variant=\"outline\" className=\"w-fit text-[10px]\">\n {course.category}\n </Badge>\n <button\n type=\"button\"\n onClick={() => openCourse(course.id)}\n className=\"mt-2 text-left text-base font-semibold outline-none hover:text-action-primary-bg focus-visible:text-action-primary-bg\"\n >\n {course.title}\n </button>\n <p className=\"text-xs text-text-secondary\">\n {course.instructor} · {course.duration} · {course.modules} modules\n </p>\n </CardHeader>\n <CardContent className=\"flex flex-1 flex-col gap-3\">\n <p className=\"line-clamp-2 text-sm text-text-secondary\">{course.description}</p>\n {course.skills.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {course.skills.slice(0, 3).map((s) => (\n <Badge key={s} variant=\"outline\" className=\"text-[9px]\">\n {s}\n </Badge>\n ))}\n </div>\n )}\n <div className=\"mt-auto space-y-3\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <RatingStars value={course.rating} size={13} showValue />\n <span className=\"flex items-center gap-1\">\n <Users className=\"h-3 w-3\" />\n {course.enrolled} enrolled\n </span>\n </div>\n {started && (\n <div className=\"space-y-1\">\n <div className=\"flex justify-between text-[11px] font-medium\">\n <span className=\"text-text-secondary\">{pct}% complete</span>\n </div>\n <div className=\"h-1.5 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg\"\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n )}\n <Button\n className=\"w-full\"\n variant={started ? 'outline' : 'default'}\n disabled={enrollingId === course.id}\n onClick={() =>\n started ? openPlayer(course.id) : void handleEnroll(course)\n }\n >\n <Play className=\"mr-1 h-4 w-4\" />\n {enrollingId === course.id\n ? 'Enrolling…'\n : started\n ? 'Continue'\n : 'Enroll'}\n </Button>\n </div>\n </CardContent>\n </GlassCard>\n );\n })\n )}\n </div>\n\n {filtered.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={filtered.length}\n onPageChange={setPage}\n />\n )}\n\n <FormModal\n open={createModal.open}\n onOpenChange={createModal.onOpenChange}\n title=\"Create Course\"\n description=\"Add a new course to the catalog.\"\n fields={COURSE_FIELDS}\n submitLabel=\"Create Course\"\n onSubmit={handleCreate}\n />\n </div>\n );\n}\n"],"mappings":"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"}