@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,57 @@
1
+ import { useCallback as e, useEffect as t, useRef as n, useState as r } from "react";
2
+ //#region src/technospam/hooks/useAssessmentIntegrity.ts
3
+ var i = 800;
4
+ function a() {
5
+ return typeof document > "u" ? null : document.fullscreenElement;
6
+ }
7
+ function o({ active: o, requireFullscreen: s, blockClipboard: c, onSignal: l }) {
8
+ let u = typeof document < "u" && document.fullscreenEnabled === !0 && typeof document.documentElement.requestFullscreen == "function", [d, f] = r(() => a() !== null), p = n(l);
9
+ t(() => {
10
+ p.current = l;
11
+ }, [l]);
12
+ let m = n(0), h = n(!1), g = e(async () => {
13
+ if (!u) return !1;
14
+ try {
15
+ return await document.documentElement.requestFullscreen(), h.current = !0, !0;
16
+ } catch {
17
+ return !1;
18
+ }
19
+ }, [u]);
20
+ return t(() => {
21
+ if (!o) return;
22
+ let e = (e, t) => p.current(e, t), t, n = () => {
23
+ t !== void 0 && window.clearTimeout(t), t = void 0;
24
+ }, r = () => {
25
+ document.visibilityState === "hidden" && (m.current = Date.now(), n(), e("VISIBILITY_HIDDEN"));
26
+ }, l = () => {
27
+ Date.now() - m.current < i || document.visibilityState !== "hidden" && (n(), t = window.setTimeout(() => {
28
+ t = void 0, document.visibilityState !== "hidden" && (Date.now() - m.current < i || e("WINDOW_BLUR"));
29
+ }, i));
30
+ }, u = () => {
31
+ let t = a() !== null;
32
+ f(t), s && e(t ? "FULLSCREEN_ENTER" : "FULLSCREEN_EXIT");
33
+ }, d = (t) => (n) => {
34
+ c && (n.preventDefault(), e(t));
35
+ }, h = d("COPY_ATTEMPT"), g = d("CUT_ATTEMPT"), _ = d("PASTE_ATTEMPT"), v = d("CONTEXT_MENU");
36
+ return document.addEventListener("visibilitychange", r), window.addEventListener("blur", l), document.addEventListener("fullscreenchange", u), document.addEventListener("copy", h), document.addEventListener("cut", g), document.addEventListener("paste", _), document.addEventListener("contextmenu", v), () => {
37
+ n(), document.removeEventListener("visibilitychange", r), window.removeEventListener("blur", l), document.removeEventListener("fullscreenchange", u), document.removeEventListener("copy", h), document.removeEventListener("cut", g), document.removeEventListener("paste", _), document.removeEventListener("contextmenu", v);
38
+ };
39
+ }, [
40
+ o,
41
+ s,
42
+ c
43
+ ]), t(() => {
44
+ let e = () => {
45
+ h.current && (h.current = !1, a() !== null && typeof document.exitFullscreen == "function" && document.exitFullscreen().catch(() => void 0));
46
+ };
47
+ return o || e(), e;
48
+ }, [o]), {
49
+ fullscreenSupported: u,
50
+ isFullscreen: d,
51
+ enterFullscreen: g
52
+ };
53
+ }
54
+ //#endregion
55
+ export { o as useAssessmentIntegrity };
56
+
57
+ //# sourceMappingURL=useAssessmentIntegrity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAssessmentIntegrity.js","names":[],"sources":["../../../src/technospam/hooks/useAssessmentIntegrity.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport type { TecAssessmentSignal } from '../api/assessmentApi';\n\n/**\n * Browser-side integrity hooks for a running assessment attempt (BOFF-4427).\n *\n * While `active`, it:\n * - reports leaving the tab (`visibilitychange`) and the window (`blur`);\n * a blur that the tab switch already explains is not reported twice;\n * - tracks fullscreen and reports leaving it when the attempt requires it;\n * - blocks copy / cut / paste and the context menu when the attempt says so,\n * and reports each try.\n *\n * These are deterrents and evidence, not a lockdown: the server decides what\n * counts as a violation and what happens to the attempt.\n */\nexport interface IntegrityOptions {\n active: boolean;\n requireFullscreen: boolean;\n blockClipboard: boolean;\n onSignal: (\n signal: TecAssessmentSignal,\n detail?: Record<string, string | number | boolean>\n ) => void;\n}\n\nexport interface IntegrityState {\n /** Fullscreen is supported by this browser (and not blocked by the embedding page). */\n fullscreenSupported: boolean;\n isFullscreen: boolean;\n enterFullscreen: () => Promise<boolean>;\n}\n\n/** Window-level blur within this window of a visibility change is the same event. */\nconst BLUR_DEDUP_MS = 800;\n\nfunction fullscreenElement(): Element | null {\n return typeof document === 'undefined' ? null : document.fullscreenElement;\n}\n\nexport function useAssessmentIntegrity({\n active,\n requireFullscreen,\n blockClipboard,\n onSignal,\n}: IntegrityOptions): IntegrityState {\n const fullscreenSupported =\n typeof document !== 'undefined' &&\n document.fullscreenEnabled === true &&\n typeof document.documentElement.requestFullscreen === 'function';\n const [isFullscreen, setIsFullscreen] = useState<boolean>(() => fullscreenElement() !== null);\n const signalRef = useRef(onSignal);\n useEffect(() => {\n signalRef.current = onSignal;\n }, [onSignal]);\n const lastHiddenAt = useRef(0);\n // Whether this hook put the page into fullscreen, so it only exits what it entered.\n const acquiredFullscreen = useRef(false);\n\n const enterFullscreen = useCallback(async (): Promise<boolean> => {\n if (!fullscreenSupported) return false;\n try {\n await document.documentElement.requestFullscreen();\n acquiredFullscreen.current = true;\n return true;\n } catch {\n return false;\n }\n }, [fullscreenSupported]);\n\n useEffect(() => {\n if (!active) return undefined;\n const report = (\n signal: TecAssessmentSignal,\n detail?: Record<string, string | number | boolean>\n ): void => signalRef.current(signal, detail);\n\n // A tab switch fires both blur and visibilitychange, in either order.\n // Blur is reported only after a short wait, and dropped if the tab was\n // hidden around it, so one switch counts once.\n let pendingBlur: number | undefined;\n const cancelBlur = (): void => {\n if (pendingBlur !== undefined) window.clearTimeout(pendingBlur);\n pendingBlur = undefined;\n };\n const onVisibility = (): void => {\n if (document.visibilityState === 'hidden') {\n lastHiddenAt.current = Date.now();\n cancelBlur();\n report('VISIBILITY_HIDDEN');\n }\n };\n const onBlur = (): void => {\n if (Date.now() - lastHiddenAt.current < BLUR_DEDUP_MS) return;\n if (document.visibilityState === 'hidden') return;\n cancelBlur();\n pendingBlur = window.setTimeout(() => {\n pendingBlur = undefined;\n if (document.visibilityState === 'hidden') return;\n if (Date.now() - lastHiddenAt.current < BLUR_DEDUP_MS) return;\n report('WINDOW_BLUR');\n }, BLUR_DEDUP_MS);\n };\n const onFullscreen = (): void => {\n const now = fullscreenElement() !== null;\n setIsFullscreen(now);\n if (!requireFullscreen) return;\n report(now ? 'FULLSCREEN_ENTER' : 'FULLSCREEN_EXIT');\n };\n const clipboard =\n (signal: TecAssessmentSignal) =>\n (event: Event): void => {\n if (!blockClipboard) return;\n event.preventDefault();\n report(signal);\n };\n const onCopy = clipboard('COPY_ATTEMPT');\n const onCut = clipboard('CUT_ATTEMPT');\n const onPaste = clipboard('PASTE_ATTEMPT');\n const onContextMenu = clipboard('CONTEXT_MENU');\n\n document.addEventListener('visibilitychange', onVisibility);\n window.addEventListener('blur', onBlur);\n document.addEventListener('fullscreenchange', onFullscreen);\n document.addEventListener('copy', onCopy);\n document.addEventListener('cut', onCut);\n document.addEventListener('paste', onPaste);\n document.addEventListener('contextmenu', onContextMenu);\n return () => {\n cancelBlur();\n document.removeEventListener('visibilitychange', onVisibility);\n window.removeEventListener('blur', onBlur);\n document.removeEventListener('fullscreenchange', onFullscreen);\n document.removeEventListener('copy', onCopy);\n document.removeEventListener('cut', onCut);\n document.removeEventListener('paste', onPaste);\n document.removeEventListener('contextmenu', onContextMenu);\n };\n }, [active, requireFullscreen, blockClipboard]);\n\n // Leave fullscreen when the attempt ends (monitoring turned off, or the exam\n // unmounts after submit) so the learner gets their window back.\n useEffect(() => {\n const release = (): void => {\n if (!acquiredFullscreen.current) return;\n acquiredFullscreen.current = false;\n if (fullscreenElement() !== null && typeof document.exitFullscreen === 'function') {\n void document.exitFullscreen().catch(() => undefined);\n }\n };\n if (!active) release();\n return release;\n }, [active]);\n\n return { fullscreenSupported, isFullscreen, enterFullscreen };\n}\n"],"mappings":";;AAkCA,IAAM,IAAgB;AAEtB,SAAS,IAAoC;AAC3C,QAAO,OAAO,WAAa,MAAc,OAAO,SAAS;;AAG3D,SAAgB,EAAuB,EACrC,WACA,sBACA,mBACA,eACmC;CACnC,IAAM,IACJ,OAAO,WAAa,OACpB,SAAS,sBAAsB,MAC/B,OAAO,SAAS,gBAAgB,qBAAsB,YAClD,CAAC,GAAc,KAAmB,QAAwB,GAAmB,KAAK,KAAK,EACvF,IAAY,EAAO,EAAS;AAClC,SAAgB;AACd,IAAU,UAAU;IACnB,CAAC,EAAS,CAAC;CACd,IAAM,IAAe,EAAO,EAAE,EAExB,IAAqB,EAAO,GAAM,EAElC,IAAkB,EAAY,YAA8B;AAChE,MAAI,CAAC,EAAqB,QAAO;AACjC,MAAI;AAGF,UAFA,MAAM,SAAS,gBAAgB,mBAAmB,EAClD,EAAmB,UAAU,IACtB;UACD;AACN,UAAO;;IAER,CAAC,EAAoB,CAAC;AAsFzB,QApFA,QAAgB;AACd,MAAI,CAAC,EAAQ;EACb,IAAM,KACJ,GACA,MACS,EAAU,QAAQ,GAAQ,EAAO,EAKxC,GACE,UAAyB;AAE7B,GADI,MAAgB,KAAA,KAAW,OAAO,aAAa,EAAY,EAC/D,IAAc,KAAA;KAEV,UAA2B;AAC/B,GAAI,SAAS,oBAAoB,aAC/B,EAAa,UAAU,KAAK,KAAK,EACjC,GAAY,EACZ,EAAO,oBAAoB;KAGzB,UAAqB;AACrB,QAAK,KAAK,GAAG,EAAa,UAAU,KACpC,SAAS,oBAAoB,aACjC,GAAY,EACZ,IAAc,OAAO,iBAAiB;AACpC,QAAc,KAAA,GACV,SAAS,oBAAoB,aAC7B,KAAK,KAAK,GAAG,EAAa,UAAU,KACxC,EAAO,cAAc;MACpB,EAAc;KAEb,UAA2B;GAC/B,IAAM,IAAM,GAAmB,KAAK;AACpC,KAAgB,EAAI,EACf,KACL,EAAO,IAAM,qBAAqB,kBAAkB;KAEhD,KACH,OACA,MAAuB;AACjB,SACL,EAAM,gBAAgB,EACtB,EAAO,EAAO;KAEZ,IAAS,EAAU,eAAe,EAClC,IAAQ,EAAU,cAAc,EAChC,IAAU,EAAU,gBAAgB,EACpC,IAAgB,EAAU,eAAe;AAS/C,SAPA,SAAS,iBAAiB,oBAAoB,EAAa,EAC3D,OAAO,iBAAiB,QAAQ,EAAO,EACvC,SAAS,iBAAiB,oBAAoB,EAAa,EAC3D,SAAS,iBAAiB,QAAQ,EAAO,EACzC,SAAS,iBAAiB,OAAO,EAAM,EACvC,SAAS,iBAAiB,SAAS,EAAQ,EAC3C,SAAS,iBAAiB,eAAe,EAAc,QAC1C;AAQX,GAPA,GAAY,EACZ,SAAS,oBAAoB,oBAAoB,EAAa,EAC9D,OAAO,oBAAoB,QAAQ,EAAO,EAC1C,SAAS,oBAAoB,oBAAoB,EAAa,EAC9D,SAAS,oBAAoB,QAAQ,EAAO,EAC5C,SAAS,oBAAoB,OAAO,EAAM,EAC1C,SAAS,oBAAoB,SAAS,EAAQ,EAC9C,SAAS,oBAAoB,eAAe,EAAc;;IAE3D;EAAC;EAAQ;EAAmB;EAAe,CAAC,EAI/C,QAAgB;EACd,IAAM,UAAsB;AACrB,KAAmB,YACxB,EAAmB,UAAU,IACzB,GAAmB,KAAK,QAAQ,OAAO,SAAS,kBAAmB,cAChE,SAAS,gBAAgB,CAAC,YAAY,KAAA,EAAU;;AAIzD,SADK,KAAQ,GAAS,EACf;IACN,CAAC,EAAO,CAAC,EAEL;EAAE;EAAqB;EAAc;EAAiB"}
@@ -1 +1 @@
1
- {"version":3,"file":"AdminAdminDashboardPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/AdminAdminDashboardPagePage.tsx"],"names":[],"mappings":"AA+nDA,wBAAgB,2BAA2B,gCA+D1C"}
1
+ {"version":3,"file":"AdminAdminDashboardPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/AdminAdminDashboardPagePage.tsx"],"names":[],"mappings":"AAioDA,wBAAgB,2BAA2B,gCAoE1C"}