@burdenoff/microfe-crewfoundry 2026.704.6 → 2026.707.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 (150) 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/HelpApiDocumentationPagePage.js +0 -41
  81. package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js.map +1 -1
  82. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +84 -75
  83. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
  84. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +368 -174
  85. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
  86. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +236 -201
  87. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
  88. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +369 -196
  89. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
  90. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +269 -270
  91. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
  92. package/dist/crewfoundry/pages/HiringJobsPagePage.js +210 -110
  93. package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
  94. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +216 -178
  95. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
  96. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +385 -0
  97. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js.map +1 -0
  98. package/dist/crewfoundry/pages/HrEmployeesPagePage.js +189 -130
  99. package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
  100. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +397 -241
  101. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
  102. package/dist/crewfoundry/pages/HrPayrollPagePage.js +262 -147
  103. package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
  104. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +345 -167
  105. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
  106. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +98 -24
  107. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
  108. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +1 -1
  109. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
  110. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +289 -108
  111. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
  112. package/dist/crewfoundry/pages/LearningCoursesPagePage.js +221 -114
  113. package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
  114. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +134 -135
  115. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
  116. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +148 -97
  117. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
  118. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +264 -157
  119. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
  120. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +85 -93
  121. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
  122. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
  123. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
  124. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
  125. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
  126. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +289 -140
  127. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
  128. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
  129. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
  130. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
  131. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
  132. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
  133. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
  134. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +140 -78
  135. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
  136. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
  137. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
  138. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
  139. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
  140. package/dist/crewfoundry/store/crewfoundryStore.js +142 -184
  141. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  142. package/dist/crewfoundry/utils/cn.js +10 -0
  143. package/dist/crewfoundry/utils/cn.js.map +1 -0
  144. package/dist/crewfoundry/utils/courseProgress.js +46 -0
  145. package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
  146. package/dist/node_modules/clsx/dist/clsx.js +18 -0
  147. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  148. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
  149. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  150. package/package.json +1 -1
@@ -1,186 +1,293 @@
1
1
  import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
2
- import { useMemo as t, useState as n } from "react";
3
- import { Award as r, BookOpen as i, Clock as a, Play as o, Star as s } from "lucide-react";
4
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
5
- import { Button as u, Card as d, CardContent as f, CardDescription as p, CardHeader as m, CardTitle as h, GlassCard as g, GradientText as _, IllustratedEmptyState as v, PagePurpose as y, Pagination as b } from "@burdenoff/fe-libs/ui";
6
- import { usePagination as x } from "@burdenoff/fe-libs/shared/hooks";
7
- import { useGlobalUi as S } from "@burdenoff/fe-libs/shared/providers/shell";
2
+ import { chartPalette as t } from "../components/viz/lib/palette.js";
3
+ import { StatCard as n } from "../components/viz/StatCard.js";
4
+ import { RatingStars as r } from "../components/viz/RatingStars.js";
5
+ import { CertificateCard as i } from "../components/viz/CertificateCard.js";
6
+ import { SegmentedTabs as a } from "../components/viz/SegmentedTabs.js";
7
+ import "../components/viz/index.js";
8
+ import { readAllCourseProgress as o } from "../utils/courseProgress.js";
9
+ import { useMemo as s, useState as c } from "react";
10
+ import { Award as l, BookOpen as u, GraduationCap as d, Layers as f, Play as p } from "lucide-react";
11
+ import { useNavigate as m } from "react-router-dom";
12
+ import { jsx as h, jsxs as g } from "react/jsx-runtime";
13
+ import { Badge as _, Button as v, GlassCard as y, GradientText as b, IllustratedEmptyState as x, PagePurpose as S } from "@burdenoff/fe-libs/ui";
14
+ import { useAuth as C } from "@burdenoff/fe-libs/shared/providers/shell";
8
15
  //#region src/crewfoundry/pages/LearningMyLearningPagePage.tsx
9
- function C() {
10
- let { courses: C, enrollCourse: w } = e(), { showToast: T } = S(), [E, D] = n(null), O = x({ initialPageSize: 6 }), k = x({ initialPageSize: 6 }), A = async (e) => {
11
- D(e);
12
- try {
13
- await w(e), T("Enrollment updated", "success");
14
- } catch (e) {
15
- T(e instanceof Error ? e.message : "Unable to update course", "error");
16
- } finally {
17
- D(null);
16
+ var w = "crewfoundry:course-enrolled:v1";
17
+ function T() {
18
+ if (typeof window > "u") return /* @__PURE__ */ new Set();
19
+ try {
20
+ let e = window.localStorage.getItem(w), t = e ? JSON.parse(e) : [];
21
+ return new Set(Array.isArray(t) ? t.filter((e) => typeof e == "string") : []);
22
+ } catch {
23
+ return /* @__PURE__ */ new Set();
24
+ }
25
+ }
26
+ function E(e) {
27
+ let n = t(8), r = 0;
28
+ for (let t = 0; t < e.length; t += 1) r = r * 31 + e.charCodeAt(t) >>> 0;
29
+ return n[r % n.length];
30
+ }
31
+ function D(e) {
32
+ if (!e) return "—";
33
+ let t = new Date(e);
34
+ return Number.isNaN(t.getTime()) ? "—" : t.toLocaleDateString(void 0, {
35
+ year: "numeric",
36
+ month: "short",
37
+ day: "numeric"
38
+ });
39
+ }
40
+ function O(e, t, n, r) {
41
+ if (typeof document > "u") return;
42
+ let i = (e) => e.replace(/[&<>"]/g, (e) => ({
43
+ "&": "&amp;",
44
+ "<": "&lt;",
45
+ ">": "&gt;",
46
+ "\"": "&quot;"
47
+ })[e] ?? e), a = `<!doctype html><html><head><meta charset="utf-8"><title>Certificate — ${i(e)}</title>
48
+ <style>
49
+ body{font-family:Georgia,'Times New Roman',serif;margin:0;padding:48px;text-align:center}
50
+ .frame{border:6px double currentColor;padding:56px 40px;max-width:760px;margin:0 auto}
51
+ .kicker{letter-spacing:.3em;text-transform:uppercase;font-size:12px;opacity:.7}
52
+ h1{font-size:34px;margin:24px 0 8px}
53
+ .recipient{font-size:26px;margin:20px 0}
54
+ .rule{width:200px;border:0;border-top:1px solid currentColor;margin:24px auto;opacity:.4}
55
+ .meta{font-size:13px;opacity:.7;margin-top:32px}
56
+ </style></head><body>
57
+ <div class="frame">
58
+ <div class="kicker">CrewFoundry · Certificate of Completion</div>
59
+ <h1>${i(e)}</h1>
60
+ <div class="kicker">Awarded to</div>
61
+ <div class="recipient">${i(t)}</div>
62
+ <hr class="rule" />
63
+ <div class="meta">Issued ${i(n)} &nbsp;·&nbsp; Credential ID: ${i(r)}</div>
64
+ </div>
65
+ </body></html>`, o = new Blob([a], { type: "text/html" }), s = URL.createObjectURL(o), c = document.createElement("a");
66
+ c.href = s, c.download = `crewfoundry-certificate-${r}.html`, document.body.appendChild(c), c.click(), c.remove(), URL.revokeObjectURL(s);
67
+ }
68
+ var k = u;
69
+ function A() {
70
+ let { courses: t } = e(), w = C(), A = m(), [j, M] = c("in-progress"), N = w.user?.name?.trim() || "CrewFoundry Learner", { inProgress: P, completed: F, modulesDone: I } = s(() => {
71
+ let e = o(), n = T(), r = [], i = [], a = 0;
72
+ for (let o of t) {
73
+ let t = e[o.id], s = t?.completed.length ?? 0;
74
+ a += s;
75
+ let c = Math.max(o.modules, 1), l = {
76
+ course: o,
77
+ completedModules: s,
78
+ totalModules: c,
79
+ pct: Math.min(100, Math.round(s / c * 100)),
80
+ completedAt: t?.completedAt
81
+ };
82
+ s >= c && s > 0 ? i.push(l) : (s > 0 || n.has(o.id)) && r.push(l);
18
83
  }
19
- }, j = t(() => C.filter((e) => e.status === "active").map((e) => {
20
- let t = Math.min(e.modules, Math.round(e.completed / Math.max(e.enrolled, 1) * e.modules)), n = Math.round(t / Math.max(e.modules, 1) * 100);
21
- return {
22
- id: e.id,
23
- title: e.title,
24
- progress: n,
25
- modules: e.modules,
26
- completedModules: t,
27
- instructor: e.instructor
84
+ return r.sort((e, t) => t.pct - e.pct), i.sort((e, t) => (t.completedAt ?? "").localeCompare(e.completedAt ?? "")), {
85
+ inProgress: r,
86
+ completed: i,
87
+ modulesDone: a
28
88
  };
29
- }), [C]), M = t(() => C.filter((e) => e.completed > 0).map((e) => ({
30
- id: `completed-${e.id}`,
31
- title: e.title,
32
- rating: Number(e.rating.toFixed(1))
33
- })), [C]), N = j.reduce((e, t) => e + t.completedModules * 1.25, 0), P = j.slice(O.offset, O.offset + O.pageSize), F = M.slice(k.offset, k.offset + k.pageSize);
34
- return /* @__PURE__ */ l("div", {
89
+ }, [t]), L = (e) => A(`../learning/course-learning-page?id=${encodeURIComponent(e)}`);
90
+ return /* @__PURE__ */ g("div", {
35
91
  className: "space-y-6 p-6",
36
92
  children: [
37
- /* @__PURE__ */ l("div", { children: [
38
- /* @__PURE__ */ c("h1", {
93
+ /* @__PURE__ */ g("div", { children: [
94
+ /* @__PURE__ */ h("h1", {
39
95
  className: "text-2xl font-semibold",
40
- children: /* @__PURE__ */ c(_, { children: "My Learning" })
96
+ children: /* @__PURE__ */ h(b, { children: "My Learning" })
41
97
  }),
42
- /* @__PURE__ */ c("p", {
98
+ /* @__PURE__ */ h("p", {
43
99
  className: "text-sm text-text-secondary",
44
100
  children: "Track your learning progress and achievements"
45
101
  }),
46
- /* @__PURE__ */ c(y, {
102
+ /* @__PURE__ */ h(S, {
47
103
  className: "mt-1",
48
- children: "Everything you're currently learning — track your enrolled courses and progress all in one place."
104
+ children: "Everything you're currently learning — track your enrolled courses, completed training and the certificates you've earned, all in one place."
49
105
  })
50
106
  ] }),
51
- /* @__PURE__ */ l("div", {
52
- className: "grid gap-4 sm:grid-cols-3",
107
+ /* @__PURE__ */ g("div", {
108
+ className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4",
53
109
  children: [
54
- /* @__PURE__ */ l(g, {
55
- treatment: "glass",
56
- glow: !0,
57
- className: "border-border-seam",
58
- children: [/* @__PURE__ */ l(m, {
59
- className: "flex flex-row items-center justify-between space-y-0 pb-2",
60
- children: [/* @__PURE__ */ c(h, {
61
- className: "text-sm font-medium",
62
- children: "In Progress"
63
- }), /* @__PURE__ */ c(i, { className: "h-4 w-4 text-status-info-text" })]
64
- }), /* @__PURE__ */ c(f, { children: /* @__PURE__ */ c("div", {
65
- className: "text-2xl font-bold tabular-nums",
66
- children: j.length
67
- }) })]
110
+ /* @__PURE__ */ h(n, {
111
+ label: "Courses in progress",
112
+ value: P.length,
113
+ icon: /* @__PURE__ */ h(u, { className: "h-4 w-4" })
114
+ }),
115
+ /* @__PURE__ */ h(n, {
116
+ label: "Completed",
117
+ value: F.length,
118
+ icon: /* @__PURE__ */ h(l, { className: "h-4 w-4" })
68
119
  }),
69
- /* @__PURE__ */ l(g, {
70
- treatment: "metric",
71
- className: "border-border-seam",
72
- children: [/* @__PURE__ */ l(m, {
73
- className: "flex flex-row items-center justify-between space-y-0 pb-2",
74
- children: [/* @__PURE__ */ c(h, {
75
- className: "text-sm font-medium",
76
- children: "Completed"
77
- }), /* @__PURE__ */ c(r, { className: "h-4 w-4 text-status-success-text" })]
78
- }), /* @__PURE__ */ c(f, { children: /* @__PURE__ */ c("div", {
79
- className: "text-2xl font-bold tabular-nums",
80
- children: M.length
81
- }) })]
120
+ /* @__PURE__ */ h(n, {
121
+ label: "Certificates",
122
+ value: F.length,
123
+ icon: /* @__PURE__ */ h(d, { className: "h-4 w-4" })
82
124
  }),
83
- /* @__PURE__ */ l(g, {
84
- treatment: "metric",
85
- className: "border-border-seam",
86
- children: [/* @__PURE__ */ l(m, {
87
- className: "flex flex-row items-center justify-between space-y-0 pb-2",
88
- children: [/* @__PURE__ */ c(h, {
89
- className: "text-sm font-medium",
90
- children: "Hours Logged"
91
- }), /* @__PURE__ */ c(a, { className: "h-4 w-4 text-text-secondary" })]
92
- }), /* @__PURE__ */ c(f, { children: /* @__PURE__ */ c("div", {
93
- className: "text-2xl font-bold tabular-nums",
94
- children: N.toFixed(1)
95
- }) })]
125
+ /* @__PURE__ */ h(n, {
126
+ label: "Modules done",
127
+ value: I,
128
+ icon: /* @__PURE__ */ h(f, { className: "h-4 w-4" })
96
129
  })
97
130
  ]
98
131
  }),
99
- /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ l(m, { children: [/* @__PURE__ */ c(h, { children: "In Progress" }), /* @__PURE__ */ c(p, { children: "Continue where you left off" })] }), /* @__PURE__ */ l(f, {
100
- className: "space-y-4",
101
- children: [j.length === 0 ? /* @__PURE__ */ c(v, {
102
- illustration: "empty-generic",
103
- title: "Nothing in progress yet",
104
- description: "Courses you enroll in will show up here so you can pick up where you left off."
105
- }) : P.map((e) => /* @__PURE__ */ l("div", {
106
- className: "flex items-center gap-4 rounded border p-4",
107
- children: [/* @__PURE__ */ l("div", {
108
- className: "flex-1",
109
- children: [
110
- /* @__PURE__ */ c("p", {
111
- className: "text-sm font-medium",
112
- children: e.title
113
- }),
114
- /* @__PURE__ */ c("p", {
115
- className: "text-xs text-text-secondary",
116
- children: e.instructor
117
- }),
118
- /* @__PURE__ */ l("div", {
119
- className: "mt-2 flex items-center gap-2",
120
- children: [/* @__PURE__ */ c("div", {
121
- className: "h-2 flex-1 overflow-hidden rounded bg-bg-sunken",
122
- children: /* @__PURE__ */ c("div", {
123
- className: "h-2 rounded bg-action-primary-bg",
124
- style: { width: `${e.progress}%` }
125
- })
126
- }), /* @__PURE__ */ l("span", {
127
- className: "text-xs font-medium",
128
- children: [e.progress, "%"]
129
- })]
130
- }),
131
- /* @__PURE__ */ l("p", {
132
- className: "mt-1 text-xs text-text-secondary",
133
- children: [
134
- e.completedModules,
135
- "/",
136
- e.modules,
137
- " modules"
138
- ]
132
+ /* @__PURE__ */ h("div", {
133
+ className: "overflow-x-auto pb-1",
134
+ children: /* @__PURE__ */ h(a, {
135
+ "aria-label": "My learning",
136
+ value: j,
137
+ onChange: (e) => M(e),
138
+ className: "w-max",
139
+ tabs: [
140
+ {
141
+ id: "in-progress",
142
+ label: "In Progress",
143
+ count: P.length
144
+ },
145
+ {
146
+ id: "completed",
147
+ label: "Completed",
148
+ count: F.length
149
+ },
150
+ {
151
+ id: "certificates",
152
+ label: "Certificates",
153
+ count: F.length
154
+ }
155
+ ]
156
+ })
157
+ }),
158
+ j === "in-progress" && (P.length === 0 ? /* @__PURE__ */ h(x, {
159
+ illustration: "empty-generic",
160
+ title: "Nothing in progress yet",
161
+ description: "Enroll in a course and it will show up here so you can pick up where you left off.",
162
+ action: /* @__PURE__ */ h(v, {
163
+ variant: "outline",
164
+ onClick: () => A("../learning/courses-page"),
165
+ children: "Browse courses"
166
+ })
167
+ }) : /* @__PURE__ */ h("div", {
168
+ className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
169
+ children: P.map(({ course: e, pct: t, completedModules: n, totalModules: r }) => {
170
+ let i = E(e.category);
171
+ return /* @__PURE__ */ g(y, {
172
+ treatment: "plain",
173
+ className: "flex flex-col overflow-hidden",
174
+ children: [/* @__PURE__ */ h("div", {
175
+ className: "flex h-20 items-center justify-center",
176
+ style: { background: `linear-gradient(135deg, color-mix(in srgb, ${i} 26%, var(--color-bg-surface)), color-mix(in srgb, ${i} 8%, var(--color-bg-surface)))` },
177
+ children: /* @__PURE__ */ h("span", {
178
+ className: "flex h-10 w-10 items-center justify-center rounded-xl bg-bg-surface/70 shadow-elevation-1",
179
+ style: { color: i },
180
+ children: /* @__PURE__ */ h(k, { className: "h-5 w-5" })
139
181
  })
140
- ]
141
- }), /* @__PURE__ */ l(u, {
142
- size: "sm",
143
- onClick: () => A(e.id),
144
- disabled: E === e.id,
145
- children: [/* @__PURE__ */ c(o, { className: "mr-1 h-3 w-3" }), E === e.id ? "Saving…" : "Continue"]
146
- })]
147
- }, e.id)), j.length > O.pageSize && /* @__PURE__ */ c(b, {
148
- page: O.page,
149
- pageSize: O.pageSize,
150
- totalItems: j.length,
151
- onPageChange: O.setPage
152
- })]
153
- })] }),
154
- /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ c(m, { children: /* @__PURE__ */ c(h, { children: "Completed" }) }), /* @__PURE__ */ l(f, {
182
+ }), /* @__PURE__ */ g("div", {
183
+ className: "flex flex-1 flex-col gap-3 p-4",
184
+ children: [
185
+ /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("p", {
186
+ className: "text-sm font-semibold",
187
+ children: e.title
188
+ }), /* @__PURE__ */ h("p", {
189
+ className: "text-xs text-text-secondary",
190
+ children: e.instructor
191
+ })] }),
192
+ /* @__PURE__ */ g("div", {
193
+ className: "mt-auto space-y-1",
194
+ children: [/* @__PURE__ */ g("div", {
195
+ className: "flex justify-between text-xs text-text-secondary",
196
+ children: [/* @__PURE__ */ g("span", {
197
+ className: "tabular-nums",
198
+ children: [t, "% complete"]
199
+ }), /* @__PURE__ */ g("span", {
200
+ className: "tabular-nums",
201
+ children: [
202
+ n,
203
+ "/",
204
+ r,
205
+ " modules"
206
+ ]
207
+ })]
208
+ }), /* @__PURE__ */ h("div", {
209
+ className: "h-2 overflow-hidden rounded-full bg-bg-sunken",
210
+ children: /* @__PURE__ */ h("div", {
211
+ className: "h-full rounded-full bg-action-primary-bg",
212
+ style: { width: `${t}%` }
213
+ })
214
+ })]
215
+ }),
216
+ /* @__PURE__ */ g(v, {
217
+ className: "w-full",
218
+ onClick: () => L(e.id),
219
+ children: [/* @__PURE__ */ h(p, { className: "mr-1 h-4 w-4" }), "Continue"]
220
+ })
221
+ ]
222
+ })]
223
+ }, e.id);
224
+ })
225
+ })),
226
+ j === "completed" && (F.length === 0 ? /* @__PURE__ */ h(x, {
227
+ illustration: "empty-generic",
228
+ title: "No completed courses yet",
229
+ description: "Finish a course from the player and it will be marked complete here."
230
+ }) : /* @__PURE__ */ h("div", {
155
231
  className: "space-y-3",
156
- children: [M.length === 0 ? /* @__PURE__ */ c(v, {
157
- illustration: "empty-generic",
158
- title: "No completed courses yet",
159
- description: "Courses your team finishes will be listed here."
160
- }) : F.map((e) => /* @__PURE__ */ l("div", {
161
- className: "flex items-center justify-between rounded border p-3",
162
- children: [/* @__PURE__ */ c("div", { children: /* @__PURE__ */ c("p", {
163
- className: "text-sm font-medium",
164
- children: e.title
165
- }) }), /* @__PURE__ */ l("div", {
166
- className: "flex items-center gap-1",
167
- children: [
168
- /* @__PURE__ */ c(s, { className: "h-3 w-3 text-status-warning-text" }),
169
- e.rating,
170
- "/5"
171
- ]
232
+ children: F.map(({ course: e, completedAt: t }) => /* @__PURE__ */ g("button", {
233
+ type: "button",
234
+ onClick: () => L(e.id),
235
+ className: "flex w-full items-center justify-between gap-3 rounded-lg border border-border-subtle p-4 text-left transition-colors hover:border-border-strong hover:bg-bg-sunken",
236
+ children: [/* @__PURE__ */ g("div", {
237
+ className: "min-w-0",
238
+ children: [/* @__PURE__ */ h("p", {
239
+ className: "truncate text-sm font-medium",
240
+ children: e.title
241
+ }), /* @__PURE__ */ g("p", {
242
+ className: "text-xs text-text-secondary",
243
+ children: [
244
+ "Completed ",
245
+ D(t),
246
+ " · ",
247
+ e.instructor
248
+ ]
249
+ })]
250
+ }), /* @__PURE__ */ g("div", {
251
+ className: "flex shrink-0 items-center gap-3",
252
+ children: [/* @__PURE__ */ h(r, {
253
+ value: e.rating,
254
+ size: 13,
255
+ showValue: !0
256
+ }), /* @__PURE__ */ h(_, {
257
+ variant: "secondary",
258
+ className: "text-[10px]",
259
+ children: "Completed"
260
+ })]
172
261
  })]
173
- }, e.id)), M.length > k.pageSize && /* @__PURE__ */ c(b, {
174
- page: k.page,
175
- pageSize: k.pageSize,
176
- totalItems: M.length,
177
- onPageChange: k.setPage
178
- })]
179
- })] })
262
+ }, e.id))
263
+ })),
264
+ j === "certificates" && (F.length === 0 ? /* @__PURE__ */ h(x, {
265
+ illustration: "empty-generic",
266
+ title: "No certificates yet",
267
+ description: "Certificates are issued when you complete a course. Finish one and it will appear here to download.",
268
+ action: /* @__PURE__ */ h(v, {
269
+ variant: "outline",
270
+ onClick: () => A("../learning/courses-page"),
271
+ children: "Browse courses"
272
+ })
273
+ }) : /* @__PURE__ */ h("div", {
274
+ className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
275
+ children: F.map(({ course: e, completedAt: t }) => {
276
+ let n = `CF-${e.id.slice(-6).toUpperCase()}`, r = D(t);
277
+ return /* @__PURE__ */ h(i, {
278
+ title: e.title,
279
+ recipient: N,
280
+ date: r,
281
+ issuer: "CrewFoundry",
282
+ credentialId: n,
283
+ onDownload: () => O(e.title, N, r, n)
284
+ }, e.id);
285
+ })
286
+ }))
180
287
  ]
181
288
  });
182
289
  }
183
290
  //#endregion
184
- export { C as LearningMyLearningPagePage };
291
+ export { A as LearningMyLearningPagePage };
185
292
 
186
293
  //# sourceMappingURL=LearningMyLearningPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LearningMyLearningPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/LearningMyLearningPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { Award, BookOpen, Clock, Play, Star } from 'lucide-react';\nimport {\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\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 { useCrewFoundryStore } from '../store/crewfoundryStore';\n\ntype EnrolledCourse = {\n id: string;\n title: string;\n progress: number;\n modules: number;\n completedModules: number;\n instructor: string;\n};\n\ntype CompletedCourse = {\n id: string;\n title: string;\n rating: number;\n};\n\nexport function LearningMyLearningPagePage() {\n const { courses, enrollCourse } = useCrewFoundryStore();\n const { showToast } = useGlobalUi();\n const [enrollingId, setEnrollingId] = useState<string | null>(null);\n const inProgressPaging = usePagination({ initialPageSize: 6 });\n const completedPaging = usePagination({ initialPageSize: 6 });\n\n const handleContinue = async (id: string) => {\n setEnrollingId(id);\n try {\n await enrollCourse(id);\n showToast('Enrollment updated', 'success');\n } catch (error) {\n showToast(error instanceof Error ? error.message : 'Unable to update course', 'error');\n } finally {\n setEnrollingId(null);\n }\n };\n\n const myEnrolledCourses = useMemo<EnrolledCourse[]>(() => {\n return courses\n .filter((course) => course.status === 'active')\n .map((course) => {\n const completedModules = Math.min(\n course.modules,\n Math.round((course.completed / Math.max(course.enrolled, 1)) * course.modules)\n );\n const progress = Math.round((completedModules / Math.max(course.modules, 1)) * 100);\n return {\n id: course.id,\n title: course.title,\n progress,\n modules: course.modules,\n completedModules,\n instructor: course.instructor,\n };\n });\n }, [courses]);\n\n const completedCourses = useMemo<CompletedCourse[]>(() => {\n return courses\n .filter((course) => course.completed > 0)\n .map((course) => ({\n id: `completed-${course.id}`,\n title: course.title,\n rating: Number(course.rating.toFixed(1)),\n }));\n }, [courses]);\n\n const hoursLogged = myEnrolledCourses.reduce(\n (sum, course) => sum + course.completedModules * 1.25,\n 0\n );\n\n const pagedEnrolled = myEnrolledCourses.slice(\n inProgressPaging.offset,\n inProgressPaging.offset + inProgressPaging.pageSize\n );\n const pagedCompleted = completedCourses.slice(\n completedPaging.offset,\n completedPaging.offset + completedPaging.pageSize\n );\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>My Learning</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Track your learning progress and achievements</p>\n <PagePurpose className=\"mt-1\">\n Everything you&apos;re currently learning — track your enrolled courses and progress all\n in one place.\n </PagePurpose>\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-3\">\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\">In Progress</CardTitle>\n <BookOpen className=\"h-4 w-4 text-status-info-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{myEnrolledCourses.length}</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\">Completed</CardTitle>\n <Award className=\"h-4 w-4 text-status-success-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{completedCourses.length}</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\">Hours Logged</CardTitle>\n <Clock className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{hoursLogged.toFixed(1)}</div>\n </CardContent>\n </GlassCard>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>In Progress</CardTitle>\n <CardDescription>Continue where you left off</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {myEnrolledCourses.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"Nothing in progress yet\"\n description=\"Courses you enroll in will show up here so you can pick up where you left off.\"\n />\n ) : (\n pagedEnrolled.map((course) => (\n <div key={course.id} className=\"flex items-center gap-4 rounded border p-4\">\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium\">{course.title}</p>\n <p className=\"text-xs text-text-secondary\">{course.instructor}</p>\n <div className=\"mt-2 flex items-center gap-2\">\n <div className=\"h-2 flex-1 overflow-hidden rounded bg-bg-sunken\">\n <div\n className=\"h-2 rounded bg-action-primary-bg\"\n style={{ width: `${course.progress}%` }}\n />\n </div>\n <span className=\"text-xs font-medium\">{course.progress}%</span>\n </div>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {course.completedModules}/{course.modules} modules\n </p>\n </div>\n <Button\n size=\"sm\"\n onClick={() => handleContinue(course.id)}\n disabled={enrollingId === course.id}\n >\n <Play className=\"mr-1 h-3 w-3\" />\n {enrollingId === course.id ? 'Saving…' : 'Continue'}\n </Button>\n </div>\n ))\n )}\n {myEnrolledCourses.length > inProgressPaging.pageSize && (\n <Pagination\n page={inProgressPaging.page}\n pageSize={inProgressPaging.pageSize}\n totalItems={myEnrolledCourses.length}\n onPageChange={inProgressPaging.setPage}\n />\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Completed</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {completedCourses.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No completed courses yet\"\n description=\"Courses your team finishes will be listed here.\"\n />\n ) : (\n pagedCompleted.map((course) => (\n <div key={course.id} className=\"flex items-center justify-between rounded border p-3\">\n <div>\n <p className=\"text-sm font-medium\">{course.title}</p>\n </div>\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n {course.rating}/5\n </div>\n </div>\n ))\n )}\n {completedCourses.length > completedPaging.pageSize && (\n <Pagination\n page={completedPaging.page}\n pageSize={completedPaging.pageSize}\n totalItems={completedCourses.length}\n onPageChange={completedPaging.setPage}\n />\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"LearningMyLearningPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/LearningMyLearningPagePage.tsx"],"sourcesContent":["import { useMemo, useState, type ComponentType } from 'react';\nimport { Award, BookOpen, GraduationCap, Layers, Play } from 'lucide-react';\nimport {\n Badge,\n Button,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useNavigate } from 'react-router-dom';\nimport { useAuth } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useCrewFoundryStore, type LearningCourse } from '../store/crewfoundryStore';\nimport { CertificateCard, chartPalette, RatingStars, SegmentedTabs, StatCard } from '../components/viz';\nimport { readAllCourseProgress } from '../utils/courseProgress';\n\nconst ENROLLED_KEY = 'crewfoundry:course-enrolled:v1';\n\nfunction readEnrolledIds(): Set<string> {\n if (typeof window === 'undefined') return new Set();\n try {\n const raw = window.localStorage.getItem(ENROLLED_KEY);\n const ids: unknown = raw ? JSON.parse(raw) : [];\n return new Set(Array.isArray(ids) ? ids.filter((x): x is string => typeof x === 'string') : []);\n } catch {\n return new Set();\n }\n}\n\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 formatDate(iso?: string): string {\n if (!iso) return '—';\n const date = new Date(iso);\n if (Number.isNaN(date.getTime())) return '—';\n return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });\n}\n\n/** Generate a self-contained, printable certificate document (no app tokens, no raw colors). */\nfunction downloadCertificate(course: string, recipient: string, dateLabel: string, id: string): void {\n if (typeof document === 'undefined') return;\n const esc = (s: string) =>\n s.replace(/[&<>\"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' })[c] ?? c);\n const html = `<!doctype html><html><head><meta charset=\"utf-8\"><title>Certificate — ${esc(course)}</title>\n<style>\n body{font-family:Georgia,'Times New Roman',serif;margin:0;padding:48px;text-align:center}\n .frame{border:6px double currentColor;padding:56px 40px;max-width:760px;margin:0 auto}\n .kicker{letter-spacing:.3em;text-transform:uppercase;font-size:12px;opacity:.7}\n h1{font-size:34px;margin:24px 0 8px}\n .recipient{font-size:26px;margin:20px 0}\n .rule{width:200px;border:0;border-top:1px solid currentColor;margin:24px auto;opacity:.4}\n .meta{font-size:13px;opacity:.7;margin-top:32px}\n</style></head><body>\n <div class=\"frame\">\n <div class=\"kicker\">CrewFoundry · Certificate of Completion</div>\n <h1>${esc(course)}</h1>\n <div class=\"kicker\">Awarded to</div>\n <div class=\"recipient\">${esc(recipient)}</div>\n <hr class=\"rule\" />\n <div class=\"meta\">Issued ${esc(dateLabel)} &nbsp;·&nbsp; Credential ID: ${esc(id)}</div>\n </div>\n</body></html>`;\n const blob = new Blob([html], { type: 'text/html' });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = `crewfoundry-certificate-${id}.html`;\n document.body.appendChild(anchor);\n anchor.click();\n anchor.remove();\n URL.revokeObjectURL(url);\n}\n\ntype Tab = 'in-progress' | 'completed' | 'certificates';\n\ninterface LearnerCourse {\n course: LearningCourse;\n completedModules: number;\n totalModules: number;\n pct: number;\n completedAt?: string;\n}\n\nconst CATEGORY_ICON: ComponentType<{ className?: string }> = BookOpen;\n\nexport function LearningMyLearningPagePage() {\n const { courses } = useCrewFoundryStore();\n const auth = useAuth();\n const navigate = useNavigate();\n const [tab, setTab] = useState<Tab>('in-progress');\n\n const recipient = auth.user?.name?.trim() || 'CrewFoundry Learner';\n\n const { inProgress, completed, modulesDone } = useMemo(() => {\n const progressMap = readAllCourseProgress();\n const enrolled = readEnrolledIds();\n const inProg: LearnerCourse[] = [];\n const done: LearnerCourse[] = [];\n let totalModulesDone = 0;\n\n for (const course of courses) {\n const entry = progressMap[course.id];\n const completedModules = entry?.completed.length ?? 0;\n totalModulesDone += completedModules;\n const totalModules = Math.max(course.modules, 1);\n const pct = Math.min(100, Math.round((completedModules / totalModules) * 100));\n const record: LearnerCourse = {\n course,\n completedModules,\n totalModules,\n pct,\n completedAt: entry?.completedAt,\n };\n if (completedModules >= totalModules && completedModules > 0) {\n done.push(record);\n } else if (completedModules > 0 || enrolled.has(course.id)) {\n inProg.push(record);\n }\n }\n inProg.sort((a, b) => b.pct - a.pct);\n done.sort((a, b) => (b.completedAt ?? '').localeCompare(a.completedAt ?? ''));\n return { inProgress: inProg, completed: done, modulesDone: totalModulesDone };\n }, [courses]);\n\n const openPlayer = (id: string) =>\n navigate(`../learning/course-learning-page?id=${encodeURIComponent(id)}`);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>My Learning</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Track your learning progress and achievements</p>\n <PagePurpose className=\"mt-1\">\n Everything you&apos;re currently learning — track your enrolled courses, completed\n training and the certificates you&apos;ve earned, all in one place.\n </PagePurpose>\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n label=\"Courses in progress\"\n value={inProgress.length}\n icon={<BookOpen className=\"h-4 w-4\" />}\n />\n <StatCard label=\"Completed\" value={completed.length} icon={<Award className=\"h-4 w-4\" />} />\n <StatCard\n label=\"Certificates\"\n value={completed.length}\n icon={<GraduationCap className=\"h-4 w-4\" />}\n />\n <StatCard label=\"Modules done\" value={modulesDone} icon={<Layers className=\"h-4 w-4\" />} />\n </div>\n\n <div className=\"overflow-x-auto pb-1\">\n <SegmentedTabs\n aria-label=\"My learning\"\n value={tab}\n onChange={(id) => setTab(id as Tab)}\n className=\"w-max\"\n tabs={[\n { id: 'in-progress', label: 'In Progress', count: inProgress.length },\n { id: 'completed', label: 'Completed', count: completed.length },\n { id: 'certificates', label: 'Certificates', count: completed.length },\n ]}\n />\n </div>\n\n {tab === 'in-progress' &&\n (inProgress.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"Nothing in progress yet\"\n description=\"Enroll in a course and it will show up here so you can pick up where you left off.\"\n action={\n <Button variant=\"outline\" onClick={() => navigate('../learning/courses-page')}>\n Browse courses\n </Button>\n }\n />\n ) : (\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {inProgress.map(({ course, pct, completedModules, totalModules }) => {\n const accent = categoryAccent(course.category);\n return (\n <GlassCard key={course.id} treatment=\"plain\" className=\"flex flex-col overflow-hidden\">\n <div\n className=\"flex h-20 items-center justify-center\"\n style={{\n background: `linear-gradient(135deg, color-mix(in srgb, ${accent} 26%, var(--color-bg-surface)), color-mix(in srgb, ${accent} 8%, var(--color-bg-surface)))`,\n }}\n >\n <span\n className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-bg-surface/70 shadow-elevation-1\"\n style={{ color: accent }}\n >\n <CATEGORY_ICON className=\"h-5 w-5\" />\n </span>\n </div>\n <div className=\"flex flex-1 flex-col gap-3 p-4\">\n <div>\n <p className=\"text-sm font-semibold\">{course.title}</p>\n <p className=\"text-xs text-text-secondary\">{course.instructor}</p>\n </div>\n <div className=\"mt-auto space-y-1\">\n <div className=\"flex justify-between text-xs text-text-secondary\">\n <span className=\"tabular-nums\">{pct}% complete</span>\n <span className=\"tabular-nums\">\n {completedModules}/{totalModules} modules\n </span>\n </div>\n <div className=\"h-2 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 <Button className=\"w-full\" onClick={() => openPlayer(course.id)}>\n <Play className=\"mr-1 h-4 w-4\" />\n Continue\n </Button>\n </div>\n </GlassCard>\n );\n })}\n </div>\n ))}\n\n {tab === 'completed' &&\n (completed.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No completed courses yet\"\n description=\"Finish a course from the player and it will be marked complete here.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {completed.map(({ course, completedAt }) => (\n <button\n key={course.id}\n type=\"button\"\n onClick={() => openPlayer(course.id)}\n className=\"flex w-full items-center justify-between gap-3 rounded-lg border border-border-subtle p-4 text-left transition-colors hover:border-border-strong hover:bg-bg-sunken\"\n >\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium\">{course.title}</p>\n <p className=\"text-xs text-text-secondary\">\n Completed {formatDate(completedAt)} · {course.instructor}\n </p>\n </div>\n <div className=\"flex shrink-0 items-center gap-3\">\n <RatingStars value={course.rating} size={13} showValue />\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n Completed\n </Badge>\n </div>\n </button>\n ))}\n </div>\n ))}\n\n {tab === 'certificates' &&\n (completed.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No certificates yet\"\n description=\"Certificates are issued when you complete a course. Finish one and it will appear here to download.\"\n action={\n <Button variant=\"outline\" onClick={() => navigate('../learning/courses-page')}>\n Browse courses\n </Button>\n }\n />\n ) : (\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {completed.map(({ course, completedAt }) => {\n const credentialId = `CF-${course.id.slice(-6).toUpperCase()}`;\n const dateLabel = formatDate(completedAt);\n return (\n <CertificateCard\n key={course.id}\n title={course.title}\n recipient={recipient}\n date={dateLabel}\n issuer=\"CrewFoundry\"\n credentialId={credentialId}\n onDownload={() =>\n downloadCertificate(course.title, recipient, dateLabel, credentialId)\n }\n />\n );\n })}\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":"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"}