@burdenoff/microfe-technospam 2026.1102.3 → 2026.1102.4

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 (46) hide show
  1. package/dist/generated/global-types.d.ts +307 -41
  2. package/dist/generated/global-types.d.ts.map +1 -1
  3. package/dist/generated/wspace-types.d.ts +1730 -8
  4. package/dist/generated/wspace-types.d.ts.map +1 -1
  5. package/dist/stories/fixtures/technospamFixtures.d.ts.map +1 -1
  6. package/dist/technospam/TechnoSpamRoutes.d.ts.map +1 -1
  7. package/dist/technospam/TechnoSpamRoutes.js +32 -28
  8. package/dist/technospam/TechnoSpamRoutes.js.map +1 -1
  9. package/dist/technospam/api/assessmentApi.d.ts +183 -0
  10. package/dist/technospam/api/assessmentApi.d.ts.map +1 -0
  11. package/dist/technospam/api/assessmentApi.js +278 -0
  12. package/dist/technospam/api/assessmentApi.js.map +1 -0
  13. package/dist/technospam/components/CourseAssessments.d.ts +9 -0
  14. package/dist/technospam/components/CourseAssessments.d.ts.map +1 -0
  15. package/dist/technospam/components/CourseAssessments.js +66 -0
  16. package/dist/technospam/components/CourseAssessments.js.map +1 -0
  17. package/dist/technospam/components/StatusBadge.d.ts.map +1 -1
  18. package/dist/technospam/components/StatusBadge.js +8 -1
  19. package/dist/technospam/components/StatusBadge.js.map +1 -1
  20. package/dist/technospam/components/admin/AssessmentsAdminTab.d.ts +7 -0
  21. package/dist/technospam/components/admin/AssessmentsAdminTab.d.ts.map +1 -0
  22. package/dist/technospam/components/admin/AssessmentsAdminTab.js +421 -0
  23. package/dist/technospam/components/admin/AssessmentsAdminTab.js.map +1 -0
  24. package/dist/technospam/components/lesson/LessonKindFields.d.ts +3 -1
  25. package/dist/technospam/components/lesson/LessonKindFields.d.ts.map +1 -1
  26. package/dist/technospam/components/lesson/LessonKindFields.js +2 -2
  27. package/dist/technospam/components/lesson/LessonKindFields.js.map +1 -1
  28. package/dist/technospam/hooks/useAssessmentIntegrity.d.ts +29 -0
  29. package/dist/technospam/hooks/useAssessmentIntegrity.d.ts.map +1 -0
  30. package/dist/technospam/hooks/useAssessmentIntegrity.js +57 -0
  31. package/dist/technospam/hooks/useAssessmentIntegrity.js.map +1 -0
  32. package/dist/technospam/pages/AdminAdminDashboardPagePage.d.ts.map +1 -1
  33. package/dist/technospam/pages/AdminAdminDashboardPagePage.js +364 -359
  34. package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
  35. package/dist/technospam/pages/CoursesAssessmentPagePage.d.ts +9 -0
  36. package/dist/technospam/pages/CoursesAssessmentPagePage.d.ts.map +1 -0
  37. package/dist/technospam/pages/CoursesAssessmentPagePage.js +464 -0
  38. package/dist/technospam/pages/CoursesAssessmentPagePage.js.map +1 -0
  39. package/dist/technospam/pages/CoursesCourseDetailsPagePage.d.ts.map +1 -1
  40. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +210 -208
  41. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
  42. package/dist/technospam/utils/assessment.d.ts +64 -0
  43. package/dist/technospam/utils/assessment.d.ts.map +1 -0
  44. package/dist/technospam/utils/assessment.js +122 -0
  45. package/dist/technospam/utils/assessment.js.map +1 -0
  46. package/package.json +1 -1
@@ -0,0 +1,278 @@
1
+ import { notify as e } from "../lib/toast.js";
2
+ import { userMessageFromError as t } from "../lib/errorMessage.js";
3
+ import { pageArg as n } from "./technospamApi.js";
4
+ import { useMutation as r, useQuery as i } from "@apollo/client/react";
5
+ import { gql as a } from "@apollo/client";
6
+ //#region src/technospam/api/assessmentApi.ts
7
+ var o = a`
8
+ fragment AssessmentFields on TecAssessment {
9
+ id
10
+ courseId
11
+ title
12
+ description
13
+ status
14
+ timeLimitMinutes
15
+ passingScore
16
+ maxAttempts
17
+ questionCount
18
+ shuffleQuestions
19
+ shuffleOptions
20
+ proctoringMode
21
+ requireFullscreen
22
+ blockClipboard
23
+ maxIntegrityViolations
24
+ issuesCertificate
25
+ publishedAt
26
+ createdAt
27
+ updatedAt
28
+ }
29
+ `, s = a`
30
+ fragment AssessmentAttemptFields on TecAssessmentAttempt {
31
+ id
32
+ assessmentId
33
+ courseId
34
+ learnerId
35
+ attemptNumber
36
+ status
37
+ startedAt
38
+ deadlineAt
39
+ submittedAt
40
+ remainingSeconds
41
+ questions {
42
+ position
43
+ prompt
44
+ options
45
+ }
46
+ savedAnswers
47
+ requireFullscreen
48
+ blockClipboard
49
+ score
50
+ passed
51
+ passingScore
52
+ correctCount
53
+ totalCount
54
+ proctoringMode
55
+ proctoringStatus
56
+ integrityViolations
57
+ maxIntegrityViolations
58
+ consentedAt
59
+ reviewedBy
60
+ reviewedAt
61
+ reviewNotes
62
+ certificateId
63
+ certificate {
64
+ id
65
+ serial
66
+ score
67
+ status
68
+ issuedAt
69
+ }
70
+ }
71
+ `, c = a`
72
+ ${o}
73
+ query TecListAssessments(
74
+ $courseId: ID
75
+ $status: TecAssessmentStatus
76
+ $pagination: PaginationInput
77
+ ) {
78
+ tecListAssessments(courseId: $courseId, status: $status, pagination: $pagination) {
79
+ ...AssessmentFields
80
+ }
81
+ }
82
+ `, l = a`
83
+ ${o}
84
+ query TecAssessment($id: ID!) {
85
+ tecAssessment(id: $id) {
86
+ ...AssessmentFields
87
+ course {
88
+ id
89
+ title
90
+ }
91
+ }
92
+ }
93
+ `, u = a`
94
+ query TecAssessmentQuestionKey($id: ID!) {
95
+ tecAssessmentQuestionKey(id: $id) {
96
+ prompt
97
+ options
98
+ correctOption
99
+ explanation
100
+ }
101
+ }
102
+ `, d = a`
103
+ ${s}
104
+ query TecMyAssessmentAttempts($assessmentId: ID, $pagination: PaginationInput) {
105
+ tecMyAssessmentAttempts(assessmentId: $assessmentId, pagination: $pagination) {
106
+ ...AssessmentAttemptFields
107
+ }
108
+ }
109
+ `, f = a`
110
+ ${s}
111
+ query TecListAssessmentAttempts(
112
+ $assessmentId: ID
113
+ $proctoringStatus: TecProctoringStatus
114
+ $pagination: PaginationInput
115
+ ) {
116
+ tecListAssessmentAttempts(
117
+ assessmentId: $assessmentId
118
+ proctoringStatus: $proctoringStatus
119
+ pagination: $pagination
120
+ ) {
121
+ ...AssessmentAttemptFields
122
+ }
123
+ }
124
+ `, p = a`
125
+ query TecAssessmentAttemptEvents($attemptId: ID!, $pagination: PaginationInput) {
126
+ tecAssessmentAttemptEvents(attemptId: $attemptId, pagination: $pagination) {
127
+ id
128
+ attemptId
129
+ type
130
+ violation
131
+ detail
132
+ occurredAt
133
+ }
134
+ }
135
+ `, m = a`
136
+ ${o}
137
+ mutation TecCreateAssessment($input: TecCreateAssessmentInput!) {
138
+ tecCreateAssessment(input: $input) {
139
+ ...AssessmentFields
140
+ }
141
+ }
142
+ `, h = a`
143
+ ${o}
144
+ mutation TecUpdateAssessment($id: ID!, $input: TecUpdateAssessmentInput!) {
145
+ tecUpdateAssessment(id: $id, input: $input) {
146
+ ...AssessmentFields
147
+ }
148
+ }
149
+ `, g = a`
150
+ ${o}
151
+ mutation TecPublishAssessment($id: ID!) {
152
+ tecPublishAssessment(id: $id) {
153
+ ...AssessmentFields
154
+ }
155
+ }
156
+ `, _ = a`
157
+ ${o}
158
+ mutation TecArchiveAssessment($id: ID!) {
159
+ tecArchiveAssessment(id: $id) {
160
+ ...AssessmentFields
161
+ }
162
+ }
163
+ `, v = a`
164
+ ${s}
165
+ mutation TecStartAssessment($assessmentId: ID!, $acceptMonitoring: Boolean) {
166
+ tecStartAssessment(assessmentId: $assessmentId, acceptMonitoring: $acceptMonitoring) {
167
+ ...AssessmentAttemptFields
168
+ }
169
+ }
170
+ `, y = a`
171
+ mutation TecSaveAssessmentAnswers($attemptId: ID!, $answers: [Int!]!) {
172
+ tecSaveAssessmentAnswers(attemptId: $attemptId, answers: $answers) {
173
+ id
174
+ status
175
+ savedAnswers
176
+ remainingSeconds
177
+ }
178
+ }
179
+ `, b = a`
180
+ mutation TecRecordAssessmentSignal(
181
+ $attemptId: ID!
182
+ $signal: TecAssessmentSignal!
183
+ $detail: JSON
184
+ ) {
185
+ tecRecordAssessmentSignal(attemptId: $attemptId, signal: $signal, detail: $detail) {
186
+ id
187
+ status
188
+ integrityViolations
189
+ remainingSeconds
190
+ }
191
+ }
192
+ `, x = a`
193
+ ${s}
194
+ mutation TecSubmitAssessment($attemptId: ID!, $answers: [Int!]) {
195
+ tecSubmitAssessment(attemptId: $attemptId, answers: $answers) {
196
+ ...AssessmentAttemptFields
197
+ }
198
+ }
199
+ `, S = a`
200
+ ${s}
201
+ mutation TecClaimAssessmentCertificate($attemptId: ID!) {
202
+ tecClaimAssessmentCertificate(attemptId: $attemptId) {
203
+ ...AssessmentAttemptFields
204
+ }
205
+ }
206
+ `, C = a`
207
+ ${s}
208
+ mutation TecReviewAssessmentAttempt(
209
+ $id: ID!
210
+ $decision: TecAssessmentReviewDecision!
211
+ $notes: String
212
+ ) {
213
+ tecReviewAssessmentAttempt(id: $id, decision: $decision, notes: $notes) {
214
+ ...AssessmentAttemptFields
215
+ }
216
+ }
217
+ `, w = (n) => {
218
+ e.error("Something went wrong", t(n));
219
+ }, T = ["TecListAssessments", "TecAssessment"], E = ["TecMyAssessmentAttempts", "TecMyCertificates"], D = (e, t = !1) => i(c, {
220
+ variables: {
221
+ courseId: e.courseId ?? void 0,
222
+ status: e.status ?? void 0,
223
+ pagination: n(100)
224
+ },
225
+ skip: t,
226
+ fetchPolicy: "cache-and-network"
227
+ }), O = (e) => i(l, {
228
+ variables: { id: e },
229
+ skip: !e,
230
+ fetchPolicy: "cache-and-network"
231
+ }), k = (e) => i(u, {
232
+ variables: { id: e ?? "" },
233
+ skip: !e,
234
+ fetchPolicy: "network-only"
235
+ }), A = (e) => i(d, {
236
+ variables: {
237
+ assessmentId: e ?? void 0,
238
+ pagination: n(50)
239
+ },
240
+ skip: !e,
241
+ fetchPolicy: "network-only"
242
+ }), j = (e) => i(f, {
243
+ variables: {
244
+ assessmentId: e.assessmentId ?? void 0,
245
+ proctoringStatus: e.proctoringStatus ?? void 0,
246
+ pagination: n(100)
247
+ },
248
+ fetchPolicy: "cache-and-network"
249
+ }), M = (e) => i(p, {
250
+ variables: {
251
+ attemptId: e ?? "",
252
+ pagination: n(100)
253
+ },
254
+ skip: !e,
255
+ fetchPolicy: "network-only"
256
+ }), N = () => r(m, {
257
+ onError: w,
258
+ refetchQueries: T
259
+ }), P = () => r(h, {
260
+ onError: w,
261
+ refetchQueries: T
262
+ }), F = () => r(g, {
263
+ onError: w,
264
+ refetchQueries: T
265
+ }), I = () => r(_, {
266
+ onError: w,
267
+ refetchQueries: T
268
+ }), L = () => r(v, { refetchQueries: E }), R = () => r(y), z = () => r(b), B = () => r(x, { refetchQueries: E }), V = () => r(S, {
269
+ onError: w,
270
+ refetchQueries: E
271
+ }), H = () => r(C, {
272
+ onError: w,
273
+ refetchQueries: ["TecListAssessmentAttempts", "TecAssessmentAttemptEvents"]
274
+ });
275
+ //#endregion
276
+ export { I as useArchiveAssessment, M as useAssessmentAttemptEventsQuery, j as useAssessmentAttemptsQuery, O as useAssessmentQuery, k as useAssessmentQuestionKeyQuery, D as useAssessmentsQuery, V as useClaimAssessmentCertificate, N as useCreateAssessment, A as useMyAssessmentAttemptsQuery, F as usePublishAssessment, z as useRecordAssessmentSignal, H as useReviewAssessmentAttempt, R as useSaveAssessmentAnswers, L as useStartAssessment, B as useSubmitAssessment, P as useUpdateAssessment };
277
+
278
+ //# sourceMappingURL=assessmentApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assessmentApi.js","names":[],"sources":["../../../src/technospam/api/assessmentApi.ts"],"sourcesContent":["/**\n * Certification assessments (BOFF-4427) — Apollo operations + typed hooks over\n * the wspace-technospam-svc assessment fields.\n *\n * The server owns the clock, the question order and the answer key: the\n * browser only ever sees shuffled questions without the key, posts answers\n * in display order, and reports integrity signals. Grading, expiry and\n * certificate issuance all happen server-side.\n */\nimport { gql, type ErrorLike } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\n\nimport { notify } from '../lib/toast';\nimport { userMessageFromError } from '../lib/errorMessage';\nimport { pageArg, type TecQuizQuestionKey } from './technospamApi';\n\n/* ------------------------------------------------------------------ enums */\n\nexport type TecAssessmentStatus = 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';\nexport type TecProctoringMode = 'NONE' | 'INTEGRITY_MONITORING' | 'REVIEW_REQUIRED';\nexport type TecAssessmentAttemptStatus = 'IN_PROGRESS' | 'SUBMITTED' | 'EXPIRED';\nexport type TecProctoringStatus =\n 'NOT_REQUIRED' | 'MONITORING' | 'PENDING_REVIEW' | 'VERIFIED' | 'FLAGGED' | 'REJECTED';\nexport type TecAssessmentSignal =\n | 'FULLSCREEN_ENTER'\n | 'FULLSCREEN_EXIT'\n | 'VISIBILITY_HIDDEN'\n | 'WINDOW_BLUR'\n | 'COPY_ATTEMPT'\n | 'CUT_ATTEMPT'\n | 'PASTE_ATTEMPT'\n | 'CONTEXT_MENU';\nexport type TecAssessmentEventType =\n TecAssessmentSignal | 'STARTED' | 'SUBMITTED' | 'EXPIRED' | 'REVIEWED' | 'CERTIFICATE_ISSUED';\nexport type TecAssessmentReviewDecision = 'VERIFIED' | 'REJECTED';\n\n/* ------------------------------------------------------------------ types */\n\nexport interface TecAssessment {\n id: string;\n courseId: string;\n title: string;\n description?: string | null;\n status: TecAssessmentStatus;\n timeLimitMinutes: number;\n passingScore: number;\n maxAttempts: number;\n questionCount: number;\n shuffleQuestions: boolean;\n shuffleOptions: boolean;\n proctoringMode: TecProctoringMode;\n requireFullscreen: boolean;\n blockClipboard: boolean;\n maxIntegrityViolations: number;\n issuesCertificate: boolean;\n publishedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n course?: { id: string; title: string } | null;\n}\n\nexport interface TecAssessmentQuestion {\n position: number;\n prompt: string;\n options: string[];\n}\n\nexport interface TecAssessmentAttempt {\n id: string;\n assessmentId: string;\n courseId: string;\n learnerId: string;\n attemptNumber: number;\n status: TecAssessmentAttemptStatus;\n startedAt: string;\n deadlineAt: string;\n submittedAt?: string | null;\n remainingSeconds: number;\n questions: TecAssessmentQuestion[];\n savedAnswers: number[];\n requireFullscreen: boolean;\n blockClipboard: boolean;\n score?: number | null;\n passed?: boolean | null;\n passingScore: number;\n correctCount: number;\n totalCount: number;\n proctoringMode: TecProctoringMode;\n proctoringStatus: TecProctoringStatus;\n integrityViolations: number;\n maxIntegrityViolations: number;\n consentedAt?: string | null;\n reviewedBy?: string | null;\n reviewedAt?: string | null;\n reviewNotes?: string | null;\n certificateId?: string | null;\n certificate?: {\n id: string;\n serial: string;\n score: number;\n status: string;\n issuedAt: string;\n } | null;\n}\n\nexport interface TecAssessmentEvent {\n id: string;\n attemptId: string;\n type: TecAssessmentEventType;\n violation: boolean;\n detail?: Record<string, unknown> | null;\n occurredAt: string;\n}\n\nexport interface TecAssessmentQuestionInput {\n prompt: string;\n options: string[];\n correctOption: number;\n explanation: string | null;\n}\n\nexport interface TecAssessmentInput {\n title?: string;\n description?: string | null;\n timeLimitMinutes?: number;\n passingScore?: number;\n maxAttempts?: number;\n shuffleQuestions?: boolean;\n shuffleOptions?: boolean;\n proctoringMode?: TecProctoringMode;\n requireFullscreen?: boolean;\n blockClipboard?: boolean;\n maxIntegrityViolations?: number;\n issuesCertificate?: boolean;\n questions?: TecAssessmentQuestionInput[];\n}\n\n/* -------------------------------------------------------------- fragments */\n\nconst ASSESSMENT_FIELDS = gql`\n fragment AssessmentFields on TecAssessment {\n id\n courseId\n title\n description\n status\n timeLimitMinutes\n passingScore\n maxAttempts\n questionCount\n shuffleQuestions\n shuffleOptions\n proctoringMode\n requireFullscreen\n blockClipboard\n maxIntegrityViolations\n issuesCertificate\n publishedAt\n createdAt\n updatedAt\n }\n`;\n\nconst ATTEMPT_FIELDS = gql`\n fragment AssessmentAttemptFields on TecAssessmentAttempt {\n id\n assessmentId\n courseId\n learnerId\n attemptNumber\n status\n startedAt\n deadlineAt\n submittedAt\n remainingSeconds\n questions {\n position\n prompt\n options\n }\n savedAnswers\n requireFullscreen\n blockClipboard\n score\n passed\n passingScore\n correctCount\n totalCount\n proctoringMode\n proctoringStatus\n integrityViolations\n maxIntegrityViolations\n consentedAt\n reviewedBy\n reviewedAt\n reviewNotes\n certificateId\n certificate {\n id\n serial\n score\n status\n issuedAt\n }\n }\n`;\n\n/* ----------------------------------------------------------- operations */\n\nconst LIST_ASSESSMENTS = gql`\n ${ASSESSMENT_FIELDS}\n query TecListAssessments(\n $courseId: ID\n $status: TecAssessmentStatus\n $pagination: PaginationInput\n ) {\n tecListAssessments(courseId: $courseId, status: $status, pagination: $pagination) {\n ...AssessmentFields\n }\n }\n`;\n\nconst GET_ASSESSMENT = gql`\n ${ASSESSMENT_FIELDS}\n query TecAssessment($id: ID!) {\n tecAssessment(id: $id) {\n ...AssessmentFields\n course {\n id\n title\n }\n }\n }\n`;\n\nconst ASSESSMENT_QUESTION_KEY = gql`\n query TecAssessmentQuestionKey($id: ID!) {\n tecAssessmentQuestionKey(id: $id) {\n prompt\n options\n correctOption\n explanation\n }\n }\n`;\n\nconst MY_ATTEMPTS = gql`\n ${ATTEMPT_FIELDS}\n query TecMyAssessmentAttempts($assessmentId: ID, $pagination: PaginationInput) {\n tecMyAssessmentAttempts(assessmentId: $assessmentId, pagination: $pagination) {\n ...AssessmentAttemptFields\n }\n }\n`;\n\nconst LIST_ATTEMPTS = gql`\n ${ATTEMPT_FIELDS}\n query TecListAssessmentAttempts(\n $assessmentId: ID\n $proctoringStatus: TecProctoringStatus\n $pagination: PaginationInput\n ) {\n tecListAssessmentAttempts(\n assessmentId: $assessmentId\n proctoringStatus: $proctoringStatus\n pagination: $pagination\n ) {\n ...AssessmentAttemptFields\n }\n }\n`;\n\nconst ATTEMPT_EVENTS = gql`\n query TecAssessmentAttemptEvents($attemptId: ID!, $pagination: PaginationInput) {\n tecAssessmentAttemptEvents(attemptId: $attemptId, pagination: $pagination) {\n id\n attemptId\n type\n violation\n detail\n occurredAt\n }\n }\n`;\n\nconst CREATE_ASSESSMENT = gql`\n ${ASSESSMENT_FIELDS}\n mutation TecCreateAssessment($input: TecCreateAssessmentInput!) {\n tecCreateAssessment(input: $input) {\n ...AssessmentFields\n }\n }\n`;\n\nconst UPDATE_ASSESSMENT = gql`\n ${ASSESSMENT_FIELDS}\n mutation TecUpdateAssessment($id: ID!, $input: TecUpdateAssessmentInput!) {\n tecUpdateAssessment(id: $id, input: $input) {\n ...AssessmentFields\n }\n }\n`;\n\nconst PUBLISH_ASSESSMENT = gql`\n ${ASSESSMENT_FIELDS}\n mutation TecPublishAssessment($id: ID!) {\n tecPublishAssessment(id: $id) {\n ...AssessmentFields\n }\n }\n`;\n\nconst ARCHIVE_ASSESSMENT = gql`\n ${ASSESSMENT_FIELDS}\n mutation TecArchiveAssessment($id: ID!) {\n tecArchiveAssessment(id: $id) {\n ...AssessmentFields\n }\n }\n`;\n\nconst START_ASSESSMENT = gql`\n ${ATTEMPT_FIELDS}\n mutation TecStartAssessment($assessmentId: ID!, $acceptMonitoring: Boolean) {\n tecStartAssessment(assessmentId: $assessmentId, acceptMonitoring: $acceptMonitoring) {\n ...AssessmentAttemptFields\n }\n }\n`;\n\nconst SAVE_ANSWERS = gql`\n mutation TecSaveAssessmentAnswers($attemptId: ID!, $answers: [Int!]!) {\n tecSaveAssessmentAnswers(attemptId: $attemptId, answers: $answers) {\n id\n status\n savedAnswers\n remainingSeconds\n }\n }\n`;\n\nconst RECORD_SIGNAL = gql`\n mutation TecRecordAssessmentSignal(\n $attemptId: ID!\n $signal: TecAssessmentSignal!\n $detail: JSON\n ) {\n tecRecordAssessmentSignal(attemptId: $attemptId, signal: $signal, detail: $detail) {\n id\n status\n integrityViolations\n remainingSeconds\n }\n }\n`;\n\nconst SUBMIT_ASSESSMENT = gql`\n ${ATTEMPT_FIELDS}\n mutation TecSubmitAssessment($attemptId: ID!, $answers: [Int!]) {\n tecSubmitAssessment(attemptId: $attemptId, answers: $answers) {\n ...AssessmentAttemptFields\n }\n }\n`;\n\nconst CLAIM_CERTIFICATE = gql`\n ${ATTEMPT_FIELDS}\n mutation TecClaimAssessmentCertificate($attemptId: ID!) {\n tecClaimAssessmentCertificate(attemptId: $attemptId) {\n ...AssessmentAttemptFields\n }\n }\n`;\n\nconst REVIEW_ATTEMPT = gql`\n ${ATTEMPT_FIELDS}\n mutation TecReviewAssessmentAttempt(\n $id: ID!\n $decision: TecAssessmentReviewDecision!\n $notes: String\n ) {\n tecReviewAssessmentAttempt(id: $id, decision: $decision, notes: $notes) {\n ...AssessmentAttemptFields\n }\n }\n`;\n\n/* ------------------------------------------------------------------ hooks */\n\nconst onMutationError = (error: ErrorLike): void => {\n notify.error('Something went wrong', userMessageFromError(error));\n};\n\nconst AUTHORING_REFETCH = ['TecListAssessments', 'TecAssessment'];\nconst ATTEMPT_REFETCH = ['TecMyAssessmentAttempts', 'TecMyCertificates'];\n\nexport const useAssessmentsQuery = (\n vars: { courseId?: string | null; status?: TecAssessmentStatus | null },\n skip = false\n) =>\n useQuery<{ tecListAssessments: TecAssessment[] }>(LIST_ASSESSMENTS, {\n variables: {\n courseId: vars.courseId ?? undefined,\n status: vars.status ?? undefined,\n pagination: pageArg(100),\n },\n skip,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useAssessmentQuery = (id: string) =>\n useQuery<{ tecAssessment: TecAssessment | null }>(GET_ASSESSMENT, {\n variables: { id },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useAssessmentQuestionKeyQuery = (id: string | null) =>\n useQuery<{ tecAssessmentQuestionKey: TecQuizQuestionKey[] }>(ASSESSMENT_QUESTION_KEY, {\n variables: { id: id ?? '' },\n skip: !id,\n fetchPolicy: 'network-only',\n });\n\nexport const useMyAssessmentAttemptsQuery = (assessmentId: string | null) =>\n useQuery<{ tecMyAssessmentAttempts: TecAssessmentAttempt[] }>(MY_ATTEMPTS, {\n variables: { assessmentId: assessmentId ?? undefined, pagination: pageArg(50) },\n skip: !assessmentId,\n fetchPolicy: 'network-only',\n });\n\nexport const useAssessmentAttemptsQuery = (vars: {\n assessmentId?: string | null;\n proctoringStatus?: TecProctoringStatus | null;\n}) =>\n useQuery<{ tecListAssessmentAttempts: TecAssessmentAttempt[] }>(LIST_ATTEMPTS, {\n variables: {\n assessmentId: vars.assessmentId ?? undefined,\n proctoringStatus: vars.proctoringStatus ?? undefined,\n pagination: pageArg(100),\n },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useAssessmentAttemptEventsQuery = (attemptId: string | null) =>\n useQuery<{ tecAssessmentAttemptEvents: TecAssessmentEvent[] }>(ATTEMPT_EVENTS, {\n variables: { attemptId: attemptId ?? '', pagination: pageArg(100) },\n skip: !attemptId,\n fetchPolicy: 'network-only',\n });\n\nexport const useCreateAssessment = () =>\n useMutation<{ tecCreateAssessment: TecAssessment }>(CREATE_ASSESSMENT, {\n onError: onMutationError,\n refetchQueries: AUTHORING_REFETCH,\n });\n\nexport const useUpdateAssessment = () =>\n useMutation<{ tecUpdateAssessment: TecAssessment }>(UPDATE_ASSESSMENT, {\n onError: onMutationError,\n refetchQueries: AUTHORING_REFETCH,\n });\n\nexport const usePublishAssessment = () =>\n useMutation<{ tecPublishAssessment: TecAssessment }>(PUBLISH_ASSESSMENT, {\n onError: onMutationError,\n refetchQueries: AUTHORING_REFETCH,\n });\n\nexport const useArchiveAssessment = () =>\n useMutation<{ tecArchiveAssessment: TecAssessment }>(ARCHIVE_ASSESSMENT, {\n onError: onMutationError,\n refetchQueries: AUTHORING_REFETCH,\n });\n\n/** Errors are shown inline on the assessment page, not as toasts. */\nexport const useStartAssessment = () =>\n useMutation<{ tecStartAssessment: TecAssessmentAttempt }>(START_ASSESSMENT, {\n refetchQueries: ATTEMPT_REFETCH,\n });\n\nexport const useSaveAssessmentAnswers = () =>\n useMutation<{\n tecSaveAssessmentAnswers: Pick<\n TecAssessmentAttempt,\n 'id' | 'status' | 'savedAnswers' | 'remainingSeconds'\n >;\n }>(SAVE_ANSWERS);\n\n/** Signals are fire-and-forget: a failed report must never interrupt the exam. */\nexport const useRecordAssessmentSignal = () =>\n useMutation<{\n tecRecordAssessmentSignal: Pick<\n TecAssessmentAttempt,\n 'id' | 'status' | 'integrityViolations' | 'remainingSeconds'\n >;\n }>(RECORD_SIGNAL);\n\nexport const useSubmitAssessment = () =>\n useMutation<{ tecSubmitAssessment: TecAssessmentAttempt }>(SUBMIT_ASSESSMENT, {\n refetchQueries: ATTEMPT_REFETCH,\n });\n\nexport const useClaimAssessmentCertificate = () =>\n useMutation<{ tecClaimAssessmentCertificate: TecAssessmentAttempt }>(CLAIM_CERTIFICATE, {\n onError: onMutationError,\n refetchQueries: ATTEMPT_REFETCH,\n });\n\nexport const useReviewAssessmentAttempt = () =>\n useMutation<{ tecReviewAssessmentAttempt: TecAssessmentAttempt }>(REVIEW_ATTEMPT, {\n onError: onMutationError,\n refetchQueries: ['TecListAssessmentAttempts', 'TecAssessmentAttemptEvents'],\n });\n"],"mappings":";;;;;;AA2IA,IAAM,IAAoB,CAAG;;;;;;;;;;;;;;;;;;;;;;GAwBvB,IAAiB,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CpB,IAAmB,CAAG;IACxB,EAAkB;;;;;;;;;;GAYhB,IAAiB,CAAG;IACtB,EAAkB;;;;;;;;;;GAYhB,IAA0B,CAAG;;;;;;;;;GAW7B,IAAc,CAAG;IACnB,EAAe;;;;;;GAQb,IAAgB,CAAG;IACrB,EAAe;;;;;;;;;;;;;;GAgBb,IAAiB,CAAG;;;;;;;;;;;GAapB,IAAoB,CAAG;IACzB,EAAkB;;;;;;GAQhB,IAAoB,CAAG;IACzB,EAAkB;;;;;;GAQhB,IAAqB,CAAG;IAC1B,EAAkB;;;;;;GAQhB,IAAqB,CAAG;IAC1B,EAAkB;;;;;;GAQhB,IAAmB,CAAG;IACxB,EAAe;;;;;;GAQb,IAAe,CAAG;;;;;;;;;GAWlB,IAAgB,CAAG;;;;;;;;;;;;;GAenB,IAAoB,CAAG;IACzB,EAAe;;;;;;GAQb,IAAoB,CAAG;IACzB,EAAe;;;;;;GAQb,IAAiB,CAAG;IACtB,EAAe;;;;;;;;;;GAcb,KAAmB,MAA2B;AAClD,GAAO,MAAM,wBAAwB,EAAqB,EAAM,CAAC;GAG7D,IAAoB,CAAC,sBAAsB,gBAAgB,EAC3D,IAAkB,CAAC,2BAA2B,oBAAoB,EAE3D,KACX,GACA,IAAO,OAEP,EAAkD,GAAkB;CAClE,WAAW;EACT,UAAU,EAAK,YAAY,KAAA;EAC3B,QAAQ,EAAK,UAAU,KAAA;EACvB,YAAY,EAAQ,IAAI;EACzB;CACD;CACA,aAAa;CACd,CAAC,EAES,KAAsB,MACjC,EAAkD,GAAgB;CAChE,WAAW,EAAE,OAAI;CACjB,MAAM,CAAC;CACP,aAAa;CACd,CAAC,EAES,KAAiC,MAC5C,EAA6D,GAAyB;CACpF,WAAW,EAAE,IAAI,KAAM,IAAI;CAC3B,MAAM,CAAC;CACP,aAAa;CACd,CAAC,EAES,KAAgC,MAC3C,EAA8D,GAAa;CACzE,WAAW;EAAE,cAAc,KAAgB,KAAA;EAAW,YAAY,EAAQ,GAAG;EAAE;CAC/E,MAAM,CAAC;CACP,aAAa;CACd,CAAC,EAES,KAA8B,MAIzC,EAAgE,GAAe;CAC7E,WAAW;EACT,cAAc,EAAK,gBAAgB,KAAA;EACnC,kBAAkB,EAAK,oBAAoB,KAAA;EAC3C,YAAY,EAAQ,IAAI;EACzB;CACD,aAAa;CACd,CAAC,EAES,KAAmC,MAC9C,EAA+D,GAAgB;CAC7E,WAAW;EAAE,WAAW,KAAa;EAAI,YAAY,EAAQ,IAAI;EAAE;CACnE,MAAM,CAAC;CACP,aAAa;CACd,CAAC,EAES,UACX,EAAoD,GAAmB;CACrE,SAAS;CACT,gBAAgB;CACjB,CAAC,EAES,UACX,EAAoD,GAAmB;CACrE,SAAS;CACT,gBAAgB;CACjB,CAAC,EAES,UACX,EAAqD,GAAoB;CACvE,SAAS;CACT,gBAAgB;CACjB,CAAC,EAES,UACX,EAAqD,GAAoB;CACvE,SAAS;CACT,gBAAgB;CACjB,CAAC,EAGS,UACX,EAA0D,GAAkB,EAC1E,gBAAgB,GACjB,CAAC,EAES,UACX,EAKG,EAAa,EAGL,UACX,EAKG,EAAc,EAEN,UACX,EAA2D,GAAmB,EAC5E,gBAAgB,GACjB,CAAC,EAES,UACX,EAAqE,GAAmB;CACtF,SAAS;CACT,gBAAgB;CACjB,CAAC,EAES,UACX,EAAkE,GAAgB;CAChF,SAAS;CACT,gBAAgB,CAAC,6BAA6B,6BAA6B;CAC5E,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The course's published certification assessments (BOFF-4427), each with
3
+ * its time limit, pass mark and integrity mode, linking to the exam page.
4
+ * Renders nothing when the course has none.
5
+ */
6
+ export declare function CourseAssessments({ courseId }: {
7
+ courseId: string;
8
+ }): import("react").JSX.Element | null;
9
+ //# sourceMappingURL=CourseAssessments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CourseAssessments.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/CourseAssessments.tsx"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,sCA0CnE"}
@@ -0,0 +1,66 @@
1
+ import { useTechnoSpamNavigate as e } from "../providers/TechnoSpamProvider.js";
2
+ import { humanizeEnum as t } from "../utils/format.js";
3
+ import { useAssessmentsQuery as n } from "../api/assessmentApi.js";
4
+ import { assessmentPath as r } from "../utils/assessment.js";
5
+ import { ArrowRight as i, ShieldCheck as a, Timer as o } from "lucide-react";
6
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
7
+ import { Button as l, GlassCard as u } from "@burdenoff/fe-libs/ui";
8
+ //#region src/technospam/components/CourseAssessments.tsx
9
+ function d({ courseId: d }) {
10
+ let f = e(), { data: p } = n({
11
+ courseId: d,
12
+ status: "PUBLISHED"
13
+ }, !d), m = p?.tecListAssessments ?? [];
14
+ return m.length === 0 ? null : /* @__PURE__ */ c(u, {
15
+ className: "mb-6 p-5",
16
+ "data-testid": "course-assessments",
17
+ children: [/* @__PURE__ */ c("h2", {
18
+ className: "mb-3 flex items-center gap-2 text-base font-semibold text-text-primary",
19
+ children: [/* @__PURE__ */ s(a, {
20
+ size: 18,
21
+ className: "text-accent-primary"
22
+ }), " Certification assessments"]
23
+ }), /* @__PURE__ */ s("div", {
24
+ className: "flex flex-col divide-y divide-border-seam",
25
+ children: m.map((e) => /* @__PURE__ */ c("div", {
26
+ className: "flex flex-wrap items-center justify-between gap-3 py-3",
27
+ children: [/* @__PURE__ */ c("div", {
28
+ className: "min-w-0",
29
+ children: [/* @__PURE__ */ s("div", {
30
+ className: "truncate text-sm font-semibold text-text-primary",
31
+ children: e.title
32
+ }), /* @__PURE__ */ c("div", {
33
+ className: "flex flex-wrap items-center gap-x-3 text-xs text-text-muted",
34
+ children: [
35
+ /* @__PURE__ */ c("span", {
36
+ className: "flex items-center gap-1",
37
+ children: [
38
+ /* @__PURE__ */ s(o, { size: 12 }),
39
+ " ",
40
+ e.timeLimitMinutes,
41
+ " min"
42
+ ]
43
+ }),
44
+ /* @__PURE__ */ c("span", { children: [e.questionCount, " questions"] }),
45
+ /* @__PURE__ */ c("span", { children: [
46
+ "Pass mark ",
47
+ e.passingScore,
48
+ "%"
49
+ ] }),
50
+ /* @__PURE__ */ s("span", { children: t(e.proctoringMode) })
51
+ ]
52
+ })]
53
+ }), /* @__PURE__ */ c(l, {
54
+ size: "sm",
55
+ variant: "outline",
56
+ onClick: () => f(r(e.id)),
57
+ children: ["Open ", /* @__PURE__ */ s(i, { size: 14 })]
58
+ })]
59
+ }, e.id))
60
+ })]
61
+ });
62
+ }
63
+ //#endregion
64
+ export { d as CourseAssessments };
65
+
66
+ //# sourceMappingURL=CourseAssessments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CourseAssessments.js","names":[],"sources":["../../../src/technospam/components/CourseAssessments.tsx"],"sourcesContent":["import { ArrowRight, ShieldCheck, Timer } from 'lucide-react';\nimport { Button, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { useAssessmentsQuery } from '../api/assessmentApi';\nimport { useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport { assessmentPath } from '../utils/assessment';\nimport { humanizeEnum } from '../utils/format';\n\n/**\n * The course's published certification assessments (BOFF-4427), each with\n * its time limit, pass mark and integrity mode, linking to the exam page.\n * Renders nothing when the course has none.\n */\nexport function CourseAssessments({ courseId }: { courseId: string }) {\n const navigate = useTechnoSpamNavigate();\n const { data } = useAssessmentsQuery({ courseId, status: 'PUBLISHED' }, !courseId);\n const assessments = data?.tecListAssessments ?? [];\n if (assessments.length === 0) return null;\n\n return (\n <GlassCard className=\"mb-6 p-5\" data-testid=\"course-assessments\">\n <h2 className=\"mb-3 flex items-center gap-2 text-base font-semibold text-text-primary\">\n <ShieldCheck size={18} className=\"text-accent-primary\" /> Certification assessments\n </h2>\n <div className=\"flex flex-col divide-y divide-border-seam\">\n {assessments.map((assessment) => (\n <div\n key={assessment.id}\n className=\"flex flex-wrap items-center justify-between gap-3 py-3\"\n >\n <div className=\"min-w-0\">\n <div className=\"truncate text-sm font-semibold text-text-primary\">\n {assessment.title}\n </div>\n <div className=\"flex flex-wrap items-center gap-x-3 text-xs text-text-muted\">\n <span className=\"flex items-center gap-1\">\n <Timer size={12} /> {assessment.timeLimitMinutes} min\n </span>\n <span>{assessment.questionCount} questions</span>\n <span>Pass mark {assessment.passingScore}%</span>\n <span>{humanizeEnum(assessment.proctoringMode)}</span>\n </div>\n </div>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate(assessmentPath(assessment.id))}\n >\n Open <ArrowRight size={14} />\n </Button>\n </div>\n ))}\n </div>\n </GlassCard>\n );\n}\n"],"mappings":";;;;;;;;AAYA,SAAgB,EAAkB,EAAE,eAAkC;CACpE,IAAM,IAAW,GAAuB,EAClC,EAAE,YAAS,EAAoB;EAAE;EAAU,QAAQ;EAAa,EAAE,CAAC,EAAS,EAC5E,IAAc,GAAM,sBAAsB,EAAE;AAGlD,QAFI,EAAY,WAAW,IAAU,OAGnC,kBAAC,GAAD;EAAW,WAAU;EAAW,eAAY;YAA5C,CACE,kBAAC,MAAD;GAAI,WAAU;aAAd,CACE,kBAAC,GAAD;IAAa,MAAM;IAAI,WAAU;IAAwB,CAAA,EAAA,6BACtD;MACL,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAY,KAAK,MAChB,kBAAC,OAAD;IAEE,WAAU;cAFZ,CAIE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAW;MACR,CAAA,EACN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;SAAE,EAAW;SAAiB;SAC5C;;OACP,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAW,eAAc,aAAiB,EAAA,CAAA;OACjD,kBAAC,QAAD,EAAA,UAAA;QAAM;QAAW,EAAW;QAAa;QAAQ,EAAA,CAAA;OACjD,kBAAC,QAAD,EAAA,UAAO,EAAa,EAAW,eAAe,EAAQ,CAAA;OAClD;QACF;QACN,kBAAC,GAAD;KACE,MAAK;KACL,SAAQ;KACR,eAAe,EAAS,EAAe,EAAW,GAAG,CAAC;eAHxD,CAIC,SACM,kBAAC,GAAD,EAAY,MAAM,IAAM,CAAA,CACtB;OACL;MAvBC,EAAW,GAuBZ,CACN;GACE,CAAA,CACI"}
@@ -1 +1 @@
1
- {"version":3,"file":"StatusBadge.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/StatusBadge.tsx"],"names":[],"mappings":"AAiEA,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,IAAe,GAChB,EAAE;IACD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC3B,sCAQA"}
1
+ {"version":3,"file":"StatusBadge.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/StatusBadge.tsx"],"names":[],"mappings":"AAyEA,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,IAAe,GAChB,EAAE;IACD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC3B,sCAQA"}
@@ -37,7 +37,14 @@ var r = {
37
37
  JUDGING: "info",
38
38
  SUBMITTED: "success",
39
39
  DISQUALIFIED: "danger",
40
- WINNER: "success"
40
+ WINNER: "success",
41
+ EXPIRED: "warning",
42
+ NOT_REQUIRED: "neutral",
43
+ MONITORING: "info",
44
+ PENDING_REVIEW: "info",
45
+ VERIFIED: "success",
46
+ FLAGGED: "warning",
47
+ REJECTED: "danger"
41
48
  }, a = {
42
49
  EASY: "success",
43
50
  MEDIUM: "warning",
@@ -1 +1 @@
1
- {"version":3,"file":"StatusBadge.js","names":[],"sources":["../../../src/technospam/components/StatusBadge.tsx"],"sourcesContent":["import { Badge } from '@burdenoff/fe-libs/ui';\nimport { humanizeEnum } from '../utils/format';\n\ntype Tone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\nconst TONE_CLASS: Record<Tone, string> = {\n neutral: 'bg-bg-sunken text-text-secondary border-border-seam',\n info: 'bg-accent-primary/6 text-accent-primary border-accent-primary/30',\n success: 'bg-status-success-bg-subtle text-status-success-text border-status-success-border',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text border-status-warning-border',\n danger: 'bg-status-error-bg-subtle text-status-error-text border-status-error-border',\n};\n\n/** Maps any Tec* status enum to a semantic tone. Unknown values fall back to neutral. */\nconst STATUS_TONE: Record<string, Tone> = {\n // course / problem\n DRAFT: 'neutral',\n PUBLISHED: 'success',\n ARCHIVED: 'warning',\n // enrollment\n ENROLLED: 'info',\n IN_PROGRESS: 'info',\n COMPLETED: 'success',\n DROPPED: 'warning',\n // certificate\n ISSUED: 'success',\n REVOKED: 'danger',\n // certificate verification (BOFF-4430)\n VALID: 'success',\n NOT_FOUND: 'warning',\n // submission verdict\n PENDING: 'neutral',\n ACCEPTED: 'success',\n WRONG_ANSWER: 'danger',\n TIME_LIMIT_EXCEEDED: 'warning',\n RUNTIME_ERROR: 'danger',\n COMPILE_ERROR: 'danger',\n // mentor\n ACTIVE: 'success',\n PAUSED: 'warning',\n INACTIVE: 'neutral',\n // session\n REQUESTED: 'info',\n CONFIRMED: 'success',\n CANCELLED: 'danger',\n NO_SHOW: 'danger',\n // hackathon\n REGISTRATION_OPEN: 'success',\n JUDGING: 'info',\n // team\n SUBMITTED: 'success',\n DISQUALIFIED: 'danger',\n WINNER: 'success',\n};\n\nconst DIFFICULTY_TONE: Record<string, Tone> = {\n EASY: 'success',\n MEDIUM: 'warning',\n HARD: 'danger',\n BEGINNER: 'success',\n INTERMEDIATE: 'info',\n ADVANCED: 'warning',\n EXPERT: 'danger',\n};\n\nexport function StatusBadge({\n status,\n kind = 'status',\n}: {\n status?: string | null;\n kind?: 'status' | 'level';\n}) {\n if (!status) return null;\n const tone = (kind === 'level' ? DIFFICULTY_TONE[status] : STATUS_TONE[status]) ?? 'neutral';\n return (\n <Badge variant=\"outline\" className={TONE_CLASS[tone]}>\n {humanizeEnum(status)}\n </Badge>\n );\n}\n"],"mappings":";;;;AAKA,IAAM,IAAmC;CACvC,SAAS;CACT,MAAM;CACN,SAAS;CACT,SAAS;CACT,QAAQ;CACT,EAGK,IAAoC;CAExC,OAAO;CACP,WAAW;CACX,UAAU;CAEV,UAAU;CACV,aAAa;CACb,WAAW;CACX,SAAS;CAET,QAAQ;CACR,SAAS;CAET,OAAO;CACP,WAAW;CAEX,SAAS;CACT,UAAU;CACV,cAAc;CACd,qBAAqB;CACrB,eAAe;CACf,eAAe;CAEf,QAAQ;CACR,QAAQ;CACR,UAAU;CAEV,WAAW;CACX,WAAW;CACX,WAAW;CACX,SAAS;CAET,mBAAmB;CACnB,SAAS;CAET,WAAW;CACX,cAAc;CACd,QAAQ;CACT,EAEK,IAAwC;CAC5C,MAAM;CACN,QAAQ;CACR,MAAM;CACN,UAAU;CACV,cAAc;CACd,UAAU;CACV,QAAQ;CACT;AAED,SAAgB,EAAY,EAC1B,WACA,UAAO,YAIN;AAGD,QAFK,IAGH,kBAAC,GAAD;EAAO,SAAQ;EAAU,WAAW,GAFxB,MAAS,UAAU,EAAgB,KAAU,EAAY,OAAY;YAG9E,EAAa,EAAO;EACf,CAAA,GALU"}
1
+ {"version":3,"file":"StatusBadge.js","names":[],"sources":["../../../src/technospam/components/StatusBadge.tsx"],"sourcesContent":["import { Badge } from '@burdenoff/fe-libs/ui';\nimport { humanizeEnum } from '../utils/format';\n\ntype Tone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\nconst TONE_CLASS: Record<Tone, string> = {\n neutral: 'bg-bg-sunken text-text-secondary border-border-seam',\n info: 'bg-accent-primary/6 text-accent-primary border-accent-primary/30',\n success: 'bg-status-success-bg-subtle text-status-success-text border-status-success-border',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text border-status-warning-border',\n danger: 'bg-status-error-bg-subtle text-status-error-text border-status-error-border',\n};\n\n/** Maps any Tec* status enum to a semantic tone. Unknown values fall back to neutral. */\nconst STATUS_TONE: Record<string, Tone> = {\n // course / problem\n DRAFT: 'neutral',\n PUBLISHED: 'success',\n ARCHIVED: 'warning',\n // enrollment\n ENROLLED: 'info',\n IN_PROGRESS: 'info',\n COMPLETED: 'success',\n DROPPED: 'warning',\n // certificate\n ISSUED: 'success',\n REVOKED: 'danger',\n // certificate verification (BOFF-4430)\n VALID: 'success',\n NOT_FOUND: 'warning',\n // submission verdict\n PENDING: 'neutral',\n ACCEPTED: 'success',\n WRONG_ANSWER: 'danger',\n TIME_LIMIT_EXCEEDED: 'warning',\n RUNTIME_ERROR: 'danger',\n COMPILE_ERROR: 'danger',\n // mentor\n ACTIVE: 'success',\n PAUSED: 'warning',\n INACTIVE: 'neutral',\n // session\n REQUESTED: 'info',\n CONFIRMED: 'success',\n CANCELLED: 'danger',\n NO_SHOW: 'danger',\n // hackathon\n REGISTRATION_OPEN: 'success',\n JUDGING: 'info',\n // team\n SUBMITTED: 'success',\n DISQUALIFIED: 'danger',\n WINNER: 'success',\n // assessment attempt / proctoring (BOFF-4427)\n EXPIRED: 'warning',\n NOT_REQUIRED: 'neutral',\n MONITORING: 'info',\n PENDING_REVIEW: 'info',\n VERIFIED: 'success',\n FLAGGED: 'warning',\n REJECTED: 'danger',\n};\n\nconst DIFFICULTY_TONE: Record<string, Tone> = {\n EASY: 'success',\n MEDIUM: 'warning',\n HARD: 'danger',\n BEGINNER: 'success',\n INTERMEDIATE: 'info',\n ADVANCED: 'warning',\n EXPERT: 'danger',\n};\n\nexport function StatusBadge({\n status,\n kind = 'status',\n}: {\n status?: string | null;\n kind?: 'status' | 'level';\n}) {\n if (!status) return null;\n const tone = (kind === 'level' ? DIFFICULTY_TONE[status] : STATUS_TONE[status]) ?? 'neutral';\n return (\n <Badge variant=\"outline\" className={TONE_CLASS[tone]}>\n {humanizeEnum(status)}\n </Badge>\n );\n}\n"],"mappings":";;;;AAKA,IAAM,IAAmC;CACvC,SAAS;CACT,MAAM;CACN,SAAS;CACT,SAAS;CACT,QAAQ;CACT,EAGK,IAAoC;CAExC,OAAO;CACP,WAAW;CACX,UAAU;CAEV,UAAU;CACV,aAAa;CACb,WAAW;CACX,SAAS;CAET,QAAQ;CACR,SAAS;CAET,OAAO;CACP,WAAW;CAEX,SAAS;CACT,UAAU;CACV,cAAc;CACd,qBAAqB;CACrB,eAAe;CACf,eAAe;CAEf,QAAQ;CACR,QAAQ;CACR,UAAU;CAEV,WAAW;CACX,WAAW;CACX,WAAW;CACX,SAAS;CAET,mBAAmB;CACnB,SAAS;CAET,WAAW;CACX,cAAc;CACd,QAAQ;CAER,SAAS;CACT,cAAc;CACd,YAAY;CACZ,gBAAgB;CAChB,UAAU;CACV,SAAS;CACT,UAAU;CACX,EAEK,IAAwC;CAC5C,MAAM;CACN,QAAQ;CACR,MAAM;CACN,UAAU;CACV,cAAc;CACd,UAAU;CACV,QAAQ;CACT;AAED,SAAgB,EAAY,EAC1B,WACA,UAAO,YAIN;AAGD,QAFK,IAGH,kBAAC,GAAD;EAAO,SAAQ;EAAU,WAAW,GAFxB,MAAS,UAAU,EAAgB,KAAU,EAAY,OAAY;YAG9E,EAAa,EAAO;EACf,CAAA,GALU"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Authoring console tab for certification assessments (BOFF-4427): pick a
3
+ * course, create / edit / publish / archive its assessments, and work the
4
+ * review queue of flagged and review-required attempts.
5
+ */
6
+ export declare function AssessmentsAdminTab(): import("react").JSX.Element;
7
+ //# sourceMappingURL=AssessmentsAdminTab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssessmentsAdminTab.d.ts","sourceRoot":"","sources":["../../../../src/technospam/components/admin/AssessmentsAdminTab.tsx"],"names":[],"mappings":"AAyUA;;;;GAIG;AACH,wBAAgB,mBAAmB,gCAsKlC"}