@burdenoff/microfe-technospam 2026.704.2 → 2026.705.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/technospam/api/technospamApi.js +233 -150
- package/dist/technospam/api/technospamApi.js.map +1 -1
- package/dist/technospam/components/LoadMore.js +18 -2
- package/dist/technospam/components/LoadMore.js.map +1 -0
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js +664 -334
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js +79 -72
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +140 -87
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCoursesPagePage.js +75 -68
- package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesMyLearningPagePage.js +3 -0
- package/dist/technospam/pages/CoursesMyLearningPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js +76 -53
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js +36 -35
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorsPagePage.js +112 -103
- package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipSessionsPagePage.js +219 -110
- package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -6,41 +6,41 @@ import { StatusBadge as a } from "../components/StatusBadge.js";
|
|
|
6
6
|
import { EmptyView as o, ErrorView as s } from "../components/StateViews.js";
|
|
7
7
|
import "../components/index.js";
|
|
8
8
|
import { notify as c } from "../lib/toast.js";
|
|
9
|
-
import {
|
|
10
|
-
import { BookOpen as
|
|
11
|
-
import { useSearchParams as
|
|
12
|
-
import { jsx as
|
|
13
|
-
import { Badge as
|
|
9
|
+
import { useCertificatesQuery as l, useCourseQuery as u, useEnroll as d, useIssueCertificate as f, useUpdateProgress as p } from "../api/technospamApi.js";
|
|
10
|
+
import { Award as m, BookOpen as h, CheckCircle2 as g, Clock as _, FileText as v, Layers as y, Lock as b, PlayCircle as x, Sparkles as S } from "lucide-react";
|
|
11
|
+
import { useSearchParams as C } from "react-router-dom";
|
|
12
|
+
import { jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
13
|
+
import { Badge as E, Button as D, GlassCard as O, Skeleton as k } from "@burdenoff/fe-libs/ui";
|
|
14
14
|
//#region src/technospam/pages/CoursesCourseDetailsPagePage.tsx
|
|
15
|
-
var
|
|
16
|
-
VIDEO:
|
|
17
|
-
ARTICLE:
|
|
18
|
-
INTERACTIVE:
|
|
19
|
-
QUIZ:
|
|
20
|
-
PROJECT:
|
|
15
|
+
var A = {
|
|
16
|
+
VIDEO: x,
|
|
17
|
+
ARTICLE: v,
|
|
18
|
+
INTERACTIVE: S,
|
|
19
|
+
QUIZ: g,
|
|
20
|
+
PROJECT: y
|
|
21
21
|
};
|
|
22
|
-
function
|
|
23
|
-
let n =
|
|
24
|
-
return /* @__PURE__ */
|
|
22
|
+
function j({ lesson: e, done: t }) {
|
|
23
|
+
let n = A[e.kind] ?? v;
|
|
24
|
+
return /* @__PURE__ */ T("div", {
|
|
25
25
|
className: "flex items-center gap-3 border-b border-border-seam py-3 last:border-0",
|
|
26
26
|
children: [
|
|
27
|
-
/* @__PURE__ */
|
|
27
|
+
/* @__PURE__ */ w("span", {
|
|
28
28
|
className: `flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ${t ? "bg-status-success-bg-subtle text-status-success-text" : "bg-bg-sunken text-text-secondary"}`,
|
|
29
|
-
children:
|
|
29
|
+
children: w(t ? g : n, { size: 16 })
|
|
30
30
|
}),
|
|
31
|
-
/* @__PURE__ */
|
|
31
|
+
/* @__PURE__ */ T("div", {
|
|
32
32
|
className: "min-w-0 flex-1",
|
|
33
|
-
children: [/* @__PURE__ */
|
|
33
|
+
children: [/* @__PURE__ */ T("div", {
|
|
34
34
|
className: "flex items-center gap-2",
|
|
35
|
-
children: [/* @__PURE__ */
|
|
35
|
+
children: [/* @__PURE__ */ w("span", {
|
|
36
36
|
className: "truncate text-sm font-medium text-text-primary",
|
|
37
37
|
children: e.title
|
|
38
|
-
}), e.isPreview ? /* @__PURE__ */
|
|
38
|
+
}), e.isPreview ? /* @__PURE__ */ w(E, {
|
|
39
39
|
variant: "secondary",
|
|
40
40
|
className: "text-[11px]",
|
|
41
41
|
children: "Preview"
|
|
42
42
|
}) : null]
|
|
43
|
-
}), /* @__PURE__ */
|
|
43
|
+
}), /* @__PURE__ */ T("div", {
|
|
44
44
|
className: "text-xs text-text-muted",
|
|
45
45
|
children: [
|
|
46
46
|
i(e.kind),
|
|
@@ -49,152 +49,205 @@ function O({ lesson: e, done: t }) {
|
|
|
49
49
|
]
|
|
50
50
|
})]
|
|
51
51
|
}),
|
|
52
|
-
!e.isPreview && !t ? /* @__PURE__ */
|
|
52
|
+
!e.isPreview && !t ? /* @__PURE__ */ w(b, {
|
|
53
53
|
size: 14,
|
|
54
54
|
className: "text-text-muted"
|
|
55
55
|
}) : null
|
|
56
56
|
]
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
|
-
function
|
|
60
|
-
let [i] =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
function M() {
|
|
60
|
+
let [i] = C(), b = i.get("id") ?? "", { currentUser: x } = e(), { data: S, loading: A, error: M, refetch: N } = u(b), [P, { loading: F }] = d(), [I, { loading: L }] = p(), { data: R, refetch: z } = l(x?.id && b ? {
|
|
61
|
+
learnerId: x.id,
|
|
62
|
+
courseId: b
|
|
63
|
+
} : {}), [B, { loading: V }] = f(), H = S?.tecCourse ?? null, U = [...H?.lessons ?? []].sort((e, t) => e.position - t.position), W = (H?.enrollments ?? []).find((e) => e.learnerId === x?.id), G = (R?.tecListCertificates ?? []).find((e) => e.status === "ISSUED"), K = !!W && W.progressPct >= 100, q = async () => {
|
|
64
|
+
!b || !x?.id || (await B({ variables: {
|
|
65
|
+
courseId: b,
|
|
66
|
+
learnerId: x.id,
|
|
67
|
+
score: 100
|
|
68
|
+
} })).data?.tecIssueCertificate && (c.success("Certificate issued", "Your verifiable certificate is ready in My Learning."), await z());
|
|
69
|
+
}, J = async () => {
|
|
70
|
+
b && (await P({ variables: { input: { courseId: b } } })).data?.tecEnroll && (c.success("Enrolled", `You're enrolled in "${H?.title}".`), await N());
|
|
71
|
+
}, Y = async () => {
|
|
72
|
+
if (!W) return;
|
|
73
|
+
let e = Math.min(U.length, W.lessonsCompleted + 1), t = U.length ? Math.round(e / U.length * 100) : 100;
|
|
74
|
+
(await I({ variables: { input: {
|
|
75
|
+
enrollmentId: W.id,
|
|
67
76
|
lessonsCompleted: e,
|
|
68
77
|
progressPct: t
|
|
69
|
-
} } })).data?.tecUpdateProgress && (c.success("Progress saved", `${t}% complete`), await
|
|
78
|
+
} } })).data?.tecUpdateProgress && (c.success("Progress saved", `${t}% complete`), await N());
|
|
70
79
|
};
|
|
71
|
-
if (
|
|
80
|
+
if (A && !H) return /* @__PURE__ */ T(t, {
|
|
72
81
|
title: "Course",
|
|
73
82
|
backPath: "/courses/courses-page",
|
|
74
|
-
children: [/* @__PURE__ */
|
|
83
|
+
children: [/* @__PURE__ */ w(k, { className: "mb-4 h-40 w-full rounded-xl" }), /* @__PURE__ */ w(k, { className: "h-64 w-full rounded-xl" })]
|
|
75
84
|
});
|
|
76
|
-
if (
|
|
85
|
+
if (M || !H) return /* @__PURE__ */ w(t, {
|
|
77
86
|
title: "Course",
|
|
78
87
|
backPath: "/courses/courses-page",
|
|
79
|
-
children:
|
|
88
|
+
children: M ? /* @__PURE__ */ w(s, {
|
|
80
89
|
title: "Couldn't load course",
|
|
81
|
-
error:
|
|
82
|
-
}) : /* @__PURE__ */
|
|
90
|
+
error: M
|
|
91
|
+
}) : /* @__PURE__ */ w(o, {
|
|
83
92
|
title: "Course not found",
|
|
84
93
|
description: "This course may have been unpublished."
|
|
85
94
|
})
|
|
86
95
|
});
|
|
87
|
-
let
|
|
88
|
-
return /* @__PURE__ */
|
|
96
|
+
let X = W?.lessonsCompleted ?? 0;
|
|
97
|
+
return /* @__PURE__ */ T(t, {
|
|
89
98
|
hero: !0,
|
|
90
99
|
backPath: "/courses/courses-page",
|
|
91
|
-
title:
|
|
92
|
-
description:
|
|
93
|
-
actions:
|
|
94
|
-
onClick:
|
|
95
|
-
disabled:
|
|
96
|
-
children: [/* @__PURE__ */
|
|
97
|
-
}) : /* @__PURE__ */
|
|
98
|
-
onClick:
|
|
99
|
-
disabled:
|
|
100
|
+
title: H.title,
|
|
101
|
+
description: H.summary ?? void 0,
|
|
102
|
+
actions: W ? /* @__PURE__ */ T(D, {
|
|
103
|
+
onClick: Y,
|
|
104
|
+
disabled: L || X >= U.length,
|
|
105
|
+
children: [/* @__PURE__ */ w(g, { size: 16 }), X >= U.length ? "Completed" : "Complete next lesson"]
|
|
106
|
+
}) : /* @__PURE__ */ T(D, {
|
|
107
|
+
onClick: J,
|
|
108
|
+
disabled: F,
|
|
100
109
|
children: [
|
|
101
|
-
/* @__PURE__ */
|
|
110
|
+
/* @__PURE__ */ w(h, { size: 16 }),
|
|
102
111
|
" ",
|
|
103
|
-
|
|
112
|
+
F ? "Enrolling…" : "Enroll"
|
|
104
113
|
]
|
|
105
114
|
}),
|
|
106
115
|
children: [
|
|
107
|
-
/* @__PURE__ */
|
|
116
|
+
/* @__PURE__ */ T("div", {
|
|
108
117
|
className: "mb-5 flex flex-wrap items-center gap-2",
|
|
109
118
|
children: [
|
|
110
|
-
/* @__PURE__ */
|
|
111
|
-
status:
|
|
119
|
+
/* @__PURE__ */ w(a, {
|
|
120
|
+
status: H.level,
|
|
112
121
|
kind: "level"
|
|
113
122
|
}),
|
|
114
|
-
/* @__PURE__ */
|
|
115
|
-
|
|
123
|
+
/* @__PURE__ */ w(a, { status: H.status }),
|
|
124
|
+
H.topic ? /* @__PURE__ */ T(E, {
|
|
116
125
|
variant: "outline",
|
|
117
126
|
className: "gap-1",
|
|
118
127
|
children: [
|
|
119
|
-
/* @__PURE__ */
|
|
128
|
+
/* @__PURE__ */ w(y, { size: 12 }),
|
|
120
129
|
" ",
|
|
121
|
-
|
|
130
|
+
H.topic
|
|
122
131
|
]
|
|
123
132
|
}) : null,
|
|
124
|
-
|
|
133
|
+
H.tags.map((e) => /* @__PURE__ */ w(E, {
|
|
125
134
|
variant: "secondary",
|
|
126
135
|
children: e
|
|
127
136
|
}, e))
|
|
128
137
|
]
|
|
129
138
|
}),
|
|
130
|
-
/* @__PURE__ */
|
|
139
|
+
/* @__PURE__ */ T("div", {
|
|
131
140
|
className: "mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4",
|
|
132
141
|
children: [
|
|
133
|
-
/* @__PURE__ */
|
|
142
|
+
/* @__PURE__ */ w(n, {
|
|
134
143
|
label: "Lessons",
|
|
135
|
-
value:
|
|
136
|
-
icon:
|
|
144
|
+
value: U.length,
|
|
145
|
+
icon: v
|
|
137
146
|
}),
|
|
138
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ w(n, {
|
|
139
148
|
label: "Duration",
|
|
140
|
-
value: r(
|
|
141
|
-
icon:
|
|
149
|
+
value: r(H.estimatedMinutes),
|
|
150
|
+
icon: _
|
|
142
151
|
}),
|
|
143
|
-
/* @__PURE__ */
|
|
152
|
+
/* @__PURE__ */ w(n, {
|
|
144
153
|
label: "Enrolled",
|
|
145
|
-
value:
|
|
146
|
-
icon:
|
|
154
|
+
value: H.enrollments?.length ?? 0,
|
|
155
|
+
icon: h
|
|
147
156
|
}),
|
|
148
|
-
/* @__PURE__ */
|
|
157
|
+
/* @__PURE__ */ w(n, {
|
|
149
158
|
label: "Your progress",
|
|
150
|
-
value:
|
|
151
|
-
icon:
|
|
159
|
+
value: W ? `${W.progressPct}%` : "Not started",
|
|
160
|
+
icon: g
|
|
152
161
|
})
|
|
153
162
|
]
|
|
154
163
|
}),
|
|
155
|
-
|
|
164
|
+
W ? /* @__PURE__ */ T(O, {
|
|
156
165
|
className: "mb-6 p-4",
|
|
157
|
-
children: [/* @__PURE__ */
|
|
166
|
+
children: [/* @__PURE__ */ T("div", {
|
|
158
167
|
className: "mb-2 flex items-center justify-between text-sm",
|
|
159
|
-
children: [/* @__PURE__ */
|
|
168
|
+
children: [/* @__PURE__ */ w("span", {
|
|
160
169
|
className: "font-medium text-text-primary",
|
|
161
170
|
children: "Your progress"
|
|
162
|
-
}), /* @__PURE__ */
|
|
171
|
+
}), /* @__PURE__ */ T("span", {
|
|
163
172
|
className: "text-text-secondary",
|
|
164
173
|
children: [
|
|
165
|
-
|
|
174
|
+
X,
|
|
166
175
|
"/",
|
|
167
|
-
|
|
176
|
+
U.length,
|
|
168
177
|
" lessons · ",
|
|
169
|
-
|
|
178
|
+
W.progressPct,
|
|
170
179
|
"%"
|
|
171
180
|
]
|
|
172
181
|
})]
|
|
173
|
-
}), /* @__PURE__ */
|
|
182
|
+
}), /* @__PURE__ */ w("div", {
|
|
174
183
|
className: "h-2 w-full overflow-hidden rounded-full bg-bg-sunken",
|
|
175
|
-
children: /* @__PURE__ */
|
|
184
|
+
children: /* @__PURE__ */ w("div", {
|
|
176
185
|
className: "h-full rounded-full bg-accent-primary transition-all",
|
|
177
|
-
style: { width: `${
|
|
186
|
+
style: { width: `${W.progressPct}%` }
|
|
178
187
|
})
|
|
179
188
|
})]
|
|
180
189
|
}) : null,
|
|
181
|
-
/* @__PURE__ */
|
|
190
|
+
G ? /* @__PURE__ */ T(O, {
|
|
191
|
+
className: "mb-6 flex flex-wrap items-center gap-3 border-status-success-border p-4",
|
|
192
|
+
children: [/* @__PURE__ */ w(m, {
|
|
193
|
+
className: "text-accent-teal",
|
|
194
|
+
size: 22
|
|
195
|
+
}), /* @__PURE__ */ T("div", {
|
|
196
|
+
className: "min-w-0",
|
|
197
|
+
children: [/* @__PURE__ */ w("div", {
|
|
198
|
+
className: "text-sm font-semibold text-text-primary",
|
|
199
|
+
children: "Certificate earned"
|
|
200
|
+
}), /* @__PURE__ */ T("div", {
|
|
201
|
+
className: "text-xs text-text-muted",
|
|
202
|
+
children: [
|
|
203
|
+
"Serial ",
|
|
204
|
+
G.serial,
|
|
205
|
+
" · Score ",
|
|
206
|
+
G.score
|
|
207
|
+
]
|
|
208
|
+
})]
|
|
209
|
+
})]
|
|
210
|
+
}) : K ? /* @__PURE__ */ T(O, {
|
|
211
|
+
className: "mb-6 flex flex-wrap items-center justify-between gap-3 p-4",
|
|
212
|
+
children: [/* @__PURE__ */ T("div", {
|
|
213
|
+
className: "flex items-center gap-3",
|
|
214
|
+
children: [/* @__PURE__ */ w(m, {
|
|
215
|
+
className: "text-accent-teal",
|
|
216
|
+
size: 22
|
|
217
|
+
}), /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("div", {
|
|
218
|
+
className: "text-sm font-semibold text-text-primary",
|
|
219
|
+
children: "You finished this course"
|
|
220
|
+
}), /* @__PURE__ */ w("div", {
|
|
221
|
+
className: "text-xs text-text-muted",
|
|
222
|
+
children: "Claim your verifiable certificate of completion."
|
|
223
|
+
})] })]
|
|
224
|
+
}), /* @__PURE__ */ T(D, {
|
|
225
|
+
onClick: q,
|
|
226
|
+
disabled: V,
|
|
227
|
+
children: [
|
|
228
|
+
/* @__PURE__ */ w(m, { size: 16 }),
|
|
229
|
+
" ",
|
|
230
|
+
V ? "Issuing…" : "Claim certificate"
|
|
231
|
+
]
|
|
232
|
+
})]
|
|
233
|
+
}) : null,
|
|
234
|
+
/* @__PURE__ */ T(O, {
|
|
182
235
|
className: "p-5",
|
|
183
|
-
children: [/* @__PURE__ */
|
|
236
|
+
children: [/* @__PURE__ */ w("h2", {
|
|
184
237
|
className: "mb-2 text-base font-semibold text-text-primary",
|
|
185
238
|
children: "Curriculum"
|
|
186
|
-
}),
|
|
239
|
+
}), U.length === 0 ? /* @__PURE__ */ w("p", {
|
|
187
240
|
className: "py-6 text-center text-sm text-text-muted",
|
|
188
241
|
children: "Lessons for this course are being prepared."
|
|
189
|
-
}) : /* @__PURE__ */
|
|
242
|
+
}) : /* @__PURE__ */ w("div", { children: U.map((e, t) => /* @__PURE__ */ w(j, {
|
|
190
243
|
lesson: e,
|
|
191
|
-
done: t <
|
|
244
|
+
done: t < X
|
|
192
245
|
}, e.id)) })]
|
|
193
246
|
})
|
|
194
247
|
]
|
|
195
248
|
});
|
|
196
249
|
}
|
|
197
250
|
//#endregion
|
|
198
|
-
export {
|
|
251
|
+
export { M as CoursesCourseDetailsPagePage };
|
|
199
252
|
|
|
200
253
|
//# sourceMappingURL=CoursesCourseDetailsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CoursesCourseDetailsPagePage.js","names":[],"sources":["../../../src/technospam/pages/CoursesCourseDetailsPagePage.tsx"],"sourcesContent":["import { useSearchParams } from 'react-router-dom';\nimport {\n BookOpen,\n CheckCircle2,\n Clock,\n FileText,\n Lock,\n PlayCircle,\n Layers,\n Sparkles,\n} from 'lucide-react';\nimport { Badge, Button, GlassCard, Skeleton } from '@burdenoff/fe-libs/ui';\nimport { EmptyView, ErrorView, PageLayout, StatCard, StatusBadge } from '../components';\nimport { useTechnoSpam } from '../providers/TechnoSpamProvider';\nimport {\n useCourseQuery,\n useEnroll,\n useUpdateProgress,\n type TecLesson,\n type TecEnrollment,\n} from '../api/technospamApi';\nimport { formatDuration, humanizeEnum } from '../utils/format';\nimport { notify } from '../lib/toast';\n\nconst LESSON_ICON: Record<string, typeof PlayCircle> = {\n VIDEO: PlayCircle,\n ARTICLE: FileText,\n INTERACTIVE: Sparkles,\n QUIZ: CheckCircle2,\n PROJECT: Layers,\n};\n\nfunction LessonRow({ lesson, done }: { lesson: TecLesson; done: boolean }) {\n const Icon = LESSON_ICON[lesson.kind] ?? FileText;\n return (\n <div className=\"flex items-center gap-3 border-b border-border-seam py-3 last:border-0\">\n <span\n className={`flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ${\n done\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {done ? <CheckCircle2 size={16} /> : <Icon size={16} />}\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"truncate text-sm font-medium text-text-primary\">{lesson.title}</span>\n {lesson.isPreview ? (\n <Badge variant=\"secondary\" className=\"text-[11px]\">\n Preview\n </Badge>\n ) : null}\n </div>\n <div className=\"text-xs text-text-muted\">\n {humanizeEnum(lesson.kind)} · {formatDuration(lesson.estimatedMinutes)}\n </div>\n </div>\n {!lesson.isPreview && !done ? <Lock size={14} className=\"text-text-muted\" /> : null}\n </div>\n );\n}\n\nexport function CoursesCourseDetailsPagePage() {\n const [params] = useSearchParams();\n const id = params.get('id') ?? '';\n const { currentUser } = useTechnoSpam();\n const { data, loading, error, refetch } = useCourseQuery(id);\n const [enroll, { loading: enrolling }] = useEnroll();\n const [updateProgress, { loading: savingProgress }] = useUpdateProgress();\n\n const course = data?.tecCourse ?? null;\n const lessons = [...(course?.lessons ?? [])].sort((a, b) => a.position - b.position);\n const myEnrollment: TecEnrollment | undefined = (course?.enrollments ?? []).find(\n (e) => e.learnerId === currentUser?.id\n );\n\n const handleEnroll = async () => {\n if (!id) return;\n const res = await enroll({ variables: { input: { courseId: id } } });\n if (res.data?.tecEnroll) {\n notify.success('Enrolled', `You're enrolled in \"${course?.title}\".`);\n await refetch();\n }\n };\n\n const handleProgress = async () => {\n if (!myEnrollment) return;\n const nextCompleted = Math.min(lessons.length, myEnrollment.lessonsCompleted + 1);\n const pct = lessons.length ? Math.round((nextCompleted / lessons.length) * 100) : 100;\n const res = await updateProgress({\n variables: {\n input: { enrollmentId: myEnrollment.id, lessonsCompleted: nextCompleted, progressPct: pct },\n },\n });\n if (res.data?.tecUpdateProgress) {\n notify.success('Progress saved', `${pct}% complete`);\n await refetch();\n }\n };\n\n if (loading && !course) {\n return (\n <PageLayout title=\"Course\" backPath=\"/courses/courses-page\">\n <Skeleton className=\"mb-4 h-40 w-full rounded-xl\" />\n <Skeleton className=\"h-64 w-full rounded-xl\" />\n </PageLayout>\n );\n }\n\n if (error || !course) {\n return (\n <PageLayout title=\"Course\" backPath=\"/courses/courses-page\">\n {error ? (\n <ErrorView title=\"Couldn't load course\" error={error} />\n ) : (\n <EmptyView\n title=\"Course not found\"\n description=\"This course may have been unpublished.\"\n />\n )}\n </PageLayout>\n );\n }\n\n const completedLessons = myEnrollment?.lessonsCompleted ?? 0;\n\n return (\n <PageLayout\n hero\n backPath=\"/courses/courses-page\"\n title={course.title}\n description={course.summary ?? undefined}\n actions={\n myEnrollment ? (\n <Button\n onClick={handleProgress}\n disabled={savingProgress || completedLessons >= lessons.length}\n >\n <CheckCircle2 size={16} />\n {completedLessons >= lessons.length ? 'Completed' : 'Complete next lesson'}\n </Button>\n ) : (\n <Button onClick={handleEnroll} disabled={enrolling}>\n <BookOpen size={16} /> {enrolling ? 'Enrolling…' : 'Enroll'}\n </Button>\n )\n }\n >\n <div className=\"mb-5 flex flex-wrap items-center gap-2\">\n <StatusBadge status={course.level} kind=\"level\" />\n <StatusBadge status={course.status} />\n {course.topic ? (\n <Badge variant=\"outline\" className=\"gap-1\">\n <Layers size={12} /> {course.topic}\n </Badge>\n ) : null}\n {course.tags.map((t) => (\n <Badge key={t} variant=\"secondary\">\n {t}\n </Badge>\n ))}\n </div>\n\n <div className=\"mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard label=\"Lessons\" value={lessons.length} icon={FileText} />\n <StatCard label=\"Duration\" value={formatDuration(course.estimatedMinutes)} icon={Clock} />\n <StatCard label=\"Enrolled\" value={course.enrollments?.length ?? 0} icon={BookOpen} />\n <StatCard\n label=\"Your progress\"\n value={myEnrollment ? `${myEnrollment.progressPct}%` : 'Not started'}\n icon={CheckCircle2}\n />\n </div>\n\n {myEnrollment ? (\n <GlassCard className=\"mb-6 p-4\">\n <div className=\"mb-2 flex items-center justify-between text-sm\">\n <span className=\"font-medium text-text-primary\">Your progress</span>\n <span className=\"text-text-secondary\">\n {completedLessons}/{lessons.length} lessons · {myEnrollment.progressPct}%\n </span>\n </div>\n <div className=\"h-2 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-accent-primary transition-all\"\n style={{ width: `${myEnrollment.progressPct}%` }}\n />\n </div>\n </GlassCard>\n ) : null}\n\n <GlassCard className=\"p-5\">\n <h2 className=\"mb-2 text-base font-semibold text-text-primary\">Curriculum</h2>\n {lessons.length === 0 ? (\n <p className=\"py-6 text-center text-sm text-text-muted\">\n Lessons for this course are being prepared.\n </p>\n ) : (\n <div>\n {lessons.map((lesson, i) => (\n <LessonRow key={lesson.id} lesson={lesson} done={i < completedLessons} />\n ))}\n </div>\n )}\n </GlassCard>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CoursesCourseDetailsPagePage.js","names":[],"sources":["../../../src/technospam/pages/CoursesCourseDetailsPagePage.tsx"],"sourcesContent":["import { useSearchParams } from 'react-router-dom';\nimport {\n Award,\n BookOpen,\n CheckCircle2,\n Clock,\n FileText,\n Lock,\n PlayCircle,\n Layers,\n Sparkles,\n} from 'lucide-react';\nimport { Badge, Button, GlassCard, Skeleton } from '@burdenoff/fe-libs/ui';\nimport { EmptyView, ErrorView, PageLayout, StatCard, StatusBadge } from '../components';\nimport { useTechnoSpam } from '../providers/TechnoSpamProvider';\nimport {\n useCertificatesQuery,\n useCourseQuery,\n useEnroll,\n useIssueCertificate,\n useUpdateProgress,\n type TecLesson,\n type TecEnrollment,\n} from '../api/technospamApi';\nimport { formatDuration, humanizeEnum } from '../utils/format';\nimport { notify } from '../lib/toast';\n\nconst LESSON_ICON: Record<string, typeof PlayCircle> = {\n VIDEO: PlayCircle,\n ARTICLE: FileText,\n INTERACTIVE: Sparkles,\n QUIZ: CheckCircle2,\n PROJECT: Layers,\n};\n\nfunction LessonRow({ lesson, done }: { lesson: TecLesson; done: boolean }) {\n const Icon = LESSON_ICON[lesson.kind] ?? FileText;\n return (\n <div className=\"flex items-center gap-3 border-b border-border-seam py-3 last:border-0\">\n <span\n className={`flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ${\n done\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {done ? <CheckCircle2 size={16} /> : <Icon size={16} />}\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"truncate text-sm font-medium text-text-primary\">{lesson.title}</span>\n {lesson.isPreview ? (\n <Badge variant=\"secondary\" className=\"text-[11px]\">\n Preview\n </Badge>\n ) : null}\n </div>\n <div className=\"text-xs text-text-muted\">\n {humanizeEnum(lesson.kind)} · {formatDuration(lesson.estimatedMinutes)}\n </div>\n </div>\n {!lesson.isPreview && !done ? <Lock size={14} className=\"text-text-muted\" /> : null}\n </div>\n );\n}\n\nexport function CoursesCourseDetailsPagePage() {\n const [params] = useSearchParams();\n const id = params.get('id') ?? '';\n const { currentUser } = useTechnoSpam();\n const { data, loading, error, refetch } = useCourseQuery(id);\n const [enroll, { loading: enrolling }] = useEnroll();\n const [updateProgress, { loading: savingProgress }] = useUpdateProgress();\n const { data: certData, refetch: refetchCerts } = useCertificatesQuery(\n currentUser?.id && id ? { learnerId: currentUser.id, courseId: id } : {}\n );\n const [issueCertificate, { loading: claiming }] = useIssueCertificate();\n\n const course = data?.tecCourse ?? null;\n const lessons = [...(course?.lessons ?? [])].sort((a, b) => a.position - b.position);\n const myEnrollment: TecEnrollment | undefined = (course?.enrollments ?? []).find(\n (e) => e.learnerId === currentUser?.id\n );\n const myCertificate = (certData?.tecListCertificates ?? []).find((c) => c.status === 'ISSUED');\n const isComplete = !!myEnrollment && myEnrollment.progressPct >= 100;\n\n const handleClaimCertificate = async () => {\n if (!id || !currentUser?.id) return;\n const res = await issueCertificate({\n variables: { courseId: id, learnerId: currentUser.id, score: 100 },\n });\n if (res.data?.tecIssueCertificate) {\n notify.success('Certificate issued', 'Your verifiable certificate is ready in My Learning.');\n await refetchCerts();\n }\n };\n\n const handleEnroll = async () => {\n if (!id) return;\n const res = await enroll({ variables: { input: { courseId: id } } });\n if (res.data?.tecEnroll) {\n notify.success('Enrolled', `You're enrolled in \"${course?.title}\".`);\n await refetch();\n }\n };\n\n const handleProgress = async () => {\n if (!myEnrollment) return;\n const nextCompleted = Math.min(lessons.length, myEnrollment.lessonsCompleted + 1);\n const pct = lessons.length ? Math.round((nextCompleted / lessons.length) * 100) : 100;\n const res = await updateProgress({\n variables: {\n input: { enrollmentId: myEnrollment.id, lessonsCompleted: nextCompleted, progressPct: pct },\n },\n });\n if (res.data?.tecUpdateProgress) {\n notify.success('Progress saved', `${pct}% complete`);\n await refetch();\n }\n };\n\n if (loading && !course) {\n return (\n <PageLayout title=\"Course\" backPath=\"/courses/courses-page\">\n <Skeleton className=\"mb-4 h-40 w-full rounded-xl\" />\n <Skeleton className=\"h-64 w-full rounded-xl\" />\n </PageLayout>\n );\n }\n\n if (error || !course) {\n return (\n <PageLayout title=\"Course\" backPath=\"/courses/courses-page\">\n {error ? (\n <ErrorView title=\"Couldn't load course\" error={error} />\n ) : (\n <EmptyView\n title=\"Course not found\"\n description=\"This course may have been unpublished.\"\n />\n )}\n </PageLayout>\n );\n }\n\n const completedLessons = myEnrollment?.lessonsCompleted ?? 0;\n\n return (\n <PageLayout\n hero\n backPath=\"/courses/courses-page\"\n title={course.title}\n description={course.summary ?? undefined}\n actions={\n myEnrollment ? (\n <Button\n onClick={handleProgress}\n disabled={savingProgress || completedLessons >= lessons.length}\n >\n <CheckCircle2 size={16} />\n {completedLessons >= lessons.length ? 'Completed' : 'Complete next lesson'}\n </Button>\n ) : (\n <Button onClick={handleEnroll} disabled={enrolling}>\n <BookOpen size={16} /> {enrolling ? 'Enrolling…' : 'Enroll'}\n </Button>\n )\n }\n >\n <div className=\"mb-5 flex flex-wrap items-center gap-2\">\n <StatusBadge status={course.level} kind=\"level\" />\n <StatusBadge status={course.status} />\n {course.topic ? (\n <Badge variant=\"outline\" className=\"gap-1\">\n <Layers size={12} /> {course.topic}\n </Badge>\n ) : null}\n {course.tags.map((t) => (\n <Badge key={t} variant=\"secondary\">\n {t}\n </Badge>\n ))}\n </div>\n\n <div className=\"mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard label=\"Lessons\" value={lessons.length} icon={FileText} />\n <StatCard label=\"Duration\" value={formatDuration(course.estimatedMinutes)} icon={Clock} />\n <StatCard label=\"Enrolled\" value={course.enrollments?.length ?? 0} icon={BookOpen} />\n <StatCard\n label=\"Your progress\"\n value={myEnrollment ? `${myEnrollment.progressPct}%` : 'Not started'}\n icon={CheckCircle2}\n />\n </div>\n\n {myEnrollment ? (\n <GlassCard className=\"mb-6 p-4\">\n <div className=\"mb-2 flex items-center justify-between text-sm\">\n <span className=\"font-medium text-text-primary\">Your progress</span>\n <span className=\"text-text-secondary\">\n {completedLessons}/{lessons.length} lessons · {myEnrollment.progressPct}%\n </span>\n </div>\n <div className=\"h-2 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-accent-primary transition-all\"\n style={{ width: `${myEnrollment.progressPct}%` }}\n />\n </div>\n </GlassCard>\n ) : null}\n\n {myCertificate ? (\n <GlassCard className=\"mb-6 flex flex-wrap items-center gap-3 border-status-success-border p-4\">\n <Award className=\"text-accent-teal\" size={22} />\n <div className=\"min-w-0\">\n <div className=\"text-sm font-semibold text-text-primary\">Certificate earned</div>\n <div className=\"text-xs text-text-muted\">\n Serial {myCertificate.serial} · Score {myCertificate.score}\n </div>\n </div>\n </GlassCard>\n ) : isComplete ? (\n <GlassCard className=\"mb-6 flex flex-wrap items-center justify-between gap-3 p-4\">\n <div className=\"flex items-center gap-3\">\n <Award className=\"text-accent-teal\" size={22} />\n <div>\n <div className=\"text-sm font-semibold text-text-primary\">\n You finished this course\n </div>\n <div className=\"text-xs text-text-muted\">\n Claim your verifiable certificate of completion.\n </div>\n </div>\n </div>\n <Button onClick={handleClaimCertificate} disabled={claiming}>\n <Award size={16} /> {claiming ? 'Issuing…' : 'Claim certificate'}\n </Button>\n </GlassCard>\n ) : null}\n\n <GlassCard className=\"p-5\">\n <h2 className=\"mb-2 text-base font-semibold text-text-primary\">Curriculum</h2>\n {lessons.length === 0 ? (\n <p className=\"py-6 text-center text-sm text-text-muted\">\n Lessons for this course are being prepared.\n </p>\n ) : (\n <div>\n {lessons.map((lesson, i) => (\n <LessonRow key={lesson.id} lesson={lesson} done={i < completedLessons} />\n ))}\n </div>\n )}\n </GlassCard>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|