@burdenoff/microfe-buildmyiq 2026.716.1 → 2026.720.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/buildmyiq/BuildmyiqAdminRoot.d.ts.map +1 -1
  2. package/dist/buildmyiq/BuildmyiqAdminRoot.js +149 -135
  3. package/dist/buildmyiq/BuildmyiqAdminRoot.js.map +1 -1
  4. package/dist/buildmyiq/BuildmyiqRoot.d.ts.map +1 -1
  5. package/dist/buildmyiq/BuildmyiqRoot.js +59 -54
  6. package/dist/buildmyiq/BuildmyiqRoot.js.map +1 -1
  7. package/dist/buildmyiq/BuildmyiqRoutes.js.map +1 -1
  8. package/dist/buildmyiq/components/Avatar.js.map +1 -1
  9. package/dist/buildmyiq/components/BuiDiscussion.js.map +1 -1
  10. package/dist/buildmyiq/components/BuiPermissionButton.d.ts +25 -0
  11. package/dist/buildmyiq/components/BuiPermissionButton.d.ts.map +1 -0
  12. package/dist/buildmyiq/components/BuiPermissionButton.js +15 -0
  13. package/dist/buildmyiq/components/BuiPermissionButton.js.map +1 -0
  14. package/dist/buildmyiq/components/BuiTags.js.map +1 -1
  15. package/dist/buildmyiq/components/DataTable.js.map +1 -1
  16. package/dist/buildmyiq/components/EmptyState.js.map +1 -1
  17. package/dist/buildmyiq/components/EvidenceUpload.js.map +1 -1
  18. package/dist/buildmyiq/components/FileLink.js.map +1 -1
  19. package/dist/buildmyiq/components/FilterTabs.js.map +1 -1
  20. package/dist/buildmyiq/components/MetricsCard.js.map +1 -1
  21. package/dist/buildmyiq/components/MiniBar.js.map +1 -1
  22. package/dist/buildmyiq/components/PageLayout.js.map +1 -1
  23. package/dist/buildmyiq/components/Pagination.js.map +1 -1
  24. package/dist/buildmyiq/components/StateViews.js.map +1 -1
  25. package/dist/buildmyiq/components/StatusBadge.js.map +1 -1
  26. package/dist/buildmyiq/components/Tabs.js.map +1 -1
  27. package/dist/buildmyiq/components/Viz.js.map +1 -1
  28. package/dist/buildmyiq/components/index.d.ts +1 -0
  29. package/dist/buildmyiq/components/index.d.ts.map +1 -1
  30. package/dist/buildmyiq/components/index.js +1 -0
  31. package/dist/buildmyiq/context/BuildmyiqContext.js.map +1 -1
  32. package/dist/buildmyiq/hooks/index.d.ts +1 -0
  33. package/dist/buildmyiq/hooks/index.d.ts.map +1 -1
  34. package/dist/buildmyiq/hooks/index.js +1 -0
  35. package/dist/buildmyiq/hooks/useBuiComments.js.map +1 -1
  36. package/dist/buildmyiq/hooks/useBuiFiles.js.map +1 -1
  37. package/dist/buildmyiq/hooks/useBuiPermissions.d.ts +54 -0
  38. package/dist/buildmyiq/hooks/useBuiPermissions.d.ts.map +1 -0
  39. package/dist/buildmyiq/hooks/useBuiPermissions.js +2 -0
  40. package/dist/buildmyiq/hooks/useBuiTags.js.map +1 -1
  41. package/dist/buildmyiq/hooks/useBuildmyiqApi.js.map +1 -1
  42. package/dist/buildmyiq/hooks/useCursorPager.js.map +1 -1
  43. package/dist/buildmyiq/pages/DashboardPage.js.map +1 -1
  44. package/dist/buildmyiq/pages/_shared/CourseCard.js.map +1 -1
  45. package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.js.map +1 -1
  46. package/dist/buildmyiq/pages/assessments/AssessmentsPage.js.map +1 -1
  47. package/dist/buildmyiq/pages/assessments/TakeAssessmentPage.js.map +1 -1
  48. package/dist/buildmyiq/pages/authoring/AuthoringPage.d.ts.map +1 -1
  49. package/dist/buildmyiq/pages/authoring/AuthoringPage.js +97 -86
  50. package/dist/buildmyiq/pages/authoring/AuthoringPage.js.map +1 -1
  51. package/dist/buildmyiq/pages/authoring/CourseBuilderPage.d.ts.map +1 -1
  52. package/dist/buildmyiq/pages/authoring/CourseBuilderPage.js +159 -118
  53. package/dist/buildmyiq/pages/authoring/CourseBuilderPage.js.map +1 -1
  54. package/dist/buildmyiq/pages/authoring/_forms.js.map +1 -1
  55. package/dist/buildmyiq/pages/catalog/CatalogPage.js.map +1 -1
  56. package/dist/buildmyiq/pages/catalog/CourseDetailPage.d.ts.map +1 -1
  57. package/dist/buildmyiq/pages/catalog/CourseDetailPage.js +75 -69
  58. package/dist/buildmyiq/pages/catalog/CourseDetailPage.js.map +1 -1
  59. package/dist/buildmyiq/pages/certificates/CertificatesPage.d.ts.map +1 -1
  60. package/dist/buildmyiq/pages/certificates/CertificatesPage.js +186 -170
  61. package/dist/buildmyiq/pages/certificates/CertificatesPage.js.map +1 -1
  62. package/dist/buildmyiq/pages/cohorts/CohortsPage.d.ts.map +1 -1
  63. package/dist/buildmyiq/pages/cohorts/CohortsPage.js +177 -166
  64. package/dist/buildmyiq/pages/cohorts/CohortsPage.js.map +1 -1
  65. package/dist/buildmyiq/pages/insights/InsightsPage.js.map +1 -1
  66. package/dist/buildmyiq/pages/learning/LessonPlayerPage.js.map +1 -1
  67. package/dist/buildmyiq/pages/learning/MyLearningPage.js.map +1 -1
  68. package/dist/buildmyiq/pages/paths/PathsPage.js.map +1 -1
  69. package/dist/buildmyiq/pages/skills/SkillsPage.js.map +1 -1
  70. package/dist/buildmyiq/pages/submissions/SubmissionsPage.d.ts.map +1 -1
  71. package/dist/buildmyiq/pages/submissions/SubmissionsPage.js +160 -154
  72. package/dist/buildmyiq/pages/submissions/SubmissionsPage.js.map +1 -1
  73. package/dist/buildmyiq/shared/hooks/useTr.js.map +1 -1
  74. package/dist/buildmyiq/types/index.js.map +1 -1
  75. package/dist/buildmyiq/utils/cn.js.map +1 -1
  76. package/dist/buildmyiq/utils/formatters.js.map +1 -1
  77. package/dist/buildmyiq/utils/navigation.js.map +1 -1
  78. package/dist/node_modules/clsx/dist/clsx.js.map +1 -1
  79. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1 -1
  80. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
  81. package/dist/services/createSandboxAssistantTransport.js.map +1 -1
  82. package/dist/utils/pageContext.d.ts.map +1 -1
  83. package/dist/utils/pageContext.js +7 -2
  84. package/dist/utils/pageContext.js.map +1 -1
  85. package/package.json +2 -2
@@ -6,31 +6,32 @@ import { formatDuration as r, formatEnumLabel as i, formatHours as a } from "../
6
6
  import { StatusBadge as o } from "../../components/StatusBadge.js";
7
7
  import { EmptyState as s } from "../../components/EmptyState.js";
8
8
  import { ErrorView as c, LoadingView as l, Section as u } from "../../components/StateViews.js";
9
- import { MiniBar as d } from "../../components/MiniBar.js";
10
- import { useBuiAssessments as f, useBuiCourse as ee, useBuiEnroll as p, useBuiEnrollments as m, useBuiModules as h } from "../../hooks/useBuildmyiqApi.js";
9
+ import { MiniBar as ee } from "../../components/MiniBar.js";
10
+ import { useBuiAssessments as d, useBuiCourse as f, useBuiEnroll as p, useBuiEnrollments as te, useBuiModules as m } from "../../hooks/useBuildmyiqApi.js";
11
11
  import "../../hooks/index.js";
12
- import { BuiDiscussion as te } from "../../components/BuiDiscussion.js";
12
+ import { BuiDiscussion as h } from "../../components/BuiDiscussion.js";
13
13
  import { BuiTags as ne } from "../../components/BuiTags.js";
14
+ import { BuiPermissionButton as re } from "../../components/BuiPermissionButton.js";
14
15
  import "../../components/index.js";
15
16
  import { useMemo as g, useState as _ } from "react";
16
- import { ArrowLeft as re, ArrowRight as v, BookOpen as y, ChevronDown as b, ClipboardCheck as x, ClipboardList as S, Clock as C, FileText as w, GraduationCap as ie, Layers as T, ListChecks as E, MousePointerClick as D, PlayCircle as ae, Radio as O, Sparkles as oe, Video as k } from "lucide-react";
17
+ import { ArrowLeft as ie, ArrowRight as v, BookOpen as ae, ChevronDown as oe, ClipboardCheck as y, ClipboardList as b, Clock as x, FileText as S, GraduationCap as se, Layers as C, ListChecks as w, MousePointerClick as T, PlayCircle as E, Radio as D, Sparkles as O, Video as k } from "lucide-react";
17
18
  import { useParams as A } from "react-router-dom";
18
19
  import { jsx as j, jsxs as M } from "react/jsx-runtime";
19
20
  import { Button as N, GlassCard as P } from "@burdenoff/fe-libs/ui";
20
21
  //#region src/buildmyiq/pages/catalog/CourseDetailPage.tsx
21
- var F = "buildmyiq-course", se = "__ungrouped__", I = {
22
- ARTICLE: w,
22
+ var F = "buildmyiq-course", ce = "__ungrouped__", I = {
23
+ ARTICLE: S,
23
24
  VIDEO: k,
24
- QUIZ: E,
25
- ASSIGNMENT: S,
26
- INTERACTIVE: D,
27
- LIVE_SESSION: O
25
+ QUIZ: w,
26
+ ASSIGNMENT: b,
27
+ INTERACTIVE: T,
28
+ LIVE_SESSION: D
28
29
  }, L = ({ lesson: e, index: t }) => /* @__PURE__ */ M("li", {
29
30
  className: "flex items-center gap-3 px-4 py-3 transition-colors hover:bg-bg-sunken/60",
30
31
  children: [
31
32
  /* @__PURE__ */ j("span", {
32
33
  className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary",
33
- children: /* @__PURE__ */ j(I[e.type] ?? w, { className: "h-4 w-4" })
34
+ children: /* @__PURE__ */ j(I[e.type] ?? S, { className: "h-4 w-4" })
34
35
  }),
35
36
  /* @__PURE__ */ M("div", {
36
37
  className: "min-w-0 flex-1",
@@ -48,7 +49,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
48
49
  e.durationMin > 0 && /* @__PURE__ */ M("span", {
49
50
  className: "hidden shrink-0 items-center gap-1 text-xs tabular-nums text-text-secondary sm:inline-flex",
50
51
  children: [
51
- /* @__PURE__ */ j(C, { className: "h-3.5 w-3.5" }),
52
+ /* @__PURE__ */ j(x, { className: "h-3.5 w-3.5" }),
52
53
  " ",
53
54
  r(e.durationMin)
54
55
  ]
@@ -65,11 +66,11 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
65
66
  "aria-hidden": !0
66
67
  }), t]
67
68
  }), z = () => {
68
- let { courseId: i } = A(), { currentUser: S, navigateTo: w } = e(), E = S?.id, D = ee(i), O = h(i), k = f(i), I = m({
69
+ let { courseId: i } = A(), { currentUser: b, navigateTo: S } = e(), w = b?.id, T = f(i), D = m(i), k = d(i), I = te({
69
70
  courseId: i,
70
- learnerId: E,
71
- enabled: !!(i && E)
72
- }), z = p(), [B, V] = _(null), [H, U] = _(null), W = D.data ?? null, G = O.data ?? [], K = k.data ?? [], q = I.data?.items ?? [], J = g(() => q.find((e) => e.status !== "DROPPED" && e.status !== "EXPIRED"), [q]), Y = g(() => (W?.lessons ?? []).filter((e) => !e.moduleId), [W]), X = g(() => {
71
+ learnerId: w,
72
+ enabled: !!(i && w)
73
+ }), z = p(), [B, V] = _(null), [H, U] = _(null), W = T.data ?? null, G = D.data ?? [], K = k.data ?? [], q = I.data?.items ?? [], J = g(() => q.find((e) => e.status !== "DROPPED" && e.status !== "EXPIRED"), [q]), Y = g(() => (W?.lessons ?? []).filter((e) => !e.moduleId), [W]), X = g(() => {
73
74
  let e = G.map((e) => ({
74
75
  id: e.id,
75
76
  title: e.title,
@@ -77,23 +78,23 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
77
78
  lessons: e.lessons ?? []
78
79
  }));
79
80
  return Y.length > 0 && e.push({
80
- id: se,
81
+ id: ce,
81
82
  title: "Additional lessons",
82
83
  lessons: Y
83
84
  }), e;
84
- }, [G, Y]), Z = W?.lessons?.length ?? 0, ce = K.filter((e) => e.status === "PUBLISHED").length, Q = H ?? new Set(X.slice(0, 1).map((e) => e.id)), $ = X.length > 0 && X.every((e) => Q.has(e.id)), le = (e) => {
85
+ }, [G, Y]), Z = W?.lessons?.length ?? 0, le = K.filter((e) => e.status === "PUBLISHED").length, Q = H ?? new Set(X.slice(0, 1).map((e) => e.id)), $ = X.length > 0 && X.every((e) => Q.has(e.id)), ue = (e) => {
85
86
  let t = new Set(Q);
86
87
  t.has(e) ? t.delete(e) : t.add(e), U(t);
87
88
  };
88
- return i ? D.isLoading ? /* @__PURE__ */ j(n, {
89
+ return i ? T.isLoading ? /* @__PURE__ */ j(n, {
89
90
  title: "Course",
90
91
  children: /* @__PURE__ */ j(l, { label: "Loading course…" })
91
- }) : D.isError ? /* @__PURE__ */ j(n, {
92
+ }) : T.isError ? /* @__PURE__ */ j(n, {
92
93
  title: "Course",
93
94
  children: /* @__PURE__ */ j(c, {
94
95
  title: "Couldn't load this course",
95
- message: D.error instanceof Error ? D.error.message : void 0,
96
- onRetry: () => D.refetch()
96
+ message: T.error instanceof Error ? T.error.message : void 0,
97
+ onRetry: () => T.refetch()
97
98
  })
98
99
  }) : W ? /* @__PURE__ */ j(n, {
99
100
  title: W.title,
@@ -108,7 +109,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
108
109
  children: [
109
110
  /* @__PURE__ */ j("button", {
110
111
  type: "button",
111
- onClick: () => w("catalog"),
112
+ onClick: () => S("catalog"),
112
113
  className: "shrink-0 font-medium text-[var(--color-accent-teal)] transition-colors hover:opacity-80",
113
114
  children: "Catalog"
114
115
  }),
@@ -123,9 +124,9 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
123
124
  ]
124
125
  }), /* @__PURE__ */ M("button", {
125
126
  type: "button",
126
- onClick: () => w("catalog"),
127
+ onClick: () => S("catalog"),
127
128
  className: "inline-flex shrink-0 items-center gap-1.5 text-sm text-text-secondary transition-colors hover:text-text-primary",
128
- children: [/* @__PURE__ */ j(re, { className: "h-4 w-4" }), " Back to catalog"]
129
+ children: [/* @__PURE__ */ j(ie, { className: "h-4 w-4" }), " Back to catalog"]
129
130
  })]
130
131
  }),
131
132
  /* @__PURE__ */ M("div", {
@@ -143,7 +144,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
143
144
  className: "h-full w-full object-cover"
144
145
  }) : /* @__PURE__ */ j("div", {
145
146
  className: "flex h-full min-h-[11rem] w-full items-center justify-center bg-[var(--color-accent-soft)]",
146
- children: /* @__PURE__ */ j(y, { className: "h-10 w-10 text-text-secondary opacity-60" })
147
+ children: /* @__PURE__ */ j(ae, { className: "h-10 w-10 text-text-secondary opacity-60" })
147
148
  })
148
149
  }), /* @__PURE__ */ M("div", {
149
150
  className: "flex flex-col gap-4 p-6",
@@ -163,11 +164,11 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
163
164
  className: "flex flex-wrap gap-2",
164
165
  children: [
165
166
  W.skill?.name && /* @__PURE__ */ j(R, {
166
- icon: oe,
167
+ icon: O,
167
168
  children: W.skill.name
168
169
  }),
169
170
  /* @__PURE__ */ M(R, {
170
- icon: T,
171
+ icon: C,
171
172
  children: [
172
173
  G.length,
173
174
  " module",
@@ -179,7 +180,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
179
180
  ]
180
181
  }),
181
182
  W.estimatedHours > 0 && /* @__PURE__ */ j(R, {
182
- icon: C,
183
+ icon: x,
183
184
  children: a(W.estimatedHours)
184
185
  })
185
186
  ]
@@ -208,8 +209,8 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
208
209
  /* @__PURE__ */ M(N, {
209
210
  size: "lg",
210
211
  className: "w-full",
211
- onClick: () => w(`learning/${J.id}`),
212
- children: [/* @__PURE__ */ j(ae, { className: "mr-2 h-4 w-4" }), " Continue learning"]
212
+ onClick: () => S(`learning/${J.id}`),
213
+ children: [/* @__PURE__ */ j(E, { className: "mr-2 h-4 w-4" }), " Continue learning"]
213
214
  }),
214
215
  /* @__PURE__ */ M("div", {
215
216
  className: "flex flex-col gap-1.5",
@@ -222,7 +223,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
222
223
  className: "font-semibold tabular-nums text-text-primary",
223
224
  children: [J.progressPct, "%"]
224
225
  })]
225
- }), /* @__PURE__ */ j(d, { value: J.progressPct })]
226
+ }), /* @__PURE__ */ j(ee, { value: J.progressPct })]
226
227
  }),
227
228
  /* @__PURE__ */ M("div", {
228
229
  className: "flex items-center justify-between border-t border-border-seam pt-3 text-xs",
@@ -235,30 +236,35 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
235
236
  }) : /* @__PURE__ */ M("div", {
236
237
  className: "flex flex-col gap-4",
237
238
  children: [
238
- /* @__PURE__ */ M(N, {
239
- size: "lg",
240
- className: "w-full",
241
- onClick: async () => {
242
- if (!(!i || !E)) {
243
- V(null);
244
- try {
245
- w(`learning/${(await z.mutateAsync({
246
- courseId: i,
247
- learnerId: E
248
- })).id}`);
249
- } catch (e) {
250
- V(e instanceof Error ? e.message : "Could not enrol in this course.");
239
+ /* @__PURE__ */ j(re, {
240
+ resource: "buildmyiq-enrollment",
241
+ action: "create",
242
+ deniedBehavior: "tooltip",
243
+ children: /* @__PURE__ */ M(N, {
244
+ size: "lg",
245
+ className: "w-full",
246
+ onClick: async () => {
247
+ if (!(!i || !w)) {
248
+ V(null);
249
+ try {
250
+ S(`learning/${(await z.mutateAsync({
251
+ courseId: i,
252
+ learnerId: w
253
+ })).id}`);
254
+ } catch (e) {
255
+ V(e instanceof Error ? e.message : "Could not enrol in this course.");
256
+ }
251
257
  }
252
- }
253
- },
254
- disabled: z.isPending || !E,
255
- children: [
256
- /* @__PURE__ */ j(ie, { className: "mr-2 h-4 w-4" }),
257
- z.isPending ? "Enrolling…" : "Enrol in this course",
258
- !z.isPending && /* @__PURE__ */ j(v, { className: "ml-2 h-4 w-4" })
259
- ]
258
+ },
259
+ disabled: z.isPending || !w,
260
+ children: [
261
+ /* @__PURE__ */ j(se, { className: "mr-2 h-4 w-4" }),
262
+ z.isPending ? "Enrolling…" : "Enrol in this course",
263
+ !z.isPending && /* @__PURE__ */ j(v, { className: "ml-2 h-4 w-4" })
264
+ ]
265
+ })
260
266
  }),
261
- !E && /* @__PURE__ */ j("p", {
267
+ !w && /* @__PURE__ */ j("p", {
262
268
  className: "text-xs text-text-tertiary",
263
269
  children: "Sign in to your workspace to enrol."
264
270
  }),
@@ -273,7 +279,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
273
279
  className: "flex items-center justify-between",
274
280
  children: [/* @__PURE__ */ M("dt", {
275
281
  className: "inline-flex items-center gap-1.5 text-text-secondary",
276
- children: [/* @__PURE__ */ j(T, { className: "h-3.5 w-3.5 text-text-tertiary" }), " Lessons"]
282
+ children: [/* @__PURE__ */ j(C, { className: "h-3.5 w-3.5 text-text-tertiary" }), " Lessons"]
277
283
  }), /* @__PURE__ */ j("dd", {
278
284
  className: "font-medium tabular-nums text-text-primary",
279
285
  children: Z
@@ -283,7 +289,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
283
289
  className: "flex items-center justify-between",
284
290
  children: [/* @__PURE__ */ M("dt", {
285
291
  className: "inline-flex items-center gap-1.5 text-text-secondary",
286
- children: [/* @__PURE__ */ j(C, { className: "h-3.5 w-3.5 text-text-tertiary" }), " Duration"]
292
+ children: [/* @__PURE__ */ j(x, { className: "h-3.5 w-3.5 text-text-tertiary" }), " Duration"]
287
293
  }), /* @__PURE__ */ j("dd", {
288
294
  className: "font-medium text-text-primary",
289
295
  children: a(W.estimatedHours)
@@ -293,10 +299,10 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
293
299
  className: "flex items-center justify-between",
294
300
  children: [/* @__PURE__ */ M("dt", {
295
301
  className: "inline-flex items-center gap-1.5 text-text-secondary",
296
- children: [/* @__PURE__ */ j(x, { className: "h-3.5 w-3.5 text-text-tertiary" }), " Assessments"]
302
+ children: [/* @__PURE__ */ j(y, { className: "h-3.5 w-3.5 text-text-tertiary" }), " Assessments"]
297
303
  }), /* @__PURE__ */ j("dd", {
298
304
  className: "font-medium tabular-nums text-text-primary",
299
- children: ce
305
+ children: le
300
306
  })]
301
307
  })
302
308
  ]
@@ -318,10 +324,10 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
318
324
  className: "text-sm font-medium text-[var(--color-accent-teal)] transition-colors hover:opacity-80",
319
325
  children: $ ? "Collapse all" : "Expand all"
320
326
  }) : void 0,
321
- children: O.isLoading ? /* @__PURE__ */ j(l, { label: "Loading curriculum…" }) : O.isError ? /* @__PURE__ */ j(c, {
327
+ children: D.isLoading ? /* @__PURE__ */ j(l, { label: "Loading curriculum…" }) : D.isError ? /* @__PURE__ */ j(c, {
322
328
  title: "Couldn't load the curriculum",
323
- message: O.error instanceof Error ? O.error.message : void 0,
324
- onRetry: () => O.refetch()
329
+ message: D.error instanceof Error ? D.error.message : void 0,
330
+ onRetry: () => D.refetch()
325
331
  }) : X.length === 0 ? /* @__PURE__ */ j(s, {
326
332
  illustration: "empty-data",
327
333
  title: "No lessons yet",
@@ -334,7 +340,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
334
340
  className: t("overflow-hidden rounded-xl border bg-bg-surface transition-colors", r ? "border-[var(--color-accent-soft)]" : "border-border-seam"),
335
341
  children: [/* @__PURE__ */ M("button", {
336
342
  type: "button",
337
- onClick: () => le(e.id),
343
+ onClick: () => ue(e.id),
338
344
  "aria-expanded": r,
339
345
  "aria-controls": i,
340
346
  className: "flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-bg-sunken/50",
@@ -361,7 +367,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
361
367
  e.lessons.length === 1 ? "" : "s"
362
368
  ]
363
369
  }),
364
- /* @__PURE__ */ j(b, {
370
+ /* @__PURE__ */ j(oe, {
365
371
  className: t("h-4 w-4 shrink-0 text-text-tertiary transition-transform", r && "rotate-180"),
366
372
  "aria-hidden": !0
367
373
  })
@@ -391,7 +397,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
391
397
  onRetry: () => k.refetch()
392
398
  }) : K.length === 0 ? /* @__PURE__ */ j(s, {
393
399
  illustration: "empty-data",
394
- icon: /* @__PURE__ */ j(x, { className: "h-9 w-9" }),
400
+ icon: /* @__PURE__ */ j(y, { className: "h-9 w-9" }),
395
401
  title: "No assessments yet",
396
402
  description: "This course doesn't have any quizzes or exams attached."
397
403
  }) : /* @__PURE__ */ j("ul", {
@@ -402,7 +408,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
402
408
  className: "flex items-start gap-3",
403
409
  children: [/* @__PURE__ */ j("span", {
404
410
  className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary",
405
- children: /* @__PURE__ */ j(x, { className: "h-4 w-4" })
411
+ children: /* @__PURE__ */ j(y, { className: "h-4 w-4" })
406
412
  }), /* @__PURE__ */ M("div", {
407
413
  className: "min-w-0 flex-1",
408
414
  children: [
@@ -429,7 +435,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
429
435
  ] }),
430
436
  e.timeLimitMin > 0 && /* @__PURE__ */ M("span", {
431
437
  className: "inline-flex items-center gap-1",
432
- children: [/* @__PURE__ */ j(C, { className: "h-3.5 w-3.5" }), r(e.timeLimitMin)]
438
+ children: [/* @__PURE__ */ j(x, { className: "h-3.5 w-3.5" }), r(e.timeLimitMin)]
433
439
  })
434
440
  ]
435
441
  })
@@ -439,13 +445,13 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
439
445
  className: "mt-3 flex justify-end",
440
446
  children: /* @__PURE__ */ j(N, {
441
447
  size: "sm",
442
- onClick: () => w(`assessments/${e.id}/take`),
448
+ onClick: () => S(`assessments/${e.id}/take`),
443
449
  children: "Take"
444
450
  })
445
451
  })]
446
452
  }, e.id))
447
453
  })
448
- }) }), /* @__PURE__ */ j("div", { children: /* @__PURE__ */ j(te, {
454
+ }) }), /* @__PURE__ */ j("div", { children: /* @__PURE__ */ j(h, {
449
455
  entityType: F,
450
456
  entityId: i,
451
457
  description: "Ask questions and discuss this course with your workspace."
@@ -465,7 +471,7 @@ var F = "buildmyiq-course", se = "__ungrouped__", I = {
465
471
  title: "Course not found",
466
472
  description: "This course may have been unpublished or removed.",
467
473
  action: /* @__PURE__ */ j(N, {
468
- onClick: () => w("catalog"),
474
+ onClick: () => S("catalog"),
469
475
  children: "Back to catalog"
470
476
  })
471
477
  })
@@ -1 +1 @@
1
- {"version":3,"file":"CourseDetailPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/catalog/CourseDetailPage.tsx"],"sourcesContent":["/**\n * CourseDetailPage — a single published course: hero, curriculum, assessments,\n * discussion + tags, and the enrol / continue-learning call to action.\n * @module buildmyiq/pages/catalog\n *\n * All data is live: `buiCourse` (hero + flat lessons), `buiListModules`\n * (curriculum), `buiListAssessments` (course exams), and `buiListEnrollments`\n * (to decide Enrol vs Continue). Enrolling calls `buiEnroll` then routes the\n * learner straight into their new enrollment. Every list has its own\n * loading / error / empty state.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport type { LucideIcon } from 'lucide-react';\nimport {\n ArrowLeft,\n ArrowRight,\n BookOpen,\n ChevronDown,\n ClipboardCheck,\n ClipboardList,\n Clock,\n FileText,\n GraduationCap,\n Layers,\n ListChecks,\n MousePointerClick,\n PlayCircle,\n Radio,\n Sparkles,\n Video,\n} from 'lucide-react';\nimport { Button, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n Section,\n LoadingView,\n ErrorView,\n EmptyState,\n MiniBar,\n BuiDiscussion,\n BuiTags,\n} from '../../components';\nimport { cn } from '../../utils/cn';\nimport { useBuildmyiq } from '../../context';\nimport {\n useBuiCourse,\n useBuiModules,\n useBuiAssessments,\n useBuiEnrollments,\n useBuiEnroll,\n} from '../../hooks';\nimport { formatHours, formatDuration, formatEnumLabel } from '../../utils/formatters';\nimport type { BuiLesson, BuiLessonType } from '../../types';\n\nconst COURSE_ENTITY = 'buildmyiq-course';\nconst UNGROUPED_ID = '__ungrouped__';\n\n/** A curriculum group is either a real module or the \"additional lessons\" bucket. */\ninterface CurriculumGroup {\n id: string;\n title: string;\n description?: string | null;\n lessons: BuiLesson[];\n}\n\n/** Lesson-type → icon, so learners can scan a module at a glance. */\nconst LESSON_ICON: Record<BuiLessonType, LucideIcon> = {\n ARTICLE: FileText,\n VIDEO: Video,\n QUIZ: ListChecks,\n ASSIGNMENT: ClipboardList,\n INTERACTIVE: MousePointerClick,\n LIVE_SESSION: Radio,\n};\n\nconst LessonRow: FC<{ lesson: BuiLesson; index: number }> = ({ lesson, index }) => {\n const Icon = LESSON_ICON[lesson.type] ?? FileText;\n return (\n <li className=\"flex items-center gap-3 px-4 py-3 transition-colors hover:bg-bg-sunken/60\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <Icon className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n <span className=\"mr-1.5 tabular-nums text-text-tertiary\">{index + 1}.</span>\n {lesson.title}\n </p>\n <p className=\"text-xs text-text-tertiary\">{formatEnumLabel(lesson.type)}</p>\n </div>\n {lesson.durationMin > 0 && (\n <span className=\"hidden shrink-0 items-center gap-1 text-xs tabular-nums text-text-secondary sm:inline-flex\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatDuration(lesson.durationMin)}\n </span>\n )}\n {lesson.isPreview && (\n <span className=\"shrink-0 rounded-full border border-[var(--color-accent-teal)] px-2 py-0.5 text-xs font-medium text-[var(--color-accent-teal)]\">\n Preview\n </span>\n )}\n </li>\n );\n};\n\n/** A single hero meta pill (skill / structure / duration). */\nconst MetaPill: FC<{ icon: LucideIcon; children: ReactNode }> = ({ icon: Icon, children }) => (\n <span className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam bg-bg-surface px-3 py-1.5 text-xs font-medium text-text-secondary\">\n <Icon className=\"h-3.5 w-3.5 text-text-tertiary\" aria-hidden />\n {children}\n </span>\n);\n\nexport const CourseDetailPage: FC = () => {\n const { courseId } = useParams<{ courseId: string }>();\n const { currentUser, navigateTo } = useBuildmyiq();\n const learnerId = currentUser?.id;\n\n const courseQuery = useBuiCourse(courseId);\n const modulesQuery = useBuiModules(courseId);\n const assessmentsQuery = useBuiAssessments(courseId);\n const enrollmentsQuery = useBuiEnrollments({\n courseId,\n learnerId,\n enabled: Boolean(courseId && learnerId),\n });\n\n const enroll = useBuiEnroll();\n const [enrolError, setEnrolError] = useState<string | null>(null);\n // null = \"not yet touched\" → default-open the first module only.\n const [openGroups, setOpenGroups] = useState<Set<string> | null>(null);\n\n const course = courseQuery.data ?? null;\n const modules = modulesQuery.data ?? [];\n const assessments = assessmentsQuery.data ?? [];\n const enrollments = enrollmentsQuery.data?.items ?? [];\n\n // An existing, non-terminal enrollment means \"Continue\" instead of \"Enrol\".\n const activeEnrollment = useMemo(\n () => enrollments.find((e) => e.status !== 'DROPPED' && e.status !== 'EXPIRED'),\n [enrollments]\n );\n\n // Lessons attached directly to the course (no module) — surfaced as their own group.\n const ungroupedLessons = useMemo(\n () => (course?.lessons ?? []).filter((lesson) => !lesson.moduleId),\n [course]\n );\n\n // Unified, ordered list of curriculum groups (modules + the leftovers bucket).\n const groups: CurriculumGroup[] = useMemo(() => {\n const moduleGroups: CurriculumGroup[] = modules.map((m) => ({\n id: m.id,\n title: m.title,\n description: m.description,\n lessons: m.lessons ?? [],\n }));\n if (ungroupedLessons.length > 0) {\n moduleGroups.push({\n id: UNGROUPED_ID,\n title: 'Additional lessons',\n lessons: ungroupedLessons,\n });\n }\n return moduleGroups;\n }, [modules, ungroupedLessons]);\n\n const totalLessons = course?.lessons?.length ?? 0;\n const publishedAssessments = assessments.filter((a) => a.status === 'PUBLISHED').length;\n\n // Effective open-set: default to the first group when the learner hasn't toggled.\n const effectiveOpen = openGroups ?? new Set(groups.slice(0, 1).map((g) => g.id));\n const allOpen = groups.length > 0 && groups.every((g) => effectiveOpen.has(g.id));\n\n const toggleGroup = (id: string): void => {\n const next = new Set(effectiveOpen);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n setOpenGroups(next);\n };\n\n const toggleAll = (): void => {\n setOpenGroups(allOpen ? new Set() : new Set(groups.map((g) => g.id)));\n };\n\n const handleEnrol = async (): Promise<void> => {\n if (!courseId || !learnerId) return;\n setEnrolError(null);\n try {\n const created = await enroll.mutateAsync({ courseId, learnerId });\n navigateTo(`learning/${created.id}`);\n } catch (err) {\n setEnrolError(err instanceof Error ? err.message : 'Could not enrol in this course.');\n }\n };\n\n // Top-level page states.\n if (!courseId) {\n return (\n <PageLayout title=\"Course\">\n <ErrorView title=\"Missing course\" message=\"No course was specified.\" />\n </PageLayout>\n );\n }\n\n if (courseQuery.isLoading) {\n return (\n <PageLayout title=\"Course\">\n <LoadingView label=\"Loading course…\" />\n </PageLayout>\n );\n }\n\n if (courseQuery.isError) {\n return (\n <PageLayout title=\"Course\">\n <ErrorView\n title=\"Couldn't load this course\"\n message={courseQuery.error instanceof Error ? courseQuery.error.message : undefined}\n onRetry={() => courseQuery.refetch()}\n />\n </PageLayout>\n );\n }\n\n if (!course) {\n return (\n <PageLayout title=\"Course\">\n <EmptyState\n illustration=\"empty-search\"\n title=\"Course not found\"\n description=\"This course may have been unpublished or removed.\"\n action={<Button onClick={() => navigateTo('catalog')}>Back to catalog</Button>}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title={course.title}>\n <div className=\"mx-auto flex w-full max-w-6xl flex-col gap-6\">\n {/* Breadcrumb + back */}\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <nav className=\"flex min-w-0 items-center gap-1.5 text-sm\" aria-label=\"Breadcrumb\">\n <button\n type=\"button\"\n onClick={() => navigateTo('catalog')}\n className=\"shrink-0 font-medium text-[var(--color-accent-teal)] transition-colors hover:opacity-80\"\n >\n Catalog\n </button>\n <span className=\"shrink-0 text-text-tertiary\">/</span>\n <span className=\"truncate text-text-secondary\">{course.title}</span>\n </nav>\n <button\n type=\"button\"\n onClick={() => navigateTo('catalog')}\n className=\"inline-flex shrink-0 items-center gap-1.5 text-sm text-text-secondary transition-colors hover:text-text-primary\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back to catalog\n </button>\n </div>\n\n {/* Hero: cover + info (left) and enrol / progress card (right) */}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-[minmax(0,1fr)_20rem]\">\n <GlassCard treatment=\"plain\" className=\"overflow-hidden\">\n <div className=\"grid grid-cols-1 sm:grid-cols-[minmax(0,15rem)_minmax(0,1fr)]\">\n <div className=\"relative h-44 w-full overflow-hidden bg-bg-sunken sm:h-full\">\n {course.cover?.downloadUrl ? (\n <img\n src={course.cover.downloadUrl}\n alt=\"\"\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"flex h-full min-h-[11rem] w-full items-center justify-center bg-[var(--color-accent-soft)]\">\n <BookOpen className=\"h-10 w-10 text-text-secondary opacity-60\" />\n </div>\n )}\n </div>\n\n <div className=\"flex flex-col gap-4 p-6\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={course.level} />\n <StatusBadge status={course.status} />\n </div>\n\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight text-text-primary\">\n {course.title}\n </h1>\n {course.summary && (\n <p className=\"mt-2 text-sm text-text-secondary\">{course.summary}</p>\n )}\n </div>\n\n <div className=\"flex flex-wrap gap-2\">\n {course.skill?.name && <MetaPill icon={Sparkles}>{course.skill.name}</MetaPill>}\n <MetaPill icon={Layers}>\n {modules.length} module{modules.length === 1 ? '' : 's'} · {totalLessons} lesson\n {totalLessons === 1 ? '' : 's'}\n </MetaPill>\n {course.estimatedHours > 0 && (\n <MetaPill icon={Clock}>{formatHours(course.estimatedHours)}</MetaPill>\n )}\n </div>\n\n {course.tags.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {course.tags.map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary\"\n >\n {tag}\n </span>\n ))}\n </div>\n )}\n\n {course.description && (\n <p className=\"whitespace-pre-wrap text-sm leading-relaxed text-text-secondary\">\n {course.description}\n </p>\n )}\n </div>\n </div>\n </GlassCard>\n\n {/* Enrol / progress card */}\n <GlassCard treatment=\"glass\" glow className=\"h-fit p-5 lg:sticky lg:top-4\">\n {activeEnrollment ? (\n <div className=\"flex flex-col gap-4\">\n <Button\n size=\"lg\"\n className=\"w-full\"\n onClick={() => navigateTo(`learning/${activeEnrollment.id}`)}\n >\n <PlayCircle className=\"mr-2 h-4 w-4\" /> Continue learning\n </Button>\n <div className=\"flex flex-col gap-1.5\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">Your progress</span>\n <span className=\"font-semibold tabular-nums text-text-primary\">\n {activeEnrollment.progressPct}%\n </span>\n </div>\n <MiniBar value={activeEnrollment.progressPct} />\n </div>\n <div className=\"flex items-center justify-between border-t border-border-seam pt-3 text-xs\">\n <span className=\"text-text-secondary\">Enrollment</span>\n <StatusBadge status={activeEnrollment.status} />\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col gap-4\">\n <Button\n size=\"lg\"\n className=\"w-full\"\n onClick={handleEnrol}\n disabled={enroll.isPending || !learnerId}\n >\n <GraduationCap className=\"mr-2 h-4 w-4\" />\n {enroll.isPending ? 'Enrolling…' : 'Enrol in this course'}\n {!enroll.isPending && <ArrowRight className=\"ml-2 h-4 w-4\" />}\n </Button>\n {!learnerId && (\n <p className=\"text-xs text-text-tertiary\">Sign in to your workspace to enrol.</p>\n )}\n {enrolError && <p className=\"text-xs text-status-error-text\">{enrolError}</p>}\n <dl className=\"flex flex-col gap-2.5 border-t border-border-seam pt-3 text-sm\">\n <div className=\"flex items-center justify-between\">\n <dt className=\"inline-flex items-center gap-1.5 text-text-secondary\">\n <Layers className=\"h-3.5 w-3.5 text-text-tertiary\" /> Lessons\n </dt>\n <dd className=\"font-medium tabular-nums text-text-primary\">{totalLessons}</dd>\n </div>\n {course.estimatedHours > 0 && (\n <div className=\"flex items-center justify-between\">\n <dt className=\"inline-flex items-center gap-1.5 text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5 text-text-tertiary\" /> Duration\n </dt>\n <dd className=\"font-medium text-text-primary\">\n {formatHours(course.estimatedHours)}\n </dd>\n </div>\n )}\n <div className=\"flex items-center justify-between\">\n <dt className=\"inline-flex items-center gap-1.5 text-text-secondary\">\n <ClipboardCheck className=\"h-3.5 w-3.5 text-text-tertiary\" /> Assessments\n </dt>\n <dd className=\"font-medium tabular-nums text-text-primary\">\n {publishedAssessments}\n </dd>\n </div>\n </dl>\n </div>\n )}\n </GlassCard>\n </div>\n\n {/* Curriculum (left) + Assessments & Discussion (right) */}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-[minmax(0,1.7fr)_minmax(0,1fr)]\">\n {/* Curriculum */}\n <div>\n <Section\n title=\"Curriculum\"\n description=\"Modules and lessons in this course.\"\n action={\n groups.length > 1 ? (\n <button\n type=\"button\"\n onClick={toggleAll}\n className=\"text-sm font-medium text-[var(--color-accent-teal)] transition-colors hover:opacity-80\"\n >\n {allOpen ? 'Collapse all' : 'Expand all'}\n </button>\n ) : undefined\n }\n >\n {modulesQuery.isLoading ? (\n <LoadingView label=\"Loading curriculum…\" />\n ) : modulesQuery.isError ? (\n <ErrorView\n title=\"Couldn't load the curriculum\"\n message={\n modulesQuery.error instanceof Error ? modulesQuery.error.message : undefined\n }\n onRetry={() => modulesQuery.refetch()}\n />\n ) : groups.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No lessons yet\"\n description=\"The instructor hasn't added any modules or lessons to this course.\"\n />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {groups.map((group, index) => {\n const open = effectiveOpen.has(group.id);\n const panelId = `curriculum-panel-${group.id}`;\n return (\n <div\n key={group.id}\n className={cn(\n 'overflow-hidden rounded-xl border bg-bg-surface transition-colors',\n open ? 'border-[var(--color-accent-soft)]' : 'border-border-seam'\n )}\n >\n <button\n type=\"button\"\n onClick={() => toggleGroup(group.id)}\n aria-expanded={open}\n aria-controls={panelId}\n className=\"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <span className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-action-primary-bg text-xs font-semibold text-action-primary-text\">\n {index + 1}\n </span>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate font-semibold text-text-primary\">\n {group.title}\n </h3>\n {group.description && open && (\n <p className=\"mt-0.5 line-clamp-2 text-sm text-text-secondary\">\n {group.description}\n </p>\n )}\n </div>\n <span className=\"shrink-0 text-xs text-text-tertiary\">\n {group.lessons.length} lesson{group.lessons.length === 1 ? '' : 's'}\n </span>\n <ChevronDown\n className={cn(\n 'h-4 w-4 shrink-0 text-text-tertiary transition-transform',\n open && 'rotate-180'\n )}\n aria-hidden\n />\n </button>\n {open &&\n (group.lessons.length === 0 ? (\n <p className=\"border-t border-border-seam px-4 py-3 text-sm text-text-tertiary\">\n No lessons in this module yet.\n </p>\n ) : (\n <ul\n id={panelId}\n className=\"divide-y divide-border-seam border-t border-border-seam\"\n >\n {group.lessons.map((lesson, li) => (\n <LessonRow key={lesson.id} lesson={lesson} index={li} />\n ))}\n </ul>\n ))}\n </div>\n );\n })}\n </div>\n )}\n </Section>\n </div>\n\n {/* Assessments + Discussion */}\n <div className=\"flex flex-col gap-6\">\n <div>\n <Section title=\"Assessments\" description=\"Quizzes and exams for this course.\">\n {assessmentsQuery.isLoading ? (\n <LoadingView label=\"Loading assessments…\" />\n ) : assessmentsQuery.isError ? (\n <ErrorView\n title=\"Couldn't load assessments\"\n message={\n assessmentsQuery.error instanceof Error\n ? assessmentsQuery.error.message\n : undefined\n }\n onRetry={() => assessmentsQuery.refetch()}\n />\n ) : assessments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<ClipboardCheck className=\"h-9 w-9\" />}\n title=\"No assessments yet\"\n description=\"This course doesn't have any quizzes or exams attached.\"\n />\n ) : (\n <ul className=\"flex flex-col gap-3\">\n {assessments.map((assessment) => (\n <li\n key={assessment.id}\n className=\"rounded-xl border border-border-seam bg-bg-surface p-4\"\n >\n <div className=\"flex items-start gap-3\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <ClipboardCheck className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-medium text-text-primary\">{assessment.title}</p>\n <div className=\"mt-1.5 flex flex-wrap items-center gap-1.5\">\n <StatusBadge status={assessment.type} />\n <StatusBadge status={assessment.status} />\n </div>\n <div className=\"mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary\">\n <span>Pass ≥ {assessment.passingScore}%</span>\n <span>\n {assessment.maxAttempts} attempt\n {assessment.maxAttempts === 1 ? '' : 's'}\n </span>\n {assessment.timeLimitMin > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" />\n {formatDuration(assessment.timeLimitMin)}\n </span>\n )}\n </div>\n </div>\n </div>\n {assessment.status === 'PUBLISHED' && activeEnrollment && (\n <div className=\"mt-3 flex justify-end\">\n <Button\n size=\"sm\"\n onClick={() => navigateTo(`assessments/${assessment.id}/take`)}\n >\n Take\n </Button>\n </div>\n )}\n </li>\n ))}\n </ul>\n )}\n </Section>\n </div>\n\n {/* Discussion (platform wspace-conversations) */}\n <div>\n <BuiDiscussion\n entityType={COURSE_ENTITY}\n entityId={courseId}\n description=\"Ask questions and discuss this course with your workspace.\"\n />\n </div>\n </div>\n </div>\n\n {/* Tags (platform wspace-tags) — full width */}\n <div>\n <BuiTags entityType={COURSE_ENTITY} entityId={courseId} />\n </div>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA0DA,IAAM,IAAgB,oBAChB,KAAe,iBAWf,IAAiD;CACrD,SAAS;CACT,OAAO;CACP,MAAM;CACN,YAAY;CACZ,aAAa;CACb,cAAc;CACf,EAEK,KAAuD,EAAE,WAAQ,eAGnE,kBAAC,MAAD;CAAI,WAAU;WAAd;EACE,kBAAC,QAAD;GAAM,WAAU;aACd,kBAJO,EAAY,EAAO,SAAS,GAInC,EAAM,WAAU,WAAY,CAAA;GACvB,CAAA;EACP,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,KAAD;IAAG,WAAU;cAAb,CACE,kBAAC,QAAD;KAAM,WAAU;eAAhB,CAA0D,IAAQ,GAAE,IAAQ;QAC3E,EAAO,MACN;OACJ,kBAAC,KAAD;IAAG,WAAU;cAA8B,EAAgB,EAAO,KAAK;IAAK,CAAA,CACxE;;EACL,EAAO,cAAc,KACpB,kBAAC,QAAD;GAAM,WAAU;aAAhB;IACE,kBAAC,GAAD,EAAO,WAAU,eAAgB,CAAA;;IAAE,EAAe,EAAO,YAAY;IAChE;;EAER,EAAO,aACN,kBAAC,QAAD;GAAM,WAAU;aAAiI;GAE1I,CAAA;EAEN;IAKH,KAA2D,EAAE,MAAM,GAAM,kBAC7E,kBAAC,QAAD;CAAM,WAAU;WAAhB,CACE,kBAAC,GAAD;EAAM,WAAU;EAAiC,eAAA;EAAc,CAAA,EAC9D,EACI;IAGI,UAA6B;CACxC,IAAM,EAAE,gBAAa,GAAiC,EAChD,EAAE,gBAAa,kBAAe,GAAc,EAC5C,IAAY,GAAa,IAEzB,IAAc,GAAa,EAAS,EACpC,IAAe,EAAc,EAAS,EACtC,IAAmB,EAAkB,EAAS,EAC9C,IAAmB,EAAkB;EACzC;EACA;EACA,SAAS,GAAQ,KAAY;EAC9B,CAAC,EAEI,IAAS,GAAc,EACvB,CAAC,GAAY,KAAiB,EAAwB,KAAK,EAE3D,CAAC,GAAY,KAAiB,EAA6B,KAAK,EAEhE,IAAS,EAAY,QAAQ,MAC7B,IAAU,EAAa,QAAQ,EAAE,EACjC,IAAc,EAAiB,QAAQ,EAAE,EACzC,IAAc,EAAiB,MAAM,SAAS,EAAE,EAGhD,IAAmB,QACjB,EAAY,MAAM,MAAM,EAAE,WAAW,aAAa,EAAE,WAAW,UAAU,EAC/E,CAAC,EAAY,CACd,EAGK,IAAmB,SAChB,GAAQ,WAAW,EAAE,EAAE,QAAQ,MAAW,CAAC,EAAO,SAAS,EAClE,CAAC,EAAO,CACT,EAGK,IAA4B,QAAc;EAC9C,IAAM,IAAkC,EAAQ,KAAK,OAAO;GAC1D,IAAI,EAAE;GACN,OAAO,EAAE;GACT,aAAa,EAAE;GACf,SAAS,EAAE,WAAW,EAAE;GACzB,EAAE;AAQH,SAPI,EAAiB,SAAS,KAC5B,EAAa,KAAK;GAChB,IAAI;GACJ,OAAO;GACP,SAAS;GACV,CAAC,EAEG;IACN,CAAC,GAAS,EAAiB,CAAC,EAEzB,IAAe,GAAQ,SAAS,UAAU,GAC1C,KAAuB,EAAY,QAAQ,MAAM,EAAE,WAAW,YAAY,CAAC,QAG3E,IAAgB,KAAc,IAAI,IAAI,EAAO,MAAM,GAAG,EAAE,CAAC,KAAK,MAAM,EAAE,GAAG,CAAC,EAC1E,IAAU,EAAO,SAAS,KAAK,EAAO,OAAO,MAAM,EAAc,IAAI,EAAE,GAAG,CAAC,EAE3E,MAAe,MAAqB;EACxC,IAAM,IAAO,IAAI,IAAI,EAAc;AAGnC,EAFI,EAAK,IAAI,EAAG,GAAE,EAAK,OAAO,EAAG,GAC5B,EAAK,IAAI,EAAG,EACjB,EAAc,EAAK;;AA4DrB,QAzCK,IAQD,EAAY,YAEZ,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EAAa,OAAM,mBAAoB,CAAA;EAC5B,CAAA,GAIb,EAAY,UAEZ,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GACE,OAAM;GACN,SAAS,EAAY,iBAAiB,QAAQ,EAAY,MAAM,UAAU,KAAA;GAC1E,eAAe,EAAY,SAAS;GACpC,CAAA;EACS,CAAA,GAIZ,IAcH,kBAAC,GAAD;EAAY,OAAO,EAAO;YACxB,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;MAA4C,cAAW;gBAAtE;OACE,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAW,UAAU;QACpC,WAAU;kBACX;QAEQ,CAAA;OACT,kBAAC,QAAD;QAAM,WAAU;kBAA8B;QAAQ,CAAA;OACtD,kBAAC,QAAD;QAAM,WAAU;kBAAgC,EAAO;QAAa,CAAA;OAChE;SACN,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAW,UAAU;MACpC,WAAU;gBAHZ,CAKE,kBAAC,IAAD,EAAW,WAAU,WAAY,CAAA,EAAA,mBAC1B;QACL;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAW,WAAU;MAAQ,WAAU;gBACrC,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAO,OAAO,cACb,kBAAC,OAAD;SACE,KAAK,EAAO,MAAM;SAClB,KAAI;SACJ,WAAU;SACV,CAAA,GAEF,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,GAAD,EAAU,WAAU,4CAA6C,CAAA;SAC7D,CAAA;QAEJ,CAAA,EAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD,EAAa,QAAQ,EAAO,OAAS,CAAA,EACrC,kBAAC,GAAD,EAAa,QAAQ,EAAO,QAAU,CAAA,CAClC;;SAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAO;UACL,CAAA,EACJ,EAAO,WACN,kBAAC,KAAD;UAAG,WAAU;oBAAoC,EAAO;UAAY,CAAA,CAElE,EAAA,CAAA;SAEN,kBAAC,OAAD;UAAK,WAAU;oBAAf;WACG,EAAO,OAAO,QAAQ,kBAAC,GAAD;YAAU,MAAM;sBAAW,EAAO,MAAM;YAAgB,CAAA;WAC/E,kBAAC,GAAD;YAAU,MAAM;sBAAhB;aACG,EAAQ;aAAO;aAAQ,EAAQ,WAAW,IAAI,KAAK;aAAI;aAAI;aAAa;aACxE,MAAiB,IAAI,KAAK;aAClB;;WACV,EAAO,iBAAiB,KACvB,kBAAC,GAAD;YAAU,MAAM;sBAAQ,EAAY,EAAO,eAAe;YAAY,CAAA;WAEpE;;SAEL,EAAO,KAAK,SAAS,KACpB,kBAAC,OAAD;UAAK,WAAU;oBACZ,EAAO,KAAK,KAAK,MAChB,kBAAC,QAAD;WAEE,WAAU;qBAET;WACI,EAJA,EAIA,CACP;UACE,CAAA;SAGP,EAAO,eACN,kBAAC,KAAD;UAAG,WAAU;oBACV,EAAO;UACN,CAAA;SAEF;UACF;;MACI,CAAA,EAGZ,kBAAC,GAAD;MAAW,WAAU;MAAQ,MAAA;MAAK,WAAU;gBACzC,IACC,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD;SACE,MAAK;SACL,WAAU;SACV,eAAe,EAAW,YAAY,EAAiB,KAAK;mBAH9D,CAKE,kBAAC,IAAD,EAAY,WAAU,gBAAiB,CAAA,EAAA,qBAChC;;QACT,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAsB;WAAoB,CAAA,EAC1D,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CACG,EAAiB,aAAY,IACzB;aACH;aACN,kBAAC,GAAD,EAAS,OAAO,EAAiB,aAAe,CAAA,CAC5C;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAsB;UAAiB,CAAA,EACvD,kBAAC,GAAD,EAAa,QAAQ,EAAiB,QAAU,CAAA,CAC5C;;QACF;WAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD;SACE,MAAK;SACL,WAAU;SACV,SA9KI,YAA2B;AACzC,iBAAC,KAAY,CAAC,IAClB;aAAc,KAAK;AACnB,eAAI;AAEF,cAAW,aADK,MAAM,EAAO,YAAY;aAAE;aAAU;aAAW,CAAC,EAClC,KAAK;oBAC7B,GAAK;AACZ,cAAc,aAAe,QAAQ,EAAI,UAAU,kCAAkC;;;;SAwKzE,UAAU,EAAO,aAAa,CAAC;mBAJjC;UAME,kBAAC,IAAD,EAAe,WAAU,gBAAiB,CAAA;UACzC,EAAO,YAAY,eAAe;UAClC,CAAC,EAAO,aAAa,kBAAC,GAAD,EAAY,WAAU,gBAAiB,CAAA;UACtD;;QACR,CAAC,KACA,kBAAC,KAAD;SAAG,WAAU;mBAA6B;SAAuC,CAAA;QAElF,KAAc,kBAAC,KAAD;SAAG,WAAU;mBAAkC;SAAe,CAAA;QAC7E,kBAAC,MAAD;SAAI,WAAU;mBAAd;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,MAAD;YAAI,WAAU;sBAAd,CACE,kBAAC,GAAD,EAAQ,WAAU,kCAAmC,CAAA,EAAA,WAClD;eACL,kBAAC,MAAD;YAAI,WAAU;sBAA8C;YAAkB,CAAA,CAC1E;;UACL,EAAO,iBAAiB,KACvB,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,MAAD;YAAI,WAAU;sBAAd,CACE,kBAAC,GAAD,EAAO,WAAU,kCAAmC,CAAA,EAAA,YACjD;eACL,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAY,EAAO,eAAe;YAChC,CAAA,CACD;;UAER,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,MAAD;YAAI,WAAU;sBAAd,CACE,kBAAC,GAAD,EAAgB,WAAU,kCAAmC,CAAA,EAAA,eAC1D;eACL,kBAAC,MAAD;YAAI,WAAU;sBACX;YACE,CAAA,CACD;;UACH;;QACD;;MAEE,CAAA,CACR;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CAEE,kBAAC,OAAD,EAAA,UACE,kBAAC,GAAD;MACE,OAAM;MACN,aAAY;MACZ,QACE,EAAO,SAAS,IACd,kBAAC,UAAD;OACE,MAAK;OACL,eAvOY;AAC5B,UAAc,oBAAU,IAAI,KAAK,GAAG,IAAI,IAAI,EAAO,KAAK,MAAM,EAAE,GAAG,CAAC,CAAC;;OAuOrD,WAAU;iBAET,IAAU,iBAAiB;OACrB,CAAA,GACP,KAAA;gBAGL,EAAa,YACZ,kBAAC,GAAD,EAAa,OAAM,uBAAwB,CAAA,GACzC,EAAa,UACf,kBAAC,GAAD;OACE,OAAM;OACN,SACE,EAAa,iBAAiB,QAAQ,EAAa,MAAM,UAAU,KAAA;OAErE,eAAe,EAAa,SAAS;OACrC,CAAA,GACA,EAAO,WAAW,IACpB,kBAAC,GAAD;OACE,cAAa;OACb,OAAM;OACN,aAAY;OACZ,CAAA,GAEF,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAO,KAAK,GAAO,MAAU;QAC5B,IAAM,IAAO,EAAc,IAAI,EAAM,GAAG,EAClC,IAAU,oBAAoB,EAAM;AAC1C,eACE,kBAAC,OAAD;SAEE,WAAW,EACT,qEACA,IAAO,sCAAsC,qBAC9C;mBALH,CAOE,kBAAC,UAAD;UACE,MAAK;UACL,eAAe,GAAY,EAAM,GAAG;UACpC,iBAAe;UACf,iBAAe;UACf,WAAU;oBALZ;WAOE,kBAAC,QAAD;YAAM,WAAU;sBACb,IAAQ;YACJ,CAAA;WACP,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,MAAD;aAAI,WAAU;uBACX,EAAM;aACJ,CAAA,EACJ,EAAM,eAAe,KACpB,kBAAC,KAAD;aAAG,WAAU;uBACV,EAAM;aACL,CAAA,CAEF;;WACN,kBAAC,QAAD;YAAM,WAAU;sBAAhB;aACG,EAAM,QAAQ;aAAO;aAAQ,EAAM,QAAQ,WAAW,IAAI,KAAK;aAC3D;;WACP,kBAAC,GAAD;YACE,WAAW,EACT,4DACA,KAAQ,aACT;YACD,eAAA;YACA,CAAA;WACK;aACR,MACE,EAAM,QAAQ,WAAW,IACxB,kBAAC,KAAD;UAAG,WAAU;oBAAmE;UAE5E,CAAA,GAEJ,kBAAC,MAAD;UACE,IAAI;UACJ,WAAU;oBAET,EAAM,QAAQ,KAAK,GAAQ,MAC1B,kBAAC,GAAD;WAAmC;WAAQ,OAAO;WAAM,EAAxC,EAAO,GAAiC,CACxD;UACC,CAAA,EAEL;WApDC,EAAM,GAoDP;SAER;OACE,CAAA;MAEA,CAAA,EACN,CAAA,EAGN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD,EAAA,UACE,kBAAC,GAAD;OAAS,OAAM;OAAc,aAAY;iBACtC,EAAiB,YAChB,kBAAC,GAAD,EAAa,OAAM,wBAAyB,CAAA,GAC1C,EAAiB,UACnB,kBAAC,GAAD;QACE,OAAM;QACN,SACE,EAAiB,iBAAiB,QAC9B,EAAiB,MAAM,UACvB,KAAA;QAEN,eAAe,EAAiB,SAAS;QACzC,CAAA,GACA,EAAY,WAAW,IACzB,kBAAC,GAAD;QACE,cAAa;QACb,MAAM,kBAAC,GAAD,EAAgB,WAAU,WAAY,CAAA;QAC5C,OAAM;QACN,aAAY;QACZ,CAAA,GAEF,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAY,KAAK,MAChB,kBAAC,MAAD;SAEE,WAAU;mBAFZ,CAIE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBACd,kBAAC,GAAD,EAAgB,WAAU,WAAY,CAAA;WACjC,CAAA,EACP,kBAAC,OAAD;WAAK,WAAU;qBAAf;YACE,kBAAC,KAAD;aAAG,WAAU;uBAAiC,EAAW;aAAU,CAAA;YACnE,kBAAC,OAAD;aAAK,WAAU;uBAAf,CACE,kBAAC,GAAD,EAAa,QAAQ,EAAW,MAAQ,CAAA,EACxC,kBAAC,GAAD,EAAa,QAAQ,EAAW,QAAU,CAAA,CACtC;;YACN,kBAAC,OAAD;aAAK,WAAU;uBAAf;cACE,kBAAC,QAAD,EAAA,UAAA;eAAM;eAAQ,EAAW;eAAa;eAAQ,EAAA,CAAA;cAC9C,kBAAC,QAAD,EAAA,UAAA;eACG,EAAW;eAAY;eACvB,EAAW,gBAAgB,IAAI,KAAK;eAChC,EAAA,CAAA;cACN,EAAW,eAAe,KACzB,kBAAC,QAAD;eAAM,WAAU;yBAAhB,CACE,kBAAC,GAAD,EAAO,WAAU,eAAgB,CAAA,EAChC,EAAe,EAAW,aAAa,CACnC;;cAEL;;YACF;aACF;aACL,EAAW,WAAW,eAAe,KACpC,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,GAAD;WACE,MAAK;WACL,eAAe,EAAW,eAAe,EAAW,GAAG,OAAO;qBAC/D;WAEQ,CAAA;UACL,CAAA,CAEL;WAtCE,EAAW,GAsCb,CACL;QACC,CAAA;OAEC,CAAA,EACN,CAAA,EAGN,kBAAC,OAAD,EAAA,UACE,kBAAC,IAAD;OACE,YAAY;OACZ,UAAU;OACV,aAAY;OACZ,CAAA,EACE,CAAA,CACF;QACF;;IAGN,kBAAC,OAAD,EAAA,UACE,kBAAC,IAAD;KAAS,YAAY;KAAe,UAAU;KAAY,CAAA,EACtD,CAAA;IACF;;EACK,CAAA,GA5WX,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,QAAQ,kBAAC,GAAD;IAAQ,eAAe,EAAW,UAAU;cAAE;IAAwB,CAAA;GAC9E,CAAA;EACS,CAAA,GAnCb,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GAAW,OAAM;GAAiB,SAAQ;GAA6B,CAAA;EAC5D,CAAA"}
1
+ {"version":3,"file":"CourseDetailPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/catalog/CourseDetailPage.tsx"],"sourcesContent":["/**\n * CourseDetailPage — a single published course: hero, curriculum, assessments,\n * discussion + tags, and the enrol / continue-learning call to action.\n * @module buildmyiq/pages/catalog\n *\n * All data is live: `buiCourse` (hero + flat lessons), `buiListModules`\n * (curriculum), `buiListAssessments` (course exams), and `buiListEnrollments`\n * (to decide Enrol vs Continue). Enrolling calls `buiEnroll` then routes the\n * learner straight into their new enrollment. Every list has its own\n * loading / error / empty state.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport type { LucideIcon } from 'lucide-react';\nimport {\n ArrowLeft,\n ArrowRight,\n BookOpen,\n ChevronDown,\n ClipboardCheck,\n ClipboardList,\n Clock,\n FileText,\n GraduationCap,\n Layers,\n ListChecks,\n MousePointerClick,\n PlayCircle,\n Radio,\n Sparkles,\n Video,\n} from 'lucide-react';\nimport { Button, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n Section,\n LoadingView,\n ErrorView,\n EmptyState,\n MiniBar,\n BuiDiscussion,\n BuiTags,\n} from '../../components';\nimport { cn } from '../../utils/cn';\nimport { useBuildmyiq } from '../../context';\nimport {\n useBuiCourse,\n useBuiModules,\n useBuiAssessments,\n useBuiEnrollments,\n useBuiEnroll,\n} from '../../hooks';\nimport { formatHours, formatDuration, formatEnumLabel } from '../../utils/formatters';\nimport type { BuiLesson, BuiLessonType } from '../../types';\nimport { BuiPermissionButton } from '../../components/BuiPermissionButton';\n\nconst COURSE_ENTITY = 'buildmyiq-course';\nconst UNGROUPED_ID = '__ungrouped__';\n\n/** A curriculum group is either a real module or the \"additional lessons\" bucket. */\ninterface CurriculumGroup {\n id: string;\n title: string;\n description?: string | null;\n lessons: BuiLesson[];\n}\n\n/** Lesson-type → icon, so learners can scan a module at a glance. */\nconst LESSON_ICON: Record<BuiLessonType, LucideIcon> = {\n ARTICLE: FileText,\n VIDEO: Video,\n QUIZ: ListChecks,\n ASSIGNMENT: ClipboardList,\n INTERACTIVE: MousePointerClick,\n LIVE_SESSION: Radio,\n};\n\nconst LessonRow: FC<{ lesson: BuiLesson; index: number }> = ({ lesson, index }) => {\n const Icon = LESSON_ICON[lesson.type] ?? FileText;\n return (\n <li className=\"flex items-center gap-3 px-4 py-3 transition-colors hover:bg-bg-sunken/60\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <Icon className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n <span className=\"mr-1.5 tabular-nums text-text-tertiary\">{index + 1}.</span>\n {lesson.title}\n </p>\n <p className=\"text-xs text-text-tertiary\">{formatEnumLabel(lesson.type)}</p>\n </div>\n {lesson.durationMin > 0 && (\n <span className=\"hidden shrink-0 items-center gap-1 text-xs tabular-nums text-text-secondary sm:inline-flex\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatDuration(lesson.durationMin)}\n </span>\n )}\n {lesson.isPreview && (\n <span className=\"shrink-0 rounded-full border border-[var(--color-accent-teal)] px-2 py-0.5 text-xs font-medium text-[var(--color-accent-teal)]\">\n Preview\n </span>\n )}\n </li>\n );\n};\n\n/** A single hero meta pill (skill / structure / duration). */\nconst MetaPill: FC<{ icon: LucideIcon; children: ReactNode }> = ({ icon: Icon, children }) => (\n <span className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam bg-bg-surface px-3 py-1.5 text-xs font-medium text-text-secondary\">\n <Icon className=\"h-3.5 w-3.5 text-text-tertiary\" aria-hidden />\n {children}\n </span>\n);\n\nexport const CourseDetailPage: FC = () => {\n const { courseId } = useParams<{ courseId: string }>();\n const { currentUser, navigateTo } = useBuildmyiq();\n const learnerId = currentUser?.id;\n\n const courseQuery = useBuiCourse(courseId);\n const modulesQuery = useBuiModules(courseId);\n const assessmentsQuery = useBuiAssessments(courseId);\n const enrollmentsQuery = useBuiEnrollments({\n courseId,\n learnerId,\n enabled: Boolean(courseId && learnerId),\n });\n\n const enroll = useBuiEnroll();\n const [enrolError, setEnrolError] = useState<string | null>(null);\n // null = \"not yet touched\" → default-open the first module only.\n const [openGroups, setOpenGroups] = useState<Set<string> | null>(null);\n\n const course = courseQuery.data ?? null;\n const modules = modulesQuery.data ?? [];\n const assessments = assessmentsQuery.data ?? [];\n const enrollments = enrollmentsQuery.data?.items ?? [];\n\n // An existing, non-terminal enrollment means \"Continue\" instead of \"Enrol\".\n const activeEnrollment = useMemo(\n () => enrollments.find((e) => e.status !== 'DROPPED' && e.status !== 'EXPIRED'),\n [enrollments]\n );\n\n // Lessons attached directly to the course (no module) — surfaced as their own group.\n const ungroupedLessons = useMemo(\n () => (course?.lessons ?? []).filter((lesson) => !lesson.moduleId),\n [course]\n );\n\n // Unified, ordered list of curriculum groups (modules + the leftovers bucket).\n const groups: CurriculumGroup[] = useMemo(() => {\n const moduleGroups: CurriculumGroup[] = modules.map((m) => ({\n id: m.id,\n title: m.title,\n description: m.description,\n lessons: m.lessons ?? [],\n }));\n if (ungroupedLessons.length > 0) {\n moduleGroups.push({\n id: UNGROUPED_ID,\n title: 'Additional lessons',\n lessons: ungroupedLessons,\n });\n }\n return moduleGroups;\n }, [modules, ungroupedLessons]);\n\n const totalLessons = course?.lessons?.length ?? 0;\n const publishedAssessments = assessments.filter((a) => a.status === 'PUBLISHED').length;\n\n // Effective open-set: default to the first group when the learner hasn't toggled.\n const effectiveOpen = openGroups ?? new Set(groups.slice(0, 1).map((g) => g.id));\n const allOpen = groups.length > 0 && groups.every((g) => effectiveOpen.has(g.id));\n\n const toggleGroup = (id: string): void => {\n const next = new Set(effectiveOpen);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n setOpenGroups(next);\n };\n\n const toggleAll = (): void => {\n setOpenGroups(allOpen ? new Set() : new Set(groups.map((g) => g.id)));\n };\n\n const handleEnrol = async (): Promise<void> => {\n if (!courseId || !learnerId) return;\n setEnrolError(null);\n try {\n const created = await enroll.mutateAsync({ courseId, learnerId });\n navigateTo(`learning/${created.id}`);\n } catch (err) {\n setEnrolError(err instanceof Error ? err.message : 'Could not enrol in this course.');\n }\n };\n\n // Top-level page states.\n if (!courseId) {\n return (\n <PageLayout title=\"Course\">\n <ErrorView title=\"Missing course\" message=\"No course was specified.\" />\n </PageLayout>\n );\n }\n\n if (courseQuery.isLoading) {\n return (\n <PageLayout title=\"Course\">\n <LoadingView label=\"Loading course…\" />\n </PageLayout>\n );\n }\n\n if (courseQuery.isError) {\n return (\n <PageLayout title=\"Course\">\n <ErrorView\n title=\"Couldn't load this course\"\n message={courseQuery.error instanceof Error ? courseQuery.error.message : undefined}\n onRetry={() => courseQuery.refetch()}\n />\n </PageLayout>\n );\n }\n\n if (!course) {\n return (\n <PageLayout title=\"Course\">\n <EmptyState\n illustration=\"empty-search\"\n title=\"Course not found\"\n description=\"This course may have been unpublished or removed.\"\n action={<Button onClick={() => navigateTo('catalog')}>Back to catalog</Button>}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title={course.title}>\n <div className=\"mx-auto flex w-full max-w-6xl flex-col gap-6\">\n {/* Breadcrumb + back */}\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <nav className=\"flex min-w-0 items-center gap-1.5 text-sm\" aria-label=\"Breadcrumb\">\n <button\n type=\"button\"\n onClick={() => navigateTo('catalog')}\n className=\"shrink-0 font-medium text-[var(--color-accent-teal)] transition-colors hover:opacity-80\"\n >\n Catalog\n </button>\n <span className=\"shrink-0 text-text-tertiary\">/</span>\n <span className=\"truncate text-text-secondary\">{course.title}</span>\n </nav>\n <button\n type=\"button\"\n onClick={() => navigateTo('catalog')}\n className=\"inline-flex shrink-0 items-center gap-1.5 text-sm text-text-secondary transition-colors hover:text-text-primary\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back to catalog\n </button>\n </div>\n\n {/* Hero: cover + info (left) and enrol / progress card (right) */}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-[minmax(0,1fr)_20rem]\">\n <GlassCard treatment=\"plain\" className=\"overflow-hidden\">\n <div className=\"grid grid-cols-1 sm:grid-cols-[minmax(0,15rem)_minmax(0,1fr)]\">\n <div className=\"relative h-44 w-full overflow-hidden bg-bg-sunken sm:h-full\">\n {course.cover?.downloadUrl ? (\n <img\n src={course.cover.downloadUrl}\n alt=\"\"\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"flex h-full min-h-[11rem] w-full items-center justify-center bg-[var(--color-accent-soft)]\">\n <BookOpen className=\"h-10 w-10 text-text-secondary opacity-60\" />\n </div>\n )}\n </div>\n\n <div className=\"flex flex-col gap-4 p-6\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={course.level} />\n <StatusBadge status={course.status} />\n </div>\n\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight text-text-primary\">\n {course.title}\n </h1>\n {course.summary && (\n <p className=\"mt-2 text-sm text-text-secondary\">{course.summary}</p>\n )}\n </div>\n\n <div className=\"flex flex-wrap gap-2\">\n {course.skill?.name && <MetaPill icon={Sparkles}>{course.skill.name}</MetaPill>}\n <MetaPill icon={Layers}>\n {modules.length} module{modules.length === 1 ? '' : 's'} · {totalLessons} lesson\n {totalLessons === 1 ? '' : 's'}\n </MetaPill>\n {course.estimatedHours > 0 && (\n <MetaPill icon={Clock}>{formatHours(course.estimatedHours)}</MetaPill>\n )}\n </div>\n\n {course.tags.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {course.tags.map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary\"\n >\n {tag}\n </span>\n ))}\n </div>\n )}\n\n {course.description && (\n <p className=\"whitespace-pre-wrap text-sm leading-relaxed text-text-secondary\">\n {course.description}\n </p>\n )}\n </div>\n </div>\n </GlassCard>\n\n {/* Enrol / progress card */}\n <GlassCard treatment=\"glass\" glow className=\"h-fit p-5 lg:sticky lg:top-4\">\n {activeEnrollment ? (\n <div className=\"flex flex-col gap-4\">\n <Button\n size=\"lg\"\n className=\"w-full\"\n onClick={() => navigateTo(`learning/${activeEnrollment.id}`)}\n >\n <PlayCircle className=\"mr-2 h-4 w-4\" /> Continue learning\n </Button>\n <div className=\"flex flex-col gap-1.5\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">Your progress</span>\n <span className=\"font-semibold tabular-nums text-text-primary\">\n {activeEnrollment.progressPct}%\n </span>\n </div>\n <MiniBar value={activeEnrollment.progressPct} />\n </div>\n <div className=\"flex items-center justify-between border-t border-border-seam pt-3 text-xs\">\n <span className=\"text-text-secondary\">Enrollment</span>\n <StatusBadge status={activeEnrollment.status} />\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col gap-4\">\n <BuiPermissionButton\n resource=\"buildmyiq-enrollment\"\n action=\"create\"\n deniedBehavior=\"tooltip\"\n >\n <Button\n size=\"lg\"\n className=\"w-full\"\n onClick={handleEnrol}\n disabled={enroll.isPending || !learnerId}\n >\n <GraduationCap className=\"mr-2 h-4 w-4\" />\n {enroll.isPending ? 'Enrolling…' : 'Enrol in this course'}\n {!enroll.isPending && <ArrowRight className=\"ml-2 h-4 w-4\" />}\n </Button>\n </BuiPermissionButton>\n {!learnerId && (\n <p className=\"text-xs text-text-tertiary\">Sign in to your workspace to enrol.</p>\n )}\n {enrolError && <p className=\"text-xs text-status-error-text\">{enrolError}</p>}\n <dl className=\"flex flex-col gap-2.5 border-t border-border-seam pt-3 text-sm\">\n <div className=\"flex items-center justify-between\">\n <dt className=\"inline-flex items-center gap-1.5 text-text-secondary\">\n <Layers className=\"h-3.5 w-3.5 text-text-tertiary\" /> Lessons\n </dt>\n <dd className=\"font-medium tabular-nums text-text-primary\">{totalLessons}</dd>\n </div>\n {course.estimatedHours > 0 && (\n <div className=\"flex items-center justify-between\">\n <dt className=\"inline-flex items-center gap-1.5 text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5 text-text-tertiary\" /> Duration\n </dt>\n <dd className=\"font-medium text-text-primary\">\n {formatHours(course.estimatedHours)}\n </dd>\n </div>\n )}\n <div className=\"flex items-center justify-between\">\n <dt className=\"inline-flex items-center gap-1.5 text-text-secondary\">\n <ClipboardCheck className=\"h-3.5 w-3.5 text-text-tertiary\" /> Assessments\n </dt>\n <dd className=\"font-medium tabular-nums text-text-primary\">\n {publishedAssessments}\n </dd>\n </div>\n </dl>\n </div>\n )}\n </GlassCard>\n </div>\n\n {/* Curriculum (left) + Assessments & Discussion (right) */}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-[minmax(0,1.7fr)_minmax(0,1fr)]\">\n {/* Curriculum */}\n <div>\n <Section\n title=\"Curriculum\"\n description=\"Modules and lessons in this course.\"\n action={\n groups.length > 1 ? (\n <button\n type=\"button\"\n onClick={toggleAll}\n className=\"text-sm font-medium text-[var(--color-accent-teal)] transition-colors hover:opacity-80\"\n >\n {allOpen ? 'Collapse all' : 'Expand all'}\n </button>\n ) : undefined\n }\n >\n {modulesQuery.isLoading ? (\n <LoadingView label=\"Loading curriculum…\" />\n ) : modulesQuery.isError ? (\n <ErrorView\n title=\"Couldn't load the curriculum\"\n message={\n modulesQuery.error instanceof Error ? modulesQuery.error.message : undefined\n }\n onRetry={() => modulesQuery.refetch()}\n />\n ) : groups.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No lessons yet\"\n description=\"The instructor hasn't added any modules or lessons to this course.\"\n />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {groups.map((group, index) => {\n const open = effectiveOpen.has(group.id);\n const panelId = `curriculum-panel-${group.id}`;\n return (\n <div\n key={group.id}\n className={cn(\n 'overflow-hidden rounded-xl border bg-bg-surface transition-colors',\n open ? 'border-[var(--color-accent-soft)]' : 'border-border-seam'\n )}\n >\n <button\n type=\"button\"\n onClick={() => toggleGroup(group.id)}\n aria-expanded={open}\n aria-controls={panelId}\n className=\"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <span className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-action-primary-bg text-xs font-semibold text-action-primary-text\">\n {index + 1}\n </span>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate font-semibold text-text-primary\">\n {group.title}\n </h3>\n {group.description && open && (\n <p className=\"mt-0.5 line-clamp-2 text-sm text-text-secondary\">\n {group.description}\n </p>\n )}\n </div>\n <span className=\"shrink-0 text-xs text-text-tertiary\">\n {group.lessons.length} lesson{group.lessons.length === 1 ? '' : 's'}\n </span>\n <ChevronDown\n className={cn(\n 'h-4 w-4 shrink-0 text-text-tertiary transition-transform',\n open && 'rotate-180'\n )}\n aria-hidden\n />\n </button>\n {open &&\n (group.lessons.length === 0 ? (\n <p className=\"border-t border-border-seam px-4 py-3 text-sm text-text-tertiary\">\n No lessons in this module yet.\n </p>\n ) : (\n <ul\n id={panelId}\n className=\"divide-y divide-border-seam border-t border-border-seam\"\n >\n {group.lessons.map((lesson, li) => (\n <LessonRow key={lesson.id} lesson={lesson} index={li} />\n ))}\n </ul>\n ))}\n </div>\n );\n })}\n </div>\n )}\n </Section>\n </div>\n\n {/* Assessments + Discussion */}\n <div className=\"flex flex-col gap-6\">\n <div>\n <Section title=\"Assessments\" description=\"Quizzes and exams for this course.\">\n {assessmentsQuery.isLoading ? (\n <LoadingView label=\"Loading assessments…\" />\n ) : assessmentsQuery.isError ? (\n <ErrorView\n title=\"Couldn't load assessments\"\n message={\n assessmentsQuery.error instanceof Error\n ? assessmentsQuery.error.message\n : undefined\n }\n onRetry={() => assessmentsQuery.refetch()}\n />\n ) : assessments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<ClipboardCheck className=\"h-9 w-9\" />}\n title=\"No assessments yet\"\n description=\"This course doesn't have any quizzes or exams attached.\"\n />\n ) : (\n <ul className=\"flex flex-col gap-3\">\n {assessments.map((assessment) => (\n <li\n key={assessment.id}\n className=\"rounded-xl border border-border-seam bg-bg-surface p-4\"\n >\n <div className=\"flex items-start gap-3\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <ClipboardCheck className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-medium text-text-primary\">{assessment.title}</p>\n <div className=\"mt-1.5 flex flex-wrap items-center gap-1.5\">\n <StatusBadge status={assessment.type} />\n <StatusBadge status={assessment.status} />\n </div>\n <div className=\"mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary\">\n <span>Pass ≥ {assessment.passingScore}%</span>\n <span>\n {assessment.maxAttempts} attempt\n {assessment.maxAttempts === 1 ? '' : 's'}\n </span>\n {assessment.timeLimitMin > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" />\n {formatDuration(assessment.timeLimitMin)}\n </span>\n )}\n </div>\n </div>\n </div>\n {assessment.status === 'PUBLISHED' && activeEnrollment && (\n <div className=\"mt-3 flex justify-end\">\n <Button\n size=\"sm\"\n onClick={() => navigateTo(`assessments/${assessment.id}/take`)}\n >\n Take\n </Button>\n </div>\n )}\n </li>\n ))}\n </ul>\n )}\n </Section>\n </div>\n\n {/* Discussion (platform wspace-conversations) */}\n <div>\n <BuiDiscussion\n entityType={COURSE_ENTITY}\n entityId={courseId}\n description=\"Ask questions and discuss this course with your workspace.\"\n />\n </div>\n </div>\n </div>\n\n {/* Tags (platform wspace-tags) — full width */}\n <div>\n <BuiTags entityType={COURSE_ENTITY} entityId={courseId} />\n </div>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CertificatesPage.d.ts","sourceRoot":"","sources":["../../../../src/buildmyiq/pages/certificates/CertificatesPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAqB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAmEnD,eAAO,MAAM,gBAAgB,EAAE,EA8e9B,CAAC"}
1
+ {"version":3,"file":"CertificatesPage.d.ts","sourceRoot":"","sources":["../../../../src/buildmyiq/pages/certificates/CertificatesPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAqB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAoEnD,eAAO,MAAM,gBAAgB,EAAE,EA4f9B,CAAC"}