@burdenoff/microfe-buildmyiq 2026.705.13 → 2026.706.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/buildmyiq/BuildmyiqRoot.d.ts.map +1 -1
- package/dist/buildmyiq/BuildmyiqRoot.js +57 -49
- package/dist/buildmyiq/BuildmyiqRoot.js.map +1 -1
- package/dist/buildmyiq/BuildmyiqRoutes.d.ts.map +1 -1
- package/dist/buildmyiq/BuildmyiqRoutes.js +15 -11
- package/dist/buildmyiq/BuildmyiqRoutes.js.map +1 -1
- package/dist/buildmyiq/components/Avatar.d.ts +15 -0
- package/dist/buildmyiq/components/Avatar.d.ts.map +1 -0
- package/dist/buildmyiq/components/Avatar.js +42 -0
- package/dist/buildmyiq/components/Avatar.js.map +1 -0
- package/dist/buildmyiq/components/Viz.d.ts +25 -0
- package/dist/buildmyiq/components/Viz.d.ts.map +1 -0
- package/dist/buildmyiq/components/Viz.js +78 -0
- package/dist/buildmyiq/components/Viz.js.map +1 -0
- package/dist/buildmyiq/components/index.d.ts +2 -0
- package/dist/buildmyiq/components/index.d.ts.map +1 -1
- package/dist/buildmyiq/components/index.js +2 -0
- package/dist/buildmyiq/pages/DashboardPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/DashboardPage.js +200 -98
- package/dist/buildmyiq/pages/DashboardPage.js.map +1 -1
- package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.js +262 -241
- package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.js.map +1 -1
- package/dist/buildmyiq/pages/assessments/AssessmentsPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/assessments/AssessmentsPage.js +142 -115
- package/dist/buildmyiq/pages/assessments/AssessmentsPage.js.map +1 -1
- package/dist/buildmyiq/pages/assessments/TakeAssessmentPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/assessments/TakeAssessmentPage.js +220 -156
- package/dist/buildmyiq/pages/assessments/TakeAssessmentPage.js.map +1 -1
- package/dist/buildmyiq/pages/authoring/AuthoringPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/authoring/AuthoringPage.js +51 -46
- package/dist/buildmyiq/pages/authoring/AuthoringPage.js.map +1 -1
- package/dist/buildmyiq/pages/authoring/CourseBuilderPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/authoring/CourseBuilderPage.js +581 -448
- package/dist/buildmyiq/pages/authoring/CourseBuilderPage.js.map +1 -1
- package/dist/buildmyiq/pages/catalog/CatalogPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/catalog/CatalogPage.js +52 -42
- package/dist/buildmyiq/pages/catalog/CatalogPage.js.map +1 -1
- package/dist/buildmyiq/pages/catalog/CourseDetailPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/catalog/CourseDetailPage.js +422 -301
- package/dist/buildmyiq/pages/catalog/CourseDetailPage.js.map +1 -1
- package/dist/buildmyiq/pages/certificates/CertificatesPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/certificates/CertificatesPage.js +237 -151
- package/dist/buildmyiq/pages/certificates/CertificatesPage.js.map +1 -1
- package/dist/buildmyiq/pages/cohorts/CohortsPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/cohorts/CohortsPage.js +219 -138
- package/dist/buildmyiq/pages/cohorts/CohortsPage.js.map +1 -1
- package/dist/buildmyiq/pages/insights/InsightsPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/insights/InsightsPage.js +276 -152
- package/dist/buildmyiq/pages/insights/InsightsPage.js.map +1 -1
- package/dist/buildmyiq/pages/learning/LessonPlayerPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/learning/LessonPlayerPage.js +237 -174
- package/dist/buildmyiq/pages/learning/LessonPlayerPage.js.map +1 -1
- package/dist/buildmyiq/pages/learning/MyLearningPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/learning/MyLearningPage.js +307 -169
- package/dist/buildmyiq/pages/learning/MyLearningPage.js.map +1 -1
- package/dist/buildmyiq/pages/paths/PathsPage.d.ts +4 -0
- package/dist/buildmyiq/pages/paths/PathsPage.d.ts.map +1 -0
- package/dist/buildmyiq/pages/paths/PathsPage.js +187 -0
- package/dist/buildmyiq/pages/paths/PathsPage.js.map +1 -0
- package/dist/buildmyiq/pages/skills/SkillsPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/skills/SkillsPage.js +233 -140
- package/dist/buildmyiq/pages/skills/SkillsPage.js.map +1 -1
- package/dist/buildmyiq/pages/submissions/SubmissionsPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/submissions/SubmissionsPage.js +379 -275
- package/dist/buildmyiq/pages/submissions/SubmissionsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,214 +1,259 @@
|
|
|
1
1
|
import { useBuildmyiq as e } from "../../context/BuildmyiqContext.js";
|
|
2
2
|
import { cn as t } from "../../utils/cn.js";
|
|
3
3
|
import { PageLayout as n } from "../../components/PageLayout.js";
|
|
4
|
-
import { formatDuration as r } from "../../utils/formatters.js";
|
|
5
|
-
import { StatusBadge as
|
|
6
|
-
import { EmptyState as
|
|
7
|
-
import { ErrorView as
|
|
4
|
+
import { formatDuration as r, formatEnumLabel as i } from "../../utils/formatters.js";
|
|
5
|
+
import { StatusBadge as a } from "../../components/StatusBadge.js";
|
|
6
|
+
import { EmptyState as o } from "../../components/EmptyState.js";
|
|
7
|
+
import { ErrorView as s, LoadingView as c } from "../../components/StateViews.js";
|
|
8
|
+
import { ProgressRing as l } from "../../components/Viz.js";
|
|
8
9
|
import "../../context/index.js";
|
|
9
|
-
import { useBuiAssessment as
|
|
10
|
+
import { useBuiAssessment as u, useBuiEnrollments as d, useBuiSubmitAssessment as f } from "../../hooks/useBuildmyiqApi.js";
|
|
10
11
|
import "../../hooks/index.js";
|
|
11
12
|
import "../../components/index.js";
|
|
12
|
-
import { useMemo as
|
|
13
|
-
import { ArrowLeft as
|
|
14
|
-
import { useParams as
|
|
15
|
-
import { jsx as
|
|
16
|
-
import { Button as
|
|
13
|
+
import { useMemo as p, useState as m } from "react";
|
|
14
|
+
import { ArrowLeft as h, CheckCircle2 as g, ClipboardCheck as _, Clock as v, FileText as y, RefreshCw as b, Send as x, Target as S } from "lucide-react";
|
|
15
|
+
import { useParams as C } from "react-router-dom";
|
|
16
|
+
import { jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
17
|
+
import { Button as E, GlassCard as D, Input as O, Textarea as k } from "@burdenoff/fe-libs/ui";
|
|
17
18
|
//#region src/buildmyiq/pages/assessments/TakeAssessmentPage.tsx
|
|
18
|
-
function
|
|
19
|
+
function A(e) {
|
|
19
20
|
return Array.isArray(e) ? e.map((e) => e && typeof e == "object" && "label" in e ? { label: String(e.label) } : null).filter((e) => e !== null && e.label.length > 0) : [];
|
|
20
21
|
}
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
})
|
|
27
|
-
|
|
22
|
+
var j = [{ label: "True" }, { label: "False" }], M = ({ icon: e, label: t, value: n }) => /* @__PURE__ */ T("div", {
|
|
23
|
+
className: "flex items-center gap-3 py-3 first:pt-0 last:pb-0 sm:px-5 sm:py-0 sm:first:pl-0 sm:last:pr-0",
|
|
24
|
+
children: [/* @__PURE__ */ w("span", {
|
|
25
|
+
className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-[var(--color-accent-teal)]",
|
|
26
|
+
children: e
|
|
27
|
+
}), /* @__PURE__ */ T("div", {
|
|
28
|
+
className: "min-w-0",
|
|
29
|
+
children: [/* @__PURE__ */ w("p", {
|
|
30
|
+
className: "text-xs text-text-secondary",
|
|
31
|
+
children: t
|
|
32
|
+
}), /* @__PURE__ */ w("p", {
|
|
33
|
+
className: "text-sm font-semibold text-text-primary",
|
|
34
|
+
children: n
|
|
35
|
+
})]
|
|
36
|
+
})]
|
|
37
|
+
}), N = () => {
|
|
38
|
+
let { assessmentId: N } = C(), { currentUser: P, navigateTo: F } = e(), I = u(N), L = I.data ?? null, R = d({
|
|
39
|
+
learnerId: P?.id,
|
|
40
|
+
courseId: L?.courseId,
|
|
41
|
+
enabled: !!(P?.id && L?.courseId)
|
|
42
|
+
}).data?.items?.[0]?.id, z = f(), [B, V] = m({}), [H, U] = m(null), W = p(() => [...L?.questions ?? []].sort((e, t) => e.position - t.position), [L]), G = (e, t) => {
|
|
43
|
+
V((n) => ({
|
|
28
44
|
...n,
|
|
29
45
|
[e]: t
|
|
30
46
|
}));
|
|
31
|
-
},
|
|
32
|
-
|
|
47
|
+
}, K = (e, t) => {
|
|
48
|
+
V((n) => {
|
|
33
49
|
let r = Array.isArray(n[e]) ? n[e] : [];
|
|
34
50
|
return {
|
|
35
51
|
...n,
|
|
36
52
|
[e]: r.includes(t) ? r.filter((e) => e !== t) : [...r, t]
|
|
37
53
|
};
|
|
38
54
|
});
|
|
39
|
-
},
|
|
40
|
-
let t =
|
|
55
|
+
}, q = (e) => {
|
|
56
|
+
let t = B[e.id];
|
|
41
57
|
return Array.isArray(t) ? t.length > 0 : !!(t && String(t).trim());
|
|
42
|
-
}).length,
|
|
43
|
-
|
|
44
|
-
assessmentId:
|
|
45
|
-
enrollmentId:
|
|
58
|
+
}, J = W.filter(q).length, Y = W.length > 0 ? J / W.length * 100 : 0, X = W.length - J, Z = J === 0 ? "Answer a question to get started." : X === 0 ? "All questions answered — ready to submit." : `${X} question${X === 1 ? "" : "s"} left to answer.`, Q = async () => {
|
|
59
|
+
N && U((await z.mutateAsync({
|
|
60
|
+
assessmentId: N,
|
|
61
|
+
enrollmentId: R,
|
|
46
62
|
attempt: 1,
|
|
47
|
-
answers:
|
|
63
|
+
answers: B
|
|
48
64
|
})).id);
|
|
49
|
-
},
|
|
65
|
+
}, $ = L ? /* @__PURE__ */ T(E, {
|
|
50
66
|
variant: "ghost",
|
|
51
67
|
size: "sm",
|
|
52
|
-
onClick: () =>
|
|
53
|
-
children: [/* @__PURE__ */
|
|
68
|
+
onClick: () => F(`catalog/${L.courseId}`),
|
|
69
|
+
children: [/* @__PURE__ */ w(h, { className: "mr-1 h-4 w-4" }), " Back to course"]
|
|
54
70
|
}) : void 0;
|
|
55
|
-
return
|
|
71
|
+
return N ? I.isLoading ? /* @__PURE__ */ w(n, {
|
|
56
72
|
title: "Assessment",
|
|
57
|
-
children: /* @__PURE__ */
|
|
58
|
-
}) :
|
|
73
|
+
children: /* @__PURE__ */ w(c, { label: "Loading the assessment…" })
|
|
74
|
+
}) : I.isError || !L ? /* @__PURE__ */ w(n, {
|
|
59
75
|
title: "Assessment",
|
|
60
|
-
actions:
|
|
61
|
-
children: /* @__PURE__ */
|
|
76
|
+
actions: $,
|
|
77
|
+
children: /* @__PURE__ */ w(s, {
|
|
62
78
|
title: "Couldn't load this assessment",
|
|
63
|
-
message:
|
|
64
|
-
onRetry: () =>
|
|
79
|
+
message: I.error instanceof Error ? I.error.message : void 0,
|
|
80
|
+
onRetry: () => I.refetch()
|
|
65
81
|
})
|
|
66
|
-
}) :
|
|
67
|
-
title:
|
|
68
|
-
actions:
|
|
69
|
-
children: /* @__PURE__ */
|
|
82
|
+
}) : L.status === "PUBLISHED" ? H ? /* @__PURE__ */ w(n, {
|
|
83
|
+
title: L.title,
|
|
84
|
+
actions: $,
|
|
85
|
+
children: /* @__PURE__ */ w("div", {
|
|
70
86
|
className: "mx-auto max-w-lg",
|
|
71
|
-
children: /* @__PURE__ */
|
|
87
|
+
children: /* @__PURE__ */ T(D, {
|
|
72
88
|
treatment: "glass",
|
|
73
89
|
glow: !0,
|
|
74
90
|
className: "flex flex-col items-center gap-4 p-8 text-center",
|
|
75
91
|
children: [
|
|
76
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ w("div", {
|
|
77
93
|
className: "flex h-14 w-14 items-center justify-center rounded-full bg-status-success-bg-subtle",
|
|
78
|
-
children: /* @__PURE__ */
|
|
94
|
+
children: /* @__PURE__ */ w(g, { className: "h-7 w-7 text-status-success-text" })
|
|
79
95
|
}),
|
|
80
|
-
/* @__PURE__ */
|
|
96
|
+
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("h2", {
|
|
81
97
|
className: "text-lg font-semibold text-text-primary",
|
|
82
98
|
children: "Submitted"
|
|
83
|
-
}), /* @__PURE__ */
|
|
99
|
+
}), /* @__PURE__ */ T("p", {
|
|
84
100
|
className: "mt-1 text-sm text-text-secondary",
|
|
85
101
|
children: [
|
|
86
102
|
"Your answers for “",
|
|
87
|
-
|
|
103
|
+
L.title,
|
|
88
104
|
"” were submitted.",
|
|
89
|
-
|
|
105
|
+
L.isGraded ? " An educator will grade them — you’ll see your score and feedback in My Learning." : " Thanks for completing it."
|
|
90
106
|
]
|
|
91
107
|
})] }),
|
|
92
|
-
/* @__PURE__ */
|
|
108
|
+
/* @__PURE__ */ T("div", {
|
|
93
109
|
className: "flex flex-wrap justify-center gap-2",
|
|
94
|
-
children: [/* @__PURE__ */
|
|
110
|
+
children: [/* @__PURE__ */ w(E, {
|
|
95
111
|
variant: "secondary",
|
|
96
|
-
onClick: () =>
|
|
112
|
+
onClick: () => F("learning"),
|
|
97
113
|
children: "Go to My Learning"
|
|
98
|
-
}), /* @__PURE__ */
|
|
114
|
+
}), /* @__PURE__ */ w(E, {
|
|
99
115
|
variant: "ghost",
|
|
100
|
-
onClick: () =>
|
|
116
|
+
onClick: () => F(`catalog/${L.courseId}`),
|
|
101
117
|
children: "Back to course"
|
|
102
118
|
})]
|
|
103
119
|
})
|
|
104
120
|
]
|
|
105
121
|
})
|
|
106
122
|
})
|
|
107
|
-
}) : /* @__PURE__ */
|
|
108
|
-
title:
|
|
109
|
-
description:
|
|
110
|
-
actions:
|
|
111
|
-
children: /* @__PURE__ */
|
|
112
|
-
className: "mx-auto max-w-3xl",
|
|
113
|
-
children: [/* @__PURE__ */
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
"
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
123
|
+
}) : /* @__PURE__ */ w(n, {
|
|
124
|
+
title: L.title,
|
|
125
|
+
description: L.description ?? void 0,
|
|
126
|
+
actions: $,
|
|
127
|
+
children: /* @__PURE__ */ T("div", {
|
|
128
|
+
className: "mx-auto max-w-3xl pb-4",
|
|
129
|
+
children: [/* @__PURE__ */ w(D, {
|
|
130
|
+
treatment: "glass",
|
|
131
|
+
className: "mb-6 p-4 sm:px-5",
|
|
132
|
+
children: /* @__PURE__ */ T("div", {
|
|
133
|
+
className: "flex flex-col divide-y divide-border-seam sm:flex-row sm:flex-wrap sm:items-center sm:divide-x sm:divide-y-0",
|
|
134
|
+
children: [
|
|
135
|
+
/* @__PURE__ */ w(M, {
|
|
136
|
+
icon: /* @__PURE__ */ w(y, { className: "h-4 w-4" }),
|
|
137
|
+
label: "Type",
|
|
138
|
+
value: /* @__PURE__ */ w(a, { status: L.type })
|
|
139
|
+
}),
|
|
140
|
+
/* @__PURE__ */ w(M, {
|
|
141
|
+
icon: /* @__PURE__ */ w(S, { className: "h-4 w-4" }),
|
|
142
|
+
label: "Passing score",
|
|
143
|
+
value: `${L.passingScore}%`
|
|
144
|
+
}),
|
|
145
|
+
L.timeLimitMin > 0 && /* @__PURE__ */ w(M, {
|
|
146
|
+
icon: /* @__PURE__ */ w(v, { className: "h-4 w-4" }),
|
|
147
|
+
label: "Time limit",
|
|
148
|
+
value: r(L.timeLimitMin)
|
|
149
|
+
}),
|
|
150
|
+
L.maxAttempts > 0 && /* @__PURE__ */ w(M, {
|
|
151
|
+
icon: /* @__PURE__ */ w(b, { className: "h-4 w-4" }),
|
|
152
|
+
label: "Attempts",
|
|
153
|
+
value: L.maxAttempts
|
|
154
|
+
}),
|
|
155
|
+
/* @__PURE__ */ T("div", {
|
|
156
|
+
className: "flex items-center gap-3 py-3 sm:ml-auto sm:py-0 sm:pl-5",
|
|
157
|
+
children: [/* @__PURE__ */ w(l, {
|
|
158
|
+
value: Y,
|
|
159
|
+
size: 44,
|
|
160
|
+
stroke: 5,
|
|
161
|
+
label: `${J}/${W.length}`
|
|
162
|
+
}), /* @__PURE__ */ T("div", {
|
|
163
|
+
className: "min-w-0",
|
|
164
|
+
children: [/* @__PURE__ */ T("p", {
|
|
165
|
+
className: "text-sm font-semibold text-text-primary tabular-nums",
|
|
166
|
+
children: [
|
|
167
|
+
J,
|
|
168
|
+
" of ",
|
|
169
|
+
W.length
|
|
170
|
+
]
|
|
171
|
+
}), /* @__PURE__ */ w("p", {
|
|
172
|
+
className: "text-xs text-text-secondary",
|
|
173
|
+
children: "answered"
|
|
174
|
+
})]
|
|
175
|
+
})]
|
|
176
|
+
})
|
|
177
|
+
]
|
|
178
|
+
})
|
|
179
|
+
}), W.length === 0 ? /* @__PURE__ */ w(o, {
|
|
180
|
+
icon: /* @__PURE__ */ w(_, { className: "h-8 w-8" }),
|
|
142
181
|
title: "No questions yet",
|
|
143
182
|
description: "This assessment doesn't have any questions to answer."
|
|
144
|
-
}) : /* @__PURE__ */
|
|
183
|
+
}) : /* @__PURE__ */ T("div", {
|
|
145
184
|
className: "flex flex-col gap-4",
|
|
146
185
|
children: [
|
|
147
|
-
|
|
148
|
-
let r = e.type === "TRUE_FALSE" ?
|
|
149
|
-
return /* @__PURE__ */
|
|
150
|
-
treatment: "plain",
|
|
151
|
-
className: "p-5",
|
|
152
|
-
children: /* @__PURE__ */
|
|
153
|
-
className: "flex items-start gap-3",
|
|
154
|
-
children: [/* @__PURE__ */
|
|
155
|
-
className: "mt-0.5 flex h-
|
|
156
|
-
children: n + 1
|
|
157
|
-
}), /* @__PURE__ */
|
|
186
|
+
W.map((e, n) => {
|
|
187
|
+
let r = e.type === "TRUE_FALSE" ? j : A(e.options), a = B[e.id], o = q(e);
|
|
188
|
+
return /* @__PURE__ */ w(D, {
|
|
189
|
+
treatment: o ? "insight" : "plain",
|
|
190
|
+
className: t("p-5 transition-shadow", o && "ring-1 ring-[var(--color-accent-soft)]"),
|
|
191
|
+
children: /* @__PURE__ */ T("div", {
|
|
192
|
+
className: "flex items-start gap-3 sm:gap-4",
|
|
193
|
+
children: [/* @__PURE__ */ w("span", {
|
|
194
|
+
className: t("mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-sm font-semibold tabular-nums transition-colors", o ? "bg-status-success-bg-subtle text-status-success-text" : "bg-[var(--color-accent-soft)] text-text-primary"),
|
|
195
|
+
children: o ? /* @__PURE__ */ w(g, { className: "h-4 w-4" }) : n + 1
|
|
196
|
+
}), /* @__PURE__ */ T("div", {
|
|
158
197
|
className: "min-w-0 flex-1",
|
|
159
198
|
children: [
|
|
160
|
-
/* @__PURE__ */
|
|
161
|
-
className: "
|
|
162
|
-
children:
|
|
199
|
+
/* @__PURE__ */ T("div", {
|
|
200
|
+
className: "flex flex-wrap items-center gap-2",
|
|
201
|
+
children: [/* @__PURE__ */ w("span", {
|
|
202
|
+
className: "rounded-md bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
|
|
203
|
+
children: i(e.type)
|
|
204
|
+
}), /* @__PURE__ */ T("span", {
|
|
205
|
+
className: "ml-auto text-xs text-text-secondary tabular-nums",
|
|
206
|
+
children: [
|
|
207
|
+
e.points,
|
|
208
|
+
" ",
|
|
209
|
+
e.points === 1 ? "point" : "points"
|
|
210
|
+
]
|
|
211
|
+
})]
|
|
163
212
|
}),
|
|
164
|
-
/* @__PURE__ */
|
|
165
|
-
className: "mt-
|
|
166
|
-
children:
|
|
167
|
-
e.points,
|
|
168
|
-
" ",
|
|
169
|
-
e.points === 1 ? "point" : "points"
|
|
170
|
-
]
|
|
213
|
+
/* @__PURE__ */ w("p", {
|
|
214
|
+
className: "mt-2.5 font-medium text-text-primary",
|
|
215
|
+
children: e.prompt
|
|
171
216
|
}),
|
|
172
|
-
/* @__PURE__ */
|
|
217
|
+
/* @__PURE__ */ T("div", {
|
|
173
218
|
className: "mt-4",
|
|
174
219
|
children: [
|
|
175
|
-
(e.type === "SINGLE_CHOICE" || e.type === "TRUE_FALSE") && /* @__PURE__ */
|
|
220
|
+
(e.type === "SINGLE_CHOICE" || e.type === "TRUE_FALSE") && /* @__PURE__ */ w("div", {
|
|
176
221
|
className: "flex flex-col gap-2",
|
|
177
|
-
children: r.map((n) => /* @__PURE__ */
|
|
178
|
-
className: t("flex cursor-pointer items-center gap-3 rounded-
|
|
179
|
-
children: [/* @__PURE__ */
|
|
222
|
+
children: r.map((n) => /* @__PURE__ */ T("label", {
|
|
223
|
+
className: t("flex min-h-[44px] cursor-pointer items-center gap-3 rounded-xl border px-3.5 py-2.5 text-sm transition-colors", a === n.label ? "border-[var(--color-accent-teal)] bg-[var(--color-accent-soft)] text-text-primary" : "border-border-seam text-text-secondary hover:border-border-strong hover:bg-bg-sunken"),
|
|
224
|
+
children: [/* @__PURE__ */ w("input", {
|
|
180
225
|
type: "radio",
|
|
181
226
|
name: e.id,
|
|
182
|
-
className: "accent-[var(--color-accent-
|
|
183
|
-
checked:
|
|
184
|
-
onChange: () =>
|
|
227
|
+
className: "h-4 w-4 accent-[var(--color-accent-teal)]",
|
|
228
|
+
checked: a === n.label,
|
|
229
|
+
onChange: () => G(e.id, n.label)
|
|
185
230
|
}), n.label]
|
|
186
231
|
}, n.label))
|
|
187
232
|
}),
|
|
188
|
-
e.type === "MULTIPLE_CHOICE" && /* @__PURE__ */
|
|
233
|
+
e.type === "MULTIPLE_CHOICE" && /* @__PURE__ */ w("div", {
|
|
189
234
|
className: "flex flex-col gap-2",
|
|
190
235
|
children: r.map((n) => {
|
|
191
|
-
let r = Array.isArray(
|
|
192
|
-
return /* @__PURE__ */
|
|
193
|
-
className: t("flex cursor-pointer items-center gap-3 rounded-
|
|
194
|
-
children: [/* @__PURE__ */
|
|
236
|
+
let r = Array.isArray(a) && a.includes(n.label);
|
|
237
|
+
return /* @__PURE__ */ T("label", {
|
|
238
|
+
className: t("flex min-h-[44px] cursor-pointer items-center gap-3 rounded-xl border px-3.5 py-2.5 text-sm transition-colors", r ? "border-[var(--color-accent-teal)] bg-[var(--color-accent-soft)] text-text-primary" : "border-border-seam text-text-secondary hover:border-border-strong hover:bg-bg-sunken"),
|
|
239
|
+
children: [/* @__PURE__ */ w("input", {
|
|
195
240
|
type: "checkbox",
|
|
196
|
-
className: "accent-[var(--color-accent-
|
|
241
|
+
className: "h-4 w-4 rounded accent-[var(--color-accent-teal)]",
|
|
197
242
|
checked: r,
|
|
198
|
-
onChange: () =>
|
|
243
|
+
onChange: () => K(e.id, n.label)
|
|
199
244
|
}), n.label]
|
|
200
245
|
}, n.label);
|
|
201
246
|
})
|
|
202
247
|
}),
|
|
203
|
-
e.type === "SHORT_ANSWER" && /* @__PURE__ */
|
|
204
|
-
value: typeof
|
|
205
|
-
onChange: (t) =>
|
|
206
|
-
placeholder: "
|
|
248
|
+
e.type === "SHORT_ANSWER" && /* @__PURE__ */ w(O, {
|
|
249
|
+
value: typeof a == "string" ? a : "",
|
|
250
|
+
onChange: (t) => G(e.id, t.target.value),
|
|
251
|
+
placeholder: "Type your answer here…"
|
|
207
252
|
}),
|
|
208
|
-
(e.type === "ESSAY" || e.type === "CODE") && /* @__PURE__ */
|
|
253
|
+
(e.type === "ESSAY" || e.type === "CODE") && /* @__PURE__ */ w(k, {
|
|
209
254
|
rows: e.type === "CODE" ? 6 : 4,
|
|
210
|
-
value: typeof
|
|
211
|
-
onChange: (t) =>
|
|
255
|
+
value: typeof a == "string" ? a : "",
|
|
256
|
+
onChange: (t) => G(e.id, t.target.value),
|
|
212
257
|
placeholder: e.type === "CODE" ? "Write your code…" : "Write your answer…",
|
|
213
258
|
className: e.type === "CODE" ? "font-mono text-sm" : void 0
|
|
214
259
|
})
|
|
@@ -219,46 +264,65 @@ var T = [{ label: "True" }, { label: "False" }], E = () => {
|
|
|
219
264
|
})
|
|
220
265
|
}, e.id);
|
|
221
266
|
}),
|
|
222
|
-
|
|
267
|
+
z.isError && /* @__PURE__ */ w("p", {
|
|
223
268
|
className: "text-sm text-status-error-text",
|
|
224
|
-
children:
|
|
269
|
+
children: z.error instanceof Error ? z.error.message : "Could not submit your answers."
|
|
225
270
|
}),
|
|
226
|
-
/* @__PURE__ */
|
|
227
|
-
className: "sticky bottom-0
|
|
228
|
-
children:
|
|
229
|
-
className: "
|
|
230
|
-
children: [
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
271
|
+
/* @__PURE__ */ w("div", {
|
|
272
|
+
className: "sticky bottom-0 z-10 pt-2",
|
|
273
|
+
children: /* @__PURE__ */ T("div", {
|
|
274
|
+
className: "flex flex-col gap-3 rounded-2xl border border-border-seam bg-bg-surface/90 p-4 shadow-elevation-2 backdrop-blur sm:flex-row sm:items-center sm:justify-between",
|
|
275
|
+
children: [/* @__PURE__ */ T("div", {
|
|
276
|
+
className: "flex items-center gap-3",
|
|
277
|
+
children: [/* @__PURE__ */ w(l, {
|
|
278
|
+
value: Y,
|
|
279
|
+
size: 44,
|
|
280
|
+
stroke: 5,
|
|
281
|
+
label: `${J}/${W.length}`
|
|
282
|
+
}), /* @__PURE__ */ T("div", {
|
|
283
|
+
className: "min-w-0",
|
|
284
|
+
children: [/* @__PURE__ */ T("p", {
|
|
285
|
+
className: "text-sm font-semibold text-text-primary tabular-nums",
|
|
286
|
+
children: [
|
|
287
|
+
J,
|
|
288
|
+
" of ",
|
|
289
|
+
W.length,
|
|
290
|
+
" answered"
|
|
291
|
+
]
|
|
292
|
+
}), /* @__PURE__ */ w("p", {
|
|
293
|
+
className: "text-xs text-text-secondary",
|
|
294
|
+
children: Z
|
|
295
|
+
})]
|
|
296
|
+
})]
|
|
297
|
+
}), /* @__PURE__ */ T(E, {
|
|
298
|
+
size: "lg",
|
|
299
|
+
className: "max-sm:w-full",
|
|
300
|
+
onClick: Q,
|
|
301
|
+
disabled: z.isPending || J === 0,
|
|
302
|
+
children: [/* @__PURE__ */ w(x, { className: "mr-1.5 h-4 w-4" }), z.isPending ? "Submitting…" : "Submit assessment"]
|
|
303
|
+
})]
|
|
304
|
+
})
|
|
241
305
|
})
|
|
242
306
|
]
|
|
243
307
|
})]
|
|
244
308
|
})
|
|
245
|
-
}) : /* @__PURE__ */
|
|
246
|
-
title:
|
|
247
|
-
actions:
|
|
248
|
-
children: /* @__PURE__ */
|
|
309
|
+
}) : /* @__PURE__ */ w(n, {
|
|
310
|
+
title: L.title,
|
|
311
|
+
actions: $,
|
|
312
|
+
children: /* @__PURE__ */ w(o, {
|
|
249
313
|
illustration: "empty-data",
|
|
250
314
|
title: "This assessment isn't open yet",
|
|
251
315
|
description: "It has to be published by an educator before you can take it."
|
|
252
316
|
})
|
|
253
|
-
}) : /* @__PURE__ */
|
|
317
|
+
}) : /* @__PURE__ */ w(n, {
|
|
254
318
|
title: "Assessment",
|
|
255
|
-
children: /* @__PURE__ */
|
|
319
|
+
children: /* @__PURE__ */ w(o, {
|
|
256
320
|
illustration: "empty-data",
|
|
257
321
|
title: "No assessment selected"
|
|
258
322
|
})
|
|
259
323
|
});
|
|
260
324
|
};
|
|
261
325
|
//#endregion
|
|
262
|
-
export {
|
|
326
|
+
export { N as TakeAssessmentPage };
|
|
263
327
|
|
|
264
328
|
//# sourceMappingURL=TakeAssessmentPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TakeAssessmentPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/assessments/TakeAssessmentPage.tsx"],"sourcesContent":["/**\n * TakeAssessmentPage — the LEARNER-facing surface to attempt a published\n * assessment and submit answers.\n * @module buildmyiq/pages/assessments\n *\n * Loads the assessment + its questions, collects an answer per question (typed\n * to the question kind), resolves the caller's enrollment for the assessment's\n * course, and submits via `buiSubmitAssessment` ({ assessmentId, enrollmentId?,\n * answers }). Grading is done by an educator in the Grading queue — this page is\n * honest about that (\"submitted, awaiting grading\"). All data is live.\n */\n\nimport type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, CheckCircle2, ClipboardCheck, Send } from 'lucide-react';\nimport { Button, GlassCard, Input, Textarea } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n LoadingView,\n ErrorView,\n EmptyState,\n} from '../../components';\nimport { useBuildmyiq } from '../../context';\nimport { useBuiAssessment, useBuiEnrollments, useBuiSubmitAssessment } from '../../hooks';\nimport { cn } from '../../utils/cn';\nimport { formatDuration } from '../../utils/formatters';\nimport type { BuiQuestion } from '../../types';\n\ninterface Choice {\n label: string;\n}\n\n/** Narrow the untyped `options` JSON blob to a list of `{ label }` choices. */\nfunction parseChoices(options: unknown): Choice[] {\n if (!Array.isArray(options)) return [];\n return options\n .map((o) => (o && typeof o === 'object' && 'label' in o ? { label: String((o as { label: unknown }).label) } : null))\n .filter((c): c is Choice => c !== null && c.label.length > 0);\n}\n\ntype AnswerValue = string | string[];\n\nconst TRUE_FALSE_CHOICES: Choice[] = [{ label: 'True' }, { label: 'False' }];\n\nexport const TakeAssessmentPage: FC = () => {\n const { assessmentId } = useParams<{ assessmentId: string }>();\n const { currentUser, navigateTo } = useBuildmyiq();\n\n const assessmentQuery = useBuiAssessment(assessmentId);\n const assessment = assessmentQuery.data ?? null;\n\n const enrollmentsQuery = useBuiEnrollments({\n learnerId: currentUser?.id,\n courseId: assessment?.courseId,\n enabled: Boolean(currentUser?.id && assessment?.courseId),\n });\n const enrollmentId = enrollmentsQuery.data?.items?.[0]?.id;\n\n const submit = useBuiSubmitAssessment();\n const [answers, setAnswers] = useState<Record<string, AnswerValue>>({});\n const [submittedId, setSubmittedId] = useState<string | null>(null);\n\n const questions = useMemo<BuiQuestion[]>(\n () => [...(assessment?.questions ?? [])].sort((a, b) => a.position - b.position),\n [assessment]\n );\n\n const setAnswer = (qid: string, value: AnswerValue): void => {\n setAnswers((prev) => ({ ...prev, [qid]: value }));\n };\n\n const toggleMulti = (qid: string, label: string): void => {\n setAnswers((prev) => {\n const cur = Array.isArray(prev[qid]) ? (prev[qid] as string[]) : [];\n return { ...prev, [qid]: cur.includes(label) ? cur.filter((l) => l !== label) : [...cur, label] };\n });\n };\n\n const answeredCount = questions.filter((q) => {\n const a = answers[q.id];\n return Array.isArray(a) ? a.length > 0 : Boolean(a && String(a).trim());\n }).length;\n\n const handleSubmit = async (): Promise<void> => {\n if (!assessmentId) return;\n const result = await submit.mutateAsync({\n assessmentId,\n enrollmentId,\n attempt: 1,\n answers,\n });\n setSubmittedId(result.id);\n };\n\n const backToCourse = assessment\n ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => navigateTo(`catalog/${assessment.courseId}`)}>\n <ArrowLeft className=\"mr-1 h-4 w-4\" /> Back to course\n </Button>\n )\n : undefined;\n\n if (!assessmentId) {\n return (\n <PageLayout title=\"Assessment\">\n <EmptyState illustration=\"empty-data\" title=\"No assessment selected\" />\n </PageLayout>\n );\n }\n\n if (assessmentQuery.isLoading) {\n return (\n <PageLayout title=\"Assessment\">\n <LoadingView label=\"Loading the assessment…\" />\n </PageLayout>\n );\n }\n\n if (assessmentQuery.isError || !assessment) {\n return (\n <PageLayout title=\"Assessment\" actions={backToCourse}>\n <ErrorView\n title=\"Couldn't load this assessment\"\n message={assessmentQuery.error instanceof Error ? assessmentQuery.error.message : undefined}\n onRetry={() => assessmentQuery.refetch()}\n />\n </PageLayout>\n );\n }\n\n if (assessment.status !== 'PUBLISHED') {\n return (\n <PageLayout title={assessment.title} actions={backToCourse}>\n <EmptyState\n illustration=\"empty-data\"\n title=\"This assessment isn't open yet\"\n description=\"It has to be published by an educator before you can take it.\"\n />\n </PageLayout>\n );\n }\n\n // Submitted confirmation\n if (submittedId) {\n return (\n <PageLayout title={assessment.title} actions={backToCourse}>\n <div className=\"mx-auto max-w-lg\">\n <GlassCard treatment=\"glass\" glow className=\"flex flex-col items-center gap-4 p-8 text-center\">\n <div className=\"flex h-14 w-14 items-center justify-center rounded-full bg-status-success-bg-subtle\">\n <CheckCircle2 className=\"h-7 w-7 text-status-success-text\" />\n </div>\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Submitted</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Your answers for “{assessment.title}” were submitted.\n {assessment.isGraded\n ? ' An educator will grade them — you’ll see your score and feedback in My Learning.'\n : ' Thanks for completing it.'}\n </p>\n </div>\n <div className=\"flex flex-wrap justify-center gap-2\">\n <Button variant=\"secondary\" onClick={() => navigateTo('learning')}>\n Go to My Learning\n </Button>\n <Button variant=\"ghost\" onClick={() => navigateTo(`catalog/${assessment.courseId}`)}>\n Back to course\n </Button>\n </div>\n </GlassCard>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={assessment.title}\n description={assessment.description ?? undefined}\n actions={backToCourse}\n >\n <div className=\"mx-auto max-w-3xl\">\n {/* Meta strip */}\n <div className=\"mb-6 flex flex-wrap items-center gap-3\">\n <StatusBadge status={assessment.type} />\n <span className=\"text-sm text-text-secondary\">Passing score {assessment.passingScore}%</span>\n {assessment.timeLimitMin > 0 && (\n <span className=\"text-sm text-text-secondary\">· {formatDuration(assessment.timeLimitMin)}</span>\n )}\n <span className=\"text-sm text-text-secondary\">\n · {answeredCount}/{questions.length} answered\n </span>\n </div>\n\n {questions.length === 0 ? (\n <EmptyState\n icon={<ClipboardCheck className=\"h-8 w-8\" />}\n title=\"No questions yet\"\n description=\"This assessment doesn't have any questions to answer.\"\n />\n ) : (\n <div className=\"flex flex-col gap-4\">\n {questions.map((q, idx) => {\n const choices =\n q.type === 'TRUE_FALSE' ? TRUE_FALSE_CHOICES : parseChoices(q.options);\n const answer = answers[q.id];\n return (\n <GlassCard key={q.id} treatment=\"plain\" className=\"p-5\">\n <div className=\"flex items-start gap-3\">\n <span className=\"mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-xs font-semibold text-text-secondary tabular-nums\">\n {idx + 1}\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-medium text-text-primary\">{q.prompt}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {q.points} {q.points === 1 ? 'point' : 'points'}\n </p>\n\n <div className=\"mt-4\">\n {(q.type === 'SINGLE_CHOICE' || q.type === 'TRUE_FALSE') && (\n <div className=\"flex flex-col gap-2\">\n {choices.map((c) => (\n <label\n key={c.label}\n className={cn(\n 'flex cursor-pointer items-center gap-3 rounded-lg border px-3 py-2 text-sm transition-colors',\n answer === c.label\n ? 'border-accent bg-[var(--color-accent-soft)] text-text-primary'\n : 'border-border-seam text-text-secondary hover:bg-bg-sunken'\n )}\n >\n <input\n type=\"radio\"\n name={q.id}\n className=\"accent-[var(--color-accent-primary)]\"\n checked={answer === c.label}\n onChange={() => setAnswer(q.id, c.label)}\n />\n {c.label}\n </label>\n ))}\n </div>\n )}\n\n {q.type === 'MULTIPLE_CHOICE' && (\n <div className=\"flex flex-col gap-2\">\n {choices.map((c) => {\n const checked = Array.isArray(answer) && answer.includes(c.label);\n return (\n <label\n key={c.label}\n className={cn(\n 'flex cursor-pointer items-center gap-3 rounded-lg border px-3 py-2 text-sm transition-colors',\n checked\n ? 'border-accent bg-[var(--color-accent-soft)] text-text-primary'\n : 'border-border-seam text-text-secondary hover:bg-bg-sunken'\n )}\n >\n <input\n type=\"checkbox\"\n className=\"accent-[var(--color-accent-primary)]\"\n checked={checked}\n onChange={() => toggleMulti(q.id, c.label)}\n />\n {c.label}\n </label>\n );\n })}\n </div>\n )}\n\n {q.type === 'SHORT_ANSWER' && (\n <Input\n value={typeof answer === 'string' ? answer : ''}\n onChange={(e) => setAnswer(q.id, e.target.value)}\n placeholder=\"Your answer\"\n />\n )}\n\n {(q.type === 'ESSAY' || q.type === 'CODE') && (\n <Textarea\n rows={q.type === 'CODE' ? 6 : 4}\n value={typeof answer === 'string' ? answer : ''}\n onChange={(e) => setAnswer(q.id, e.target.value)}\n placeholder={q.type === 'CODE' ? 'Write your code…' : 'Write your answer…'}\n className={q.type === 'CODE' ? 'font-mono text-sm' : undefined}\n />\n )}\n </div>\n </div>\n </div>\n </GlassCard>\n );\n })}\n\n {submit.isError && (\n <p className=\"text-sm text-status-error-text\">\n {submit.error instanceof Error ? submit.error.message : 'Could not submit your answers.'}\n </p>\n )}\n\n <div className=\"sticky bottom-0 flex items-center justify-between gap-3 border-t border-border-seam bg-bg-surface/90 py-3 backdrop-blur\">\n <span className=\"text-sm text-text-secondary tabular-nums\">\n {answeredCount} of {questions.length} answered\n </span>\n <Button onClick={handleSubmit} disabled={submit.isPending || answeredCount === 0}>\n <Send className=\"mr-1 h-4 w-4\" />\n {submit.isPending ? 'Submitting…' : 'Submit assessment'}\n </Button>\n </div>\n </div>\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TakeAssessmentPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/assessments/TakeAssessmentPage.tsx"],"sourcesContent":["/**\n * TakeAssessmentPage — the LEARNER-facing surface to attempt a published\n * assessment and submit answers.\n * @module buildmyiq/pages/assessments\n *\n * Loads the assessment + its questions, collects an answer per question (typed\n * to the question kind), resolves the caller's enrollment for the assessment's\n * course, and submits via `buiSubmitAssessment` ({ assessmentId, enrollmentId?,\n * answers }). Grading is done by an educator in the Grading queue — this page is\n * honest about that (\"submitted, awaiting grading\"). All data is live.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n CheckCircle2,\n ClipboardCheck,\n Clock,\n FileText,\n RefreshCw,\n Send,\n Target,\n} from 'lucide-react';\nimport { Button, GlassCard, Input, Textarea } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n ProgressRing,\n LoadingView,\n ErrorView,\n EmptyState,\n} from '../../components';\nimport { useBuildmyiq } from '../../context';\nimport { useBuiAssessment, useBuiEnrollments, useBuiSubmitAssessment } from '../../hooks';\nimport { cn } from '../../utils/cn';\nimport { formatDuration, formatEnumLabel } from '../../utils/formatters';\nimport type { BuiQuestion } from '../../types';\n\ninterface Choice {\n label: string;\n}\n\n/** Narrow the untyped `options` JSON blob to a list of `{ label }` choices. */\nfunction parseChoices(options: unknown): Choice[] {\n if (!Array.isArray(options)) return [];\n return options\n .map((o) => (o && typeof o === 'object' && 'label' in o ? { label: String((o as { label: unknown }).label) } : null))\n .filter((c): c is Choice => c !== null && c.label.length > 0);\n}\n\ntype AnswerValue = string | string[];\n\nconst TRUE_FALSE_CHOICES: Choice[] = [{ label: 'True' }, { label: 'False' }];\n\ninterface MetaCellProps {\n icon: ReactNode;\n label: string;\n value: ReactNode;\n}\n\nconst MetaCell: FC<MetaCellProps> = ({ icon, label, value }) => (\n <div className=\"flex items-center gap-3 py-3 first:pt-0 last:pb-0 sm:px-5 sm:py-0 sm:first:pl-0 sm:last:pr-0\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-[var(--color-accent-teal)]\">\n {icon}\n </span>\n <div className=\"min-w-0\">\n <p className=\"text-xs text-text-secondary\">{label}</p>\n <p className=\"text-sm font-semibold text-text-primary\">{value}</p>\n </div>\n </div>\n);\n\nexport const TakeAssessmentPage: FC = () => {\n const { assessmentId } = useParams<{ assessmentId: string }>();\n const { currentUser, navigateTo } = useBuildmyiq();\n\n const assessmentQuery = useBuiAssessment(assessmentId);\n const assessment = assessmentQuery.data ?? null;\n\n const enrollmentsQuery = useBuiEnrollments({\n learnerId: currentUser?.id,\n courseId: assessment?.courseId,\n enabled: Boolean(currentUser?.id && assessment?.courseId),\n });\n const enrollmentId = enrollmentsQuery.data?.items?.[0]?.id;\n\n const submit = useBuiSubmitAssessment();\n const [answers, setAnswers] = useState<Record<string, AnswerValue>>({});\n const [submittedId, setSubmittedId] = useState<string | null>(null);\n\n const questions = useMemo<BuiQuestion[]>(\n () => [...(assessment?.questions ?? [])].sort((a, b) => a.position - b.position),\n [assessment]\n );\n\n const setAnswer = (qid: string, value: AnswerValue): void => {\n setAnswers((prev) => ({ ...prev, [qid]: value }));\n };\n\n const toggleMulti = (qid: string, label: string): void => {\n setAnswers((prev) => {\n const cur = Array.isArray(prev[qid]) ? (prev[qid] as string[]) : [];\n return { ...prev, [qid]: cur.includes(label) ? cur.filter((l) => l !== label) : [...cur, label] };\n });\n };\n\n const isAnswered = (q: BuiQuestion): boolean => {\n const a = answers[q.id];\n return Array.isArray(a) ? a.length > 0 : Boolean(a && String(a).trim());\n };\n\n const answeredCount = questions.filter(isAnswered).length;\n const answeredPct = questions.length > 0 ? (answeredCount / questions.length) * 100 : 0;\n const remaining = questions.length - answeredCount;\n const encouragement =\n answeredCount === 0\n ? 'Answer a question to get started.'\n : remaining === 0\n ? 'All questions answered — ready to submit.'\n : `${remaining} question${remaining === 1 ? '' : 's'} left to answer.`;\n\n const handleSubmit = async (): Promise<void> => {\n if (!assessmentId) return;\n const result = await submit.mutateAsync({\n assessmentId,\n enrollmentId,\n attempt: 1,\n answers,\n });\n setSubmittedId(result.id);\n };\n\n const backToCourse = assessment\n ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => navigateTo(`catalog/${assessment.courseId}`)}>\n <ArrowLeft className=\"mr-1 h-4 w-4\" /> Back to course\n </Button>\n )\n : undefined;\n\n if (!assessmentId) {\n return (\n <PageLayout title=\"Assessment\">\n <EmptyState illustration=\"empty-data\" title=\"No assessment selected\" />\n </PageLayout>\n );\n }\n\n if (assessmentQuery.isLoading) {\n return (\n <PageLayout title=\"Assessment\">\n <LoadingView label=\"Loading the assessment…\" />\n </PageLayout>\n );\n }\n\n if (assessmentQuery.isError || !assessment) {\n return (\n <PageLayout title=\"Assessment\" actions={backToCourse}>\n <ErrorView\n title=\"Couldn't load this assessment\"\n message={assessmentQuery.error instanceof Error ? assessmentQuery.error.message : undefined}\n onRetry={() => assessmentQuery.refetch()}\n />\n </PageLayout>\n );\n }\n\n if (assessment.status !== 'PUBLISHED') {\n return (\n <PageLayout title={assessment.title} actions={backToCourse}>\n <EmptyState\n illustration=\"empty-data\"\n title=\"This assessment isn't open yet\"\n description=\"It has to be published by an educator before you can take it.\"\n />\n </PageLayout>\n );\n }\n\n // Submitted confirmation\n if (submittedId) {\n return (\n <PageLayout title={assessment.title} actions={backToCourse}>\n <div className=\"mx-auto max-w-lg\">\n <GlassCard treatment=\"glass\" glow className=\"flex flex-col items-center gap-4 p-8 text-center\">\n <div className=\"flex h-14 w-14 items-center justify-center rounded-full bg-status-success-bg-subtle\">\n <CheckCircle2 className=\"h-7 w-7 text-status-success-text\" />\n </div>\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Submitted</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Your answers for “{assessment.title}” were submitted.\n {assessment.isGraded\n ? ' An educator will grade them — you’ll see your score and feedback in My Learning.'\n : ' Thanks for completing it.'}\n </p>\n </div>\n <div className=\"flex flex-wrap justify-center gap-2\">\n <Button variant=\"secondary\" onClick={() => navigateTo('learning')}>\n Go to My Learning\n </Button>\n <Button variant=\"ghost\" onClick={() => navigateTo(`catalog/${assessment.courseId}`)}>\n Back to course\n </Button>\n </div>\n </GlassCard>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={assessment.title}\n description={assessment.description ?? undefined}\n actions={backToCourse}\n >\n <div className=\"mx-auto max-w-3xl pb-4\">\n {/* Meta strip — type · passing score · time limit · attempts · answered */}\n <GlassCard treatment=\"glass\" className=\"mb-6 p-4 sm:px-5\">\n <div className=\"flex flex-col divide-y divide-border-seam sm:flex-row sm:flex-wrap sm:items-center sm:divide-x sm:divide-y-0\">\n <MetaCell\n icon={<FileText className=\"h-4 w-4\" />}\n label=\"Type\"\n value={<StatusBadge status={assessment.type} />}\n />\n <MetaCell\n icon={<Target className=\"h-4 w-4\" />}\n label=\"Passing score\"\n value={`${assessment.passingScore}%`}\n />\n {assessment.timeLimitMin > 0 && (\n <MetaCell\n icon={<Clock className=\"h-4 w-4\" />}\n label=\"Time limit\"\n value={formatDuration(assessment.timeLimitMin)}\n />\n )}\n {assessment.maxAttempts > 0 && (\n <MetaCell\n icon={<RefreshCw className=\"h-4 w-4\" />}\n label=\"Attempts\"\n value={assessment.maxAttempts}\n />\n )}\n <div className=\"flex items-center gap-3 py-3 sm:ml-auto sm:py-0 sm:pl-5\">\n <ProgressRing\n value={answeredPct}\n size={44}\n stroke={5}\n label={`${answeredCount}/${questions.length}`}\n />\n <div className=\"min-w-0\">\n <p className=\"text-sm font-semibold text-text-primary tabular-nums\">\n {answeredCount} of {questions.length}\n </p>\n <p className=\"text-xs text-text-secondary\">answered</p>\n </div>\n </div>\n </div>\n </GlassCard>\n\n {questions.length === 0 ? (\n <EmptyState\n icon={<ClipboardCheck className=\"h-8 w-8\" />}\n title=\"No questions yet\"\n description=\"This assessment doesn't have any questions to answer.\"\n />\n ) : (\n <div className=\"flex flex-col gap-4\">\n {questions.map((q, idx) => {\n const choices =\n q.type === 'TRUE_FALSE' ? TRUE_FALSE_CHOICES : parseChoices(q.options);\n const answer = answers[q.id];\n const answered = isAnswered(q);\n return (\n <GlassCard\n key={q.id}\n treatment={answered ? 'insight' : 'plain'}\n className={cn(\n 'p-5 transition-shadow',\n answered && 'ring-1 ring-[var(--color-accent-soft)]'\n )}\n >\n <div className=\"flex items-start gap-3 sm:gap-4\">\n <span\n className={cn(\n 'mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-sm font-semibold tabular-nums transition-colors',\n answered\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-[var(--color-accent-soft)] text-text-primary'\n )}\n >\n {answered ? <CheckCircle2 className=\"h-4 w-4\" /> : idx + 1}\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-md bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {formatEnumLabel(q.type)}\n </span>\n <span className=\"ml-auto text-xs text-text-secondary tabular-nums\">\n {q.points} {q.points === 1 ? 'point' : 'points'}\n </span>\n </div>\n <p className=\"mt-2.5 font-medium text-text-primary\">{q.prompt}</p>\n\n <div className=\"mt-4\">\n {(q.type === 'SINGLE_CHOICE' || q.type === 'TRUE_FALSE') && (\n <div className=\"flex flex-col gap-2\">\n {choices.map((c) => (\n <label\n key={c.label}\n className={cn(\n 'flex min-h-[44px] cursor-pointer items-center gap-3 rounded-xl border px-3.5 py-2.5 text-sm transition-colors',\n answer === c.label\n ? 'border-[var(--color-accent-teal)] bg-[var(--color-accent-soft)] text-text-primary'\n : 'border-border-seam text-text-secondary hover:border-border-strong hover:bg-bg-sunken'\n )}\n >\n <input\n type=\"radio\"\n name={q.id}\n className=\"h-4 w-4 accent-[var(--color-accent-teal)]\"\n checked={answer === c.label}\n onChange={() => setAnswer(q.id, c.label)}\n />\n {c.label}\n </label>\n ))}\n </div>\n )}\n\n {q.type === 'MULTIPLE_CHOICE' && (\n <div className=\"flex flex-col gap-2\">\n {choices.map((c) => {\n const checked = Array.isArray(answer) && answer.includes(c.label);\n return (\n <label\n key={c.label}\n className={cn(\n 'flex min-h-[44px] cursor-pointer items-center gap-3 rounded-xl border px-3.5 py-2.5 text-sm transition-colors',\n checked\n ? 'border-[var(--color-accent-teal)] bg-[var(--color-accent-soft)] text-text-primary'\n : 'border-border-seam text-text-secondary hover:border-border-strong hover:bg-bg-sunken'\n )}\n >\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 rounded accent-[var(--color-accent-teal)]\"\n checked={checked}\n onChange={() => toggleMulti(q.id, c.label)}\n />\n {c.label}\n </label>\n );\n })}\n </div>\n )}\n\n {q.type === 'SHORT_ANSWER' && (\n <Input\n value={typeof answer === 'string' ? answer : ''}\n onChange={(e) => setAnswer(q.id, e.target.value)}\n placeholder=\"Type your answer here…\"\n />\n )}\n\n {(q.type === 'ESSAY' || q.type === 'CODE') && (\n <Textarea\n rows={q.type === 'CODE' ? 6 : 4}\n value={typeof answer === 'string' ? answer : ''}\n onChange={(e) => setAnswer(q.id, e.target.value)}\n placeholder={q.type === 'CODE' ? 'Write your code…' : 'Write your answer…'}\n className={q.type === 'CODE' ? 'font-mono text-sm' : undefined}\n />\n )}\n </div>\n </div>\n </div>\n </GlassCard>\n );\n })}\n\n {submit.isError && (\n <p className=\"text-sm text-status-error-text\">\n {submit.error instanceof Error ? submit.error.message : 'Could not submit your answers.'}\n </p>\n )}\n\n {/* Sticky submit bar */}\n <div className=\"sticky bottom-0 z-10 pt-2\">\n <div className=\"flex flex-col gap-3 rounded-2xl border border-border-seam bg-bg-surface/90 p-4 shadow-elevation-2 backdrop-blur sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3\">\n <ProgressRing\n value={answeredPct}\n size={44}\n stroke={5}\n label={`${answeredCount}/${questions.length}`}\n />\n <div className=\"min-w-0\">\n <p className=\"text-sm font-semibold text-text-primary tabular-nums\">\n {answeredCount} of {questions.length} answered\n </p>\n <p className=\"text-xs text-text-secondary\">{encouragement}</p>\n </div>\n </div>\n <Button\n size=\"lg\"\n className=\"max-sm:w-full\"\n onClick={handleSubmit}\n disabled={submit.isPending || answeredCount === 0}\n >\n <Send className=\"mr-1.5 h-4 w-4\" />\n {submit.isPending ? 'Submitting…' : 'Submit assessment'}\n </Button>\n </div>\n </div>\n </div>\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AA6CA,SAAS,EAAa,GAA4B;AAEhD,QADK,MAAM,QAAQ,EAAQ,GACpB,EACJ,KAAK,MAAO,KAAK,OAAO,KAAM,YAAY,WAAW,IAAI,EAAE,OAAO,OAAQ,EAAyB,MAAM,EAAE,GAAG,KAAM,CACpH,QAAQ,MAAmB,MAAM,QAAQ,EAAE,MAAM,SAAS,EAAE,GAH3B,EAAE;;AAQxC,IAAM,IAA+B,CAAC,EAAE,OAAO,QAAQ,EAAE,EAAE,OAAO,SAAS,CAAC,EAQtE,KAA+B,EAAE,SAAM,UAAO,eAClD,kBAAC,OAAD;CAAK,WAAU;WAAf,CACE,kBAAC,QAAD;EAAM,WAAU;YACb;EACI,CAAA,EACP,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,KAAD;GAAG,WAAU;aAA+B;GAAU,CAAA,EACtD,kBAAC,KAAD;GAAG,WAAU;aAA2C;GAAU,CAAA,CAC9D;IACF;IAGK,UAA+B;CAC1C,IAAM,EAAE,oBAAiB,GAAqC,EACxD,EAAE,gBAAa,kBAAe,GAAc,EAE5C,IAAkB,EAAiB,EAAa,EAChD,IAAa,EAAgB,QAAQ,MAOrC,IALmB,EAAkB;EACzC,WAAW,GAAa;EACxB,UAAU,GAAY;EACtB,SAAS,GAAQ,GAAa,MAAM,GAAY;EACjD,CAAC,CACoC,MAAM,QAAQ,IAAI,IAElD,IAAS,GAAwB,EACjC,CAAC,GAAS,KAAc,EAAsC,EAAE,CAAC,EACjE,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAE7D,IAAY,QACV,CAAC,GAAI,GAAY,aAAa,EAAE,CAAE,CAAC,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,SAAS,EAChF,CAAC,EAAW,CACb,EAEK,KAAa,GAAa,MAA6B;AAC3D,KAAY,OAAU;GAAE,GAAG;IAAO,IAAM;GAAO,EAAE;IAG7C,KAAe,GAAa,MAAwB;AACxD,KAAY,MAAS;GACnB,IAAM,IAAM,MAAM,QAAQ,EAAK,GAAK,GAAI,EAAK,KAAoB,EAAE;AACnE,UAAO;IAAE,GAAG;KAAO,IAAM,EAAI,SAAS,EAAM,GAAG,EAAI,QAAQ,MAAM,MAAM,EAAM,GAAG,CAAC,GAAG,GAAK,EAAM;IAAE;IACjG;IAGE,KAAc,MAA4B;EAC9C,IAAM,IAAI,EAAQ,EAAE;AACpB,SAAO,MAAM,QAAQ,EAAE,GAAG,EAAE,SAAS,IAAI,GAAQ,KAAK,OAAO,EAAE,CAAC,MAAM;IAGlE,IAAgB,EAAU,OAAO,EAAW,CAAC,QAC7C,IAAc,EAAU,SAAS,IAAK,IAAgB,EAAU,SAAU,MAAM,GAChF,IAAY,EAAU,SAAS,GAC/B,IACJ,MAAkB,IACd,sCACA,MAAc,IACZ,8CACA,GAAG,EAAU,WAAW,MAAc,IAAI,KAAK,IAAI,mBAErD,IAAe,YAA2B;AACzC,OAOL,GANe,MAAM,EAAO,YAAY;GACtC;GACA;GACA,SAAS;GACT;GACD,CAAC,EACoB,GAAG;IAGrB,IAAe,IAEf,kBAAC,GAAD;EAAQ,SAAQ;EAAQ,MAAK;EAAK,eAAe,EAAW,WAAW,EAAW,WAAW;YAA7F,CACE,kBAAC,GAAD,EAAW,WAAU,gBAAiB,CAAA,EAAA,kBAC/B;MAEX,KAAA;AA0EJ,QAxEK,IAQD,EAAgB,YAEhB,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EAAa,OAAM,2BAA4B,CAAA;EACpC,CAAA,GAIb,EAAgB,WAAW,CAAC,IAE5B,kBAAC,GAAD;EAAY,OAAM;EAAa,SAAS;YACtC,kBAAC,GAAD;GACE,OAAM;GACN,SAAS,EAAgB,iBAAiB,QAAQ,EAAgB,MAAM,UAAU,KAAA;GAClF,eAAe,EAAgB,SAAS;GACxC,CAAA;EACS,CAAA,GAIb,EAAW,WAAW,cAatB,IAEA,kBAAC,GAAD;EAAY,OAAO,EAAW;EAAO,SAAS;YAC5C,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IAAW,WAAU;IAAQ,MAAA;IAAK,WAAU;cAA5C;KACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD,EAAc,WAAU,oCAAqC,CAAA;MACzD,CAAA;KACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA0C;MAAc,CAAA,EACtE,kBAAC,KAAD;MAAG,WAAU;gBAAb;OAAgD;OAC3B,EAAW;OAAM;OACnC,EAAW,WACR,sFACA;OACF;QACA,EAAA,CAAA;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAQ,SAAQ;OAAY,eAAe,EAAW,WAAW;iBAAE;OAE1D,CAAA,EACT,kBAAC,GAAD;OAAQ,SAAQ;OAAQ,eAAe,EAAW,WAAW,EAAW,WAAW;iBAAE;OAE5E,CAAA,CACL;;KACI;;GACR,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAO,EAAW;EAClB,aAAa,EAAW,eAAe,KAAA;EACvC,SAAS;YAET,kBAAC,OAAD;GAAK,WAAU;aAAf,CAEE,kBAAC,GAAD;IAAW,WAAU;IAAQ,WAAU;cACrC,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;OACtC,OAAM;OACN,OAAO,kBAAC,GAAD,EAAa,QAAQ,EAAW,MAAQ,CAAA;OAC/C,CAAA;MACF,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;OACpC,OAAM;OACN,OAAO,GAAG,EAAW,aAAa;OAClC,CAAA;MACD,EAAW,eAAe,KACzB,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;OACnC,OAAM;OACN,OAAO,EAAe,EAAW,aAAa;OAC9C,CAAA;MAEH,EAAW,cAAc,KACxB,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;OACvC,OAAM;OACN,OAAO,EAAW;OAClB,CAAA;MAEJ,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QACE,OAAO;QACP,MAAM;QACN,QAAQ;QACR,OAAO,GAAG,EAAc,GAAG,EAAU;QACrC,CAAA,EACF,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAb;UACG;UAAc;UAAK,EAAU;UAC5B;YACJ,kBAAC,KAAD;SAAG,WAAU;mBAA8B;SAAY,CAAA,CACnD;UACF;;MACF;;IACI,CAAA,EAEX,EAAU,WAAW,IACpB,kBAAC,GAAD;IACE,MAAM,kBAAC,GAAD,EAAgB,WAAU,WAAY,CAAA;IAC5C,OAAM;IACN,aAAY;IACZ,CAAA,GAEF,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,EAAU,KAAK,GAAG,MAAQ;MACzB,IAAM,IACJ,EAAE,SAAS,eAAe,IAAqB,EAAa,EAAE,QAAQ,EAClE,IAAS,EAAQ,EAAE,KACnB,IAAW,EAAW,EAAE;AAC9B,aACE,kBAAC,GAAD;OAEE,WAAW,IAAW,YAAY;OAClC,WAAW,EACT,yBACA,KAAY,yCACb;iBAED,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SACE,WAAW,EACT,8HACA,IACI,yDACA,kDACL;mBAEA,IAAW,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA,GAAG,IAAM;SACpD,CAAA,EACP,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBACb,EAAgB,EAAE,KAAK;YACnB,CAAA,EACP,kBAAC,QAAD;YAAM,WAAU;sBAAhB;aACG,EAAE;aAAO;aAAE,EAAE,WAAW,IAAI,UAAU;aAClC;cACH;;UACN,kBAAC,KAAD;WAAG,WAAU;qBAAwC,EAAE;WAAW,CAAA;UAElE,kBAAC,OAAD;WAAK,WAAU;qBAAf;aACI,EAAE,SAAS,mBAAmB,EAAE,SAAS,iBACzC,kBAAC,OAAD;aAAK,WAAU;uBACZ,EAAQ,KAAK,MACZ,kBAAC,SAAD;cAEE,WAAW,EACT,iHACA,MAAW,EAAE,QACT,sFACA,uFACL;wBAPH,CASE,kBAAC,SAAD;eACE,MAAK;eACL,MAAM,EAAE;eACR,WAAU;eACV,SAAS,MAAW,EAAE;eACtB,gBAAgB,EAAU,EAAE,IAAI,EAAE,MAAM;eACxC,CAAA,EACD,EAAE,MACG;gBAhBD,EAAE,MAgBD,CACR;aACE,CAAA;YAGP,EAAE,SAAS,qBACV,kBAAC,OAAD;aAAK,WAAU;uBACZ,EAAQ,KAAK,MAAM;cAClB,IAAM,IAAU,MAAM,QAAQ,EAAO,IAAI,EAAO,SAAS,EAAE,MAAM;AACjE,qBACE,kBAAC,SAAD;eAEE,WAAW,EACT,iHACA,IACI,sFACA,uFACL;yBAPH,CASE,kBAAC,SAAD;gBACE,MAAK;gBACL,WAAU;gBACD;gBACT,gBAAgB,EAAY,EAAE,IAAI,EAAE,MAAM;gBAC1C,CAAA,EACD,EAAE,MACG;iBAfD,EAAE,MAeD;eAEV;aACE,CAAA;YAGP,EAAE,SAAS,kBACV,kBAAC,GAAD;aACE,OAAO,OAAO,KAAW,WAAW,IAAS;aAC7C,WAAW,MAAM,EAAU,EAAE,IAAI,EAAE,OAAO,MAAM;aAChD,aAAY;aACZ,CAAA;aAGF,EAAE,SAAS,WAAW,EAAE,SAAS,WACjC,kBAAC,GAAD;aACE,MAAM,EAAE,SAAS,SAAS,IAAI;aAC9B,OAAO,OAAO,KAAW,WAAW,IAAS;aAC7C,WAAW,MAAM,EAAU,EAAE,IAAI,EAAE,OAAO,MAAM;aAChD,aAAa,EAAE,SAAS,SAAS,qBAAqB;aACtD,WAAW,EAAE,SAAS,SAAS,sBAAsB,KAAA;aACrD,CAAA;YAEA;;UACF;WACF;;OACI,EAtGL,EAAE,GAsGG;OAEd;KAED,EAAO,WACN,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAO,iBAAiB,QAAQ,EAAO,MAAM,UAAU;MACtD,CAAA;KAIN,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SACE,OAAO;SACP,MAAM;SACN,QAAQ;SACR,OAAO,GAAG,EAAc,GAAG,EAAU;SACrC,CAAA,EACF,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAAb;WACG;WAAc;WAAK,EAAU;WAAO;WACnC;aACJ,kBAAC,KAAD;UAAG,WAAU;oBAA+B;UAAkB,CAAA,CAC1D;WACF;WACN,kBAAC,GAAD;QACE,MAAK;QACL,WAAU;QACV,SAAS;QACT,UAAU,EAAO,aAAa,MAAkB;kBAJlD,CAME,kBAAC,GAAD,EAAM,WAAU,kBAAmB,CAAA,EAClC,EAAO,YAAY,gBAAgB,oBAC7B;UACL;;MACF,CAAA;KACF;MAEJ;;EACK,CAAA,GA3PX,kBAAC,GAAD;EAAY,OAAO,EAAW;EAAO,SAAS;YAC5C,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,CAAA;EACS,CAAA,GAlCb,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GAAY,cAAa;GAAa,OAAM;GAA2B,CAAA;EAC5D,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthoringPage.d.ts","sourceRoot":"","sources":["../../../../src/buildmyiq/pages/authoring/AuthoringPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAmLhC,eAAO,MAAM,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"AuthoringPage.d.ts","sourceRoot":"","sources":["../../../../src/buildmyiq/pages/authoring/AuthoringPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAmLhC,eAAO,MAAM,aAAa,EAAE,EA0H3B,CAAC"}
|