@burdenoff/microfe-buildmyiq 2026.705.13 → 2026.706.10

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 (67) hide show
  1. package/dist/buildmyiq/BuildmyiqRoot.d.ts.map +1 -1
  2. package/dist/buildmyiq/BuildmyiqRoot.js +57 -49
  3. package/dist/buildmyiq/BuildmyiqRoot.js.map +1 -1
  4. package/dist/buildmyiq/BuildmyiqRoutes.d.ts.map +1 -1
  5. package/dist/buildmyiq/BuildmyiqRoutes.js +15 -11
  6. package/dist/buildmyiq/BuildmyiqRoutes.js.map +1 -1
  7. package/dist/buildmyiq/components/Avatar.d.ts +15 -0
  8. package/dist/buildmyiq/components/Avatar.d.ts.map +1 -0
  9. package/dist/buildmyiq/components/Avatar.js +42 -0
  10. package/dist/buildmyiq/components/Avatar.js.map +1 -0
  11. package/dist/buildmyiq/components/Viz.d.ts +25 -0
  12. package/dist/buildmyiq/components/Viz.d.ts.map +1 -0
  13. package/dist/buildmyiq/components/Viz.js +78 -0
  14. package/dist/buildmyiq/components/Viz.js.map +1 -0
  15. package/dist/buildmyiq/components/index.d.ts +2 -0
  16. package/dist/buildmyiq/components/index.d.ts.map +1 -1
  17. package/dist/buildmyiq/components/index.js +2 -0
  18. package/dist/buildmyiq/pages/DashboardPage.d.ts.map +1 -1
  19. package/dist/buildmyiq/pages/DashboardPage.js +200 -98
  20. package/dist/buildmyiq/pages/DashboardPage.js.map +1 -1
  21. package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.d.ts.map +1 -1
  22. package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.js +262 -241
  23. package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.js.map +1 -1
  24. package/dist/buildmyiq/pages/assessments/AssessmentsPage.d.ts.map +1 -1
  25. package/dist/buildmyiq/pages/assessments/AssessmentsPage.js +142 -115
  26. package/dist/buildmyiq/pages/assessments/AssessmentsPage.js.map +1 -1
  27. package/dist/buildmyiq/pages/assessments/TakeAssessmentPage.d.ts.map +1 -1
  28. package/dist/buildmyiq/pages/assessments/TakeAssessmentPage.js +220 -156
  29. package/dist/buildmyiq/pages/assessments/TakeAssessmentPage.js.map +1 -1
  30. package/dist/buildmyiq/pages/authoring/AuthoringPage.d.ts.map +1 -1
  31. package/dist/buildmyiq/pages/authoring/AuthoringPage.js +51 -46
  32. package/dist/buildmyiq/pages/authoring/AuthoringPage.js.map +1 -1
  33. package/dist/buildmyiq/pages/authoring/CourseBuilderPage.d.ts.map +1 -1
  34. package/dist/buildmyiq/pages/authoring/CourseBuilderPage.js +581 -448
  35. package/dist/buildmyiq/pages/authoring/CourseBuilderPage.js.map +1 -1
  36. package/dist/buildmyiq/pages/catalog/CatalogPage.d.ts.map +1 -1
  37. package/dist/buildmyiq/pages/catalog/CatalogPage.js +52 -42
  38. package/dist/buildmyiq/pages/catalog/CatalogPage.js.map +1 -1
  39. package/dist/buildmyiq/pages/catalog/CourseDetailPage.d.ts.map +1 -1
  40. package/dist/buildmyiq/pages/catalog/CourseDetailPage.js +422 -301
  41. package/dist/buildmyiq/pages/catalog/CourseDetailPage.js.map +1 -1
  42. package/dist/buildmyiq/pages/certificates/CertificatesPage.d.ts.map +1 -1
  43. package/dist/buildmyiq/pages/certificates/CertificatesPage.js +237 -151
  44. package/dist/buildmyiq/pages/certificates/CertificatesPage.js.map +1 -1
  45. package/dist/buildmyiq/pages/cohorts/CohortsPage.d.ts.map +1 -1
  46. package/dist/buildmyiq/pages/cohorts/CohortsPage.js +219 -138
  47. package/dist/buildmyiq/pages/cohorts/CohortsPage.js.map +1 -1
  48. package/dist/buildmyiq/pages/insights/InsightsPage.d.ts.map +1 -1
  49. package/dist/buildmyiq/pages/insights/InsightsPage.js +276 -152
  50. package/dist/buildmyiq/pages/insights/InsightsPage.js.map +1 -1
  51. package/dist/buildmyiq/pages/learning/LessonPlayerPage.d.ts.map +1 -1
  52. package/dist/buildmyiq/pages/learning/LessonPlayerPage.js +237 -174
  53. package/dist/buildmyiq/pages/learning/LessonPlayerPage.js.map +1 -1
  54. package/dist/buildmyiq/pages/learning/MyLearningPage.d.ts.map +1 -1
  55. package/dist/buildmyiq/pages/learning/MyLearningPage.js +307 -169
  56. package/dist/buildmyiq/pages/learning/MyLearningPage.js.map +1 -1
  57. package/dist/buildmyiq/pages/paths/PathsPage.d.ts +4 -0
  58. package/dist/buildmyiq/pages/paths/PathsPage.d.ts.map +1 -0
  59. package/dist/buildmyiq/pages/paths/PathsPage.js +187 -0
  60. package/dist/buildmyiq/pages/paths/PathsPage.js.map +1 -0
  61. package/dist/buildmyiq/pages/skills/SkillsPage.d.ts.map +1 -1
  62. package/dist/buildmyiq/pages/skills/SkillsPage.js +233 -140
  63. package/dist/buildmyiq/pages/skills/SkillsPage.js.map +1 -1
  64. package/dist/buildmyiq/pages/submissions/SubmissionsPage.d.ts.map +1 -1
  65. package/dist/buildmyiq/pages/submissions/SubmissionsPage.js +379 -275
  66. package/dist/buildmyiq/pages/submissions/SubmissionsPage.js.map +1 -1
  67. package/package.json +1 -1
@@ -3,79 +3,127 @@ import { PageLayout as t } from "../../components/PageLayout.js";
3
3
  import { MetricsCard as n } from "../../components/MetricsCard.js";
4
4
  import { formatEnumLabel as r, formatPercent as i } from "../../utils/formatters.js";
5
5
  import { EmptyState as a } from "../../components/EmptyState.js";
6
- import { LoadingView as o, Section as s } from "../../components/StateViews.js";
7
- import { MiniBar as c } from "../../components/MiniBar.js";
8
- import { useBuiCertificates as l, useBuiCourses as u, useBuiEnrollments as d, useBuiSubmissions as f } from "../../hooks/useBuildmyiqApi.js";
6
+ import { ErrorView as o, LoadingView as s, Section as c } from "../../components/StateViews.js";
7
+ import { MiniBar as l } from "../../components/MiniBar.js";
8
+ import { ProgressRing as u, Sparkline as d } from "../../components/Viz.js";
9
+ import { useBuiCertificates as f, useBuiCourses as p, useBuiEnrollments as m, useBuiSubmissions as h } from "../../hooks/useBuildmyiqApi.js";
9
10
  import "../../hooks/index.js";
10
11
  import "../../components/index.js";
11
- import { useMemo as p } from "react";
12
- import { Award as m, BookOpen as h, CheckCircle2 as g, GraduationCap as _, TrendingUp as v, Users as y } from "lucide-react";
13
- import { jsx as b, jsxs as x } from "react/jsx-runtime";
14
- import { GlassCard as S } from "@burdenoff/fe-libs/ui";
12
+ import { useMemo as g } from "react";
13
+ import { AlarmClock as _, Award as v, BookOpen as y, CheckCircle2 as b, Clock as x, GraduationCap as S, TrendingUp as C, User as w, Users as T, XCircle as E } from "lucide-react";
14
+ import { jsx as D, jsxs as O } from "react/jsx-runtime";
15
+ import { GlassCard as k } from "@burdenoff/fe-libs/ui";
15
16
  //#region src/buildmyiq/pages/insights/InsightsPage.tsx
16
- var C = [
17
+ var A = [
17
18
  "ENROLLED",
18
19
  "IN_PROGRESS",
19
20
  "COMPLETED",
20
21
  "DROPPED",
21
22
  "EXPIRED"
22
- ], w = ({ rows: e }) => /* @__PURE__ */ b("div", {
23
+ ], j = {
24
+ ENROLLED: {
25
+ icon: w,
26
+ bar: "bg-[var(--color-accent-teal)]",
27
+ icon_tint: "text-[var(--color-accent-teal)]"
28
+ },
29
+ IN_PROGRESS: {
30
+ icon: x,
31
+ bar: "bg-[var(--color-accent-primary)]",
32
+ icon_tint: "text-[var(--color-accent-primary)]"
33
+ },
34
+ COMPLETED: {
35
+ icon: b,
36
+ bar: "bg-[var(--color-status-success-text)]",
37
+ icon_tint: "text-[var(--color-status-success-text)]"
38
+ },
39
+ DROPPED: {
40
+ icon: E,
41
+ bar: "bg-[var(--color-status-error-text)]",
42
+ icon_tint: "text-[var(--color-status-error-text)]"
43
+ },
44
+ EXPIRED: {
45
+ icon: _,
46
+ bar: "bg-[var(--color-text-tertiary)]",
47
+ icon_tint: "text-[var(--color-text-tertiary)]"
48
+ }
49
+ }, M = {
50
+ info: "bg-[var(--color-status-info-bg)] text-[var(--color-status-info-text)]",
51
+ success: "bg-[var(--color-status-success-bg)] text-[var(--color-status-success-text)]",
52
+ warning: "bg-[var(--color-status-warning-bg)] text-[var(--color-status-warning-text)]",
53
+ accent: "bg-[var(--color-accent-soft)] text-[var(--color-accent-teal)]"
54
+ }, N = ({ tint: t, children: n }) => /* @__PURE__ */ D("span", {
55
+ className: e("flex h-11 w-11 items-center justify-center rounded-full", M[t]),
56
+ children: n
57
+ }), P = ({ rows: t }) => /* @__PURE__ */ D("div", {
23
58
  className: "flex flex-col gap-3",
24
- children: e.map((e) => /* @__PURE__ */ x("div", {
25
- className: "flex items-center gap-3",
26
- children: [
27
- /* @__PURE__ */ b("span", {
28
- className: "w-28 shrink-0 text-sm text-text-secondary",
29
- children: e.label
30
- }),
31
- /* @__PURE__ */ b(c, {
32
- value: e.pct,
33
- barClassName: e.tone,
34
- className: "flex-1",
35
- height: 8
36
- }),
37
- /* @__PURE__ */ b("span", {
38
- className: "w-10 shrink-0 text-right text-sm tabular-nums text-text-primary",
39
- children: e.count
40
- })
41
- ]
42
- }, e.label))
43
- }), T = () => {
44
- let T = u({ limit: 100 }), E = d({ limit: 100 }), D = f({ limit: 100 }), O = l(), k = p(() => T.data?.items ?? [], [T.data]), A = p(() => E.data?.items ?? [], [E.data]), j = p(() => D.data?.items ?? [], [D.data]), M = O.data ?? [], N = p(() => {
45
- let e = k.filter((e) => e.status === "PUBLISHED").length, t = A.filter((e) => e.status === "COMPLETED").length, n = A.length > 0 ? t / A.length * 100 : 0, r = A.length > 0 ? A.reduce((e, t) => e + (t.progressPct ?? 0), 0) / A.length : 0, i = j.filter((e) => e.status === "GRADED"), a = i.filter((e) => e.passed === !0).length, o = i.length > 0 ? a / i.length * 100 : 0, s = new Set(A.map((e) => e.learnerId)).size;
59
+ children: t.map((t) => {
60
+ let n = j[t.status], r = n.icon;
61
+ return /* @__PURE__ */ O("div", {
62
+ className: "flex items-center gap-3",
63
+ children: [
64
+ /* @__PURE__ */ O("span", {
65
+ className: "flex w-24 shrink-0 items-center gap-2 text-sm text-text-secondary sm:w-28",
66
+ children: [/* @__PURE__ */ D(r, { className: e("h-4 w-4 shrink-0", n.icon_tint) }), /* @__PURE__ */ D("span", {
67
+ className: "truncate",
68
+ children: t.label
69
+ })]
70
+ }),
71
+ /* @__PURE__ */ D(l, {
72
+ value: t.pct,
73
+ barClassName: n.bar,
74
+ className: "flex-1",
75
+ height: 8
76
+ }),
77
+ /* @__PURE__ */ D("span", {
78
+ className: "w-9 shrink-0 text-right text-sm tabular-nums text-text-primary",
79
+ children: t.count
80
+ })
81
+ ]
82
+ }, t.status);
83
+ })
84
+ }), F = () => {
85
+ let _ = p({ limit: 100 }), b = m({ limit: 100 }), x = h({ limit: 100 }), w = f(), E = g(() => _.data?.items ?? [], [_.data]), j = g(() => b.data?.items ?? [], [b.data]), M = g(() => x.data?.items ?? [], [x.data]), F = w.data ?? [], I = g(() => {
86
+ let e = E.filter((e) => e.status === "PUBLISHED").length, t = j.filter((e) => e.status === "COMPLETED").length, n = j.filter((e) => e.status === "IN_PROGRESS").length, r = j.length > 0 ? t / j.length * 100 : 0, i = j.length > 0 ? j.reduce((e, t) => e + (t.progressPct ?? 0), 0) / j.length : 0, a = M.filter((e) => e.status === "GRADED"), o = a.filter((e) => e.passed === !0).length, s = a.length > 0 ? o / a.length * 100 : 0, c = new Set(j.map((e) => e.learnerId)).size;
46
87
  return {
47
88
  published: e,
89
+ totalCourses: E.length,
48
90
  completed: t,
49
- completionRate: n,
50
- avgProgress: r,
51
- gradedCount: i.length,
52
- passRate: o,
53
- activeLearners: s
91
+ inProgress: n,
92
+ completionRate: r,
93
+ avgProgress: i,
94
+ gradedCount: a.length,
95
+ passed: o,
96
+ passRate: s,
97
+ activeLearners: c
54
98
  };
55
99
  }, [
56
- k,
57
- A,
58
- j
59
- ]), P = p(() => {
60
- let e = A.length, t = {
61
- ENROLLED: "bg-[var(--color-accent-teal)]",
62
- IN_PROGRESS: "bg-[var(--color-accent-teal)]",
63
- COMPLETED: "bg-[var(--color-status-success-text)]",
64
- DROPPED: "bg-[var(--color-status-error-text)]",
65
- EXPIRED: "bg-[var(--color-text-tertiary)]"
66
- };
67
- return C.map((n) => {
68
- let i = A.filter((e) => e.status === n).length;
100
+ E,
101
+ j,
102
+ M
103
+ ]), L = g(() => {
104
+ let e = j.length;
105
+ return A.map((t) => {
106
+ let n = j.filter((e) => e.status === t).length;
69
107
  return {
70
- label: r(n),
71
- count: i,
72
- pct: e > 0 ? i / e * 100 : 0,
73
- tone: t[n] ?? "bg-accent"
108
+ status: t,
109
+ label: r(t),
110
+ count: n,
111
+ pct: e > 0 ? n / e * 100 : 0
74
112
  };
75
113
  }).filter((e) => e.count > 0);
76
- }, [A]), F = p(() => {
77
- let e = new Map(k.map((e) => [e.id, e.title])), t = /* @__PURE__ */ new Map();
78
- for (let e of A) t.set(e.courseId, (t.get(e.courseId) ?? 0) + 1);
114
+ }, [j]), R = g(() => {
115
+ if (j.length === 0) return [];
116
+ let e = /* @__PURE__ */ new Map();
117
+ for (let t of j) {
118
+ let n = new Date(t.enrolledAt);
119
+ if (Number.isNaN(n.getTime())) continue;
120
+ let r = `${n.getFullYear()}-${String(n.getMonth() + 1).padStart(2, "0")}`;
121
+ e.set(r, (e.get(r) ?? 0) + 1);
122
+ }
123
+ return [...e.entries()].sort(([e], [t]) => e.localeCompare(t)).map(([, e]) => e);
124
+ }, [j]), z = g(() => {
125
+ let e = new Map(E.map((e) => [e.id, e.title])), t = /* @__PURE__ */ new Map();
126
+ for (let e of j) t.set(e.courseId, (t.get(e.courseId) ?? 0) + 1);
79
127
  let n = Math.max(1, ...t.values());
80
128
  return [...t.entries()].map(([t, r]) => ({
81
129
  courseId: t,
@@ -83,108 +131,179 @@ var C = [
83
131
  count: r,
84
132
  pct: r / n * 100
85
133
  })).sort((e, t) => t.count - e.count).slice(0, 6);
86
- }, [k, A]), I = T.isLoading || E.isLoading || D.isLoading, L = k.length > 0 || A.length > 0 || j.length > 0 || M.length > 0;
87
- return /* @__PURE__ */ b(t, {
134
+ }, [E, j]), B = _.isLoading || b.isLoading || x.isLoading, V = _.isError || b.isError || x.isError || w.isError, H = E.length > 0 || j.length > 0 || M.length > 0 || F.length > 0;
135
+ return /* @__PURE__ */ D(t, {
88
136
  title: "Insights",
89
137
  description: "Learning analytics across your workspace — completion, engagement and outcomes.",
90
138
  titleGradient: !0,
91
139
  aurora: !0,
92
- children: I ? /* @__PURE__ */ b(o, { label: "Crunching your learning data…" }) : L ? /* @__PURE__ */ x("div", {
140
+ children: B ? /* @__PURE__ */ D(s, { label: "Crunching your learning data…" }) : V ? /* @__PURE__ */ D(o, {
141
+ title: "Couldn't load insights",
142
+ message: "We hit a snag pulling your learning data. Try again in a moment.",
143
+ onRetry: () => {
144
+ _.refetch(), b.refetch(), x.refetch(), w.refetch();
145
+ }
146
+ }) : H ? /* @__PURE__ */ O("div", {
93
147
  className: "flex flex-col gap-8",
94
148
  children: [
95
- /* @__PURE__ */ x("div", {
149
+ /* @__PURE__ */ O("div", {
96
150
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4",
97
151
  children: [
98
- /* @__PURE__ */ b(n, {
99
- icon: /* @__PURE__ */ b(h, { className: "h-5 w-5" }),
100
- value: N.published,
152
+ /* @__PURE__ */ D(n, {
153
+ icon: /* @__PURE__ */ D(N, {
154
+ tint: "info",
155
+ children: /* @__PURE__ */ D(y, { className: "h-5 w-5" })
156
+ }),
157
+ value: I.published,
101
158
  label: "Published courses",
102
- featured: !0
159
+ footer: /* @__PURE__ */ O("span", {
160
+ className: "text-xs text-text-secondary",
161
+ children: [
162
+ "of ",
163
+ I.totalCourses,
164
+ " total"
165
+ ]
166
+ })
103
167
  }),
104
- /* @__PURE__ */ b(n, {
105
- icon: /* @__PURE__ */ b(y, { className: "h-5 w-5" }),
106
- value: N.activeLearners,
107
- label: "Active learners"
168
+ /* @__PURE__ */ D(n, {
169
+ icon: /* @__PURE__ */ D(N, {
170
+ tint: "success",
171
+ children: /* @__PURE__ */ D(T, { className: "h-5 w-5" })
172
+ }),
173
+ value: I.activeLearners,
174
+ label: "Active learners",
175
+ footer: /* @__PURE__ */ O("span", {
176
+ className: "text-xs text-text-secondary",
177
+ children: [
178
+ j.length,
179
+ " enrolment",
180
+ j.length === 1 ? "" : "s"
181
+ ]
182
+ })
108
183
  }),
109
- /* @__PURE__ */ b(n, {
110
- icon: /* @__PURE__ */ b(v, { className: "h-5 w-5" }),
111
- value: i(N.completionRate),
184
+ /* @__PURE__ */ D(n, {
185
+ icon: /* @__PURE__ */ D(N, {
186
+ tint: "accent",
187
+ children: /* @__PURE__ */ D(C, { className: "h-5 w-5" })
188
+ }),
189
+ value: i(I.completionRate),
112
190
  label: "Completion rate",
113
- accent: "success",
114
- footer: /* @__PURE__ */ b(c, {
115
- value: N.completionRate,
116
- barClassName: "bg-[var(--color-status-success-text)]"
191
+ footer: /* @__PURE__ */ D(l, {
192
+ value: I.completionRate,
193
+ barClassName: "bg-[var(--color-accent-teal)]"
117
194
  })
118
195
  }),
119
- /* @__PURE__ */ b(n, {
120
- icon: /* @__PURE__ */ b(m, { className: "h-5 w-5" }),
121
- value: M.length,
196
+ /* @__PURE__ */ D(n, {
197
+ icon: /* @__PURE__ */ D(N, {
198
+ tint: "warning",
199
+ children: /* @__PURE__ */ D(v, { className: "h-5 w-5" })
200
+ }),
201
+ value: F.length,
122
202
  label: "Certificates issued"
123
203
  })
124
204
  ]
125
205
  }),
126
- /* @__PURE__ */ x("div", {
206
+ /* @__PURE__ */ O("div", {
127
207
  className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
128
- children: [/* @__PURE__ */ b(s, {
208
+ children: [/* @__PURE__ */ D(c, {
129
209
  title: "Enrolment status",
130
- description: `${A.length} enrolments`,
131
- children: P.length === 0 ? /* @__PURE__ */ b("p", {
132
- className: "text-sm text-text-secondary",
133
- children: "No enrolments yet."
134
- }) : /* @__PURE__ */ x(S, {
210
+ description: `${j.length} enrolments`,
211
+ children: L.length === 0 ? /* @__PURE__ */ D(k, {
212
+ treatment: "plain",
213
+ className: "p-5",
214
+ children: /* @__PURE__ */ D("p", {
215
+ className: "text-sm text-text-secondary",
216
+ children: "No enrolments yet."
217
+ })
218
+ }) : /* @__PURE__ */ O(k, {
135
219
  treatment: "plain",
136
220
  className: "p-5",
137
- children: [/* @__PURE__ */ b(w, { rows: P }), /* @__PURE__ */ x("div", {
138
- className: "mt-4 flex items-center gap-2 border-t border-border-seam pt-3",
139
- children: [/* @__PURE__ */ b(_, { className: "h-4 w-4 text-text-secondary" }), /* @__PURE__ */ x("span", {
140
- className: "text-sm text-text-secondary",
221
+ children: [/* @__PURE__ */ D(P, { rows: L }), /* @__PURE__ */ O("div", {
222
+ className: "mt-4 flex flex-wrap items-center justify-between gap-3 border-t border-border-seam pt-3",
223
+ children: [/* @__PURE__ */ O("span", {
224
+ className: "inline-flex items-center gap-1.5 text-sm text-text-secondary",
141
225
  children: [
142
- "Average progress",
143
- " ",
144
- /* @__PURE__ */ b("span", {
226
+ /* @__PURE__ */ D(S, { className: "h-4 w-4" }),
227
+ " Avg progress",
228
+ /* @__PURE__ */ D("span", {
145
229
  className: "font-medium text-text-primary",
146
- children: i(N.avgProgress)
230
+ children: i(I.avgProgress)
147
231
  })
148
232
  ]
233
+ }), R.length >= 2 && /* @__PURE__ */ O("span", {
234
+ className: "inline-flex items-center gap-2",
235
+ children: [/* @__PURE__ */ D(d, {
236
+ data: R,
237
+ color: "var(--color-accent-teal)"
238
+ }), /* @__PURE__ */ D("span", {
239
+ className: "text-xs text-text-secondary",
240
+ children: "new / month"
241
+ })]
149
242
  })]
150
243
  })]
151
244
  })
152
- }), /* @__PURE__ */ b(s, {
153
- title: "Assessment outcomes",
154
- description: `${j.length} submissions`,
155
- children: /* @__PURE__ */ x(S, {
245
+ }), /* @__PURE__ */ D(c, {
246
+ title: "Learning outcomes",
247
+ description: `${M.length} submissions`,
248
+ children: /* @__PURE__ */ O(k, {
156
249
  treatment: "plain",
157
- className: "flex flex-col gap-4 p-5",
250
+ className: "flex flex-col gap-5 p-5",
158
251
  children: [
159
- /* @__PURE__ */ x("div", {
160
- className: "flex items-center justify-between",
161
- children: [/* @__PURE__ */ b("span", {
162
- className: "text-sm text-text-secondary",
163
- children: "Graded"
164
- }), /* @__PURE__ */ x("span", {
165
- className: "text-sm font-medium tabular-nums text-text-primary",
166
- children: [
167
- N.gradedCount,
168
- "/",
169
- j.length
170
- ]
252
+ /* @__PURE__ */ O("div", {
253
+ className: "flex items-center justify-around gap-4",
254
+ children: [/* @__PURE__ */ O("div", {
255
+ className: "flex flex-col items-center gap-2 text-center",
256
+ children: [/* @__PURE__ */ D(u, {
257
+ value: I.completionRate,
258
+ size: 96,
259
+ stroke: 8,
260
+ color: "var(--color-accent-teal)",
261
+ label: j.length === 0 ? "—" : void 0
262
+ }), /* @__PURE__ */ D("span", {
263
+ className: "text-sm text-text-secondary",
264
+ children: "Completion rate"
265
+ })]
266
+ }), /* @__PURE__ */ O("div", {
267
+ className: "flex flex-col items-center gap-2 text-center",
268
+ children: [/* @__PURE__ */ D(u, {
269
+ value: I.passRate,
270
+ size: 96,
271
+ stroke: 8,
272
+ color: "var(--color-status-success-text)",
273
+ label: I.gradedCount === 0 ? "—" : void 0
274
+ }), /* @__PURE__ */ D("span", {
275
+ className: "text-sm text-text-secondary",
276
+ children: "Pass rate"
277
+ })]
171
278
  })]
172
279
  }),
173
- /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ x("div", {
174
- className: "mb-1 flex items-center justify-between",
175
- children: [/* @__PURE__ */ x("span", {
176
- className: "inline-flex items-center gap-1.5 text-sm text-text-secondary",
177
- children: [/* @__PURE__ */ b(g, { className: "h-4 w-4 text-status-success-text" }), " Pass rate"]
178
- }), /* @__PURE__ */ b("span", {
179
- className: "text-sm font-medium tabular-nums text-text-primary",
180
- children: i(N.passRate)
181
- })]
182
- }), /* @__PURE__ */ b(c, {
183
- value: N.passRate,
184
- barClassName: "bg-[var(--color-status-success-text)]",
185
- height: 8
186
- })] }),
187
- N.gradedCount === 0 && /* @__PURE__ */ b("p", {
280
+ /* @__PURE__ */ O("div", {
281
+ className: "grid grid-cols-2 gap-3 border-t border-border-seam pt-4",
282
+ children: [/* @__PURE__ */ O("div", { children: [/* @__PURE__ */ O("p", {
283
+ className: "text-lg font-semibold tabular-nums text-text-primary",
284
+ children: [I.gradedCount, /* @__PURE__ */ O("span", {
285
+ className: "text-sm font-normal text-text-secondary",
286
+ children: ["/", M.length]
287
+ })]
288
+ }), /* @__PURE__ */ D("p", {
289
+ className: "text-xs text-text-secondary",
290
+ children: "Graded"
291
+ })] }), /* @__PURE__ */ O("div", { children: [/* @__PURE__ */ O("p", {
292
+ className: "text-lg font-semibold tabular-nums text-text-primary",
293
+ children: [I.passed, /* @__PURE__ */ O("span", {
294
+ className: "text-sm font-normal text-text-secondary",
295
+ children: [
296
+ " ",
297
+ "of ",
298
+ I.gradedCount
299
+ ]
300
+ })]
301
+ }), /* @__PURE__ */ D("p", {
302
+ className: "text-xs text-text-secondary",
303
+ children: "Passed"
304
+ })] })]
305
+ }),
306
+ I.gradedCount === 0 && /* @__PURE__ */ D("p", {
188
307
  className: "text-xs text-text-secondary",
189
308
  children: "No submissions have been graded yet — pass rate appears once grading begins."
190
309
  })
@@ -192,44 +311,49 @@ var C = [
192
311
  })
193
312
  })]
194
313
  }),
195
- /* @__PURE__ */ b(s, {
314
+ /* @__PURE__ */ D(c, {
196
315
  title: "Top courses by enrolment",
197
- children: F.length === 0 ? /* @__PURE__ */ b("p", {
198
- className: "text-sm text-text-secondary",
199
- children: "No enrolments yet."
200
- }) : /* @__PURE__ */ b(S, {
316
+ children: z.length === 0 ? /* @__PURE__ */ D(k, {
317
+ treatment: "plain",
318
+ className: "p-5",
319
+ children: /* @__PURE__ */ D("p", {
320
+ className: "text-sm text-text-secondary",
321
+ children: "No enrolments yet."
322
+ })
323
+ }) : /* @__PURE__ */ D(k, {
201
324
  treatment: "plain",
202
325
  className: "p-5",
203
- children: /* @__PURE__ */ b("div", {
204
- className: "flex flex-col gap-3",
205
- children: F.map((t, n) => /* @__PURE__ */ x("div", {
326
+ children: /* @__PURE__ */ D("div", {
327
+ className: "flex flex-col gap-4",
328
+ children: z.map((t, n) => /* @__PURE__ */ O("div", {
206
329
  className: "flex items-center gap-3",
207
- children: [
208
- /* @__PURE__ */ b("span", {
209
- className: e("flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-semibold tabular-nums", n === 0 ? "bg-[var(--color-accent-soft)] text-text-primary" : "bg-bg-sunken text-text-secondary"),
210
- children: n + 1
211
- }),
212
- /* @__PURE__ */ b("span", {
213
- className: "w-48 shrink-0 truncate text-sm text-text-primary",
214
- children: t.title
215
- }),
216
- /* @__PURE__ */ b(c, {
330
+ children: [/* @__PURE__ */ D("span", {
331
+ className: e("flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-semibold tabular-nums", n === 0 ? "bg-[var(--color-accent-soft)] text-[var(--color-accent-teal)]" : "bg-bg-sunken text-text-secondary"),
332
+ children: n + 1
333
+ }), /* @__PURE__ */ O("div", {
334
+ className: "min-w-0 flex-1",
335
+ children: [/* @__PURE__ */ O("div", {
336
+ className: "flex items-center justify-between gap-2",
337
+ children: [/* @__PURE__ */ D("span", {
338
+ className: "truncate text-sm text-text-primary",
339
+ children: t.title
340
+ }), /* @__PURE__ */ D("span", {
341
+ className: "shrink-0 text-sm tabular-nums text-text-secondary",
342
+ children: t.count
343
+ })]
344
+ }), /* @__PURE__ */ D(l, {
217
345
  value: t.pct,
218
346
  barClassName: "bg-[var(--color-accent-teal)]",
219
- className: "flex-1",
347
+ className: "mt-1.5",
220
348
  height: 8
221
- }),
222
- /* @__PURE__ */ b("span", {
223
- className: "w-10 shrink-0 text-right text-sm tabular-nums text-text-secondary",
224
- children: t.count
225
- })
226
- ]
349
+ })]
350
+ })]
227
351
  }, t.courseId))
228
352
  })
229
353
  })
230
354
  })
231
355
  ]
232
- }) : /* @__PURE__ */ b(a, {
356
+ }) : /* @__PURE__ */ D(a, {
233
357
  illustration: "empty-data",
234
358
  title: "No data to analyse yet",
235
359
  description: "Publish courses and enrol learners — insights appear here as activity accrues."
@@ -237,6 +361,6 @@ var C = [
237
361
  });
238
362
  };
239
363
  //#endregion
240
- export { T as InsightsPage };
364
+ export { F as InsightsPage };
241
365
 
242
366
  //# sourceMappingURL=InsightsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InsightsPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/insights/InsightsPage.tsx"],"sourcesContent":["/**\n * InsightsPage — educator/admin learning analytics, DERIVED entirely from live\n * `bui*` data (no analytics tables, no fabricated numbers).\n * @module buildmyiq/pages/insights\n *\n * Everything here is computed client-side from real queries:\n * - courses (total / published / by level)\n * - enrollments (status split, completion rate, average progress)\n * - submissions (graded / pass rate)\n * - certificates issued\n * - top courses by enrolment\n * When the workspace has no data yet, the page shows honest zero/empty states.\n */\n\nimport type { FC } from 'react';\nimport { useMemo } from 'react';\nimport { BookOpen, GraduationCap, CheckCircle2, Award, TrendingUp, Users } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, MetricsCard, LoadingView, Section, EmptyState, MiniBar } from '../../components';\nimport {\n useBuiCourses,\n useBuiEnrollments,\n useBuiSubmissions,\n useBuiCertificates,\n} from '../../hooks';\nimport { formatEnumLabel, formatPercent } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { BuiCourse, BuiEnrollment, BuiSubmission } from '../../types';\n\nconst ENROLLMENT_STATUS_ORDER = ['ENROLLED', 'IN_PROGRESS', 'COMPLETED', 'DROPPED', 'EXPIRED'] as const;\n\ninterface DistRow {\n label: string;\n count: number;\n pct: number;\n tone: string;\n}\n\nconst DistBars: FC<{ rows: DistRow[] }> = ({ rows }) => (\n <div className=\"flex flex-col gap-3\">\n {rows.map((r) => (\n <div key={r.label} className=\"flex items-center gap-3\">\n <span className=\"w-28 shrink-0 text-sm text-text-secondary\">{r.label}</span>\n <MiniBar value={r.pct} barClassName={r.tone} className=\"flex-1\" height={8} />\n <span className=\"w-10 shrink-0 text-right text-sm tabular-nums text-text-primary\">{r.count}</span>\n </div>\n ))}\n </div>\n);\n\nexport const InsightsPage: FC = () => {\n const coursesQuery = useBuiCourses({ limit: 100 });\n const enrollmentsQuery = useBuiEnrollments({ limit: 100 });\n const submissionsQuery = useBuiSubmissions({ limit: 100 });\n const certsQuery = useBuiCertificates();\n\n const courses: BuiCourse[] = useMemo(() => coursesQuery.data?.items ?? [], [coursesQuery.data]);\n const enrollments: BuiEnrollment[] = useMemo(\n () => enrollmentsQuery.data?.items ?? [],\n [enrollmentsQuery.data]\n );\n const submissions: BuiSubmission[] = useMemo(\n () => submissionsQuery.data?.items ?? [],\n [submissionsQuery.data]\n );\n const certificates = certsQuery.data ?? [];\n\n const stats = useMemo(() => {\n const published = courses.filter((c) => c.status === 'PUBLISHED').length;\n const completed = enrollments.filter((e) => e.status === 'COMPLETED').length;\n const completionRate = enrollments.length > 0 ? (completed / enrollments.length) * 100 : 0;\n const avgProgress =\n enrollments.length > 0\n ? enrollments.reduce((s, e) => s + (e.progressPct ?? 0), 0) / enrollments.length\n : 0;\n const graded = submissions.filter((s) => s.status === 'GRADED');\n const passed = graded.filter((s) => s.passed === true).length;\n const passRate = graded.length > 0 ? (passed / graded.length) * 100 : 0;\n const activeLearners = new Set(enrollments.map((e) => e.learnerId)).size;\n return {\n published,\n completed,\n completionRate,\n avgProgress,\n gradedCount: graded.length,\n passRate,\n activeLearners,\n };\n }, [courses, enrollments, submissions]);\n\n const enrollmentDist: DistRow[] = useMemo(() => {\n const total = enrollments.length;\n const tones: Record<string, string> = {\n ENROLLED: 'bg-[var(--color-accent-teal)]',\n IN_PROGRESS: 'bg-[var(--color-accent-teal)]',\n COMPLETED: 'bg-[var(--color-status-success-text)]',\n DROPPED: 'bg-[var(--color-status-error-text)]',\n EXPIRED: 'bg-[var(--color-text-tertiary)]',\n };\n return ENROLLMENT_STATUS_ORDER.map((status) => {\n const count = enrollments.filter((e) => e.status === status).length;\n return {\n label: formatEnumLabel(status),\n count,\n pct: total > 0 ? (count / total) * 100 : 0,\n tone: tones[status] ?? 'bg-accent',\n };\n }).filter((r) => r.count > 0);\n }, [enrollments]);\n\n const topCourses = useMemo(() => {\n const titleById = new Map(courses.map((c) => [c.id, c.title]));\n const counts = new Map<string, number>();\n for (const e of enrollments) counts.set(e.courseId, (counts.get(e.courseId) ?? 0) + 1);\n const max = Math.max(1, ...counts.values());\n return [...counts.entries()]\n .map(([courseId, count]) => ({\n courseId,\n title: titleById.get(courseId) ?? 'Course',\n count,\n pct: (count / max) * 100,\n }))\n .sort((a, b) => b.count - a.count)\n .slice(0, 6);\n }, [courses, enrollments]);\n\n const isLoading =\n coursesQuery.isLoading || enrollmentsQuery.isLoading || submissionsQuery.isLoading;\n\n const hasAnyData =\n courses.length > 0 || enrollments.length > 0 || submissions.length > 0 || certificates.length > 0;\n\n return (\n <PageLayout\n title=\"Insights\"\n description=\"Learning analytics across your workspace — completion, engagement and outcomes.\"\n titleGradient\n aurora\n >\n {isLoading ? (\n <LoadingView label=\"Crunching your learning data…\" />\n ) : !hasAnyData ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No data to analyse yet\"\n description=\"Publish courses and enrol learners — insights appear here as activity accrues.\"\n />\n ) : (\n <div className=\"flex flex-col gap-8\">\n {/* KPI row */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <MetricsCard\n icon={<BookOpen className=\"h-5 w-5\" />}\n value={stats.published}\n label=\"Published courses\"\n featured\n />\n <MetricsCard\n icon={<Users className=\"h-5 w-5\" />}\n value={stats.activeLearners}\n label=\"Active learners\"\n />\n <MetricsCard\n icon={<TrendingUp className=\"h-5 w-5\" />}\n value={formatPercent(stats.completionRate)}\n label=\"Completion rate\"\n accent=\"success\"\n footer={<MiniBar value={stats.completionRate} barClassName=\"bg-[var(--color-status-success-text)]\" />}\n />\n <MetricsCard\n icon={<Award className=\"h-5 w-5\" />}\n value={certificates.length}\n label=\"Certificates issued\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n {/* Enrollment status distribution */}\n <Section title=\"Enrolment status\" description={`${enrollments.length} enrolments`}>\n {enrollmentDist.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">No enrolments yet.</p>\n ) : (\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <DistBars rows={enrollmentDist} />\n <div className=\"mt-4 flex items-center gap-2 border-t border-border-seam pt-3\">\n <GraduationCap className=\"h-4 w-4 text-text-secondary\" />\n <span className=\"text-sm text-text-secondary\">\n Average progress{' '}\n <span className=\"font-medium text-text-primary\">\n {formatPercent(stats.avgProgress)}\n </span>\n </span>\n </div>\n </GlassCard>\n )}\n </Section>\n\n {/* Assessment outcomes */}\n <Section title=\"Assessment outcomes\" description={`${submissions.length} submissions`}>\n <GlassCard treatment=\"plain\" className=\"flex flex-col gap-4 p-5\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-text-secondary\">Graded</span>\n <span className=\"text-sm font-medium tabular-nums text-text-primary\">\n {stats.gradedCount}/{submissions.length}\n </span>\n </div>\n <div>\n <div className=\"mb-1 flex items-center justify-between\">\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-secondary\">\n <CheckCircle2 className=\"h-4 w-4 text-status-success-text\" /> Pass rate\n </span>\n <span className=\"text-sm font-medium tabular-nums text-text-primary\">\n {formatPercent(stats.passRate)}\n </span>\n </div>\n <MiniBar\n value={stats.passRate}\n barClassName=\"bg-[var(--color-status-success-text)]\"\n height={8}\n />\n </div>\n {stats.gradedCount === 0 && (\n <p className=\"text-xs text-text-secondary\">\n No submissions have been graded yet — pass rate appears once grading begins.\n </p>\n )}\n </GlassCard>\n </Section>\n </div>\n\n {/* Top courses by enrolment */}\n <Section title=\"Top courses by enrolment\">\n {topCourses.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">No enrolments yet.</p>\n ) : (\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <div className=\"flex flex-col gap-3\">\n {topCourses.map((c, i) => (\n <div key={c.courseId} className=\"flex items-center gap-3\">\n <span\n className={cn(\n 'flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-semibold tabular-nums',\n i === 0 ? 'bg-[var(--color-accent-soft)] text-text-primary' : 'bg-bg-sunken text-text-secondary'\n )}\n >\n {i + 1}\n </span>\n <span className=\"w-48 shrink-0 truncate text-sm text-text-primary\">{c.title}</span>\n <MiniBar value={c.pct} barClassName=\"bg-[var(--color-accent-teal)]\" className=\"flex-1\" height={8} />\n <span className=\"w-10 shrink-0 text-right text-sm tabular-nums text-text-secondary\">\n {c.count}\n </span>\n </div>\n ))}\n </div>\n </GlassCard>\n )}\n </Section>\n </div>\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"InsightsPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/insights/InsightsPage.tsx"],"sourcesContent":["/**\n * InsightsPage — educator/admin learning analytics, DERIVED entirely from live\n * `bui*` data (no analytics tables, no fabricated numbers).\n * @module buildmyiq/pages/insights\n *\n * Everything here is computed client-side from real queries:\n * - courses (total / published)\n * - enrollments (status split, completion rate, average progress, trend by month)\n * - submissions (graded / passed / pass rate)\n * - certificates issued\n * - top courses by enrolment\n * The circular meters (completion + pass rate), the tinted KPI cards, the\n * status-distribution bars, the enrolment sparkline and the ranked top-course\n * bars all read as one tokenized system. When the workspace has no data yet the\n * page shows honest zero/empty states.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useMemo } from 'react';\nimport {\n BookOpen,\n Award,\n TrendingUp,\n Users,\n GraduationCap,\n CheckCircle2,\n User,\n Clock,\n XCircle,\n AlarmClock,\n type LucideIcon,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n MetricsCard,\n LoadingView,\n ErrorView,\n Section,\n EmptyState,\n MiniBar,\n ProgressRing,\n Sparkline,\n} from '../../components';\nimport {\n useBuiCourses,\n useBuiEnrollments,\n useBuiSubmissions,\n useBuiCertificates,\n} from '../../hooks';\nimport { formatEnumLabel, formatPercent } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { BuiCourse, BuiEnrollment, BuiSubmission } from '../../types';\n\nconst ENROLLMENT_STATUS_ORDER = ['ENROLLED', 'IN_PROGRESS', 'COMPLETED', 'DROPPED', 'EXPIRED'] as const;\ntype EnrollmentStatusKey = (typeof ENROLLMENT_STATUS_ORDER)[number];\n\n/** Per-status icon + bar/icon tone so the distribution reads as one system. */\nconst STATUS_META: Record<EnrollmentStatusKey, { icon: LucideIcon; bar: string; icon_tint: string }> = {\n ENROLLED: {\n icon: User,\n bar: 'bg-[var(--color-accent-teal)]',\n icon_tint: 'text-[var(--color-accent-teal)]',\n },\n IN_PROGRESS: {\n icon: Clock,\n bar: 'bg-[var(--color-accent-primary)]',\n icon_tint: 'text-[var(--color-accent-primary)]',\n },\n COMPLETED: {\n icon: CheckCircle2,\n bar: 'bg-[var(--color-status-success-text)]',\n icon_tint: 'text-[var(--color-status-success-text)]',\n },\n DROPPED: {\n icon: XCircle,\n bar: 'bg-[var(--color-status-error-text)]',\n icon_tint: 'text-[var(--color-status-error-text)]',\n },\n EXPIRED: {\n icon: AlarmClock,\n bar: 'bg-[var(--color-text-tertiary)]',\n icon_tint: 'text-[var(--color-text-tertiary)]',\n },\n};\n\ntype Tint = 'info' | 'success' | 'warning' | 'accent';\nconst TINT_CLASS: Record<Tint, string> = {\n info: 'bg-[var(--color-status-info-bg)] text-[var(--color-status-info-text)]',\n success: 'bg-[var(--color-status-success-bg)] text-[var(--color-status-success-text)]',\n warning: 'bg-[var(--color-status-warning-bg)] text-[var(--color-status-warning-text)]',\n accent: 'bg-[var(--color-accent-soft)] text-[var(--color-accent-teal)]',\n};\n\n/** Soft tinted circle behind a KPI icon (matches the concept's tinted badges). */\nconst TintedIcon: FC<{ tint: Tint; children: ReactNode }> = ({ tint, children }) => (\n <span className={cn('flex h-11 w-11 items-center justify-center rounded-full', TINT_CLASS[tint])}>\n {children}\n </span>\n);\n\ninterface DistRow {\n status: EnrollmentStatusKey;\n label: string;\n count: number;\n pct: number;\n}\n\nconst DistBars: FC<{ rows: DistRow[] }> = ({ rows }) => (\n <div className=\"flex flex-col gap-3\">\n {rows.map((r) => {\n const meta = STATUS_META[r.status];\n const Icon = meta.icon;\n return (\n <div key={r.status} className=\"flex items-center gap-3\">\n <span className=\"flex w-24 shrink-0 items-center gap-2 text-sm text-text-secondary sm:w-28\">\n <Icon className={cn('h-4 w-4 shrink-0', meta.icon_tint)} />\n <span className=\"truncate\">{r.label}</span>\n </span>\n <MiniBar value={r.pct} barClassName={meta.bar} className=\"flex-1\" height={8} />\n <span className=\"w-9 shrink-0 text-right text-sm tabular-nums text-text-primary\">{r.count}</span>\n </div>\n );\n })}\n </div>\n);\n\nexport const InsightsPage: FC = () => {\n const coursesQuery = useBuiCourses({ limit: 100 });\n const enrollmentsQuery = useBuiEnrollments({ limit: 100 });\n const submissionsQuery = useBuiSubmissions({ limit: 100 });\n const certsQuery = useBuiCertificates();\n\n const courses: BuiCourse[] = useMemo(() => coursesQuery.data?.items ?? [], [coursesQuery.data]);\n const enrollments: BuiEnrollment[] = useMemo(\n () => enrollmentsQuery.data?.items ?? [],\n [enrollmentsQuery.data]\n );\n const submissions: BuiSubmission[] = useMemo(\n () => submissionsQuery.data?.items ?? [],\n [submissionsQuery.data]\n );\n const certificates = certsQuery.data ?? [];\n\n const stats = useMemo(() => {\n const published = courses.filter((c) => c.status === 'PUBLISHED').length;\n const completed = enrollments.filter((e) => e.status === 'COMPLETED').length;\n const inProgress = enrollments.filter((e) => e.status === 'IN_PROGRESS').length;\n const completionRate = enrollments.length > 0 ? (completed / enrollments.length) * 100 : 0;\n const avgProgress =\n enrollments.length > 0\n ? enrollments.reduce((s, e) => s + (e.progressPct ?? 0), 0) / enrollments.length\n : 0;\n const graded = submissions.filter((s) => s.status === 'GRADED');\n const passed = graded.filter((s) => s.passed === true).length;\n const passRate = graded.length > 0 ? (passed / graded.length) * 100 : 0;\n const activeLearners = new Set(enrollments.map((e) => e.learnerId)).size;\n return {\n published,\n totalCourses: courses.length,\n completed,\n inProgress,\n completionRate,\n avgProgress,\n gradedCount: graded.length,\n passed,\n passRate,\n activeLearners,\n };\n }, [courses, enrollments, submissions]);\n\n const enrollmentDist: DistRow[] = useMemo(() => {\n const total = enrollments.length;\n return ENROLLMENT_STATUS_ORDER.map((status) => {\n const count = enrollments.filter((e) => e.status === status).length;\n return {\n status,\n label: formatEnumLabel(status),\n count,\n pct: total > 0 ? (count / total) * 100 : 0,\n };\n }).filter((r) => r.count > 0);\n }, [enrollments]);\n\n /** New enrolments bucketed by calendar month (real `enrolledAt` timestamps). */\n const enrolmentTrend = useMemo(() => {\n if (enrollments.length === 0) return [];\n const byMonth = new Map<string, number>();\n for (const e of enrollments) {\n const d = new Date(e.enrolledAt);\n if (Number.isNaN(d.getTime())) continue;\n const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;\n byMonth.set(key, (byMonth.get(key) ?? 0) + 1);\n }\n return [...byMonth.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([, v]) => v);\n }, [enrollments]);\n\n const topCourses = useMemo(() => {\n const titleById = new Map(courses.map((c) => [c.id, c.title]));\n const counts = new Map<string, number>();\n for (const e of enrollments) counts.set(e.courseId, (counts.get(e.courseId) ?? 0) + 1);\n const max = Math.max(1, ...counts.values());\n return [...counts.entries()]\n .map(([courseId, count]) => ({\n courseId,\n title: titleById.get(courseId) ?? 'Course',\n count,\n pct: (count / max) * 100,\n }))\n .sort((a, b) => b.count - a.count)\n .slice(0, 6);\n }, [courses, enrollments]);\n\n const isLoading =\n coursesQuery.isLoading || enrollmentsQuery.isLoading || submissionsQuery.isLoading;\n const isError =\n coursesQuery.isError ||\n enrollmentsQuery.isError ||\n submissionsQuery.isError ||\n certsQuery.isError;\n\n const hasAnyData =\n courses.length > 0 || enrollments.length > 0 || submissions.length > 0 || certificates.length > 0;\n\n const retry = () => {\n void coursesQuery.refetch();\n void enrollmentsQuery.refetch();\n void submissionsQuery.refetch();\n void certsQuery.refetch();\n };\n\n return (\n <PageLayout\n title=\"Insights\"\n description=\"Learning analytics across your workspace — completion, engagement and outcomes.\"\n titleGradient\n aurora\n >\n {isLoading ? (\n <LoadingView label=\"Crunching your learning data…\" />\n ) : isError ? (\n <ErrorView\n title=\"Couldn't load insights\"\n message=\"We hit a snag pulling your learning data. Try again in a moment.\"\n onRetry={retry}\n />\n ) : !hasAnyData ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No data to analyse yet\"\n description=\"Publish courses and enrol learners — insights appear here as activity accrues.\"\n />\n ) : (\n <div className=\"flex flex-col gap-8\">\n {/* KPI row — tinted-icon cards, all values derived from live data */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <MetricsCard\n icon={\n <TintedIcon tint=\"info\">\n <BookOpen className=\"h-5 w-5\" />\n </TintedIcon>\n }\n value={stats.published}\n label=\"Published courses\"\n footer={\n <span className=\"text-xs text-text-secondary\">of {stats.totalCourses} total</span>\n }\n />\n <MetricsCard\n icon={\n <TintedIcon tint=\"success\">\n <Users className=\"h-5 w-5\" />\n </TintedIcon>\n }\n value={stats.activeLearners}\n label=\"Active learners\"\n footer={\n <span className=\"text-xs text-text-secondary\">\n {enrollments.length} enrolment{enrollments.length === 1 ? '' : 's'}\n </span>\n }\n />\n <MetricsCard\n icon={\n <TintedIcon tint=\"accent\">\n <TrendingUp className=\"h-5 w-5\" />\n </TintedIcon>\n }\n value={formatPercent(stats.completionRate)}\n label=\"Completion rate\"\n footer={\n <MiniBar value={stats.completionRate} barClassName=\"bg-[var(--color-accent-teal)]\" />\n }\n />\n <MetricsCard\n icon={\n <TintedIcon tint=\"warning\">\n <Award className=\"h-5 w-5\" />\n </TintedIcon>\n }\n value={certificates.length}\n label=\"Certificates issued\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n {/* Enrolment status distribution */}\n <Section title=\"Enrolment status\" description={`${enrollments.length} enrolments`}>\n {enrollmentDist.length === 0 ? (\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <p className=\"text-sm text-text-secondary\">No enrolments yet.</p>\n </GlassCard>\n ) : (\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <DistBars rows={enrollmentDist} />\n <div className=\"mt-4 flex flex-wrap items-center justify-between gap-3 border-t border-border-seam pt-3\">\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-secondary\">\n <GraduationCap className=\"h-4 w-4\" /> Avg progress\n <span className=\"font-medium text-text-primary\">\n {formatPercent(stats.avgProgress)}\n </span>\n </span>\n {enrolmentTrend.length >= 2 && (\n <span className=\"inline-flex items-center gap-2\">\n <Sparkline data={enrolmentTrend} color=\"var(--color-accent-teal)\" />\n <span className=\"text-xs text-text-secondary\">new / month</span>\n </span>\n )}\n </div>\n </GlassCard>\n )}\n </Section>\n\n {/* Learning outcomes — paired circular meters */}\n <Section title=\"Learning outcomes\" description={`${submissions.length} submissions`}>\n <GlassCard treatment=\"plain\" className=\"flex flex-col gap-5 p-5\">\n <div className=\"flex items-center justify-around gap-4\">\n <div className=\"flex flex-col items-center gap-2 text-center\">\n <ProgressRing\n value={stats.completionRate}\n size={96}\n stroke={8}\n color=\"var(--color-accent-teal)\"\n label={enrollments.length === 0 ? '—' : undefined}\n />\n <span className=\"text-sm text-text-secondary\">Completion rate</span>\n </div>\n <div className=\"flex flex-col items-center gap-2 text-center\">\n <ProgressRing\n value={stats.passRate}\n size={96}\n stroke={8}\n color=\"var(--color-status-success-text)\"\n label={stats.gradedCount === 0 ? '—' : undefined}\n />\n <span className=\"text-sm text-text-secondary\">Pass rate</span>\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-3 border-t border-border-seam pt-4\">\n <div>\n <p className=\"text-lg font-semibold tabular-nums text-text-primary\">\n {stats.gradedCount}\n <span className=\"text-sm font-normal text-text-secondary\">\n /{submissions.length}\n </span>\n </p>\n <p className=\"text-xs text-text-secondary\">Graded</p>\n </div>\n <div>\n <p className=\"text-lg font-semibold tabular-nums text-text-primary\">\n {stats.passed}\n <span className=\"text-sm font-normal text-text-secondary\">\n {' '}\n of {stats.gradedCount}\n </span>\n </p>\n <p className=\"text-xs text-text-secondary\">Passed</p>\n </div>\n </div>\n {stats.gradedCount === 0 && (\n <p className=\"text-xs text-text-secondary\">\n No submissions have been graded yet — pass rate appears once grading begins.\n </p>\n )}\n </GlassCard>\n </Section>\n </div>\n\n {/* Top courses by enrolment */}\n <Section title=\"Top courses by enrolment\">\n {topCourses.length === 0 ? (\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <p className=\"text-sm text-text-secondary\">No enrolments yet.</p>\n </GlassCard>\n ) : (\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <div className=\"flex flex-col gap-4\">\n {topCourses.map((c, i) => (\n <div key={c.courseId} className=\"flex items-center gap-3\">\n <span\n className={cn(\n 'flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-semibold tabular-nums',\n i === 0\n ? 'bg-[var(--color-accent-soft)] text-[var(--color-accent-teal)]'\n : 'bg-bg-sunken text-text-secondary'\n )}\n >\n {i + 1}\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate text-sm text-text-primary\">{c.title}</span>\n <span className=\"shrink-0 text-sm tabular-nums text-text-secondary\">\n {c.count}\n </span>\n </div>\n <MiniBar\n value={c.pct}\n barClassName=\"bg-[var(--color-accent-teal)]\"\n className=\"mt-1.5\"\n height={8}\n />\n </div>\n </div>\n ))}\n </div>\n </GlassCard>\n )}\n </Section>\n </div>\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"LessonPlayerPage.d.ts","sourceRoot":"","sources":["../../../../src/buildmyiq/pages/learning/LessonPlayerPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AA2ChC,eAAO,MAAM,gBAAgB,EAAE,EAwX9B,CAAC"}
1
+ {"version":3,"file":"LessonPlayerPage.d.ts","sourceRoot":"","sources":["../../../../src/buildmyiq/pages/learning/LessonPlayerPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AA6DhC,eAAO,MAAM,gBAAgB,EAAE,EAuc9B,CAAC"}