@tinyweb_dev/oe-exam-sdk 0.1.7 → 0.1.9
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/api/exam-entry.d.ts +1 -1
- package/dist/api/exam-entry.types.d.ts +14 -0
- package/dist/api/exam-taking.types.d.ts +2 -0
- package/dist/components/exams/entry/StudentExamEntryPageContainer.d.ts +4 -2
- package/dist/components/exams/entry/StudentExamEntryPageContainer.js +1 -1
- package/dist/components/exams/take/ExamTakingPageContainer.d.ts +4 -2
- package/dist/components/exams/take/ExamTakingPageContainer.js +1 -1
- package/dist/components/exams/take/components/question-renderers/MoversWritingRenderer.js +1 -1
- package/dist/components/exams/take/exam-taking.utils.d.ts +8 -2
- package/dist/components/exams/take/exam-taking.utils.js +1 -1
- package/dist/components/exams/take/utils/question-transformers.d.ts +4 -0
- package/dist/components/exams/take/utils/question-transformers.js +1 -1
- package/dist/components/features/exam-entry/themed/CambridgeYleWaitingRoom.js +1 -1
- package/dist/components/features/exam-entry/themed/cambridge-yle-waiting-parts.d.ts +18 -0
- package/dist/components/features/exam-entry/themed/cambridge-yle-waiting-parts.js +1 -0
- package/dist/components/features/exam-entry/themed/index.d.ts +3 -0
- package/dist/components/features/exam-entry/themed/index.js +1 -1
- package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +1 -1
- package/dist/components/results/ResultReviewPageContainer.js +1 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.d.ts +2 -0
- package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.js +1 -1
- package/dist/components/themes/english-certification/EcAnswerTheQuestion.js +1 -1
- package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +1 -1
- package/dist/components/themes/english-certification/EcWordFillParagraph.js +1 -1
- package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -1
- package/dist/components/themes/english-certification/EcWritingTask.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationExamLayout.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationInstructionBanner.d.ts +17 -0
- package/dist/components/themes/english-certification/EnglishCertificationInstructionBanner.js +1 -0
- package/dist/components/themes/english-certification/EnglishCertificationPartHeader.d.ts +24 -0
- package/dist/components/themes/english-certification/EnglishCertificationPartHeader.js +1 -0
- package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.d.ts +3 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.d.ts +0 -2
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +1 -1
- package/dist/components/themes/english-certification/english-cert-scroll.d.ts +32 -0
- package/dist/components/themes/english-certification/english-cert-scroll.js +1 -0
- package/dist/components/themes/english-certification/index.d.ts +4 -1
- package/dist/components/themes/english-certification/index.js +1 -1
- package/dist/shared/lib/html-content.d.ts +14 -0
- package/dist/shared/lib/html-content.js +1 -0
- package/dist/shared/types/exam-taking.types.d.ts +2 -0
- package/dist/shared/types/student.types.d.ts +14 -0
- package/package.json +1 -1
package/dist/api/exam-entry.d.ts
CHANGED
|
@@ -11,4 +11,4 @@ export declare function createMockExamEntryApi(seed: {
|
|
|
11
11
|
room: ExamEntryRoom;
|
|
12
12
|
attempt?: ExamEntryAttempt | null;
|
|
13
13
|
}): ExamEntrySdkApi;
|
|
14
|
-
export type { ExamEntryAttempt, ExamEntryContest, ExamEntryExam, ExamEntryFetchApiOptions, ExamEntryRegistrationField, ExamEntryRegistrationFormConfig, ExamEntryRoom, ExamEntrySdkApi, } from './exam-entry.types';
|
|
14
|
+
export type { ExamEntryAttempt, ExamEntryContest, ExamEntryExam, ExamEntryFetchApiOptions, ExamEntryPartSummary, ExamEntryRegistrationField, ExamEntryRegistrationFormConfig, ExamEntryRoom, ExamEntrySdkApi, } from './exam-entry.types';
|
|
@@ -18,6 +18,17 @@ export interface ExamEntryRegistrationFormConfig {
|
|
|
18
18
|
enabled: boolean;
|
|
19
19
|
fields: ExamEntryRegistrationField[];
|
|
20
20
|
}
|
|
21
|
+
/** Summary of one exam part for student waiting room / room detail. */
|
|
22
|
+
export interface ExamEntryPartSummary {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
skill?: string;
|
|
26
|
+
category?: string;
|
|
27
|
+
points: number;
|
|
28
|
+
questionCount: number;
|
|
29
|
+
instructions?: string;
|
|
30
|
+
questionType?: string;
|
|
31
|
+
}
|
|
21
32
|
/** Exam summary nested inside a room. */
|
|
22
33
|
export interface ExamEntryExam {
|
|
23
34
|
id: string;
|
|
@@ -26,6 +37,7 @@ export interface ExamEntryExam {
|
|
|
26
37
|
durationMinutes?: number;
|
|
27
38
|
totalScore?: number;
|
|
28
39
|
passScore?: number;
|
|
40
|
+
numberOfParts?: number | null;
|
|
29
41
|
level?: string;
|
|
30
42
|
theme?: string;
|
|
31
43
|
template?: {
|
|
@@ -33,6 +45,8 @@ export interface ExamEntryExam {
|
|
|
33
45
|
subTitle?: string;
|
|
34
46
|
title?: string;
|
|
35
47
|
};
|
|
48
|
+
/** Summary parts from exams.template.parts */
|
|
49
|
+
parts?: ExamEntryPartSummary[];
|
|
36
50
|
}
|
|
37
51
|
/** Contest summary nested inside a room. */
|
|
38
52
|
export interface ExamEntryContest {
|
|
@@ -46,6 +46,8 @@ export interface ExamTakingTemplatePart {
|
|
|
46
46
|
endIndex?: number;
|
|
47
47
|
audioUrl?: string;
|
|
48
48
|
category?: string;
|
|
49
|
+
/** Max points for this part from exams.template.parts */
|
|
50
|
+
points?: number;
|
|
49
51
|
questionType?: string;
|
|
50
52
|
sections?: Array<Record<string, unknown>>;
|
|
51
53
|
isGroup?: boolean;
|
|
@@ -7,8 +7,10 @@ export interface StudentExamEntryPageContainerProps {
|
|
|
7
7
|
inviteToken?: string | null;
|
|
8
8
|
/** API adapter; create one via `createExamEntryApi`. */
|
|
9
9
|
api: ExamEntrySdkApi;
|
|
10
|
-
/** Navigation callback; falls back to `window.location.href` when omitted. */
|
|
11
|
-
onNavigate?: (href: string
|
|
10
|
+
/** Navigation callback; falls back to `window.location.href`/`replace` when omitted. */
|
|
11
|
+
onNavigate?: (href: string, options?: {
|
|
12
|
+
replace?: boolean;
|
|
13
|
+
}) => void;
|
|
12
14
|
/** Path to navigate to when starting/continuing the attempt. */
|
|
13
15
|
takePath?: (roomId: string) => string;
|
|
14
16
|
/** Path to navigate to on close/back. Overrides the default contest/discover logic. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,Fragment as t,jsxs as a}from"react/jsx-runtime";import{useState as r,useEffect as n,useCallback as i,useMemo as o}from"react";import{Dialog as s,DialogContent as l,DialogDescription as d,DialogTitle as c}from"../../../components/ui/dialog";import{t as m}from"../../../shared/lib/i18n";import{ROUTES as h}from"../../../shared/constants/routes";import{normalizeExamTheme as x,resolveThemeConfig as u}from"../../../shared/lib/themes";import{unwrap as p}from"../take/exam-taking.utils";import{toast as g}from"sonner";import{Loader2 as b,Clock as f,Trophy as v,ArrowLeft as w}from"lucide-react";import y from"next/image";import{BeforeStartCard as N,ExpiredCard as _,AlreadySubmittedCard as k}from"../../../components/features/exam-entry";import{CloseButton as T}from"../../../components/features/exam-entry/themed/components";import{ToeicWaitingRoom as E}from"../../../components/features/exam-entry/themed/ToeicWaitingRoom";import{CambridgeYleWaitingRoom as D}from"../../../components/features/exam-entry/themed/CambridgeYleWaitingRoom";import{SummerSkyWaitingRoom as S}from"../../../components/themes/summer-sky/SummerSkyWaitingRoom";import{FullscreenLoading as R}from"./fullscreen-loading";export function StudentExamEntryPageContainer({roomId:I,inviteToken:A=null,api:O,onNavigate:M,takePath:C=e=>`/student/exams/${e}/take`,closePath:B,renderRegistrationForm:W}){const L=i(e=>{M?M(e):"undefined"!=typeof window&&(window.location.href=e)},[M]),[j,F]=r(null),[z,U]=r(null),[$,P]=r("LOADING"),[X,Y]=r(0),[H,V]=r(5),[G,K]=r(!1),[Q,q]=r(!1),[J,Z]=r(null),[ee,te]=r(!1),[ae,re]=r(!1),[ne,ie]=r(!1),oe=o(()=>{const e=j?.exam?.theme,t=j?.exam?.template?.theme;return u({examTheme:e,templateTheme:t,level:j?.exam?.level})},[j?.exam,I,j]),se=o(()=>B?B(j):j?.contest?.id?h.STUDENT.CONTEST_ROOMS(j.contest.id):h.STUDENT.CONTESTS_DISCOVER,[B,j]),le=i((e,t)=>{const a=!0===e.allowMultipleSubmissions;if(t){const e=t.status;if("SUBMITTED"===e||"GRADED"===e||"PUBLISHED"===e)return a?"WITHIN_WINDOW":"ALREADY_SUBMITTED";if("IN_PROGRESS"===e)return"WITHIN_WINDOW"}const r=(new Date).getTime(),n=e.startDatetime?new Date(e.startDatetime).getTime():null,i=e.endDatetime?new Date(e.endDatetime).getTime():null;return!a&&i&&r>i?"EXPIRED":n&&r<n?"BEFORE_START":"WITHIN_WINDOW"},[]);n(()=>{(async()=>{try{if(A)try{await(O.joinViaInvite?.(I,A))}catch{}const e=await O.getRoom(I),t=p(e);if(F(t),!t.canAccess&&!A)return void P("NO_ACCESS");if(t.registrationFormConfig?.enabled&&t.registrationFormConfig.fields?.length>0&&!t.hasSubmittedFormData)return void re(!0);if(!t.exam)return void P("NO_EXAM");const a=await O.getActiveAttemptByRoom(I),r=p(a);r&&(Z(r),U(r));const n=!0===t.allowMultipleSubmissions;if(t.hasJoined&&!r&&!n)return void P("ALREADY_SUBMITTED");const i=le(t,r??null);if(P(i),"BEFORE_START"===i&&t.startDatetime){const e=new Date(t.startDatetime).getTime(),a=(new Date).getTime();Y(Math.max(0,Math.floor((e-a)/1e3)))}}catch(e){console.error("Failed to load room data:",e),g.error(m("student.exam.entry.loadError"))}})()},[I,A,le]),n(()=>{if("BEFORE_START"!==$||X<=0)return;const e=setInterval(()=>{Y(e=>e<=1?(P("WITHIN_WINDOW"),0):e-1)},1e3);return()=>clearInterval(e)},[$,X]);const de=i(async()=>{try{K(!0),await O.startAttempt(I),L(C(I))}catch(e){const t=e,a=t.response?.data?.errorCode;"ROOM_NO_EXAM"===a?P("NO_EXAM"):"ROOM_NOT_STARTED"===a?(g.error(m("student.exam.entry.notStarted")),P("BEFORE_START"),q(!1),V(5)):"ROOM_ENDED"===a?(g.error(m("student.exam.entry.expired")),P("EXPIRED")):"ATTEMPT_ALREADY_SUBMITTED"===a?(g.error("Bạn đã hoàn thành bài thi này rồi."),P("ALREADY_SUBMITTED")):g.error(m("student.exam.entry.startError")),K(!1)}},[I]),ce=i(()=>{J?te(!0):de()},[J,de]),me=i(()=>{te(!1),g.success(m("student.exam.entry.continue")),L(C(I))},[I]),he=i(async()=>{if(J)try{te(!1),K(!0),await O.deleteAttempt(J.id),Z(null),await de()}catch(e){console.error("Failed to restart attempt:",e),g.error(m("student.exam.entry.restartError")),K(!1)}},[J,de]);n(()=>{if(!Q||H<=0)return;const e=setInterval(()=>{V(e=>e<=1?(L(C(I)),0):e-1)},1e3);return()=>clearInterval(e)},[Q,H,I]);const xe=i(async e=>{if(j?.contest?.id){ie(!0);try{await(O.registerContest?.(j.contest.id,e)),re(!1);const t=await O.getRoom(I),a=p(t);if(F(a),!a.exam)return void P("NO_EXAM");const r=await O.getActiveAttemptByRoom(I),n=p(r);n&&(Z(n),U(n));const i=!0===a.allowMultipleSubmissions;if(a.hasJoined&&!n&&!i)return void P("ALREADY_SUBMITTED");const o=le(a,n??null);if(P(o),"BEFORE_START"===o&&a.startDatetime){const e=new Date(a.startDatetime).getTime(),t=(new Date).getTime();Y(Math.max(0,Math.floor((e-t)/1e3)))}}catch{g.error("Không thể gửi thông tin đăng ký. Vui lòng thử lại.")}finally{ie(!1)}}},[j?.contest?.id,I,le]);if(ae&&j?.registrationFormConfig&&W)return a(t,{children:[e(R,{}),W({room:j,onSubmit:xe,isSubmitting:ne})]});if("LOADING"===$)return e(R,{});if("NO_EXAM"===$)return e("div",{className:"fixed inset-0 z-50 flex items-center justify-center overflow-hidden bg-gradient-to-b from-sky-100 via-blue-50 to-indigo-100",children:a("div",{className:"mx-auto max-w-md p-4 text-center",children:[e("div",{className:"mb-6 text-7xl",children:"📝✨"}),e("h2",{className:"mb-3 text-2xl font-bold text-sky-700",children:"Bài thi đang được chuẩn bị"}),j&&a("div",{className:"mb-4 rounded-xl bg-white/60 px-5 py-3 text-left text-sm text-sky-700 shadow-sm backdrop-blur-sm",children:[e("p",{className:"font-semibold text-base",children:j.name}),j.code&&a("p",{className:"mt-1 text-sky-500",children:["Mã phòng: ",e("span",{className:"font-mono font-medium",children:j.code})]}),(j.startDatetime||j.endDatetime)&&a("p",{className:"mt-1 text-sky-500",children:["Thời gian thi:"," ",j.startDatetime?new Date(j.startDatetime).toLocaleString("vi-VN"):"—"," → ",j.endDatetime?new Date(j.endDatetime).toLocaleString("vi-VN"):"—"]})]}),e("p",{className:"mb-6 text-base text-sky-600",children:"Thầy cô đang chuẩn bị đề thi cho phòng này. Bạn quay lại sau nhé! 😊"}),e("button",{className:"mx-auto inline-flex items-center gap-2 rounded-2xl border-b-4 border-sky-600 bg-sky-500 px-8 py-3 text-lg font-bold text-white shadow-md transition-all hover:brightness-110 active:translate-y-0.5 active:border-b-2 active:shadow-sm",onClick:()=>window.history.back(),children:"← Quay lại"})]})});if("NO_ACCESS"===$)return e("div",{className:"fixed inset-0 z-50 flex items-center justify-center overflow-hidden bg-gradient-to-b from-red-50 via-orange-50 to-amber-50",children:a("div",{className:"mx-auto max-w-md p-4 text-center",children:[e("div",{className:"mb-6 text-7xl",children:"🔒"}),e("h2",{className:"mb-3 text-2xl font-bold text-red-600",children:"Không có quyền truy cập"}),e("p",{className:"mb-6 text-base text-red-500",children:"Bạn chưa được đăng ký vào phòng thi này. Hãy liên hệ thầy cô để được thêm vào phòng thi nhé!"}),e("button",{className:"mx-auto inline-flex items-center gap-2 rounded-2xl border-b-4 border-red-600 bg-red-500 px-8 py-3 text-lg font-bold text-white shadow-md transition-all hover:brightness-110 active:translate-y-0.5 active:border-b-2 active:shadow-sm",onClick:()=>window.history.back(),children:"← Quay lại"})]})});const ue="TOEIC"===j?.exam?.template?.subTitle,pe="SUMMER_SKY"===x(j?.exam?.theme||j?.exam?.template?.theme);if("WITHIN_WINDOW"===$&&j)return a(t,{children:[ue?e(E,{room:j,onStart:ce,isStarting:G,showCountdown:Q,autoStartCountdown:H,closeRedirectUrl:se,onClose:()=>{L(se)}}):pe?e(S,{room:j,onStart:ce,isStarting:G,onExit:()=>{L(se)}}):e(D,{room:j,onStart:ce,isStarting:G,showCountdown:Q,autoStartCountdown:H,closeRedirectUrl:se,onClose:()=>{L(se)}}),e(s,{open:ee,onOpenChange:te,children:e(l,{className:"overflow-visible border-0 bg-transparent p-0 shadow-none sm:max-w-md",children:a("div",{className:"relative overflow-visible rounded-[28px] bg-gradient-to-br from-cyan-300/25 via-white/5 to-white/0 p-px shadow-[0_30px_80px_-20px_rgba(10,75,140,0.85)] backdrop-blur-xl",children:[e("div",{className:"pointer-events-none absolute -left-16 -top-16 h-48 w-48 rounded-full bg-cyan-400/35 blur-3xl"}),e("div",{className:"pointer-events-none absolute -right-16 -bottom-16 h-48 w-48 rounded-full bg-sky-500/30 blur-3xl"}),e("div",{className:"pointer-events-none absolute left-1/2 top-0 h-24 w-1/2 -translate-x-1/2 rounded-full bg-cyan-300/15 blur-2xl"}),a("div",{className:"relative overflow-hidden rounded-[calc(28px-1px)] bg-gradient-to-b from-[#0e3d70]/97 via-[#0a4b8c]/97 to-[#072d54]/97 ring-1 ring-cyan-300/25",children:[e("div",{className:"pointer-events-none absolute inset-0 opacity-[0.04]",style:{backgroundImage:"radial-gradient(circle at 1px 1px, white 1px, transparent 0)",backgroundSize:"24px 24px"}}),e("div",{className:"pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-cyan-300/40 to-transparent"}),a("div",{className:"relative flex flex-col items-center gap-4 px-8 pt-10 pb-6",children:[a("div",{className:"relative",children:[e("div",{className:"absolute inset-0 animate-ping rounded-full bg-cyan-300/30",style:{animationDuration:"2.8s"}}),e("div",{className:"absolute -inset-3 rounded-full bg-gradient-to-br from-cyan-300/15 to-sky-500/10 blur-md"}),e("div",{className:"absolute -inset-1.5 rounded-full bg-gradient-to-br from-cyan-200/30 to-sky-400/20"}),e("div",{className:"relative flex h-16 w-16 items-center justify-center rounded-full bg-gradient-to-br from-cyan-300 via-sky-500 to-sky-700 shadow-[0_10px_30px_-6px_rgba(34,211,238,0.7),inset_0_2px_4px_rgba(255,255,255,0.4)] ring-[3px] ring-cyan-200/40",children:a("svg",{className:"h-8 w-8 text-white drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)]",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",children:[e("path",{d:"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"}),e("line",{x1:"12",y1:"9",x2:"12",y2:"13"}),e("line",{x1:"12",y1:"17",x2:"12.01",y2:"17"})]})})]}),a("div",{className:"flex flex-col items-center gap-2",children:[e(c,{className:"text-center text-xl font-black tracking-tight text-white drop-shadow-[0_2px_8px_rgba(34,211,238,0.4)]",children:"Bạn đang có bài thi dở"}),e(d,{className:"max-w-sm text-center text-[13px] font-medium leading-relaxed text-cyan-100/75",children:"Bạn đã bắt đầu làm bài thi này trước đó. Bạn muốn tiếp tục làm bài hay bắt đầu lại từ đầu?"})]})]}),e("div",{className:"mx-8 h-px bg-gradient-to-r from-transparent via-cyan-300/30 to-transparent"}),a("div",{className:"relative flex flex-col-reverse gap-3 px-8 py-6 sm:flex-row sm:justify-center",children:[a("button",{onClick:me,className:"group relative inline-flex min-w-[140px] cursor-pointer items-center justify-center gap-2 overflow-hidden rounded-full bg-white/[0.08] px-7 py-3 text-sm font-bold text-white ring-1 ring-cyan-200/30 backdrop-blur-md transition-all duration-200 hover:-translate-y-0.5 hover:bg-white/[0.14] hover:ring-cyan-200/60 hover:shadow-[0_8px_20px_-4px_rgba(34,211,238,0.3)] active:translate-y-0",children:[e("span",{className:"pointer-events-none absolute inset-0 -translate-x-full bg-gradient-to-r from-transparent via-white/20 to-transparent transition-transform duration-700 group-hover:translate-x-full"}),e("span",{className:"relative",children:"Làm tiếp"})]}),a("button",{onClick:he,disabled:G,className:"group relative inline-flex min-w-[160px] cursor-pointer items-center justify-center gap-2 overflow-hidden rounded-full bg-gradient-to-b from-[#ffd54a] via-[#ffb733] to-[#ff8a1f] px-7 py-3 text-sm font-black uppercase tracking-wide text-white shadow-[0_6px_0_0_#c46410,0_10px_22px_rgba(255,138,31,0.5)] ring-2 ring-orange-300/70 transition-all duration-150 hover:-translate-y-0.5 hover:brightness-110 hover:shadow-[0_8px_0_0_#c46410,0_14px_26px_rgba(255,138,31,0.55)] active:translate-y-1.5 active:shadow-[0_1px_0_0_#c46410,0_3px_8px_rgba(255,138,31,0.3)] disabled:cursor-not-allowed disabled:opacity-70",style:{textShadow:"0 2px 0 rgba(180,80,10,0.55)"},children:[e("span",{className:"pointer-events-none absolute inset-x-0 top-0 h-1/2 bg-gradient-to-b from-white/30 to-transparent"}),G?a(t,{children:[e(b,{className:"relative h-4 w-4 animate-spin"}),e("span",{className:"relative",children:"Đang xử lý..."})]}):e("span",{className:"relative",children:"Làm lại từ đầu"})]})]})]})]})})})]});const ge=oe.visuals?.backgroundFilter??"grayscale(1) blur(10px) saturate(0.85) brightness(0.9)",be=oe.visuals?.backgroundOverlay??"linear-gradient(to bottom, rgba(0, 0, 0, 0.2), transparent, rgba(0, 0, 0, 0.3))",fe=oe.visuals?.cardBackground??"radial-gradient(60% 60% at 50% 40%, rgba(184, 229, 157, 0.85) 0%, rgba(115, 213, 133, 0.85) 100%)";return a("div",{className:"fixed inset-0 z-50 flex items-center justify-center overflow-hidden",children:[e("div",{className:"absolute inset-0 scale-110 bg-cover bg-center",style:{backgroundImage:`url(${oe.assets.background})`,filter:ge}}),e("div",{className:"absolute inset-0",style:{background:be}}),a("div",{className:"relative z-10 w-[88%] max-w-2xl sm:w-[70%] md:w-[50%] lg:w-[42%]",children:[e(T,{imageSrc:oe.assets.closeButton,onClick:()=>L(se),className:"absolute -right-3 -top-7 z-30",size:72}),a("div",{className:"absolute left-1/2 top-0 z-10 -translate-x-1/2 -translate-y-1/2",children:[e(y,{src:oe.assets.titleBar,alt:"",width:260,height:56,className:"drop-shadow-lg",priority:!0,unoptimized:!0}),e("span",{className:"absolute inset-0 mt-2.5 flex items-center justify-center pb-1 text-sm font-extrabold tracking-wider text-white drop-shadow",children:oe.displayName})]}),a("div",{className:"relative overflow-hidden rounded-3xl shadow-2xl ring-1 ring-white/20",children:[e("div",{className:"h-2 w-full",style:{backgroundImage:`url(${oe.assets.cardFrame})`,backgroundSize:"100% 100%"}}),a("div",{className:"relative p-6 pt-12 md:p-8 md:pt-14",style:{background:fe},children:[a("div",{className:"mb-4 rounded-2xl bg-black/20 px-4 py-3.5 text-center ring-1 ring-white/10 backdrop-blur-sm",children:[e("h2",{className:"text-base font-extrabold tracking-wide text-white drop-shadow-sm",children:j?.name}),j?.exam?.name&&e("p",{className:"mt-0.5 text-xs font-medium text-white/80",children:j.exam.name})]}),(j?.exam?.durationMinutes||j?.exam?.totalScore)&&a("div",{className:"mb-4 grid grid-cols-2 gap-3",children:[j?.exam?.durationMinutes&&a("div",{className:"flex flex-col items-center rounded-2xl bg-black/20 px-2 py-4 ring-1 ring-white/10 backdrop-blur-sm",children:[e("div",{className:"mb-2 flex h-8 w-8 items-center justify-center rounded-full bg-white/10",children:e(f,{className:"h-4 w-4 text-white"})}),e("span",{className:"text-2xl font-extrabold text-white",children:j.exam.durationMinutes}),e("span",{className:"text-xs font-semibold text-white/80",children:"Phút"})]}),j?.exam?.totalScore&&a("div",{className:"flex flex-col items-center rounded-2xl bg-black/20 px-2 py-4 ring-1 ring-white/10 backdrop-blur-sm",children:[e("div",{className:"mb-2 flex h-8 w-8 items-center justify-center rounded-full bg-white/10",children:e(v,{className:"h-4 w-4 text-white"})}),e("span",{className:"text-2xl font-extrabold text-white",children:j.exam.totalScore}),e("span",{className:"text-xs font-semibold text-white/80",children:"Thang điểm"})]})]}),"BEFORE_START"===$&&e(N,{countdown:X,formatCountdown:e=>{const t=Math.floor(e/86400),a=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),n=e%60;return t>0?`${t} ngày ${a} giờ ${r} phút`:a>0?`${a} giờ ${r} phút ${n} giây`:r>0?`${r} phút ${n} giây`:`${n} giây`}}),"EXPIRED"===$&&e(_,{}),"ALREADY_SUBMITTED"===$&&e(k,{attempt:z}),e("div",{className:"mt-5 flex justify-center",children:a("button",{className:"group relative inline-flex cursor-pointer items-center gap-2 rounded-full bg-[#0473f9] px-8 py-3 shadow-[0_4px_0_0_#1d4ed8] transition-all duration-150 hover:brightness-110 active:translate-y-[2px] active:shadow-[0_2px_0_0_#1d4ed8]",onClick:()=>L(se),children:[e(w,{className:"h-5 w-5 text-white transition-transform group-hover:-translate-x-0.5"}),e("span",{className:"text-sm font-extrabold uppercase tracking-wider text-white",children:"Quay lại"})]})}),e("div",{className:"pointer-events-none absolute -bottom-1 -left-1 opacity-60",children:e(y,{src:oe.assets.bottomLeft,alt:"",width:80,height:80,unoptimized:!0})}),e("div",{className:"pointer-events-none absolute -bottom-1 -right-1 opacity-60",children:e(y,{src:oe.assets.bottomRight,alt:"",width:80,height:80,unoptimized:!0})})]})]})]})]})}
|
|
1
|
+
"use client";import{jsx as e,Fragment as t,jsxs as a}from"react/jsx-runtime";import{useState as r,useEffect as n,useCallback as i,useMemo as o}from"react";import{Dialog as s,DialogContent as l,DialogDescription as d,DialogTitle as c}from"../../../components/ui/dialog";import{t as m}from"../../../shared/lib/i18n";import{ROUTES as h}from"../../../shared/constants/routes";import{normalizeExamTheme as x,resolveThemeConfig as u}from"../../../shared/lib/themes";import{unwrap as p}from"../take/exam-taking.utils";import{toast as g}from"sonner";import{Loader2 as b,Clock as f,Trophy as v,ArrowLeft as w}from"lucide-react";import y from"next/image";import{BeforeStartCard as N,ExpiredCard as _,AlreadySubmittedCard as k}from"../../../components/features/exam-entry";import{CloseButton as T}from"../../../components/features/exam-entry/themed/components";import{ToeicWaitingRoom as E}from"../../../components/features/exam-entry/themed/ToeicWaitingRoom";import{CambridgeYleWaitingRoom as D}from"../../../components/features/exam-entry/themed/CambridgeYleWaitingRoom";import{SummerSkyWaitingRoom as S}from"../../../components/themes/summer-sky/SummerSkyWaitingRoom";import{FullscreenLoading as R}from"./fullscreen-loading";export function StudentExamEntryPageContainer({roomId:I,inviteToken:A=null,api:O,onNavigate:M,takePath:C=e=>`/student/exams/${e}/take`,closePath:B,renderRegistrationForm:W}){const L=i((e,t=!1)=>{M?M(e,{replace:t}):"undefined"!=typeof window&&(t?window.location.replace(e):window.location.href=e)},[M]),[j,F]=r(null),[z,U]=r(null),[$,P]=r("LOADING"),[X,Y]=r(0),[H,V]=r(5),[G,K]=r(!1),[Q,q]=r(!1),[J,Z]=r(null),[ee,te]=r(!1),[ae,re]=r(!1),[ne,ie]=r(!1),oe=o(()=>{const e=j?.exam?.theme,t=j?.exam?.template?.theme;return u({examTheme:e,templateTheme:t,level:j?.exam?.level})},[j?.exam,I,j]),se=o(()=>B?B(j):j?.contest?.id?h.STUDENT.CONTEST_ROOMS(j.contest.id):h.STUDENT.CONTESTS_DISCOVER,[B,j]),le=i((e,t)=>{const a=!0===e.allowMultipleSubmissions;if(t){const e=t.status;if("SUBMITTED"===e||"GRADED"===e||"PUBLISHED"===e)return a?"WITHIN_WINDOW":"ALREADY_SUBMITTED";if("IN_PROGRESS"===e)return"WITHIN_WINDOW"}const r=(new Date).getTime(),n=e.startDatetime?new Date(e.startDatetime).getTime():null,i=e.endDatetime?new Date(e.endDatetime).getTime():null;return!a&&i&&r>i?"EXPIRED":n&&r<n?"BEFORE_START":"WITHIN_WINDOW"},[]);n(()=>{(async()=>{try{if(A)try{await(O.joinViaInvite?.(I,A))}catch{}const e=await O.getRoom(I),t=p(e);if(F(t),!t.canAccess&&!A)return void P("NO_ACCESS");if(t.registrationFormConfig?.enabled&&t.registrationFormConfig.fields?.length>0&&!t.hasSubmittedFormData)return void re(!0);if(!t.exam)return void P("NO_EXAM");const a=await O.getActiveAttemptByRoom(I),r=p(a);r&&(Z(r),U(r));const n=!0===t.allowMultipleSubmissions;if(t.hasJoined&&!r&&!n)return void P("ALREADY_SUBMITTED");const i=le(t,r??null);if(P(i),"BEFORE_START"===i&&t.startDatetime){const e=new Date(t.startDatetime).getTime(),a=(new Date).getTime();Y(Math.max(0,Math.floor((e-a)/1e3)))}}catch(e){console.error("Failed to load room data:",e),g.error(m("student.exam.entry.loadError"))}})()},[I,A,le]),n(()=>{if("BEFORE_START"!==$||X<=0)return;const e=setInterval(()=>{Y(e=>e<=1?(P("WITHIN_WINDOW"),0):e-1)},1e3);return()=>clearInterval(e)},[$,X]);const de=i(async()=>{try{K(!0),await O.startAttempt(I),L(C(I),!0)}catch(e){const t=e,a=t.response?.data?.errorCode;"ROOM_NO_EXAM"===a?P("NO_EXAM"):"ROOM_NOT_STARTED"===a?(g.error(m("student.exam.entry.notStarted")),P("BEFORE_START"),q(!1),V(5)):"ROOM_ENDED"===a?(g.error(m("student.exam.entry.expired")),P("EXPIRED")):"ATTEMPT_ALREADY_SUBMITTED"===a?(g.error("Bạn đã hoàn thành bài thi này rồi."),P("ALREADY_SUBMITTED")):g.error(m("student.exam.entry.startError")),K(!1)}},[I]),ce=i(()=>{J?te(!0):de()},[J,de]),me=i(()=>{te(!1),g.success(m("student.exam.entry.continue")),L(C(I),!0)},[I]),he=i(async()=>{if(J)try{te(!1),K(!0),await O.deleteAttempt(J.id),Z(null),await de()}catch(e){console.error("Failed to restart attempt:",e),g.error(m("student.exam.entry.restartError")),K(!1)}},[J,de]);n(()=>{if(!Q||H<=0)return;const e=setInterval(()=>{V(e=>e<=1?(L(C(I),!0),0):e-1)},1e3);return()=>clearInterval(e)},[Q,H,I]);const xe=i(async e=>{if(j?.contest?.id){ie(!0);try{await(O.registerContest?.(j.contest.id,e)),re(!1);const t=await O.getRoom(I),a=p(t);if(F(a),!a.exam)return void P("NO_EXAM");const r=await O.getActiveAttemptByRoom(I),n=p(r);n&&(Z(n),U(n));const i=!0===a.allowMultipleSubmissions;if(a.hasJoined&&!n&&!i)return void P("ALREADY_SUBMITTED");const o=le(a,n??null);if(P(o),"BEFORE_START"===o&&a.startDatetime){const e=new Date(a.startDatetime).getTime(),t=(new Date).getTime();Y(Math.max(0,Math.floor((e-t)/1e3)))}}catch{g.error("Không thể gửi thông tin đăng ký. Vui lòng thử lại.")}finally{ie(!1)}}},[j?.contest?.id,I,le]);if(ae&&j?.registrationFormConfig&&W)return a(t,{children:[e(R,{}),W({room:j,onSubmit:xe,isSubmitting:ne})]});if("LOADING"===$)return e(R,{});if("NO_EXAM"===$)return e("div",{className:"fixed inset-0 z-50 flex items-center justify-center overflow-hidden bg-gradient-to-b from-sky-100 via-blue-50 to-indigo-100",children:a("div",{className:"mx-auto max-w-md p-4 text-center",children:[e("div",{className:"mb-6 text-7xl",children:"📝✨"}),e("h2",{className:"mb-3 text-2xl font-bold text-sky-700",children:"Bài thi đang được chuẩn bị"}),j&&a("div",{className:"mb-4 rounded-xl bg-white/60 px-5 py-3 text-left text-sm text-sky-700 shadow-sm backdrop-blur-sm",children:[e("p",{className:"font-semibold text-base",children:j.name}),j.code&&a("p",{className:"mt-1 text-sky-500",children:["Mã phòng: ",e("span",{className:"font-mono font-medium",children:j.code})]}),(j.startDatetime||j.endDatetime)&&a("p",{className:"mt-1 text-sky-500",children:["Thời gian thi:"," ",j.startDatetime?new Date(j.startDatetime).toLocaleString("vi-VN"):"—"," → ",j.endDatetime?new Date(j.endDatetime).toLocaleString("vi-VN"):"—"]})]}),e("p",{className:"mb-6 text-base text-sky-600",children:"Thầy cô đang chuẩn bị đề thi cho phòng này. Bạn quay lại sau nhé! 😊"}),e("button",{className:"mx-auto inline-flex items-center gap-2 rounded-2xl border-b-4 border-sky-600 bg-sky-500 px-8 py-3 text-lg font-bold text-white shadow-md transition-all hover:brightness-110 active:translate-y-0.5 active:border-b-2 active:shadow-sm",onClick:()=>window.history.back(),children:"← Quay lại"})]})});if("NO_ACCESS"===$)return e("div",{className:"fixed inset-0 z-50 flex items-center justify-center overflow-hidden bg-gradient-to-b from-red-50 via-orange-50 to-amber-50",children:a("div",{className:"mx-auto max-w-md p-4 text-center",children:[e("div",{className:"mb-6 text-7xl",children:"🔒"}),e("h2",{className:"mb-3 text-2xl font-bold text-red-600",children:"Không có quyền truy cập"}),e("p",{className:"mb-6 text-base text-red-500",children:"Bạn chưa được đăng ký vào phòng thi này. Hãy liên hệ thầy cô để được thêm vào phòng thi nhé!"}),e("button",{className:"mx-auto inline-flex items-center gap-2 rounded-2xl border-b-4 border-red-600 bg-red-500 px-8 py-3 text-lg font-bold text-white shadow-md transition-all hover:brightness-110 active:translate-y-0.5 active:border-b-2 active:shadow-sm",onClick:()=>window.history.back(),children:"← Quay lại"})]})});const ue="TOEIC"===j?.exam?.template?.subTitle,pe="SUMMER_SKY"===x(j?.exam?.theme||j?.exam?.template?.theme);if("WITHIN_WINDOW"===$&&j)return a(t,{children:[ue?e(E,{room:j,onStart:ce,isStarting:G,showCountdown:Q,autoStartCountdown:H,closeRedirectUrl:se,onClose:()=>{L(se)}}):pe?e(S,{room:j,onStart:ce,isStarting:G,onExit:()=>{L(se)}}):e(D,{room:j,onStart:ce,isStarting:G,showCountdown:Q,autoStartCountdown:H,closeRedirectUrl:se,onClose:()=>{L(se)}}),e(s,{open:ee,onOpenChange:te,children:e(l,{className:"overflow-visible border-0 bg-transparent p-0 shadow-none sm:max-w-md",children:a("div",{className:"relative overflow-visible rounded-[28px] bg-gradient-to-br from-cyan-300/25 via-white/5 to-white/0 p-px shadow-[0_30px_80px_-20px_rgba(10,75,140,0.85)] backdrop-blur-xl",children:[e("div",{className:"pointer-events-none absolute -left-16 -top-16 h-48 w-48 rounded-full bg-cyan-400/35 blur-3xl"}),e("div",{className:"pointer-events-none absolute -right-16 -bottom-16 h-48 w-48 rounded-full bg-sky-500/30 blur-3xl"}),e("div",{className:"pointer-events-none absolute left-1/2 top-0 h-24 w-1/2 -translate-x-1/2 rounded-full bg-cyan-300/15 blur-2xl"}),a("div",{className:"relative overflow-hidden rounded-[calc(28px-1px)] bg-gradient-to-b from-[#0e3d70]/97 via-[#0a4b8c]/97 to-[#072d54]/97 ring-1 ring-cyan-300/25",children:[e("div",{className:"pointer-events-none absolute inset-0 opacity-[0.04]",style:{backgroundImage:"radial-gradient(circle at 1px 1px, white 1px, transparent 0)",backgroundSize:"24px 24px"}}),e("div",{className:"pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-cyan-300/40 to-transparent"}),a("div",{className:"relative flex flex-col items-center gap-4 px-8 pt-10 pb-6",children:[a("div",{className:"relative",children:[e("div",{className:"absolute inset-0 animate-ping rounded-full bg-cyan-300/30",style:{animationDuration:"2.8s"}}),e("div",{className:"absolute -inset-3 rounded-full bg-gradient-to-br from-cyan-300/15 to-sky-500/10 blur-md"}),e("div",{className:"absolute -inset-1.5 rounded-full bg-gradient-to-br from-cyan-200/30 to-sky-400/20"}),e("div",{className:"relative flex h-16 w-16 items-center justify-center rounded-full bg-gradient-to-br from-cyan-300 via-sky-500 to-sky-700 shadow-[0_10px_30px_-6px_rgba(34,211,238,0.7),inset_0_2px_4px_rgba(255,255,255,0.4)] ring-[3px] ring-cyan-200/40",children:a("svg",{className:"h-8 w-8 text-white drop-shadow-[0_2px_3px_rgba(0,0,0,0.3)]",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",children:[e("path",{d:"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"}),e("line",{x1:"12",y1:"9",x2:"12",y2:"13"}),e("line",{x1:"12",y1:"17",x2:"12.01",y2:"17"})]})})]}),a("div",{className:"flex flex-col items-center gap-2",children:[e(c,{className:"text-center text-xl font-black tracking-tight text-white drop-shadow-[0_2px_8px_rgba(34,211,238,0.4)]",children:"Bạn đang có bài thi dở"}),e(d,{className:"max-w-sm text-center text-[13px] font-medium leading-relaxed text-cyan-100/75",children:"Bạn đã bắt đầu làm bài thi này trước đó. Bạn muốn tiếp tục làm bài hay bắt đầu lại từ đầu?"})]})]}),e("div",{className:"mx-8 h-px bg-gradient-to-r from-transparent via-cyan-300/30 to-transparent"}),a("div",{className:"relative flex flex-col-reverse gap-3 px-8 py-6 sm:flex-row sm:justify-center",children:[a("button",{onClick:me,className:"group relative inline-flex min-w-[140px] cursor-pointer items-center justify-center gap-2 overflow-hidden rounded-full bg-white/[0.08] px-7 py-3 text-sm font-bold text-white ring-1 ring-cyan-200/30 backdrop-blur-md transition-all duration-200 hover:-translate-y-0.5 hover:bg-white/[0.14] hover:ring-cyan-200/60 hover:shadow-[0_8px_20px_-4px_rgba(34,211,238,0.3)] active:translate-y-0",children:[e("span",{className:"pointer-events-none absolute inset-0 -translate-x-full bg-gradient-to-r from-transparent via-white/20 to-transparent transition-transform duration-700 group-hover:translate-x-full"}),e("span",{className:"relative",children:"Làm tiếp"})]}),a("button",{onClick:he,disabled:G,className:"group relative inline-flex min-w-[160px] cursor-pointer items-center justify-center gap-2 overflow-hidden rounded-full bg-gradient-to-b from-[#ffd54a] via-[#ffb733] to-[#ff8a1f] px-7 py-3 text-sm font-black uppercase tracking-wide text-white shadow-[0_6px_0_0_#c46410,0_10px_22px_rgba(255,138,31,0.5)] ring-2 ring-orange-300/70 transition-all duration-150 hover:-translate-y-0.5 hover:brightness-110 hover:shadow-[0_8px_0_0_#c46410,0_14px_26px_rgba(255,138,31,0.55)] active:translate-y-1.5 active:shadow-[0_1px_0_0_#c46410,0_3px_8px_rgba(255,138,31,0.3)] disabled:cursor-not-allowed disabled:opacity-70",style:{textShadow:"0 2px 0 rgba(180,80,10,0.55)"},children:[e("span",{className:"pointer-events-none absolute inset-x-0 top-0 h-1/2 bg-gradient-to-b from-white/30 to-transparent"}),G?a(t,{children:[e(b,{className:"relative h-4 w-4 animate-spin"}),e("span",{className:"relative",children:"Đang xử lý..."})]}):e("span",{className:"relative",children:"Làm lại từ đầu"})]})]})]})]})})})]});const ge=oe.visuals?.backgroundFilter??"grayscale(1) blur(10px) saturate(0.85) brightness(0.9)",be=oe.visuals?.backgroundOverlay??"linear-gradient(to bottom, rgba(0, 0, 0, 0.2), transparent, rgba(0, 0, 0, 0.3))",fe=oe.visuals?.cardBackground??"radial-gradient(60% 60% at 50% 40%, rgba(184, 229, 157, 0.85) 0%, rgba(115, 213, 133, 0.85) 100%)";return a("div",{className:"fixed inset-0 z-50 flex items-center justify-center overflow-hidden",children:[e("div",{className:"absolute inset-0 scale-110 bg-cover bg-center",style:{backgroundImage:`url(${oe.assets.background})`,filter:ge}}),e("div",{className:"absolute inset-0",style:{background:be}}),a("div",{className:"relative z-10 w-[88%] max-w-2xl sm:w-[70%] md:w-[50%] lg:w-[42%]",children:[e(T,{imageSrc:oe.assets.closeButton,onClick:()=>L(se),className:"absolute -right-3 -top-7 z-30",size:72}),a("div",{className:"absolute left-1/2 top-0 z-10 -translate-x-1/2 -translate-y-1/2",children:[e(y,{src:oe.assets.titleBar,alt:"",width:260,height:56,className:"drop-shadow-lg",priority:!0,unoptimized:!0}),e("span",{className:"absolute inset-0 mt-2.5 flex items-center justify-center pb-1 text-sm font-extrabold tracking-wider text-white drop-shadow",children:oe.displayName})]}),a("div",{className:"relative overflow-hidden rounded-3xl shadow-2xl ring-1 ring-white/20",children:[e("div",{className:"h-2 w-full",style:{backgroundImage:`url(${oe.assets.cardFrame})`,backgroundSize:"100% 100%"}}),a("div",{className:"relative p-6 pt-12 md:p-8 md:pt-14",style:{background:fe},children:[a("div",{className:"mb-4 rounded-2xl bg-black/20 px-4 py-3.5 text-center ring-1 ring-white/10 backdrop-blur-sm",children:[e("h2",{className:"text-base font-extrabold tracking-wide text-white drop-shadow-sm",children:j?.name}),j?.exam?.name&&e("p",{className:"mt-0.5 text-xs font-medium text-white/80",children:j.exam.name})]}),(j?.exam?.durationMinutes||j?.exam?.totalScore)&&a("div",{className:"mb-4 grid grid-cols-2 gap-3",children:[j?.exam?.durationMinutes&&a("div",{className:"flex flex-col items-center rounded-2xl bg-black/20 px-2 py-4 ring-1 ring-white/10 backdrop-blur-sm",children:[e("div",{className:"mb-2 flex h-8 w-8 items-center justify-center rounded-full bg-white/10",children:e(f,{className:"h-4 w-4 text-white"})}),e("span",{className:"text-2xl font-extrabold text-white",children:j.exam.durationMinutes}),e("span",{className:"text-xs font-semibold text-white/80",children:"Phút"})]}),j?.exam?.totalScore&&a("div",{className:"flex flex-col items-center rounded-2xl bg-black/20 px-2 py-4 ring-1 ring-white/10 backdrop-blur-sm",children:[e("div",{className:"mb-2 flex h-8 w-8 items-center justify-center rounded-full bg-white/10",children:e(v,{className:"h-4 w-4 text-white"})}),e("span",{className:"text-2xl font-extrabold text-white",children:j.exam.totalScore}),e("span",{className:"text-xs font-semibold text-white/80",children:"Thang điểm"})]})]}),"BEFORE_START"===$&&e(N,{countdown:X,formatCountdown:e=>{const t=Math.floor(e/86400),a=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),n=e%60;return t>0?`${t} ngày ${a} giờ ${r} phút`:a>0?`${a} giờ ${r} phút ${n} giây`:r>0?`${r} phút ${n} giây`:`${n} giây`}}),"EXPIRED"===$&&e(_,{}),"ALREADY_SUBMITTED"===$&&e(k,{attempt:z}),e("div",{className:"mt-5 flex justify-center",children:a("button",{className:"group relative inline-flex cursor-pointer items-center gap-2 rounded-full bg-[#0473f9] px-8 py-3 shadow-[0_4px_0_0_#1d4ed8] transition-all duration-150 hover:brightness-110 active:translate-y-[2px] active:shadow-[0_2px_0_0_#1d4ed8]",onClick:()=>L(se),children:[e(w,{className:"h-5 w-5 text-white transition-transform group-hover:-translate-x-0.5"}),e("span",{className:"text-sm font-extrabold uppercase tracking-wider text-white",children:"Quay lại"})]})}),e("div",{className:"pointer-events-none absolute -bottom-1 -left-1 opacity-60",children:e(y,{src:oe.assets.bottomLeft,alt:"",width:80,height:80,unoptimized:!0})}),e("div",{className:"pointer-events-none absolute -bottom-1 -right-1 opacity-60",children:e(y,{src:oe.assets.bottomRight,alt:"",width:80,height:80,unoptimized:!0})})]})]})]})]})}
|
|
@@ -4,8 +4,10 @@ export interface ExamTakingPageContainerProps {
|
|
|
4
4
|
roomId: string;
|
|
5
5
|
/** API adapter; create one via `createExamTakingApi`. */
|
|
6
6
|
api: ExamTakingSdkApi;
|
|
7
|
-
/** Navigation callback; falls back to `window.location.href` when omitted. */
|
|
8
|
-
onNavigate?: (href: string
|
|
7
|
+
/** Navigation callback; falls back to `window.location.href`/`replace` when omitted. */
|
|
8
|
+
onNavigate?: (href: string, options?: {
|
|
9
|
+
replace?: boolean;
|
|
10
|
+
}) => void;
|
|
9
11
|
/** Build the results page path from an attemptId. */
|
|
10
12
|
resultPath?: (attemptId: string) => string;
|
|
11
13
|
/** Path to navigate to when loading/close fails (e.g. discover page). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import{useEffect as i,useRef as s,useState as r,useMemo as a,useCallback as o}from"react";import d from"next/image";import l from"../../../components/themes/summer-sky/assets/images/clock.png";import m from"../../../components/themes/summer-sky/assets/images/submit.png";import c from"../../../components/themes/summer-sky/assets/images/has_answered.png";import{toast as p}from"sonner";import{Loader2 as u}from"lucide-react";import{t as g}from"../../../shared/lib/i18n";import{transformAnswersForSubmission as h}from"./utils/answer-transformers";import{getThemeForLevel as x,normalizeExamTheme as b}from"../../../shared/lib/themes";import{useExamTakingStore as I}from"../../../shared/lib/stores/examTakingStore";import{useGradingTransientStore as f}from"../../../shared/lib/stores/gradingTransientStore";import{AlertDialog as w,AlertDialogAction as E,AlertDialogCancel as S,AlertDialogContent as y,AlertDialogDescription as _,AlertDialogFooter as v,AlertDialogHeader as N,AlertDialogTitle as A}from"../../../components/ui/alert-dialog";import{useExamTimer as T}from"./hooks/useExamTimer";import{useAutoSave as C}from"./hooks/useAutoSave";import{useProctoringCamera as k}from"./hooks/useProctoringCamera";import{getStandardExamTheme as P}from"../../../components/themes";import{QuestionRenderer as q}from"./components/QuestionRenderer";import{FullscreenLoading as R}from"../entry/fullscreen-loading";import{SummerSkySubmitModal as M}from"../../../components/themes/summer-sky/SummerSkySubmitModal";import{EnglishCertificationExamLayout as D,EnglishCertificationQuestionRenderer as L,englishCertQuestionDomId as G}from"../../../components/themes/english-certification";import{groupQuestionsByPart as Q}from"./utils/question-transformers";import{unwrap as B,unwrapAttempt as O}from"./exam-taking.utils";import{ExamTakingApiProvider as Y}from"./ExamTakingApiContext";function F({roomId:Y,api:F,onNavigate:K,resultPath:U=e=>`/student/results/${e}`,fallbackPath:V="/student/contests/discover",proctoringEnabled:$=!1,achieversExamTitle:j,onSubmitted:H}){const z=I(),W=s(!1),J=o(e=>{K?K(e):"undefined"!=typeof window&&(window.location.href=e)},[K]),{isCameraActive:X}=k({api:F,attemptId:z.attemptId,intervalMs:1e4,enabled:$}),[Z,ee]=r(!0),te=z.currentPartIndex,ne=z.currentQuestionGlobalIndex,ie=o(e=>{const t=I.getState().currentPartIndex,n="function"==typeof e?e(t):e;I.getState().setCurrentPartIndex(n)},[]),se=o(e=>{const t=I.getState().currentQuestionGlobalIndex,n="function"==typeof e?e(t):e;I.getState().setCurrentQuestionGlobalIndex(n)},[]),[re,ae]=r([]),[oe,de]=r("SUMMER_SKY"),[le,me]=r(""),[ce,pe]=r(!1),[ue,ge]=r(null),[he,xe]=r(""),be=o(e=>{I.getState().markIntroPlayed(e)},[]),Ie="TOEIC"===z.examType||"ENGLISH_CERTIFICATION"===le,fe=a(()=>{if(!Ie||0===z.parts.length)return te;const e=z.currentIndex;for(let t=0;t<z.parts.length;t++){const n=z.parts[t],i=n.startIndex??0,s=n.endIndex??i;if(e>=i&&e<=s)return t}return 0},[Ie,z.currentIndex,z.parts,te]);i(()=>{(async()=>{try{ee(!0);let e=B(await F.getActiveAttempt(Y));e||(e=O(B(await F.startAttempt(Y))));let t=null;try{t=F.getRoom?B(await F.getRoom(Y)):null,t&&ge(t)}catch{}const{examTemplate:n,questions:i}=B(await F.getQuestions(e.id));n?.title&&xe(n.title);const s=n?.parts??e.exam?.template?.parts,r=Q(i,s),a=n?.subTitle??null,o=(r.every(e=>e.questions.every(e=>"SPEAKING"===e.question_skill_type)),r.some(e=>"SPEAKING"===e.category||e.questions.every(e=>"SPEAKING"===e.question_skill_type)));ae(r);const d=n?.theme||e?.exam?.template?.theme||e?.exam?.theme||t?.exam?.template?.theme||t?.exam?.theme||"",l=b(d);if(o){const e=["SUMMER_SKY"].includes(d);de(e?d:"SUMMER_SKY")}const m=new Date(e.startedAt),c=60*e.durationMinutes*1e3,u=m.getTime()+c,h=Date.now();if(0===Math.max(0,u-h)){p.info(g("student.exam.take.timeExpired"));try{await F.submitAttempt(e.id)}catch{}return I.persist.clearStorage(),void J(U(e.id))}z.hydrateFromServer({attemptId:e.id,examRoomId:Y,questions:i.map(e=>({id:e.id,question_type:e.question_type,content:e.content,is_example:e.is_example,total_points:e.total_points,part_id:e.part_id,part_no:e.part_no,question_number:e.question_number})),durationMinutes:e.durationMinutes,startedAt:e.startedAt,examType:a??void 0,examTitle:n?.title??void 0,parts:s}),a&&z.setExamType(a),me(l),s&&z.setParts(s),ee(!1)}catch(e){console.error("Failed to load exam data:",e),p.error(g("student.exam.take.loadError")),J(V)}})()},[Y]);const we=a(()=>re.length>0&&re.every(e=>e.questions.every(e=>"SPEAKING"===e.question_skill_type)),[re]),Ee=a(()=>{const e=re[te];return!!e&&(("SPEAKING_DESCRIBE_IMAGE"!==e.questionType&&"SPONTANEOUS_QA"!==e.questionType&&"SPEAKING_CUE_CARD"!==e.questionType&&"READ_DISPLAYED_CONTENT"!==e.questionType||"CAMBRIDGE_YLE"!==le)&&("SPEAKING"===e.category||e.questions.every(e=>"SPEAKING"===e.question_skill_type)))},[re,te,le]),{remainingSeconds:Se,warningLevel:ye}=T({onTimeExpired:async()=>{p.info(g("student.exam.take.autoSubmit")),await Ae()},onWarningThreshold:we||Ie?void 0:()=>{p.warning(g("student.exam.take.timeWarning"))},warningThresholdSeconds:we||Ie?void 0:300,warningThresholds:Ie?[{seconds:900,level:"warning",callback:()=>p.warning("Còn 15 phút!",{duration:3e3})},{seconds:300,level:"critical",callback:()=>p.warning("Còn 5 phút! Hãy ná»™p bà i ngay!",{duration:5e3})}]:we?[{seconds:300,level:"warning",callback:()=>p.warning("Còn 5 phút! Hãy hoà n thà nh bà i thi.",{duration:5e3})},{seconds:120,level:"critical",callback:()=>p.warning("Còn 2 phút! Bà i thi sẽ được tá»± động ná»™p.",{duration:5e3})}]:void 0}),_e=C({api:F,attemptId:z.attemptId||"",parts:re,intervalMs:Ie?15e3:3e4,onSaveError:e=>{console.error("Save error:",e)}}),ve=s(_e.saveNow),Ne=s(re);i(()=>{ve.current=_e.saveNow,Ne.current=re}),i(()=>{const e=()=>{const e=I.getState();if(!e.attemptId||!e.isDirty||e.isSubmitting)return;const t=h(e.answers,Ne.current);if(0!==t.length)try{F.saveAnswers?.({attemptId:e.attemptId,answers:t,keepalive:!0})}catch{}},t=()=>{"hidden"===document.visibilityState&&e()},n=()=>{const e=I.getState();e.isDirty&&!e.isSubmitting&&ve.current()};return document.addEventListener("visibilitychange",t),window.addEventListener("pagehide",e),window.addEventListener("online",n),()=>{document.removeEventListener("visibilitychange",t),window.removeEventListener("pagehide",e),window.removeEventListener("online",n)}},[]),i(()=>{we||ve.current()},[z.currentIndex,te,ne,we]);const Ae=async()=>{if(!W.current){W.current=!0,z.setIsSubmitting(!0),pe(!1);try{z.isDirty&&await _e.saveNow();const e=B(await F.submitAttempt(z.attemptId)),t=e?.pendingAnswerIds??[];z.attemptId&&(f.getState().setPending(z.attemptId,t),H?.({attemptId:z.attemptId,pendingAnswerIds:t})),0===t.length?p.success(g("student.exam.take.submitSuccess")):p.success(g("student.exam.take.submittedAIGradingInProgress")),I.persist.clearStorage(),J(U(z.attemptId))}catch(e){console.error("Failed to submit exam:",e);const t=e?.response?.data?.errorCode;if("ATTEMPT_ALREADY_SUBMITTED"===t)return I.persist.clearStorage(),void J(U(z.attemptId));p.warning(g("student.exam.take.submitError")),W.current=!1,z.setIsSubmitting(!1)}}},Te=o(()=>{pe(!0)},[]),Ce=s(new Map),ke=s([]),Pe=o((e,t)=>{z.setAnswer(e,t);const n=Ce.current.get(e)||e,i=ke.current.findIndex(e=>e.questionId===n);-1!==i&&se(e=>e!==i?i:e)},[]),qe=s("forward"),Re=e=>{if("CAMBRIDGE_YLE"!==le)return!1;const t=re[e];return"SPEAKING_DESCRIBE_IMAGE"===t?.questionType||"SPONTANEOUS_QA"===t?.questionType||"SPEAKING_CUE_CARD"===t?.questionType||"READ_DISPLAYED_CONTENT"===t?.questionType},Me=()=>{const e=()=>{window.scrollTo({top:0,behavior:"smooth"});const e=document.getElementById("exam-main-scroll-area");if(e){e.scrollTo({top:0,behavior:"smooth"});e.querySelectorAll(".overflow-y-auto").forEach(e=>{e.scrollTo({top:0,behavior:"smooth"})})}};requestAnimationFrame(e),setTimeout(e,100),setTimeout(e,250)},De=()=>{if("ENGLISH_CERTIFICATION"===le){const e=z.parts[fe+1];e&&z.goToQuestion(e.startIndex??0)}else if(Ie)z.goToQuestion(Math.min(z.currentIndex+1,z.questions.length-1));else if("CAMBRIDGE_YLE"===le&&Re(te)){const e=ne+1,t=Ve[e];t&&(t.partIndex!==te&&(qe.current="forward",ie(t.partIndex)),se(e))}else qe.current="forward",ie(e=>{const t=Math.min(e+1,re.length-1);if("CAMBRIDGE_YLE"===le){const e=Ve.find(e=>e.partIndex===t);e&&se(e.globalIndex)}return t});Me()},Le=()=>{if("ENGLISH_CERTIFICATION"===le){const e=z.parts[fe-1];e&&z.goToQuestion(e.startIndex??0)}else if(Ie)z.goToQuestion(Math.max(z.currentIndex-1,0));else if("CAMBRIDGE_YLE"===le&&Re(te)){const e=ne-1,t=Ve[e];t&&(t.partIndex!==te&&(qe.current="backward",ie(t.partIndex)),se(e))}else qe.current="backward",ie(e=>{const t=Math.max(e-1,0);if("CAMBRIDGE_YLE"===le){const e=Ve.find(e=>e.partIndex===t);e&&se(e.globalIndex)}return t});Me()},Ge=()=>{J(V)},Qe=a(()=>re.reduce((e,t)=>e+("CAMBRIDGE_YLE"===le?t.questions.length:t.questions.filter(e=>!e.is_example).length),0),[re,le]),Be=a(()=>{const e=new Map;return re.forEach(t=>{t.questions.forEach(n=>{if(n.is_example)return;const i=n.content;if("FILL_MISSING_WORDS_IN_GRID"===t.questionType&&i?.grid&&i.grid.forEach((t,i)=>{t.forEach((t,s)=>{e.set(`${i}-${s}`,n.id)})}),"LABEL_THE_PICTURE"===t.questionType&&i?.labels&&i.labels.forEach(t=>{t.id&&e.set(t.id,n.id)}),"READ_AND_COLOR_OBJECTS"===t.questionType){const t=i?.regions||i?.regionNodes;t?.forEach(t=>{t.id&&e.set(t.id,n.id)})}if("IMAGE_OBJECT_MATCHING"===t.questionType){const t=i?.regions||i?.regionNodes;t?.forEach(t=>{t.id&&e.set(t.id,n.id)})}if("LOOK_PICTURE_FILL_WORD_HINT"===t.questionType){const t=i?.word;if(t&&"string"==typeof t){const i=/\{(\d+)\}/g;let s;for(;null!==(s=i.exec(t));){const t=s[1];e.set(`${n.id}-blank-${t}`,n.id)}}}})}),e},[re]);i(()=>{Ce.current=Be},[Be]);const Oe=a(()=>{if(!z.answers)return new Set;const e=new Set(re.flatMap(e=>e.questions.filter(e=>!e.is_example).map(e=>e.id))),t=new Set;return Object.keys(z.answers).forEach(n=>{const i=z.answers[n];if(void 0===i||""===i)return;if(e.has(n))return void t.add(n);const s=Be.get(n);s&&e.has(s)&&t.add(s)}),t},[z.answers,re,Be]),Ye=Oe.size+("CAMBRIDGE_YLE"===le?re.reduce((e,t)=>e+t.questions.filter(e=>e.is_example).length,0):0),Fe=a(()=>ue?.exam?.name||ue?.name||(Ie?"TOEIC Listening and Reading Test":"Bà i thi"),[ue,Ie]),Ke=a(()=>x(ue?.exam?.level).displayName,[ue?.exam?.level]),{sidebarParts:Ue,sidebarQuestions:Ve}=a(()=>{const e=[],t=[];let n=0;return re.forEach((i,s)=>{const r="CAMBRIDGE_YLE"===le?i.questions:i.questions.filter(e=>!e.is_example);let a=0;r.forEach(e=>{const r=!("CAMBRIDGE_YLE"!==le||!e.is_example)||Oe.has(e.id);r&&a++;const o=i.questions.findIndex(t=>t.id===e.id);t.push({globalIndex:n,partIndex:s,indexInPart:o,questionNumber:e.question_number,isAnswered:r,questionId:e.id,isExample:e.is_example}),n++}),e.push({partIndex:s,partNo:i.partNo,name:i.name,category:i.category,totalQuestions:"CAMBRIDGE_YLE"===le?i.questions.length:i.questions.filter(e=>!e.is_example).length,answeredCount:a})}),{sidebarParts:e,sidebarQuestions:t}},[re,Oe,le]);if(i(()=>{ke.current=Ve},[Ve]),Z)return e(R,{});const $e=te,je=re[$e];if(!je)return e("div",{className:"flex min-h-screen items-center justify-center",children:t("div",{className:"text-center",children:[e("p",{className:"text-lg font-semibold text-red-500",children:"Không tìm thấy câu há»i"}),e("button",{type:"button",onClick:()=>J(V),className:"mt-4 rounded-lg bg-blue-500 px-4 py-2 text-white hover:bg-blue-600",children:"Quay lại"})]})});if(Ee)return t(n,{children:[e(q,{part:je,answers:z.answers||{},onAnswerChange:Pe,isReviewMode:!1,onExit:Ge,onPartComplete:$e<re.length-1?De:Te,onPartBack:$e>0?Le:void 0,speakingTheme:oe,initialQuestionIndex:"backward"===qe.current?je.questions.length-1:0,skipTeacherVideo:z.playedIntroParts.has($e)||he!==j,onTeacherIntroPlayed:()=>be($e)},`${je.partId}-${$e}`),"SUMMER_SKY"===oe?ce&&e(M,{onClose:()=>pe(!1),onSubmit:Ae,isSubmitting:z.isSubmitting}):e(w,{open:ce,onOpenChange:pe,children:t(y,{children:[t(N,{children:[e(A,{children:"Ná»™p bà i thi"}),e(_,{children:"Bạn có chắc chắn muốn ná»™p bà i không? Sau khi ná»™p, bạn sẽ không thể thay đổi câu trả lá»i."})]}),t(v,{children:[e(S,{disabled:z.isSubmitting,children:"Quay lại"}),e(E,{onClick:Ae,disabled:z.isSubmitting,children:z.isSubmitting?t(n,{children:[e(u,{className:"mr-2 h-4 w-4 animate-spin"}),"Äang ná»™p..."]}):"Ná»™p bà i"})]})]})}),t("div",{className:"fixed top-8 right-6 z-[100] flex flex-col items-end gap-4 sm:gap-6 lg:top-10 lg:right-16",children:[t("div",{className:"flex items-center gap-4 sm:gap-6",children:[Se>0&&t("div",{className:"flex items-center w-[130px] sm:w-[170px] h-[40px] sm:h-[50px] rounded-[33.5px] backdrop-blur-[8px] transition-all duration-300 ease-in-out border-none shadow-[0_4px_20px_rgba(0,0,0,0.25)] "+("critical"===ye?"bg-[rgba(220,38,38,0.85)] shadow-[0_0_24px_rgba(220,38,38,0.5)] animate-pulse":"warning"===ye?"bg-[rgba(180,120,0,0.85)]":"bg-[#001590]"),children:[e(d,{src:l,alt:"clock",width:75,height:75,className:"w-[50px] h-[50px] sm:w-[75px] sm:h-[75px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none z-10"}),t("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:"'SVN-Volte Rounded', 'Quicksand', sans-serif",textShadow:"0 2px 4px rgba(0, 0, 0, 0.2)"},children:[Math.floor(Se/60).toString().padStart(2,"0"),":",(Se%60).toString().padStart(2,"0")]})]}),t("div",{className:"flex items-center w-[130px] sm:w-[170px] h-[40px] sm:h-[50px] rounded-[33.5px] bg-[#FF9900] shadow-[0_4px_20px_rgba(0,0,0,0.25)] border-none shrink-0",title:"Số câu há»i đã hoà n thà nh",children:[e(d,{src:c,alt:"Progress",width:75,height:75,className:"w-[50px] h-[50px] sm:w-[75px] sm:h-[75px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none z-10"}),t("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',textShadow:"0 2px 4px rgba(0,0,0,0.2)"},children:[Ye,"/",Qe]})]})]}),t("button",{onClick:Te,disabled:z.isSubmitting,className:"group cursor-pointer flex items-center h-[40px] sm:h-[50px] w-[130px] sm:w-[170px] rounded-[33.5px] shadow-[0_4px_20px_rgba(0,0,0,0.25)] transition-all duration-300 hover:scale-105 active:scale-95 disabled:pointer-events-none disabled:opacity-60 border-none "+(z.isSubmitting?"bg-slate-400":"bg-[#16CA3B] hover:bg-[#15b736]"),children:[e(d,{src:m,alt:"Submit",width:75,height:75,className:"w-[50px] h-[50px] sm:w-[75px] sm:h-[75px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none transition-transform duration-300 group-hover:scale-110 z-10"}),z.isSubmitting?e("div",{className:"flex-1 flex justify-center pr-[10px] sm:pr-[16px]",children:e(u,{className:"h-6 w-6 animate-spin text-white"})}):e("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',textShadow:"0 2px 4px rgba(0,0,0,0.2)"},children:"Ná»™p bà i"})]})]}),z.isSubmitting&&e("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm",children:t("div",{className:"rounded-xl bg-white p-8 text-center shadow-2xl",children:[e(u,{className:"mx-auto h-12 w-12 animate-spin text-green-500"}),e("p",{className:"mt-4 text-lg font-semibold text-gray-700",children:"Äang ná»™p bà i..."}),e("p",{className:"mt-2 text-sm text-gray-500",children:"Vui lòng đợi trong giây lát"})]})})]});if(Ie){const i=re[fe],s=z.parts[fe],r=s?Math.max(0,z.currentIndex-(s.startIndex??0)):0,a=(s?.startIndex??0)+1,o=(s?.endIndex??a-1)+1,d={examName:Fe,remainingSeconds:z.remainingSeconds,totalQuestions:Qe,answeredCount:Ye,isSubmitting:z.isSubmitting,onSubmit:Ae,onClose:Ge,lastSavedAt:z.lastSavedAt,isSaving:_e.isSaving,partLabel:(s?.name||i?.name||"").toUpperCase()||void 0,partSubLabel:s?.category||void 0,questionRange:`${a}–${o}`},l=i?.questions?.[r],m="ENGLISH_CERTIFICATION"===le,c={onPrevious:Le,onClear:m?void 0:()=>{l&&Pe(l.id,{optionId:null})},onToggleMark:m?void 0:()=>{l&&z.toggleFlag(l.id)},onNext:De,isMarked:!!l&&z.flaggedQuestions.has(l.id),showSecondaryActions:!m,isPreviousDisabled:m?fe<=0:z.currentIndex<=0,isNextDisabled:m?fe>=z.parts.length-1:z.currentIndex>=z.questions.length-1},p={parts:z.parts,questions:z.questions,answers:z.answers,flaggedQuestions:z.flaggedQuestions,currentIndex:z.currentIndex,onQuestionClick:e=>{z.goToQuestion(e);const t=z.questions[e];t&&setTimeout(()=>{document.getElementById(G(t.id))?.scrollIntoView({behavior:"smooth",block:"start"})},80)},onPartClick:e=>{const t=z.parts[e];t&&(z.goToQuestion(t.startIndex??0),z.setCurrentPartIndex(e))}};if(i&&s)return t(n,{children:[e(D,{headerProps:d,navigationProps:p,footerProps:c,children:e(L,{part:i,partConfig:s,currentQuestionIndex:r,answers:z.answers,flaggedQuestions:z.flaggedQuestions,onAnswerChange:Pe,onToggleFlag:e=>z.toggleFlag(e),isReviewMode:!1,isAudioPlayed:z.playedListeningAudioParts.has(i.partId),onAudioFirstPlay:()=>z.markListeningAudioPlayed(i.partId)})}),z.isSubmitting&&e("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50",children:t("div",{className:"rounded-xl bg-white p-8 text-center shadow-2xl",children:[e(u,{className:"mx-auto h-12 w-12 animate-spin text-green-500"}),e("p",{className:"mt-4 text-lg font-semibold text-gray-700",children:"Äang ná»™p bà i..."}),e("p",{className:"mt-2 text-sm text-gray-500",children:"Vui lòng đợi trong giây lát"})]})})]})}return t(n,{children:[(()=>{const{Layout:n,QuestionCard:i}=P(le),s={headerProps:{examName:Fe,examType:"EXAM",levelLabel:Ke,totalQuestions:Qe,answeredCount:Ye,remainingSeconds:z.remainingSeconds,isSubmitting:z.isSubmitting,isCameraActive:X,onSubmit:Te},onPrevious:Le,onNext:De,onClose:Ge,isNavDisabled:z.isNavDisabled,partName:je?.name||(je?.partNo?`PART ${je.partNo}`:void 0)};if("CAMBRIDGE_YLE"===le){const e=Re($e);s.isFirstQuestion=e?0===ne:0===$e,s.isLastQuestion=e?ne===Ve.length-1:$e===re.length-1,s.sidebarProps={parts:Ue,questions:Ve,currentQuestionGlobalIndex:ne,isNavDisabled:z.isNavDisabled,onPartClick:e=>{if(z.isNavDisabled)return;qe.current=e>$e?"forward":"backward",ie(e);const t=Ve.find(t=>t.partIndex===e);t&&se(t.globalIndex),Me()},onQuestionClick:e=>{if(z.isNavDisabled)return;const t=Ve[e];t&&t.partIndex!==$e&&(qe.current=t.partIndex>$e?"forward":"backward",ie(t.partIndex)),se(e),t&&setTimeout(()=>{const e=document.getElementById(`question-${t.questionId}`);e&&e.scrollIntoView({behavior:"smooth",block:"center"})},100)}}}else s.isFirstQuestion=0===$e,s.isLastQuestion=$e===re.length-1;const r="CAMBRIDGE_YLE"===le&&("SPEAKING_DESCRIBE_IMAGE"===je?.questionType||"SPONTANEOUS_QA"===je?.questionType||"SPEAKING_CUE_CARD"===je?.questionType||"READ_DISPLAYED_CONTENT"===je?.questionType),a=Ve[ne],o=r&&a?.partIndex===$e?a.indexInPart:void 0;return t(n,{...s,children:[e(i,{partName:je?.name||(je?.partNo?`PART ${je.partNo}`:void 0),children:e(q,{part:je,answers:z.answers||{},onAnswerChange:Pe,isReviewMode:!1,currentQuestionIndex:o,onExit:Ge,onPartComplete:$e<re.length-1?De:Te,onPartBack:$e>0?Le:void 0,speakingTheme:"CAMBRIDGE_YLE"===le?"CAMBRIDGE_YLE":oe,initialQuestionIndex:"backward"===qe.current?je?.questions.length-1:0,skipTeacherVideo:z.playedIntroParts.has($e)||he!==j,onTeacherIntroPlayed:()=>be($e)})}),z.isSubmitting&&e("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50",children:t("div",{className:"rounded-xl bg-white p-8 text-center shadow-2xl",children:[e(u,{className:"mx-auto h-12 w-12 animate-spin text-green-500"}),e("p",{className:"mt-4 text-lg font-semibold text-gray-700",children:"Äang ná»™p bà i..."}),e("p",{className:"mt-2 text-sm text-gray-500",children:"Vui lòng đợi trong giây lát"})]})})]})})(),"CAMBRIDGE_YLE"===le?ce&&e(M,{onClose:()=>pe(!1),onSubmit:Ae,isSubmitting:z.isSubmitting}):e(w,{open:ce,onOpenChange:pe,children:t(y,{children:[t(N,{children:[e(A,{children:"Ná»™p bà i thi"}),e(_,{children:"Bạn có chắc chắn muốn ná»™p bà i không? Sau khi ná»™p, bạn sẽ không thể thay đổi câu trả lá»i."})]}),t(v,{children:[e(S,{disabled:z.isSubmitting,children:"Quay lại"}),e(E,{onClick:Ae,disabled:z.isSubmitting,children:z.isSubmitting?t(n,{children:[e(u,{className:"mr-2 h-4 w-4 animate-spin"}),"Äang ná»™p..."]}):"Ná»™p bà i"})]})]})})]})}export function ExamTakingPageContainer(t){return e(Y,{api:t.api,children:e(F,{...t})})}
|
|
1
|
+
"use client";import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import{useEffect as i,useRef as s,useState as r,useMemo as a,useCallback as o}from"react";import d from"next/image";import l from"../../../components/themes/summer-sky/assets/images/clock.png";import m from"../../../components/themes/summer-sky/assets/images/submit.png";import c from"../../../components/themes/summer-sky/assets/images/has_answered.png";import{toast as p}from"sonner";import{Loader2 as u}from"lucide-react";import{t as g}from"../../../shared/lib/i18n";import{transformAnswersForSubmission as h}from"./utils/answer-transformers";import{getThemeForLevel as x,normalizeExamTheme as b}from"../../../shared/lib/themes";import{useExamTakingStore as I}from"../../../shared/lib/stores/examTakingStore";import{useGradingTransientStore as f}from"../../../shared/lib/stores/gradingTransientStore";import{AlertDialog as w,AlertDialogAction as E,AlertDialogCancel as S,AlertDialogContent as _,AlertDialogDescription as y,AlertDialogFooter as v,AlertDialogHeader as N,AlertDialogTitle as A}from"../../../components/ui/alert-dialog";import{useExamTimer as T}from"./hooks/useExamTimer";import{useAutoSave as C}from"./hooks/useAutoSave";import{useProctoringCamera as k}from"./hooks/useProctoringCamera";import{getStandardExamTheme as P}from"../../../components/themes";import{QuestionRenderer as q}from"./components/QuestionRenderer";import{FullscreenLoading as M}from"../entry/fullscreen-loading";import{SummerSkySubmitModal as R}from"../../../components/themes/summer-sky/SummerSkySubmitModal";import{EnglishCertificationExamLayout as D,EnglishCertificationQuestionRenderer as L,scrollToEnglishCertQuestion as G}from"../../../components/themes/english-certification";import{groupQuestionsByPart as Q}from"./utils/question-transformers";import{unwrap as B,unwrapAttempt as O}from"./exam-taking.utils";import{ExamTakingApiProvider as Y}from"./ExamTakingApiContext";function F({roomId:Y,api:F,onNavigate:K,resultPath:U=e=>`/student/results/${e}`,fallbackPath:V="/student/contests/discover",proctoringEnabled:$=!1,achieversExamTitle:j,onSubmitted:H}){const z=I(),W=s(!1),J=o((e,t=!1)=>{K?K(e,{replace:t}):"undefined"!=typeof window&&(t?window.location.replace(e):window.location.href=e)},[K]),{isCameraActive:X}=k({api:F,attemptId:z.attemptId,intervalMs:1e4,enabled:$}),[Z,ee]=r(!0),te=z.currentPartIndex,ne=z.currentQuestionGlobalIndex,ie=o(e=>{const t=I.getState().currentPartIndex,n="function"==typeof e?e(t):e;I.getState().setCurrentPartIndex(n)},[]),se=o(e=>{const t=I.getState().currentQuestionGlobalIndex,n="function"==typeof e?e(t):e;I.getState().setCurrentQuestionGlobalIndex(n)},[]),[re,ae]=r([]),[oe,de]=r("SUMMER_SKY"),[le,me]=r(""),[ce,pe]=r(!1),[ue,ge]=r(null),[he,xe]=r(""),be=o(e=>{I.getState().markIntroPlayed(e)},[]),Ie="TOEIC"===z.examType||"ENGLISH_CERTIFICATION"===le,fe=a(()=>{if(!Ie||0===z.parts.length)return te;const e=z.currentIndex;for(let t=0;t<z.parts.length;t++){const n=z.parts[t],i=n.startIndex??0,s=n.endIndex??i;if(e>=i&&e<=s)return t}return 0},[Ie,z.currentIndex,z.parts,te]);i(()=>{(async()=>{try{ee(!0);let e=B(await F.getActiveAttempt(Y));e||(e=O(B(await F.startAttempt(Y))));let t=null;try{t=F.getRoom?B(await F.getRoom(Y)):null,t&&ge(t)}catch{}const{examTemplate:n,questions:i}=B(await F.getQuestions(e.id));n?.title&&xe(n.title);const s=n?.parts??e.exam?.template?.parts,r=Q(i,s),a=n?.subTitle??null,o=(r.every(e=>e.questions.every(e=>"SPEAKING"===e.question_skill_type)),r.some(e=>"SPEAKING"===e.category||e.questions.every(e=>"SPEAKING"===e.question_skill_type)));ae(r);const d=n?.theme||e?.exam?.template?.theme||e?.exam?.theme||t?.exam?.template?.theme||t?.exam?.theme||"",l=b(d);if(o){const e=["SUMMER_SKY"].includes(d);de(e?d:"SUMMER_SKY")}const m=new Date(e.startedAt),c=60*e.durationMinutes*1e3,u=m.getTime()+c,h=Date.now();if(0===Math.max(0,u-h)){p.info(g("student.exam.take.timeExpired"));try{await F.submitAttempt(e.id)}catch{}return I.persist.clearStorage(),void J(U(e.id))}z.hydrateFromServer({attemptId:e.id,examRoomId:Y,questions:i.map(e=>({id:e.id,question_type:e.question_type,content:e.content,is_example:e.is_example,total_points:e.total_points,part_id:e.part_id,part_no:e.part_no,question_number:e.question_number})),durationMinutes:e.durationMinutes,startedAt:e.startedAt,examType:a??void 0,examTitle:n?.title??void 0,parts:s}),a&&z.setExamType(a),me(l),s&&z.setParts(s),ee(!1)}catch(e){const t=e?.response?.data?.errorCode;if("ATTEMPT_ALREADY_SUBMITTED"===t)return p.info(g("student.exam.take.submitted")),void J(V,!0);console.error("Failed to load exam data:",e),p.error(g("student.exam.take.loadError")),J(V,!0)}})()},[Y]);const we=a(()=>re.length>0&&re.every(e=>e.questions.every(e=>"SPEAKING"===e.question_skill_type)),[re]),Ee=a(()=>{const e=re[te];return!!e&&(("SPEAKING_DESCRIBE_IMAGE"!==e.questionType&&"SPONTANEOUS_QA"!==e.questionType&&"SPEAKING_CUE_CARD"!==e.questionType&&"READ_DISPLAYED_CONTENT"!==e.questionType||"CAMBRIDGE_YLE"!==le)&&("SPEAKING"===e.category||e.questions.every(e=>"SPEAKING"===e.question_skill_type)))},[re,te,le]),{remainingSeconds:Se,warningLevel:_e}=T({onTimeExpired:async()=>{p.info(g("student.exam.take.autoSubmit")),await Ae()},onWarningThreshold:we||Ie?void 0:()=>{p.warning(g("student.exam.take.timeWarning"))},warningThresholdSeconds:we||Ie?void 0:300,warningThresholds:Ie?[{seconds:900,level:"warning",callback:()=>p.warning("Còn 15 phút!",{duration:3e3})},{seconds:300,level:"critical",callback:()=>p.warning("Còn 5 phút! Hãy ná»™p bà i ngay!",{duration:5e3})}]:we?[{seconds:300,level:"warning",callback:()=>p.warning("Còn 5 phút! Hãy hoà n thà nh bà i thi.",{duration:5e3})},{seconds:120,level:"critical",callback:()=>p.warning("Còn 2 phút! Bà i thi sẽ được tá»± động ná»™p.",{duration:5e3})}]:void 0}),ye=C({api:F,attemptId:z.attemptId||"",parts:re,intervalMs:Ie?15e3:3e4,onSaveError:e=>{console.error("Save error:",e)}}),ve=s(ye.saveNow),Ne=s(re);i(()=>{ve.current=ye.saveNow,Ne.current=re}),i(()=>{const e=()=>{const e=I.getState();if(!e.attemptId||!e.isDirty||e.isSubmitting)return;const t=h(e.answers,Ne.current);if(0!==t.length)try{F.saveAnswers?.({attemptId:e.attemptId,answers:t,keepalive:!0})}catch{}},t=()=>{"hidden"===document.visibilityState&&e()},n=()=>{const e=I.getState();e.isDirty&&!e.isSubmitting&&ve.current()};return document.addEventListener("visibilitychange",t),window.addEventListener("pagehide",e),window.addEventListener("online",n),()=>{document.removeEventListener("visibilitychange",t),window.removeEventListener("pagehide",e),window.removeEventListener("online",n)}},[]),i(()=>{we||ve.current()},[z.currentIndex,te,ne,we]);const Ae=async()=>{if(!W.current){W.current=!0,z.setIsSubmitting(!0),pe(!1);try{z.isDirty&&await ye.saveNow();const e=B(await F.submitAttempt(z.attemptId)),t=e?.pendingAnswerIds??[];z.attemptId&&(f.getState().setPending(z.attemptId,t),H?.({attemptId:z.attemptId,pendingAnswerIds:t})),0===t.length?p.success(g("student.exam.take.submitSuccess")):p.success(g("student.exam.take.submittedAIGradingInProgress")),I.persist.clearStorage(),J(U(z.attemptId),!0)}catch(e){console.error("Failed to submit exam:",e);const t=e?.response?.data?.errorCode;if("ATTEMPT_ALREADY_SUBMITTED"===t)return I.persist.clearStorage(),void J(U(z.attemptId),!0);p.warning(g("student.exam.take.submitError")),W.current=!1,z.setIsSubmitting(!1)}}},Te=o(()=>{pe(!0)},[]),Ce=s(new Map),ke=s([]),Pe=o((e,t)=>{z.setAnswer(e,t);const n=Ce.current.get(e)||e,i=ke.current.findIndex(e=>e.questionId===n);-1!==i&&se(e=>e!==i?i:e)},[]),qe=s("forward"),Me=e=>{if("CAMBRIDGE_YLE"!==le)return!1;const t=re[e];return"SPEAKING_DESCRIBE_IMAGE"===t?.questionType||"SPONTANEOUS_QA"===t?.questionType||"SPEAKING_CUE_CARD"===t?.questionType||"READ_DISPLAYED_CONTENT"===t?.questionType},Re=()=>{const e=()=>{window.scrollTo({top:0,behavior:"smooth"});const e=document.getElementById("exam-main-scroll-area");if(e){e.scrollTo({top:0,behavior:"smooth"});e.querySelectorAll(".overflow-y-auto").forEach(e=>{e.scrollTo({top:0,behavior:"smooth"})})}};requestAnimationFrame(e),setTimeout(e,100),setTimeout(e,250)},De=()=>{if("ENGLISH_CERTIFICATION"===le){const e=z.parts[fe+1];e&&z.goToQuestion(e.startIndex??0)}else if(Ie)z.goToQuestion(Math.min(z.currentIndex+1,z.questions.length-1));else if("CAMBRIDGE_YLE"===le&&Me(te)){const e=ne+1,t=Ve[e];t&&(t.partIndex!==te&&(qe.current="forward",ie(t.partIndex)),se(e))}else qe.current="forward",ie(e=>{const t=Math.min(e+1,re.length-1);if("CAMBRIDGE_YLE"===le){const e=Ve.find(e=>e.partIndex===t);e&&se(e.globalIndex)}return t});Re()},Le=()=>{if("ENGLISH_CERTIFICATION"===le){const e=z.parts[fe-1];e&&z.goToQuestion(e.startIndex??0)}else if(Ie)z.goToQuestion(Math.max(z.currentIndex-1,0));else if("CAMBRIDGE_YLE"===le&&Me(te)){const e=ne-1,t=Ve[e];t&&(t.partIndex!==te&&(qe.current="backward",ie(t.partIndex)),se(e))}else qe.current="backward",ie(e=>{const t=Math.max(e-1,0);if("CAMBRIDGE_YLE"===le){const e=Ve.find(e=>e.partIndex===t);e&&se(e.globalIndex)}return t});Re()},Ge=()=>{J(V)},Qe=a(()=>re.reduce((e,t)=>e+("CAMBRIDGE_YLE"===le?t.questions.length:t.questions.filter(e=>!e.is_example).length),0),[re,le]),Be=a(()=>{const e=new Map;return re.forEach(t=>{t.questions.forEach(n=>{if(n.is_example)return;const i=n.content;if("FILL_MISSING_WORDS_IN_GRID"===t.questionType&&i?.grid&&i.grid.forEach((t,i)=>{t.forEach((t,s)=>{e.set(`${i}-${s}`,n.id)})}),"LABEL_THE_PICTURE"===t.questionType&&i?.labels&&i.labels.forEach(t=>{t.id&&e.set(t.id,n.id)}),"READ_AND_COLOR_OBJECTS"===t.questionType){const t=i?.regions||i?.regionNodes;t?.forEach(t=>{t.id&&e.set(t.id,n.id)})}if("IMAGE_OBJECT_MATCHING"===t.questionType){const t=i?.regions||i?.regionNodes;t?.forEach(t=>{t.id&&e.set(t.id,n.id)})}if("LOOK_PICTURE_FILL_WORD_HINT"===t.questionType){const t=i?.word;if(t&&"string"==typeof t){const i=/\{(\d+)\}/g;let s;for(;null!==(s=i.exec(t));){const t=s[1];e.set(`${n.id}-blank-${t}`,n.id)}}}})}),e},[re]);i(()=>{Ce.current=Be},[Be]);const Oe=a(()=>{if(!z.answers)return new Set;const e=new Set(re.flatMap(e=>e.questions.filter(e=>!e.is_example).map(e=>e.id))),t=new Set;return Object.keys(z.answers).forEach(n=>{const i=z.answers[n];if(void 0===i||""===i)return;if(e.has(n))return void t.add(n);const s=Be.get(n);s&&e.has(s)&&t.add(s)}),t},[z.answers,re,Be]),Ye=Oe.size+("CAMBRIDGE_YLE"===le?re.reduce((e,t)=>e+t.questions.filter(e=>e.is_example).length,0):0),Fe=a(()=>ue?.exam?.name||ue?.name||(Ie?"TOEIC Listening and Reading Test":"Bà i thi"),[ue,Ie]),Ke=a(()=>x(ue?.exam?.level).displayName,[ue?.exam?.level]),{sidebarParts:Ue,sidebarQuestions:Ve}=a(()=>{const e=[],t=[];let n=0;return re.forEach((i,s)=>{const r="CAMBRIDGE_YLE"===le?i.questions:i.questions.filter(e=>!e.is_example);let a=0;r.forEach(e=>{const r=!("CAMBRIDGE_YLE"!==le||!e.is_example)||Oe.has(e.id);r&&a++;const o=i.questions.findIndex(t=>t.id===e.id);t.push({globalIndex:n,partIndex:s,indexInPart:o,questionNumber:e.question_number,isAnswered:r,questionId:e.id,isExample:e.is_example}),n++}),e.push({partIndex:s,partNo:i.partNo,name:i.name,category:i.category,points:i.points,totalQuestions:"CAMBRIDGE_YLE"===le?i.questions.length:i.questions.filter(e=>!e.is_example).length,answeredCount:a})}),{sidebarParts:e,sidebarQuestions:t}},[re,Oe,le]);if(i(()=>{ke.current=Ve},[Ve]),Z)return e(M,{});const $e=te,je=re[$e];if(!je)return e("div",{className:"flex min-h-screen items-center justify-center",children:t("div",{className:"text-center",children:[e("p",{className:"text-lg font-semibold text-red-500",children:"Không tìm thấy câu há»i"}),e("button",{type:"button",onClick:()=>J(V),className:"mt-4 rounded-lg bg-blue-500 px-4 py-2 text-white hover:bg-blue-600",children:"Quay lại"})]})});if(Ee)return t(n,{children:[e(q,{part:je,answers:z.answers||{},onAnswerChange:Pe,isReviewMode:!1,onExit:Ge,onPartComplete:$e<re.length-1?De:Te,onPartBack:$e>0?Le:void 0,speakingTheme:oe,initialQuestionIndex:"backward"===qe.current?je.questions.length-1:0,skipTeacherVideo:z.playedIntroParts.has($e)||he!==j,onTeacherIntroPlayed:()=>be($e)},`${je.partId}-${$e}`),"SUMMER_SKY"===oe?ce&&e(R,{onClose:()=>pe(!1),onSubmit:Ae,isSubmitting:z.isSubmitting}):e(w,{open:ce,onOpenChange:pe,children:t(_,{children:[t(N,{children:[e(A,{children:"Ná»™p bà i thi"}),e(y,{children:"Bạn có chắc chắn muốn ná»™p bà i không? Sau khi ná»™p, bạn sẽ không thể thay đổi câu trả lá»i."})]}),t(v,{children:[e(S,{disabled:z.isSubmitting,children:"Quay lại"}),e(E,{onClick:Ae,disabled:z.isSubmitting,children:z.isSubmitting?t(n,{children:[e(u,{className:"mr-2 h-4 w-4 animate-spin"}),"Äang ná»™p..."]}):"Ná»™p bà i"})]})]})}),t("div",{className:"fixed top-8 right-6 z-[100] flex flex-col items-end gap-4 sm:gap-6 lg:top-10 lg:right-16",children:[t("div",{className:"flex items-center gap-4 sm:gap-6",children:[Se>0&&t("div",{className:"flex items-center w-[130px] sm:w-[170px] h-[40px] sm:h-[50px] rounded-[33.5px] backdrop-blur-[8px] transition-all duration-300 ease-in-out border-none shadow-[0_4px_20px_rgba(0,0,0,0.25)] "+("critical"===_e?"bg-[rgba(220,38,38,0.85)] shadow-[0_0_24px_rgba(220,38,38,0.5)] animate-pulse":"warning"===_e?"bg-[rgba(180,120,0,0.85)]":"bg-[#001590]"),children:[e(d,{src:l,alt:"clock",width:75,height:75,className:"w-[50px] h-[50px] sm:w-[75px] sm:h-[75px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none z-10"}),t("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:"'SVN-Volte Rounded', 'Quicksand', sans-serif",textShadow:"0 2px 4px rgba(0, 0, 0, 0.2)"},children:[Math.floor(Se/60).toString().padStart(2,"0"),":",(Se%60).toString().padStart(2,"0")]})]}),t("div",{className:"flex items-center w-[130px] sm:w-[170px] h-[40px] sm:h-[50px] rounded-[33.5px] bg-[#FF9900] shadow-[0_4px_20px_rgba(0,0,0,0.25)] border-none shrink-0",title:"Số câu há»i đã hoà n thà nh",children:[e(d,{src:c,alt:"Progress",width:75,height:75,className:"w-[50px] h-[50px] sm:w-[75px] sm:h-[75px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none z-10"}),t("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',textShadow:"0 2px 4px rgba(0,0,0,0.2)"},children:[Ye,"/",Qe]})]})]}),t("button",{onClick:Te,disabled:z.isSubmitting,className:"group cursor-pointer flex items-center h-[40px] sm:h-[50px] w-[130px] sm:w-[170px] rounded-[33.5px] shadow-[0_4px_20px_rgba(0,0,0,0.25)] transition-all duration-300 hover:scale-105 active:scale-95 disabled:pointer-events-none disabled:opacity-60 border-none "+(z.isSubmitting?"bg-slate-400":"bg-[#16CA3B] hover:bg-[#15b736]"),children:[e(d,{src:m,alt:"Submit",width:75,height:75,className:"w-[50px] h-[50px] sm:w-[75px] sm:h-[75px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none transition-transform duration-300 group-hover:scale-110 z-10"}),z.isSubmitting?e("div",{className:"flex-1 flex justify-center pr-[10px] sm:pr-[16px]",children:e(u,{className:"h-6 w-6 animate-spin text-white"})}):e("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',textShadow:"0 2px 4px rgba(0,0,0,0.2)"},children:"Ná»™p bà i"})]})]}),z.isSubmitting&&e("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm",children:t("div",{className:"rounded-xl bg-white p-8 text-center shadow-2xl",children:[e(u,{className:"mx-auto h-12 w-12 animate-spin text-green-500"}),e("p",{className:"mt-4 text-lg font-semibold text-gray-700",children:"Äang ná»™p bà i..."}),e("p",{className:"mt-2 text-sm text-gray-500",children:"Vui lòng đợi trong giây lát"})]})})]});if(Ie){const i=re[fe],s=z.parts[fe],r=s?Math.max(0,z.currentIndex-(s.startIndex??0)):0,a=(s?.startIndex??0)+1,o=(s?.endIndex??a-1)+1,d={examName:Fe,remainingSeconds:z.remainingSeconds,totalQuestions:Qe,answeredCount:Ye,isSubmitting:z.isSubmitting,onSubmit:Ae,onClose:Ge,lastSavedAt:z.lastSavedAt,isSaving:ye.isSaving,partLabel:(s?.name||i?.name||"").toUpperCase()||void 0,partSubLabel:s?.category||void 0,questionRange:`${a}–${o}`},l=i?.questions?.[r],m="ENGLISH_CERTIFICATION"===le,c={onPrevious:Le,onClear:m?void 0:()=>{l&&Pe(l.id,{optionId:null})},onToggleMark:m?void 0:()=>{l&&z.toggleFlag(l.id)},onNext:De,isMarked:!!l&&z.flaggedQuestions.has(l.id),showSecondaryActions:!m,isPreviousDisabled:m?fe<=0:z.currentIndex<=0,isNextDisabled:m?fe>=z.parts.length-1:z.currentIndex>=z.questions.length-1},p={parts:z.parts,questions:z.questions,answers:z.answers,flaggedQuestions:z.flaggedQuestions,currentIndex:z.currentIndex,onQuestionClick:e=>{z.goToQuestion(e);const t=z.questions[e];t&&G(t.id,{behavior:"smooth",block:"start"})},onPartClick:e=>{const t=z.parts[e];t&&(z.goToQuestion(t.startIndex??0),z.setCurrentPartIndex(e))}};if(i&&s)return t(n,{children:[e(D,{headerProps:d,navigationProps:p,footerProps:c,children:e(L,{part:i,partConfig:s,currentQuestionIndex:r,answers:z.answers,flaggedQuestions:z.flaggedQuestions,onAnswerChange:Pe,onToggleFlag:e=>z.toggleFlag(e),isReviewMode:!1,isAudioPlayed:z.playedListeningAudioParts.has(i.partId),onAudioFirstPlay:()=>z.markListeningAudioPlayed(i.partId)})}),z.isSubmitting&&e("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50",children:t("div",{className:"rounded-xl bg-white p-8 text-center shadow-2xl",children:[e(u,{className:"mx-auto h-12 w-12 animate-spin text-green-500"}),e("p",{className:"mt-4 text-lg font-semibold text-gray-700",children:"Äang ná»™p bà i..."}),e("p",{className:"mt-2 text-sm text-gray-500",children:"Vui lòng đợi trong giây lát"})]})})]})}return t(n,{children:[(()=>{const{Layout:n,QuestionCard:i}=P(le),s={headerProps:{examName:Fe,examType:"EXAM",levelLabel:Ke,totalQuestions:Qe,answeredCount:Ye,remainingSeconds:z.remainingSeconds,isSubmitting:z.isSubmitting,isCameraActive:X,onSubmit:Te},onPrevious:Le,onNext:De,onClose:Ge,isNavDisabled:z.isNavDisabled,partName:je?.name||(je?.partNo?`PART ${je.partNo}`:void 0)};if("CAMBRIDGE_YLE"===le){const e=Me($e);s.isFirstQuestion=e?0===ne:0===$e,s.isLastQuestion=e?ne===Ve.length-1:$e===re.length-1,s.sidebarProps={parts:Ue,questions:Ve,currentQuestionGlobalIndex:ne,isNavDisabled:z.isNavDisabled,onPartClick:e=>{if(z.isNavDisabled)return;qe.current=e>$e?"forward":"backward",ie(e);const t=Ve.find(t=>t.partIndex===e);t&&se(t.globalIndex),Re()},onQuestionClick:e=>{if(z.isNavDisabled)return;const t=Ve[e];t&&t.partIndex!==$e&&(qe.current=t.partIndex>$e?"forward":"backward",ie(t.partIndex)),se(e),t&&setTimeout(()=>{const e=document.getElementById(`question-${t.questionId}`);e&&e.scrollIntoView({behavior:"smooth",block:"center"})},100)}}}else s.isFirstQuestion=0===$e,s.isLastQuestion=$e===re.length-1;const r="CAMBRIDGE_YLE"===le&&("SPEAKING_DESCRIBE_IMAGE"===je?.questionType||"SPONTANEOUS_QA"===je?.questionType||"SPEAKING_CUE_CARD"===je?.questionType||"READ_DISPLAYED_CONTENT"===je?.questionType),a=Ve[ne],o=r&&a?.partIndex===$e?a.indexInPart:void 0;return t(n,{...s,children:[e(i,{partName:je?.name||(je?.partNo?`PART ${je.partNo}`:void 0),children:e(q,{part:je,answers:z.answers||{},onAnswerChange:Pe,isReviewMode:!1,currentQuestionIndex:o,onExit:Ge,onPartComplete:$e<re.length-1?De:Te,onPartBack:$e>0?Le:void 0,speakingTheme:"CAMBRIDGE_YLE"===le?"CAMBRIDGE_YLE":oe,initialQuestionIndex:"backward"===qe.current?je?.questions.length-1:0,skipTeacherVideo:z.playedIntroParts.has($e)||he!==j,onTeacherIntroPlayed:()=>be($e)})}),z.isSubmitting&&e("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50",children:t("div",{className:"rounded-xl bg-white p-8 text-center shadow-2xl",children:[e(u,{className:"mx-auto h-12 w-12 animate-spin text-green-500"}),e("p",{className:"mt-4 text-lg font-semibold text-gray-700",children:"Äang ná»™p bà i..."}),e("p",{className:"mt-2 text-sm text-gray-500",children:"Vui lòng đợi trong giây lát"})]})})]})})(),"CAMBRIDGE_YLE"===le?ce&&e(R,{onClose:()=>pe(!1),onSubmit:Ae,isSubmitting:z.isSubmitting}):e(w,{open:ce,onOpenChange:pe,children:t(_,{children:[t(N,{children:[e(A,{children:"Ná»™p bà i thi"}),e(y,{children:"Bạn có chắc chắn muốn ná»™p bà i không? Sau khi ná»™p, bạn sẽ không thể thay đổi câu trả lá»i."})]}),t(v,{children:[e(S,{disabled:z.isSubmitting,children:"Quay lại"}),e(E,{onClick:Ae,disabled:z.isSubmitting,children:z.isSubmitting?t(n,{children:[e(u,{className:"mr-2 h-4 w-4 animate-spin"}),"Äang ná»™p..."]}):"Ná»™p bà i"})]})]})})]})}export function ExamTakingPageContainer(t){return e(Y,{api:t.api,children:e(F,{...t})})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as r,Fragment as t}from"react/jsx-runtime";import{useMemo as s}from"react";import{ResolvedImage as a}from"../../../../../components/common/ResolvedImage";import l from"../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import i from"../../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner";export function MoversWritingRenderer({partNumber:
|
|
1
|
+
"use client";import{jsx as e,jsxs as r,Fragment as t}from"react/jsx-runtime";import{useMemo as s}from"react";import{ResolvedImage as a}from"../../../../../components/common/ResolvedImage";import l from"../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import i from"../../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner";import{HtmlOrText as d}from"../../../../../shared/lib/html-content";export function MoversWritingRenderer({partNumber:n,partName:m,instruction:o,prompt:c,requirements:x,minWords:p,maxWords:b,answer:h,onAnswerChange:g,isReviewMode:u=!1,guideImages:f,teacherScore:N,maxScore:v,teacherFeedback:w}){const y=s(()=>h&&h.trim()?h.trim().split(/\s+/).filter(Boolean).length:0,[h]);return r("div",{className:"flex flex-col h-full gap-4 sm:gap-6 overflow-y-auto custom-scrollbar relative",children:[r("div",{className:"flex flex-col gap-2 sm:gap-3 p-3 sm:px-6 sm:pt-4",children:[e(l,{partNumber:n,questionCount:1,partName:m,isReviewMode:u}),o&&e(i,{instruction:o,isReviewMode:u})]}),e("div",{className:"flex flex-col gap-4 p-3 sm:px-6 sm:pt-0 sticky top-0 z-20 bg-white/95 backdrop-blur pb-2 shadow-sm border-b border-gray-100",children:r("div",{className:"flex flex-col gap-4",children:[e("div",{className:"rounded-2xl border border-slate-200 bg-white p-5 shadow-sm",children:r("div",{className:"flex flex-col gap-4 text-base leading-relaxed text-gray-800",children:[r("div",{className:"space-y-3",children:[e("p",{className:"text-lg font-semibold text-slate-900",children:"Writing task"}),e(d,{value:c,className:"text-base leading-relaxed text-gray-800"})]}),x&&x.length>0&&r("div",{className:"rounded-xl bg-slate-50 p-4",children:[e("p",{className:"text-sm font-bold uppercase tracking-wide text-slate-700",children:"Include"}),e("ul",{className:"mt-3 space-y-2",children:x.map((t,s)=>r("li",{className:"flex items-start gap-2 text-sm text-slate-700",children:[e("span",{className:"mt-1.5 h-2 w-2 rounded-full bg-blue-500"}),e(d,{value:t,as:"span"})]},s))})]}),(p||b)&&r("div",{className:"flex flex-wrap gap-2",children:[p&&r("div",{className:"inline-flex items-center rounded-full border border-blue-200 bg-blue-50 px-3 py-1 text-sm font-medium text-blue-700",children:["Minimum: ",p," words"]}),b&&r("div",{className:"inline-flex items-center rounded-full border border-slate-200 bg-white px-3 py-1 text-sm font-medium text-slate-600",children:["Suggested max: ",b," words"]})]})]})}),f&&f.length>0&&r("div",{className:"rounded-2xl border border-slate-200 bg-white p-4 shadow-sm",children:[r("div",{className:"mb-3 flex items-center justify-between gap-3",children:[e("p",{className:"text-sm font-semibold uppercase tracking-wide text-slate-600",children:"Story pictures"}),e("p",{className:"text-xs text-slate-400",children:"Read the sequence from left to right"})]}),e("div",{className:"grid gap-4 "+(1===f.length?"grid-cols-1":"grid-cols-1 sm:grid-cols-2"),children:f.map((t,s)=>r("div",{className:"rounded-xl border border-slate-200 bg-slate-50/80 p-2 shadow-sm",children:[e(a,{src:t,alt:`Picture ${s+1}`,className:"w-full rounded-lg bg-white object-contain "+(1===f.length?"max-h-[400px]":"aspect-[4/3]")}),e("div",{className:"pt-2 text-center text-[13px] font-medium text-slate-500",children:f.length>1?`Picture ${s+1}`:"Reference Image"})]},s))})]})]})}),r("div",{className:"flex flex-col gap-3 p-3 sm:px-6 sm:pb-6",children:[r("div",{className:"rounded-2xl border border-slate-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center justify-between gap-3 border-b border-slate-100 px-5 py-3 bg-slate-50/50 rounded-t-2xl",children:[r("div",{children:[e("p",{className:"text-sm font-semibold uppercase tracking-wide text-slate-500",children:"Your answer"}),e("p",{className:"text-xs text-slate-400",children:"Write clearly and organise your ideas in order."})]}),r("div",{className:"rounded-full px-3 py-1 text-sm font-semibold "+(p&&y<p?"border border-amber-200 bg-amber-50 text-amber-700":"border border-emerald-200 bg-emerald-50 text-emerald-700"),children:[y," words"]})]}),r("div",{className:"p-4",children:[e("textarea",{id:"writing-answer",name:"writing-answer",value:h,onChange:e=>{const r=e.target.value;if(b){const e=Number(b);if((r.trim()?r.trim().split(/\s+/).filter(Boolean).length:0)>e&&r.length>=(h?.length||0))return}g(r)},disabled:u,placeholder:"Write your answer here...",className:"min-h-[340px] w-full resize-y rounded-xl border border-slate-200 bg-slate-50/50 p-4 text-base leading-8 text-gray-800 outline-none transition focus:border-blue-400 focus:bg-white focus:ring-2 focus:ring-blue-100 disabled:bg-gray-50 disabled:text-gray-700"}),r("div",{className:"mt-3 flex flex-wrap items-center justify-between gap-3 text-sm",children:[e("p",{className:"text-slate-500",children:p||b?r(t,{children:[p&&r("span",{children:["Minimum required: ",r("span",{className:"font-semibold text-slate-700",children:[p," words"]})]}),p&&b&&e("span",{className:"mx-2 text-slate-300",children:"|"}),b&&r("span",{children:["Maximum allowed: ",r("span",{className:"font-semibold text-slate-700",children:[b," words"]})]})]}):"Write a complete answer."}),r("p",{className:"font-medium "+(b&&y>=b?"text-red-500":"text-slate-500"),children:["Word count: ",y," ",b&&`/ ${b}`]})]})]})]}),u&&(null!=N?r("div",{className:"mt-1 rounded-2xl border border-green-200 bg-green-50 p-4",children:[e("div",{className:"mb-2 flex items-center gap-2",children:r("span",{className:"text-lg font-semibold text-green-700",children:["Điểm: ",N,"/",v]})}),w&&r("div",{className:"text-sm text-gray-700",children:[e("span",{className:"font-medium",children:"Nhận xét:"})," ",w]})]}):e("div",{className:"mt-1 rounded-2xl border border-amber-200 bg-amber-50 p-4",children:r("div",{className:"flex items-center gap-2",children:[e("svg",{className:"h-5 w-5 shrink-0 text-amber-500",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:e("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"})}),e("span",{className:"text-sm font-medium text-amber-700",children:"Bài viết đang chờ giáo viên chấm điểm"})]})}))]})]})}
|
|
@@ -91,11 +91,17 @@ export declare function transformWordFillParagraph(questions: ExamTakingQuestion
|
|
|
91
91
|
viewMode: string;
|
|
92
92
|
instruction: string;
|
|
93
93
|
};
|
|
94
|
+
/**
|
|
95
|
+
* WRITE_A_SHORT_LETTER — mirrors utils/question-transformers.transformWriteShortLetter.
|
|
96
|
+
*
|
|
97
|
+
* New API shape: instructions.mainInstruction + informations[]
|
|
98
|
+
* Legacy shape: contexts[] (type=text) as prompt
|
|
99
|
+
*/
|
|
94
100
|
export declare function transformWriteShortLetter(question: ExamTakingQuestion | undefined): {
|
|
95
101
|
prompt: string;
|
|
96
102
|
requirements: string[];
|
|
97
|
-
minWords: number;
|
|
98
|
-
maxWords: number;
|
|
103
|
+
minWords: number | undefined;
|
|
104
|
+
maxWords: number | undefined;
|
|
99
105
|
guideImages: string[];
|
|
100
106
|
};
|
|
101
107
|
export declare function transformWordFillStructuredForm(questions: ExamTakingQuestion[]): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function unwrap(t){return function(t){return"object"==typeof t&&null!==t&&"data"in t}(t)?t.data:t}export function unwrapAttempt(t){return"attempt"in t?t.attempt:t}export function groupQuestions(t){const n=t.examTemplate?.parts??[],e=new Map;for(const n of t.questions){const t=n.part_id??String(n.part_no??"default");e.set(t,[...e.get(t)??[],n])}return Array.from(e.entries()).map(([t,e])=>{const
|
|
1
|
+
export function unwrap(t){return function(t){return"object"==typeof t&&null!==t&&"data"in t}(t)?t.data:t}export function unwrapAttempt(t){return"attempt"in t?t.attempt:t}export function groupQuestions(t){const n=t.examTemplate?.parts??[],e=new Map;for(const n of t.questions){const t=n.part_id??String(n.part_no??"default");e.set(t,[...e.get(t)??[],n])}return Array.from(e.entries()).map(([t,e])=>{const r=n.find(n=>String(n.id)===t);return{id:t,name:r?.name??`Part ${e[0]?.part_no??t}`,template:r,partId:t,partNo:e[0]?.part_no,instructions:r?.instructions,audioUrl:r?.audioUrl,questionType:r?.questionType??e[0]?.question_type,isGroup:r?.isGroup,group:r?.group,sections:r?.sections,viewMode:"string"==typeof r?.group?.viewMode?r.group.viewMode:void 0,startIndex:r?.startIndex,endIndex:r?.endIndex,questions:e.sort((t,n)=>t.question_number-n.question_number)}})}export function transformAnswerTheQuestion(t){return{instruction:n(t[0]?.content,"instruction"),imageUrl:n(t[0]?.content,"imageUrl"),title:n(t[0]?.content,"title"),groupContent:n(t[0]?.content,"groupContent"),questions:t.map(t=>({id:t.id,questionNumber:t.question_number,question:n(t.content,"question")||n(t.content,"text"),imageUrl:n(t.content,"imageUrl"),prefixText:n(t.content,"prefixText"),suffixText:n(t.content,"suffixText"),exampleAnswer:n(t.content,"exampleAnswer"),suggestedAnswers:r(t.content,"suggestedAnswers"),isExample:Boolean(t.is_example)}))}}export function transformMatchByWritingAnswer(t){return{instruction:n(t[0]?.content,"instruction"),groupImageUrl:n(t[0]?.content,"groupImageUrl"),options:o(t[0]?.content,"options").map(t=>({answer:String(t.answer??t.value??""),text:String(t.text??t.label??""),content:String(t.content??t.text??t.label??""),imageUrl:"string"==typeof t.imageUrl?t.imageUrl:void 0})),questions:t.map(t=>({id:t.id,questionNumber:t.question_number,question:n(t.content,"question")||n(t.content,"text"),imageUrl:n(t.content,"imageUrl"),exampleAnswer:n(t.content,"exampleAnswer"),isExample:Boolean(t.is_example)}))}}export function transformWordFillParagraph(t){const e=t[0];return{questionId:e?.id??"",paragraph:n(e?.content,"paragraph")||n(e?.content,"text"),title:n(e?.content,"title"),imageUrl:n(e?.content,"imageUrl"),wordBank:o(e?.content,"wordBank").map(t=>({word:String(t.word??t.text??""),isExample:Boolean(t.isExample)})),viewMode:n(e?.content,"viewMode"),instruction:n(e?.content,"instruction")}}export function transformWriteShortLetter(o){if(!o)return{prompt:"",requirements:[],minWords:void 0,maxWords:void 0,guideImages:[]};const i=t(o.content),s=t(i.instructions),u="string"==typeof s.mainInstruction?s.mainInstruction:"",a=Array.isArray(i.informations)?i.informations.filter(t=>"string"==typeof t):[],c=r(o.content,"guideImages"),p=e(o.content,"minWords"),m=e(o.content,"maxWords");if(u||a.length)return{prompt:u,requirements:a,minWords:p,maxWords:m,guideImages:c};return{prompt:(Array.isArray(i.contexts)?i.contexts:[]).map(t).filter(t=>"text"===t.type&&"string"==typeof t.text).map(t=>String(t.text)).join("\n")||n(o.content,"prompt")||n(o.content,"question"),requirements:r(o.content,"requirements"),minWords:p,maxWords:m,guideImages:c}}export function transformWordFillStructuredForm(e){return{instruction:n(e[0]?.content,"instruction"),groupTitle:n(e[0]?.content,"groupTitle"),groupContent:n(e[0]?.content,"groupContent"),groupImageUrl:n(e[0]?.content,"groupImageUrl"),questions:e.map(e=>({id:e.id,title:n(e.content,"title"),content:n(e.content,"content")||n(e.content,"html")||n(e.content,"text"),answers:i(e.content,"answers"),caseSensitive:Boolean(t(e.content).caseSensitive),imageUrl:n(e.content,"imageUrl"),questionNumber:e.question_number}))}}function t(t){return"object"==typeof t&&null!==t?t:{}}function n(n,e){const r=t(n)[e];return"string"==typeof r?r:""}function e(n,e){const r=t(n)[e];return"number"==typeof r?r:void 0}function r(n,e){const r=t(n)[e];return Array.isArray(r)?r.filter(t=>"string"==typeof t):[]}function o(n,e){const r=t(n)[e];return Array.isArray(r)?r.map(t):[]}function i(n,e){const r=t(n)[e],o=t(r);return Object.fromEntries(Object.entries(o).map(([t,n])=>[t,String(n??"")]))}
|
|
@@ -45,6 +45,8 @@ export interface QuestionPart {
|
|
|
45
45
|
audioUrl?: string;
|
|
46
46
|
templateOrder?: number;
|
|
47
47
|
category?: string;
|
|
48
|
+
/** Max points for this part from template.parts[].points */
|
|
49
|
+
points?: number;
|
|
48
50
|
/** Section-level metadata carried from the template when a part is split by sections. */
|
|
49
51
|
sectionId?: number;
|
|
50
52
|
isGroup?: boolean;
|
|
@@ -104,6 +106,8 @@ export interface TemplatePart {
|
|
|
104
106
|
sections?: TemplateSection[];
|
|
105
107
|
audioUrl?: string;
|
|
106
108
|
category?: string;
|
|
109
|
+
/** Max points for this part from exams.template.parts */
|
|
110
|
+
points?: number;
|
|
107
111
|
}
|
|
108
112
|
/**
|
|
109
113
|
* Group questions by part_id AND questionGroup.id
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function groupQuestionsByPart(e,t){const n=new Map,o=new Map;for(const t of e){const e=o.get(t.part_id)||[];e.push(t),o.set(t.part_id,e)}for(const[e,r]of o.entries()){const o=[...r].sort((e,t)=>e.question_number-t.question_number),i=o[0];if(!i)continue;const s=t?.find(t=>String(t.id)===String(e)),a=void 0!==s?.id?Number(s.id):void 0,u=s?.name?.match(/\d+/),c=u?parseInt(u[0],10):i.part_no,l=s?.group,m=Boolean(s?.isGroup)&&"DOCUMENT"===l?.type,p=s?.sections??[],d=new Set(p.map(e=>e.questionType).filter(Boolean)),g=p.length>1&&d.size>1;if(m||g){const t=`${e}_part`;n.set(t,{partId:e,partNo:c,questionType:i.question_type,questions:o,name:s?.name,instructions:s?.instructions,audioUrl:s?.audioUrl,templateOrder:a,category:s?.category,isGroup:!0,group:l,sections:s?.sections,startIndex:s?.startIndex,endIndex:s?.endIndex});continue}if(!s?.sections?.length){const t=`${e}_part`;n.set(t,{partId:e,partNo:c,questionType:i.question_type,questions:o,name:s?.name,instructions:s?.instructions,audioUrl:s?.audioUrl,templateOrder:a,category:s?.category,isGroup:s?.isGroup,optionMode:s?.optionMode,optionCount:s?.optionCount,viewMode:s?.viewMode,defaultValue:s?.defaultValue,multipleAnswers:s?.multipleAnswers,questionConfig:s?.questionConfig,wordBankConfig:s?.wordBankConfig,group:s?.group,startIndex:s?.startIndex,endIndex:s?.endIndex});continue}for(const[t,r]of s.sections.entries()){const i=o.filter(e=>{const t=e.question_number-1;return t>=r.startIndex&&t<=r.endIndex});if(!i.length)continue;const u=`${e}_section_${t}`,l=Boolean(r.isGroup||r.group?.type);n.set(u,{partId:e,partNo:c,questionType:r.questionType||i[0].question_type,questions:i,name:s.name,instructions:r.instructions||r.name||s.instructions,audioUrl:s.audioUrl,templateOrder:a,category:s.category,sectionId:r.sectionId,isGroup:l,optionMode:r.optionMode,optionCount:r.optionCount,viewMode:r.viewMode,defaultValue:r.defaultValue,multipleAnswers:r.multipleAnswers,questionConfig:r.questionConfig,wordBankConfig:r.wordBankConfig,group:r.group,startIndex:r.startIndex,endIndex:r.endIndex})}}return Array.from(n.values()).sort((e,t)=>{const n=void 0===e.templateOrder||isNaN(e.templateOrder)?1/0:e.templateOrder,o=void 0===t.templateOrder||isNaN(t.templateOrder)?1/0:t.templateOrder;return n!==o?n-o:(e.questions[0]?.question_number||0)-(t.questions[0]?.question_number||0)})}export function transformFillInBlank(e){const t=e[0],n=t?.content,o=t?.questionGroup?.payload,r=[];for(const t of e){const e=t.content,n=t.is_example||!1,o=e.question||e.blanks?.[0]?.text||"";if([...o.matchAll(/\{(\d+)\}/g)].length>1){const i=o.split("\n").filter(e=>e.trim());for(const o of i){const i=o.match(/\{(\d+)\}/);if(!i)continue;const s=parseInt(i[1],10),a=o.split(/\{\d+\}/),u=a[0]?.trim()||"",c=a[1]?.trim()||"";r.push({id:`${t.id}-blank-${s}`,questionNumber:t.question_number,textBefore:u,textAfter:c,imageUrl:e.imageUrl,hints:e.hints,isExample:n,correctAnswer:n?t.correct_answer?.answers?.[s]:void 0})}}else{const i=o.match(/^(.*?)\{0\}(.*)$/),s=i?i[1].trim():o,a=i?i[2].trim():"";r.push({id:t.id,questionNumber:t.question_number,textBefore:s,textAfter:a,imageUrl:e.imageUrl,hints:e.hints,isExample:n,correctAnswer:n?t.correct_answer?.answers?.[0]:void 0})}}return{questions:r,title:n?.title||o?.title||"FILL IN THE BLANK",imageUrl:n?.imageUrl,audioUrl:n?.audioUrl,exampleText:n?.exampleText,exampleHighlight:n?.exampleHighlight,instruction:n?.instruction||"LISTEN AND WRITE",showHints:n?.showHints,groupContent:o?.content||o?.groupContent,groupTitle:o?.title,groupImageUrl:o?.mainImageUrl||o?.imageUrl}}export function transformWriteCorrectVerbForm(e){const t=e[0],n=t?.content;return{questions:e.map(e=>{const t=e.content,n=t.sentence||"",o=n.match(/^(.*?)\{0\}(.*)$/),r=o?o[1].trim():n,i=o?o[2].trim():"";return{id:e.id,questionNumber:e.question_number,textBefore:r,textAfter:i,verbHint:t.verbHint}}),title:"WRITE THE CORRECT VERB FORM",instruction:n?.instruction||"Write the correct form of the verb in parentheses."}}const e=["A","B","C","D","E","F"];export function transformChooseCorrectAnswer(t){const n=t[0]?.content,o=t[0]?.questionGroup?.payload,r=t.find(e=>e.is_example),i=t.filter(e=>!e.is_example);let s;if(r){const t=r.content,n=(t.options||[]).map((t,n)=>({id:`${r.id}-opt-${n}`,label:e[n]||String(n+1),text:t})),o="number"==typeof r.correct_answer?.answer?r.correct_answer.answer:-1;s={questionNumber:r.question_number,questionText:t.question||"",options:n,correctOptionId:o>=0?n[o]?.id||"":n[0]?.id||"",optionType:t.optionType||"text",imageUrl:t.imageUrl}}return{questions:i.map(t=>{const n=t.content,o=n.optionType||"text",r=(n.options||[]).map((n,o)=>({id:`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:n})),i=t.correct_answer?.answer,s=Array.isArray(i)?i.filter(e=>"number"==typeof e).map(e=>r[e]?.id).filter(e=>Boolean(e)):"number"==typeof i?[r[i]?.id].filter(e=>Boolean(e)):[];return{id:t.id,questionNumber:t.question_number,questionText:n.question||"",options:r,correctOptionId:s[0],correctOptionIds:s,imageUrl:n.imageUrl,optionType:o,multipleAnswers:Boolean(n.multipleAnswers||Array.isArray(i)),explanation:t.explanation}}),example:s,imageUrl:n?.imageUrl,groupImageUrl:o?.mainImageUrl||o?.imageUrl,groupTitle:o?.title,groupContent:o?.content,articles:o?.articles,audioUrl:n?.audioUrl,instruction:n?.instruction||"CHOOSE THE CORRECT ANSWER"}}export function transformChooseCorrectAdjective(t){return{questions:t.map(t=>{const n=t.content,o=n.sentence||"",r=o.match(/^(.*?)\{0\}(.*)$/),i=r?r[1]:o,s=r?r[2]:"";return{id:t.id,questionNumber:t.question_number,sentenceBefore:i,sentenceAfter:s,options:(n.options||[]).map((n,o)=>({id:`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:n}))}}),instruction:"CHOOSE THE CORRECT ADJECTIVE"}}export function transformWriteShortLetter(e){const t=e.content;if(t.instructions?.mainInstruction||t.informations?.length)return{prompt:t.instructions?.mainInstruction||"",requirements:t.informations,minWords:t.minWords,maxWords:t.maxWords,guideImages:t.guideImages};return{prompt:t.contexts?.filter(e=>"text"===e.type).map(e=>e.text).join("\n")||"",minWords:t.minWords,maxWords:t.maxWords,guideImages:t.guideImages}}export function transformColorObjects(e){const t=e[0],n=t?.content,o=n?.colorNodes?.map(e=>({id:e.id,color:e.color,label:e.label}))||n?.hintItems||[],r=n?.regionNodes?.map(e=>({id:e.id,x:e.x,y:e.y,width:e.width,height:e.height,correctHintId:e.linkedColorNodeId}))||n?.regions||[],i=n?.instructions;return{instruction:(i&&i.length>0?i.join(" "):n?.instruction)||"READ AND COLOR THE OBJECTS",instructions:i,imageUrl:n?.backgroundImageUrl||n?.imageUrl||"",audioUrl:n?.audioUrl,hintItems:o,regions:r}}export function transformPictureChoose(t){const n=t[0]?.content;return{subQuestions:t.map(t=>{const n=t.content;return{id:t.id,questionNumber:t.question_number,imageUrl:n.imageUrl||"",questionText:n.questionText,options:(n.options||[]).map((n,o)=>({id:n.id||`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:"string"==typeof n?n:n.text}))}}),instruction:n?.instruction||"LOOK AT THE PICTURE AND CHOOSE THE CORRECT ANSWER"}}export function transformPictureFillBlankChoose(t){const n=t[0]?.content;return{subQuestions:t.map(t=>{const n=t.content;return{id:t.id,questionNumber:t.question_number,imageUrl:n.imageUrl||"",question:n.question||"",options:(n.options||[]).map((n,o)=>({id:n.id||`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:"string"==typeof n?n:n.text}))}}),instruction:n?.instruction||"LOOK AT THE PICTURE, FILL IN THE BLANK AND CHOOSE THE ANSWER"}}export function transformReadingPassage(t){if(function(e){const t=e[0];if(!t)return!1;const n=t.content;return void 0!==n?.question&&!n?.questions&&void 0!==t.questionGroup?.payload?.passage}(t)){const n=t[0],o=n.questionGroup?.payload||{},r=t.map(t=>{const n=t.content;return{id:t.id,questionNumber:t.question_number,questionText:n?.question||"",options:(n?.options||[]).map((n,o)=>({id:`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:"string"==typeof n?n:String(n)}))}});return{passage:o.passage||"",passageTitle:o.passageTitle,passageImageUrl:o.passageImageUrl||o.mainImageUrl,instruction:o.instructions||"READ THE PASSAGE AND ANSWER QUESTIONS",questions:r}}const n=t[0],o=n?.content,r=o?.questions?.map((t,o)=>({id:t.id||`${n.id}-sq-${o}`,questionNumber:o+1,questionText:t.question,options:(t.options||[]).map((o,r)=>({id:`${t.id||n.id}-opt-${r}`,label:e[r]||String(r+1),text:o}))}))||[];return{passage:o?.passage||"",passageTitle:o?.passageTitle,passageImageUrl:o?.passageImageUrl||o?.mainImageUrl,instruction:o?.instructions?.mainInstruction||"READ THE PASSAGE AND ANSWER QUESTIONS",questions:r}}export function transformLabelPicture(e){const t=e[0],n=t?.content;return{imageUrl:n?.imageUrl||"",wordBank:n?.wordBank||[],labels:n?.labels?.map(e=>({id:e.id,number:e.number,isPreFilled:e.isPreFilled||!1,correctAnswer:e.correctAnswer}))||[],instruction:n?.instruction||"LABEL THE PICTURE"}}function t(e){return e&&"string"==typeof e.word&&!e.subQuestions}export function transformFillWordHint(e){const n=e[0],o=n?.content;if(e.length>1&&e.every(e=>t(e.content))){const t=n.questionGroup?.payload?.hintLetters||[];return{subQuestions:e.map(e=>{const t=e.content,n=t.word.replace(/\{\d+\}/,"_");return{id:e.id,questionNumber:e.question_number,imageUrl:t.imageUrl||"",word:n}}),hintLetters:t,instruction:o?.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}if(t(o)){const e=o,t=n.questionGroup?.payload?.hintLetters||[];return{subQuestions:function(e){const t=[],n=e.split(",").map(e=>e.trim());for(const e of n){let n;const o=/\{(\d+)\}/g;for(;null!==(n=o.exec(e));){const o=parseInt(n[1],10),r=e.replace(n[0],"_");t.push({index:o,displayWord:r})}}return t.sort((e,t)=>e.index-t.index),t}(e.word).map(t=>({id:`${n.id}-blank-${t.index}`,questionNumber:n.question_number,imageUrl:e.imageUrl||"",word:t.displayWord,blankIndex:t.index})),hintLetters:t,instruction:e.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}const r=o;return{subQuestions:r?.subQuestions?.map((e,t)=>({id:e.id,questionNumber:n.question_number+t,imageUrl:e.imageUrl||"",word:e.word||""}))||[],hintLetters:r?.hintLetters||n.questionGroup?.payload?.hintLetters||[],instruction:r?.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}export function transformGridFill(e){const t=e[0],n=t?.content;return{grid:n?.grid||[],rows:n?.rows||0,columns:n?.columns||0,instruction:n?.instruction||"FILL IN THE MISSING WORDS",disabledCells:n?.disabledCells||[]}}export function transformAnswerTheQuestion(e){const t=e[0],n=t?.questionGroup?.payload,o=t?.content;return{questions:e.map(e=>{const t=e.content,n=e.is_example||t.isExample||!1;return{id:e.id,questionNumber:e.question_number,question:(t.question||"").replace(/\{\d+\}/g,"______"),imageUrl:t.imageUrl,prefixText:t.prefixText,suffixText:t.suffixText,suggestedAnswers:t.suggestedAnswers,isExample:n,exampleAnswer:n?e.correct_answer?.answer:void 0}}),instruction:"ANSWER THE QUESTION",imageUrl:n?.mainImageUrl||n?.imageUrl||o?.imageUrl,title:o?.title,groupContent:n?.groupContent||o?.groupContent}}export function transformTrueFalse(e){const t=e[0]?.questionGroup?.payload;return{questions:e.map(e=>{const t=e.content,n=e.is_example||t.isExample||!1,o=n&&"boolean"==typeof e.correct_answer?.answer?e.correct_answer.answer:void 0;return{id:e.id,questionNumber:e.question_number,question:t.question||"",imageUrl:t.imageUrl,isExample:n,exampleCorrectAnswer:o}}),instruction:"READ AND CHOOSE TRUE OR FALSE",imageUrl:t?.mainImageUrl||t?.imageUrl,groupContent:t?.content||t?.groupContent}}export function transformWordOrdering(e){return{questions:e.map(e=>{const t=e.content,n=e.is_example||t.isExample||!1,o=Array.isArray(e.correct_answer?.answer)?e.correct_answer.answer:Array.isArray(t.answer)?t.answer:void 0;return{id:e.id,questionNumber:e.question_number,words:t.words||[],imageUrl:t.imageUrl,isExample:n,exampleAnswer:n?o:void 0}}),instruction:"ARRANGE THE LETTERS TO MAKE A WORD"}}export function transformWordFillParagraph(e){const t=e[0],n=t?.questionGroup?.payload,o=t?.content,r=o?.title||n?.title||e.find(e=>e.content?.title)?.content?.title,i=o?.wordBank||[],s=i.map(e=>"string"==typeof e?{word:e}:e),a=o?.viewMode,u=void 0!==o?.wordBank?.[0]?.options;let c;c="EMAIL"===a?"EMAIL":a||!o?.emailFrom&&!o?.emailTo?"DEFAULT"===a?"DEFAULT":"WITH_OPTIONS"===a||u?"WITH_OPTIONS":a||0!==i.length?"WITH_WORD_BANK":"DEFAULT":"EMAIL";const l=o?.emailFrom||o?.metadata?.emailFrom,m=o?.emailTo||o?.metadata?.emailTo;return{questionId:t?.id||"",paragraph:o?.paragraph||"",title:r,imageUrl:o?.imageUrl,wordBank:s,viewMode:c,instruction:"READ AND FILL IN THE BLANKS",exampleAnswer:o?.exampleAnswer,emailFrom:l,emailTo:m}}export function transformMatchByWritingAnswer(e){const t=e[0]?.questionGroup?.payload,n=e.some(e=>!!e.content?.askerName),o=e.map(e=>{const t=e.content,n=e.is_example||t.isExample||!1;return{id:e.id,questionNumber:e.question_number,question:t.question||"",imageUrl:t.imageUrl,isExample:n,exampleAnswer:n?e.correct_answer?.answer:void 0,askerName:t.askerName,answererName:t.answererName}}),r=t?.options?.map(e=>({answer:e.answer,imageUrl:e.imageUrl||"",content:e.content||""}))||[],i=n?e[0]?.content:void 0;return{questions:o,options:r,instruction:"LOOK AND WRITE THE ANSWER",viewMode:n?"CONVERSATION":"DEFAULT",groupImageUrl:t?.groupImageUrl||"",askerName:i?.askerName,answererName:i?.answererName}}export function transformWriteSentences(e){const t=e[0],n=t?.content,o=t?.questionGroup?.payload;return{questions:e.map(e=>({id:e.id,questionNumber:e.question_number})),instruction:n?.instruction||"WRITE SENTENCES ABOUT THE PICTURE",imageUrl:o?.mainImageUrl||o?.imageUrl||n?.imageUrl,title:n?.title,groupContent:o?.groupContent||n?.groupContent}}export function transformWordFillStructuredForm(e){const t=e[0],n=t?.questionGroup?.payload;return{questions:e.map(e=>{const t=e.content,n=e.correct_answer||{};let o=t?.content||"";const r=t?.blocks;return!o&&r?.length&&(o=r.map(e=>(e.heading?`<h3>${e.heading}</h3>`:"")+(e.content||"")).join("")),{id:e.id,questionNumber:e.question_number,title:t?.title||"",imageUrl:t?.imageUrl,content:o,answers:n?.answers||{},caseSensitive:n?.caseSensitive??t?.caseSensitive??!1}}),instruction:n?.instructions||"COMPLETE THE FORM BELOW",groupTitle:n?.title,groupContent:n?.content,groupImageUrl:n?.imageUrl,audioUrl:t?.audio_url||n?.audioUrl}}export function transformListenChooseObjects(e){const t=e[0],n=t?.content,o=t?.questionGroup?.payload||{};return{audioUrl:n?.audioUrl||"",backgroundImageUrl:o.backgroundImageUrl||"",objectNodes:o.objectNodes||[],correctObjectId:t?.correctAnswer?.objectId||t?.correct_answer?.objectId||"",isBackup:n?.isBackup||!1,instruction:"LISTEN AND CHOOSE THE CORRECT OBJECT"}}export function transformListenSpeakAnswer(e){return{questions:e.map(e=>{const t=e.content,n=e.questionGroup?.payload||{};return{id:e.id,questionNumber:e.question_number,audioUrl:t?.audioUrl||"",arrowNode:t?.arrowNode,backgroundImageUrl:n.backgroundImageUrl||n.imageUrl||"",isBackup:t?.isBackup||!1}}),instruction:"LISTEN AND SPEAK YOUR ANSWER"}}
|
|
1
|
+
export function groupQuestionsByPart(e,t){const n=new Map,o=new Map;for(const t of e){const e=o.get(t.part_id)||[];e.push(t),o.set(t.part_id,e)}for(const[e,r]of o.entries()){const o=[...r].sort((e,t)=>e.question_number-t.question_number),i=o[0];if(!i)continue;const s=t?.find(t=>String(t.id)===String(e)),a=void 0!==s?.id?Number(s.id):void 0,u=s?.name?.match(/\d+/),c=u?parseInt(u[0],10):i.part_no,l=s?.group,m=Boolean(s?.isGroup)&&"DOCUMENT"===l?.type,p=s?.sections??[],d=new Set(p.map(e=>e.questionType).filter(Boolean)),g=p.length>1&&d.size>1;if(m||g){const t=`${e}_part`;n.set(t,{partId:e,partNo:c,questionType:i.question_type,questions:o,name:s?.name,instructions:s?.instructions,audioUrl:s?.audioUrl,templateOrder:a,category:s?.category,points:s?.points,isGroup:!0,group:l,sections:s?.sections,startIndex:s?.startIndex,endIndex:s?.endIndex});continue}if(!s?.sections?.length){const t=`${e}_part`;n.set(t,{partId:e,partNo:c,questionType:i.question_type,questions:o,name:s?.name,instructions:s?.instructions,audioUrl:s?.audioUrl,templateOrder:a,category:s?.category,points:s?.points,isGroup:s?.isGroup,optionMode:s?.optionMode,optionCount:s?.optionCount,viewMode:s?.viewMode,defaultValue:s?.defaultValue,multipleAnswers:s?.multipleAnswers,questionConfig:s?.questionConfig,wordBankConfig:s?.wordBankConfig,group:s?.group,startIndex:s?.startIndex,endIndex:s?.endIndex});continue}for(const[t,r]of s.sections.entries()){const i=o.filter(e=>{const t=e.question_number-1;return t>=r.startIndex&&t<=r.endIndex});if(!i.length)continue;const u=`${e}_section_${t}`,l=Boolean(r.isGroup||r.group?.type);n.set(u,{partId:e,partNo:c,questionType:r.questionType||i[0].question_type,questions:i,name:s.name,instructions:r.instructions||r.name||s.instructions,audioUrl:s.audioUrl,templateOrder:a,category:s.category,points:s.points,sectionId:r.sectionId,isGroup:l,optionMode:r.optionMode,optionCount:r.optionCount,viewMode:r.viewMode,defaultValue:r.defaultValue,multipleAnswers:r.multipleAnswers,questionConfig:r.questionConfig,wordBankConfig:r.wordBankConfig,group:r.group,startIndex:r.startIndex,endIndex:r.endIndex})}}return Array.from(n.values()).sort((e,t)=>{const n=void 0===e.templateOrder||isNaN(e.templateOrder)?1/0:e.templateOrder,o=void 0===t.templateOrder||isNaN(t.templateOrder)?1/0:t.templateOrder;return n!==o?n-o:(e.questions[0]?.question_number||0)-(t.questions[0]?.question_number||0)})}export function transformFillInBlank(e){const t=e[0],n=t?.content,o=t?.questionGroup?.payload,r=[];for(const t of e){const e=t.content,n=t.is_example||!1,o=e.question||e.blanks?.[0]?.text||"";if([...o.matchAll(/\{(\d+)\}/g)].length>1){const i=o.split("\n").filter(e=>e.trim());for(const o of i){const i=o.match(/\{(\d+)\}/);if(!i)continue;const s=parseInt(i[1],10),a=o.split(/\{\d+\}/),u=a[0]?.trim()||"",c=a[1]?.trim()||"";r.push({id:`${t.id}-blank-${s}`,questionNumber:t.question_number,textBefore:u,textAfter:c,imageUrl:e.imageUrl,hints:e.hints,isExample:n,correctAnswer:n?t.correct_answer?.answers?.[s]:void 0})}}else{const i=o.match(/^(.*?)\{0\}(.*)$/),s=i?i[1].trim():o,a=i?i[2].trim():"";r.push({id:t.id,questionNumber:t.question_number,textBefore:s,textAfter:a,imageUrl:e.imageUrl,hints:e.hints,isExample:n,correctAnswer:n?t.correct_answer?.answers?.[0]:void 0})}}return{questions:r,title:n?.title||o?.title||"FILL IN THE BLANK",imageUrl:n?.imageUrl,audioUrl:n?.audioUrl,exampleText:n?.exampleText,exampleHighlight:n?.exampleHighlight,instruction:n?.instruction||"LISTEN AND WRITE",showHints:n?.showHints,groupContent:o?.content||o?.groupContent,groupTitle:o?.title,groupImageUrl:o?.mainImageUrl||o?.imageUrl}}export function transformWriteCorrectVerbForm(e){const t=e[0],n=t?.content;return{questions:e.map(e=>{const t=e.content,n=t.sentence||"",o=n.match(/^(.*?)\{0\}(.*)$/),r=o?o[1].trim():n,i=o?o[2].trim():"";return{id:e.id,questionNumber:e.question_number,textBefore:r,textAfter:i,verbHint:t.verbHint}}),title:"WRITE THE CORRECT VERB FORM",instruction:n?.instruction||"Write the correct form of the verb in parentheses."}}const e=["A","B","C","D","E","F"];export function transformChooseCorrectAnswer(t){const n=t[0]?.content,o=t[0]?.questionGroup?.payload,r=t.find(e=>e.is_example),i=t.filter(e=>!e.is_example);let s;if(r){const t=r.content,n=(t.options||[]).map((t,n)=>({id:`${r.id}-opt-${n}`,label:e[n]||String(n+1),text:t})),o="number"==typeof r.correct_answer?.answer?r.correct_answer.answer:-1;s={questionNumber:r.question_number,questionText:t.question||"",options:n,correctOptionId:o>=0?n[o]?.id||"":n[0]?.id||"",optionType:t.optionType||"text",imageUrl:t.imageUrl}}return{questions:i.map(t=>{const n=t.content,o=n.optionType||"text",r=(n.options||[]).map((n,o)=>({id:`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:n})),i=t.correct_answer?.answer,s=Array.isArray(i)?i.filter(e=>"number"==typeof e).map(e=>r[e]?.id).filter(e=>Boolean(e)):"number"==typeof i?[r[i]?.id].filter(e=>Boolean(e)):[];return{id:t.id,questionNumber:t.question_number,questionText:n.question||"",options:r,correctOptionId:s[0],correctOptionIds:s,imageUrl:n.imageUrl,optionType:o,multipleAnswers:Boolean(n.multipleAnswers||Array.isArray(i)),explanation:t.explanation}}),example:s,imageUrl:n?.imageUrl,groupImageUrl:o?.mainImageUrl||o?.imageUrl,groupTitle:o?.title,groupContent:o?.content,articles:o?.articles,audioUrl:n?.audioUrl,instruction:n?.instruction||"CHOOSE THE CORRECT ANSWER"}}export function transformChooseCorrectAdjective(t){return{questions:t.map(t=>{const n=t.content,o=n.sentence||"",r=o.match(/^(.*?)\{0\}(.*)$/),i=r?r[1]:o,s=r?r[2]:"";return{id:t.id,questionNumber:t.question_number,sentenceBefore:i,sentenceAfter:s,options:(n.options||[]).map((n,o)=>({id:`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:n}))}}),instruction:"CHOOSE THE CORRECT ADJECTIVE"}}export function transformWriteShortLetter(e){const t=e.content;if(t.instructions?.mainInstruction||t.informations?.length)return{prompt:t.instructions?.mainInstruction||"",requirements:t.informations,minWords:t.minWords,maxWords:t.maxWords,guideImages:t.guideImages};return{prompt:t.contexts?.filter(e=>"text"===e.type).map(e=>e.text).join("\n")||"",minWords:t.minWords,maxWords:t.maxWords,guideImages:t.guideImages}}export function transformColorObjects(e){const t=e[0],n=t?.content,o=n?.colorNodes?.map(e=>({id:e.id,color:e.color,label:e.label}))||n?.hintItems||[],r=n?.regionNodes?.map(e=>({id:e.id,x:e.x,y:e.y,width:e.width,height:e.height,correctHintId:e.linkedColorNodeId}))||n?.regions||[],i=n?.instructions;return{instruction:(i&&i.length>0?i.join(" "):n?.instruction)||"READ AND COLOR THE OBJECTS",instructions:i,imageUrl:n?.backgroundImageUrl||n?.imageUrl||"",audioUrl:n?.audioUrl,hintItems:o,regions:r}}export function transformPictureChoose(t){const n=t[0]?.content;return{subQuestions:t.map(t=>{const n=t.content;return{id:t.id,questionNumber:t.question_number,imageUrl:n.imageUrl||"",questionText:n.questionText,options:(n.options||[]).map((n,o)=>({id:n.id||`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:"string"==typeof n?n:n.text}))}}),instruction:n?.instruction||"LOOK AT THE PICTURE AND CHOOSE THE CORRECT ANSWER"}}export function transformPictureFillBlankChoose(t){const n=t[0]?.content;return{subQuestions:t.map(t=>{const n=t.content;return{id:t.id,questionNumber:t.question_number,imageUrl:n.imageUrl||"",question:n.question||"",options:(n.options||[]).map((n,o)=>({id:n.id||`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:"string"==typeof n?n:n.text}))}}),instruction:n?.instruction||"LOOK AT THE PICTURE, FILL IN THE BLANK AND CHOOSE THE ANSWER"}}export function transformReadingPassage(t){if(function(e){const t=e[0];if(!t)return!1;const n=t.content;return void 0!==n?.question&&!n?.questions&&void 0!==t.questionGroup?.payload?.passage}(t)){const n=t[0],o=n.questionGroup?.payload||{},r=t.map(t=>{const n=t.content;return{id:t.id,questionNumber:t.question_number,questionText:n?.question||"",options:(n?.options||[]).map((n,o)=>({id:`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:"string"==typeof n?n:String(n)}))}});return{passage:o.passage||"",passageTitle:o.passageTitle,passageImageUrl:o.passageImageUrl||o.mainImageUrl,instruction:o.instructions||"READ THE PASSAGE AND ANSWER QUESTIONS",questions:r}}const n=t[0],o=n?.content,r=o?.questions?.map((t,o)=>({id:t.id||`${n.id}-sq-${o}`,questionNumber:o+1,questionText:t.question,options:(t.options||[]).map((o,r)=>({id:`${t.id||n.id}-opt-${r}`,label:e[r]||String(r+1),text:o}))}))||[];return{passage:o?.passage||"",passageTitle:o?.passageTitle,passageImageUrl:o?.passageImageUrl||o?.mainImageUrl,instruction:o?.instructions?.mainInstruction||"READ THE PASSAGE AND ANSWER QUESTIONS",questions:r}}export function transformLabelPicture(e){const t=e[0],n=t?.content;return{imageUrl:n?.imageUrl||"",wordBank:n?.wordBank||[],labels:n?.labels?.map(e=>({id:e.id,number:e.number,isPreFilled:e.isPreFilled||!1,correctAnswer:e.correctAnswer}))||[],instruction:n?.instruction||"LABEL THE PICTURE"}}function t(e){return e&&"string"==typeof e.word&&!e.subQuestions}export function transformFillWordHint(e){const n=e[0],o=n?.content;if(e.length>1&&e.every(e=>t(e.content))){const t=n.questionGroup?.payload?.hintLetters||[];return{subQuestions:e.map(e=>{const t=e.content,n=t.word.replace(/\{\d+\}/,"_");return{id:e.id,questionNumber:e.question_number,imageUrl:t.imageUrl||"",word:n}}),hintLetters:t,instruction:o?.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}if(t(o)){const e=o,t=n.questionGroup?.payload?.hintLetters||[];return{subQuestions:function(e){const t=[],n=e.split(",").map(e=>e.trim());for(const e of n){let n;const o=/\{(\d+)\}/g;for(;null!==(n=o.exec(e));){const o=parseInt(n[1],10),r=e.replace(n[0],"_");t.push({index:o,displayWord:r})}}return t.sort((e,t)=>e.index-t.index),t}(e.word).map(t=>({id:`${n.id}-blank-${t.index}`,questionNumber:n.question_number,imageUrl:e.imageUrl||"",word:t.displayWord,blankIndex:t.index})),hintLetters:t,instruction:e.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}const r=o;return{subQuestions:r?.subQuestions?.map((e,t)=>({id:e.id,questionNumber:n.question_number+t,imageUrl:e.imageUrl||"",word:e.word||""}))||[],hintLetters:r?.hintLetters||n.questionGroup?.payload?.hintLetters||[],instruction:r?.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}export function transformGridFill(e){const t=e[0],n=t?.content;return{grid:n?.grid||[],rows:n?.rows||0,columns:n?.columns||0,instruction:n?.instruction||"FILL IN THE MISSING WORDS",disabledCells:n?.disabledCells||[]}}export function transformAnswerTheQuestion(e){const t=e[0],n=t?.questionGroup?.payload,o=t?.content;return{questions:e.map(e=>{const t=e.content,n=e.is_example||t.isExample||!1;return{id:e.id,questionNumber:e.question_number,question:(t.question||"").replace(/\{\d+\}/g,"______"),imageUrl:t.imageUrl,prefixText:t.prefixText,suffixText:t.suffixText,suggestedAnswers:t.suggestedAnswers,isExample:n,exampleAnswer:n?e.correct_answer?.answer:void 0}}),instruction:"ANSWER THE QUESTION",imageUrl:n?.mainImageUrl||n?.imageUrl||o?.imageUrl,title:o?.title,groupContent:n?.groupContent||o?.groupContent}}export function transformTrueFalse(e){const t=e[0]?.questionGroup?.payload;return{questions:e.map(e=>{const t=e.content,n=e.is_example||t.isExample||!1,o=n&&"boolean"==typeof e.correct_answer?.answer?e.correct_answer.answer:void 0;return{id:e.id,questionNumber:e.question_number,question:t.question||"",imageUrl:t.imageUrl,isExample:n,exampleCorrectAnswer:o}}),instruction:"READ AND CHOOSE TRUE OR FALSE",imageUrl:t?.mainImageUrl||t?.imageUrl,groupContent:t?.content||t?.groupContent}}export function transformWordOrdering(e){return{questions:e.map(e=>{const t=e.content,n=e.is_example||t.isExample||!1,o=Array.isArray(e.correct_answer?.answer)?e.correct_answer.answer:Array.isArray(t.answer)?t.answer:void 0;return{id:e.id,questionNumber:e.question_number,words:t.words||[],imageUrl:t.imageUrl,isExample:n,exampleAnswer:n?o:void 0}}),instruction:"ARRANGE THE LETTERS TO MAKE A WORD"}}export function transformWordFillParagraph(e){const t=e[0],n=t?.questionGroup?.payload,o=t?.content,r=o?.title||n?.title||e.find(e=>e.content?.title)?.content?.title,i=o?.wordBank||[],s=i.map(e=>"string"==typeof e?{word:e}:e),a=o?.viewMode,u=void 0!==o?.wordBank?.[0]?.options;let c;c="EMAIL"===a?"EMAIL":a||!o?.emailFrom&&!o?.emailTo?"DEFAULT"===a?"DEFAULT":"WITH_OPTIONS"===a||u?"WITH_OPTIONS":a||0!==i.length?"WITH_WORD_BANK":"DEFAULT":"EMAIL";const l=o?.emailFrom||o?.metadata?.emailFrom,m=o?.emailTo||o?.metadata?.emailTo;return{questionId:t?.id||"",paragraph:o?.paragraph||"",title:r,imageUrl:o?.imageUrl,wordBank:s,viewMode:c,instruction:"READ AND FILL IN THE BLANKS",exampleAnswer:o?.exampleAnswer,emailFrom:l,emailTo:m}}export function transformMatchByWritingAnswer(e){const t=e[0]?.questionGroup?.payload,n=e.some(e=>!!e.content?.askerName),o=e.map(e=>{const t=e.content,n=e.is_example||t.isExample||!1;return{id:e.id,questionNumber:e.question_number,question:t.question||"",imageUrl:t.imageUrl,isExample:n,exampleAnswer:n?e.correct_answer?.answer:void 0,askerName:t.askerName,answererName:t.answererName}}),r=t?.options?.map(e=>({answer:e.answer,imageUrl:e.imageUrl||"",content:e.content||""}))||[],i=n?e[0]?.content:void 0;return{questions:o,options:r,instruction:"LOOK AND WRITE THE ANSWER",viewMode:n?"CONVERSATION":"DEFAULT",groupImageUrl:t?.groupImageUrl||"",askerName:i?.askerName,answererName:i?.answererName}}export function transformWriteSentences(e){const t=e[0],n=t?.content,o=t?.questionGroup?.payload;return{questions:e.map(e=>({id:e.id,questionNumber:e.question_number})),instruction:n?.instruction||"WRITE SENTENCES ABOUT THE PICTURE",imageUrl:o?.mainImageUrl||o?.imageUrl||n?.imageUrl,title:n?.title,groupContent:o?.groupContent||n?.groupContent}}export function transformWordFillStructuredForm(e){const t=e[0],n=t?.questionGroup?.payload;return{questions:e.map(e=>{const t=e.content,n=e.correct_answer||{};let o=t?.content||"";const r=t?.blocks;return!o&&r?.length&&(o=r.map(e=>(e.heading?`<h3>${e.heading}</h3>`:"")+(e.content||"")).join("")),{id:e.id,questionNumber:e.question_number,title:t?.title||"",imageUrl:t?.imageUrl,content:o,answers:n?.answers||{},caseSensitive:n?.caseSensitive??t?.caseSensitive??!1}}),instruction:n?.instructions||"COMPLETE THE FORM BELOW",groupTitle:n?.title,groupContent:n?.content,groupImageUrl:n?.imageUrl,audioUrl:t?.audio_url||n?.audioUrl}}export function transformListenChooseObjects(e){const t=e[0],n=t?.content,o=t?.questionGroup?.payload||{};return{audioUrl:n?.audioUrl||"",backgroundImageUrl:o.backgroundImageUrl||"",objectNodes:o.objectNodes||[],correctObjectId:t?.correctAnswer?.objectId||t?.correct_answer?.objectId||"",isBackup:n?.isBackup||!1,instruction:"LISTEN AND CHOOSE THE CORRECT OBJECT"}}export function transformListenSpeakAnswer(e){return{questions:e.map(e=>{const t=e.content,n=e.questionGroup?.payload||{};return{id:e.id,questionNumber:e.question_number,audioUrl:t?.audioUrl||"",arrowNode:t?.arrowNode,backgroundImageUrl:n.backgroundImageUrl||n.imageUrl||"",isBackup:t?.isBackup||!1}}),instruction:"LISTEN AND SPEAK YOUR ANSWER"}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as n}from"react";import a from"next/image";import{Loader2 as i,FileText as l,Clock as s,Trophy as r,Layers as c,Target as h,HelpCircle as o,ChevronDown as m,X as d}from"lucide-react";import x from"../../../../components/themes/cambridge-yle/assets/images/background-ocean-edu-2.png";import g from"../../../../components/themes/cambridge-yle/assets/images/frame.png";import p from"../../../../components/themes/cambridge-yle/assets/images/bg-title.png";import u from"../../../../components/themes/cambridge-yle/assets/images/close.png";import b from"../../../../components/themes/cambridge-yle/assets/images/rocket.png";const f=[{q:"Bài test này kéo dài bao lâu?",a:"Thời gian làm bài sẽ được hiển thị trên màn hình. Hãy theo dõi đồng hồ để phân bổ thời gian hợp lý."},{q:"Em có cần hoàn thành tất cả câu hỏi không?",a:"Để kết quả phản ánh chính xác nhất năng lực hiện tại, em cố gắng hoàn thành toàn bộ câu hỏi trong thời gian quy định."},{q:"Nếu mất mạng giữa chừng thì sao?",a:"Trong một số trường hợp, hệ thống có thể tự động lưu tiến trình làm bài. Hãy kết nối lại internet sớm nhất có thể. Tuy nhiên để tránh gián đoạn, em nên sử dụng kết nối internet ổn định trong suốt quá trình làm bài."},{q:"Em không nghe được audio thì phải làm sao?",a:"Em hãy kiểm tra loa, tai nghe và âm lượng thiết bị trước. Nếu vẫn gặp lỗi, hãy thử tải lại trang hoặc đổi sang trình duyệt khác để tiếp tục làm bài."},{q:"Trang web bị lag hoặc không tải được câu hỏi?",a:"Em có thể thử làm mới trang, kiểm tra lại kết nối internet hoặc đổi trình duyệt/thiết bị khác. Nếu tình trạng vẫn tiếp diễn, hãy liên hệ trung tâm để được hỗ trợ nhanh nhất."},{q:"Em có thể xem lại đáp án sau khi nộp bài không?",a:"Sau khi nộp bài, sẽ có phiếu kết quả AI chấm điểm trả về, phân tích từng câu hỏi em đã làm."},{q:"Nếu em nộp nhầm thì sao?",a:"Sau khi nộp bài, em sẽ không thể chỉnh sửa câu trả lời. Em có thể liên hệ thầy cô ở trung tâm để hỗ trợ làm lại bài khác."},{q:"Em có được dùng từ điển hoặc tài liệu không?",a:"Để kết quả phản ánh đúng năng lực hiện tại, em nên làm bài trong điều kiện tương tự một bài kiểm tra thực tế và hạn chế sử dụng tài liệu hỗ trợ."},{q:"Em cần chuẩn bị gì trước khi bắt đầu?",a:"Em nên chuẩn bị thiết bị có kết nối internet ổn định, tai nghe (nếu có phần Listening), không gian yên tĩnh và dành đủ thời gian để hoàn thành bài test liên tục."},{q:"Em nên làm gì nếu gặp lỗi hệ thống?",a:"Nếu gặp lỗi trong quá trình làm bài, em hãy chụp lại màn hình lỗi (nếu có) và liên hệ trung tâm để được hỗ trợ xử lý nhanh nhất."}];function w({className:t="",size:n=18}){return e("svg",{width:n,height:n,viewBox:"0 0 24 24",className:t,fill:"currentColor",children:e("path",{d:"M12 0l2.4 9.6L24 12l-9.6 2.4L12 24l-2.4-9.6L0 12l9.6-2.4L12 0z"})})}export function CambridgeYleWaitingRoom({room:i,onStart:b,isStarting:y,showCountdown:k,autoStartCountdown:_,closeRedirectUrl:C,onClose:z}){const j=i.exam?.name||"",q=i.contest?.name||"",S=i.exam?.numberOfParts||1,E=i.exam?.durationMinutes||45,B=i.exam?.totalScore||100,L=i.exam?.passScore||0,[T,W]=n(!1),[O,P]=n(0);return t("div",{className:"fixed inset-0 z-50 flex items-center justify-center overflow-hidden",children:[e("div",{className:"absolute inset-0 scale-105 bg-cover bg-center",style:{backgroundImage:`url(${x.src})`,filter:"blur(2px) brightness(0.8) saturate(0.9)"}}),e("div",{className:"absolute inset-0 bg-gradient-to-b from-blue-950/50 via-blue-900/40 to-blue-950/60"}),e(w,{className:"absolute left-[8%] top-[14%] text-yellow-300 drop-shadow-[0_0_8px_rgba(255,255,150,0.8)]",size:22}),e(w,{className:"absolute right-[10%] top-[10%] text-yellow-200 drop-shadow-[0_0_8px_rgba(255,255,150,0.8)]",size:16}),e(w,{className:"absolute left-[15%] bottom-[18%] text-white/80",size:14}),e(w,{className:"absolute right-[6%] bottom-[24%] text-yellow-300 drop-shadow-[0_0_8px_rgba(255,255,150,0.8)]",size:20}),e(w,{className:"absolute left-[45%] top-[8%] text-white/70",size:12}),e("div",{className:"relative z-10",style:{width:"min(98vw, calc(98vh * 1552 / 672), 1800px)"},children:t("div",{className:"relative aspect-[1552/672] w-full",children:[e(a,{src:g,alt:"",fill:!0,className:"object-contain",priority:!0,unoptimized:!0}),e("div",{className:"absolute left-1/2 top-0 z-20 -translate-x-1/2 -translate-y-1/2",children:t("div",{className:"relative",children:[e(a,{src:p,alt:"",width:320,height:72,className:"drop-shadow-xl",priority:!0,unoptimized:!0}),e("div",{className:"absolute inset-0 flex items-center justify-center px-10 pt-1",title:q,children:e("span",{className:"block truncate text-center text-base font-extrabold uppercase tracking-[0.15em] text-white drop-shadow",children:q})})]})}),e("button",{onClick:()=>{z?z():C&&(window.location.href=C)},className:"absolute right-[7%] top-[-2%] z-30 cursor-pointer transition-transform hover:scale-110 active:scale-95","aria-label":"Close",children:e(a,{src:u,alt:"Close",width:56,height:56,unoptimized:!0})}),e("div",{className:"absolute inset-0 z-10 flex items-stretch overflow-hidden px-[9%] py-[10%]",children:t("div",{className:"flex h-full w-full items-stretch gap-4",children:[t("div",{className:"mx-auto flex w-full max-w-[560px] flex-[0_0_46%] flex-col justify-center gap-1",children:[e("h1",{className:"whitespace-nowrap text-center text-3xl font-black uppercase tracking-wide text-white md:text-4xl lg:text-5xl 2xl:text-6xl",style:{fontWeight:900,margin:"0.2em 0",textShadow:["0 1px 0 #cfe3ff","0 2px 0 #a8c8ee","0 3px 0 #6f9cd4","0 4px 0 #4a7cb8","0 5px 0 #2f5e9c","0 6px 0 #1a4480","0 8px 12px rgba(0,0,0,0.45)","0 0 22px rgba(120,180,255,0.55)"].join(", ")},children:i.name}),e("p",{className:"mt-1 hidden text-center text-sm font-bold text-[#21cffb] md:text-base 2xl:block 2xl:text-lg",children:"Đánh giá năng lực • Xác định lộ trình • Bứt phá tương lai"}),e("p",{className:"mx-auto mt-1 hidden max-w-2xl text-center text-xs text-white/95 md:text-sm 2xl:block",children:"Bài thi giúp bạn biết chính xác trình độ hiện tại và được Ocean Edu tư vấn lộ trình học tập phù hợp nhất."}),t("div",{className:"mt-4 flex items-center justify-center gap-2 2xl:mt-6",children:[e("span",{className:"h-px w-10 bg-white"}),e(w,{className:"text-white",size:12}),e("span",{className:"text-xs font-extrabold uppercase tracking-[0.3em] text-white md:text-sm",children:"Bài thi bao gồm"}),e(w,{className:"text-white",size:12}),e("span",{className:"h-px w-10 bg-white"})]}),t("div",{className:"mt-4 grid grid-cols-3 gap-2.5",children:[e(v,{icon:e(c,{className:"h-6 w-6"}),value:S,label:"Phần thi"}),e(v,{icon:e(s,{className:"h-6 w-6"}),value:E,label:"Phút"}),e(v,{icon:e(r,{className:"h-6 w-6"}),value:B,label:"Thang điểm"})]}),t("div",{className:"mt-4 space-y-2.5",children:[t("div",{className:"flex items-center gap-3 rounded-xl bg-[#0000001c] px-3 py-2.5",children:[e("span",{className:"flex h-9 w-9 flex-none items-center justify-center rounded-full bg-[#00000021] text-white",children:e(l,{className:"h-4 w-4"})}),e("span",{className:"text-sm font-bold text-white md:text-base",children:"Đề thi"}),e("span",{className:"ml-auto truncate text-sm font-bold text-white md:text-base",children:j})]}),L>0&&t("div",{className:"flex items-center gap-3 rounded-xl bg-[#0000001c] px-3 py-2.5",children:[e("span",{className:"flex h-9 w-9 flex-none items-center justify-center rounded-full bg-[#00000021] text-white",children:e(h,{className:"h-4 w-4"})}),e("span",{className:"text-sm font-bold text-white md:text-base",children:"Điểm tối thiểu cần đạt"}),t("span",{className:"ml-auto text-sm font-black text-yellow-300 md:text-lg",children:[L,"/",B]})]})]}),e("div",{className:"mt-5 flex justify-center",children:e(N,{onClick:b,isStarting:y,showCountdown:k,autoStartCountdown:_})})]}),e("div",{className:"relative hidden flex-[0_0_42%] md:block",children:e("div",{className:"absolute left-0 top-[4%] z-20 max-w-[60%]",children:t("div",{className:"relative rounded-2xl bg-white px-3 py-2 text-center text-[11px] font-semibold text-sky-900 shadow-xl ring-2 ring-sky-200 md:text-xs",children:["Cùng mình khám phá trình độ của bạn nhé!",e("span",{className:"absolute -bottom-1.5 right-6 h-3 w-3 rotate-45 bg-white ring-2 ring-sky-200"})]})})})]})})]})}),t("button",{type:"button",onClick:()=>W(!0),"aria-label":"Câu hỏi thường gặp",className:"group fixed bottom-5 right-5 z-40 inline-flex cursor-pointer items-center gap-2 rounded-full bg-gradient-to-b from-cyan-300 via-sky-500 to-sky-700 px-4 py-3 text-sm font-bold text-white shadow-[0_6px_0_0_#0c4a6e,0_10px_22px_rgba(14,165,233,0.45)] ring-2 ring-cyan-200/50 transition-all duration-150 hover:-translate-y-0.5 hover:brightness-110 active:translate-y-1 active:shadow-[0_1px_0_0_#0c4a6e,0_3px_8px_rgba(14,165,233,0.3)]",children:[e(o,{className:"h-5 w-5",strokeWidth:2.5}),e("span",{className:"hidden sm:inline",style:{textShadow:"0 1px 0 rgba(12,74,110,0.5)"},children:"Câu hỏi thường gặp"})]}),T&&t("div",{className:"fixed inset-0 z-[60] flex items-center justify-center p-4",role:"dialog","aria-modal":"true","aria-label":"Câu hỏi thường gặp",children:[e("div",{className:"absolute inset-0 bg-blue-950/70 backdrop-blur-sm",onClick:()=>W(!1)}),t("div",{className:"relative z-10 flex max-h-[85vh] w-full max-w-2xl flex-col overflow-hidden rounded-3xl bg-gradient-to-br from-cyan-300/20 via-white/5 to-white/0 p-px shadow-[0_20px_60px_-15px_rgba(10,75,140,0.7)] backdrop-blur-xl",children:[e("div",{className:"pointer-events-none absolute -left-12 -top-12 h-40 w-40 rounded-full bg-cyan-400/30 blur-3xl"}),e("div",{className:"pointer-events-none absolute -right-12 -bottom-12 h-40 w-40 rounded-full bg-sky-500/25 blur-3xl"}),t("div",{className:"relative flex max-h-[85vh] flex-col overflow-hidden rounded-[calc(1.5rem-1px)] bg-gradient-to-b from-[#0e3d70]/95 via-[#0a4b8c]/95 to-[#0a3866]/95 ring-1 ring-cyan-300/20",children:[t("div",{className:"flex items-center gap-3 px-6 py-5",children:[e("div",{className:"flex h-12 w-12 flex-none items-center justify-center rounded-full bg-gradient-to-br from-cyan-300 to-sky-600 shadow-[0_6px_18px_-4px_rgba(34,211,238,0.6)] ring-4 ring-cyan-300/20",children:e(o,{className:"h-6 w-6 text-white",strokeWidth:2.5})}),t("div",{className:"flex-1",children:[e("h2",{className:"text-lg font-extrabold tracking-tight text-white drop-shadow-md",children:"Câu hỏi thường gặp"}),e("p",{className:"mt-0.5 text-xs font-medium text-cyan-100/70",children:"Những điều cần biết trước khi làm bài"})]}),e("button",{type:"button",onClick:()=>W(!1),"aria-label":"Đóng",className:"flex h-9 w-9 flex-none cursor-pointer items-center justify-center rounded-full bg-white/10 text-white/80 ring-1 ring-white/15 transition-all duration-150 hover:bg-white/20 hover:text-white",children:e(d,{className:"h-5 w-5"})})]}),e("div",{className:"mx-6 h-px bg-gradient-to-r from-transparent via-cyan-300/25 to-transparent"}),e("div",{className:"flex-1 overflow-y-auto px-4 py-4 sm:px-6",children:e("ul",{className:"space-y-2",children:f.map((n,a)=>{const i=O===a;return t("li",{className:"overflow-hidden rounded-2xl ring-1 transition-colors duration-200 "+(i?"bg-white/[0.08] ring-cyan-300/30":"bg-white/[0.04] ring-white/10 hover:bg-white/[0.06]"),children:[t("button",{type:"button",onClick:()=>P(i?null:a),className:"flex w-full cursor-pointer items-center gap-3 px-4 py-3 text-left","aria-expanded":i,children:[e("span",{className:"flex h-7 w-7 flex-none items-center justify-center rounded-full text-xs font-black transition-colors "+(i?"bg-gradient-to-br from-yellow-300 to-orange-500 text-white":"bg-white/10 text-cyan-100"),children:a+1}),e("span",{className:"flex-1 text-sm font-bold text-white",children:n.q}),e(m,{className:"h-5 w-5 flex-none text-cyan-200 transition-transform duration-200 "+(i?"rotate-180":"")})]}),e("div",{className:"grid transition-all duration-200 "+(i?"grid-rows-[1fr] opacity-100":"grid-rows-[0fr] opacity-0"),children:e("div",{className:"overflow-hidden",children:e("p",{className:"px-4 pb-4 pl-14 text-sm leading-relaxed text-cyan-50/90",children:n.a})})})]},a)})})}),e("div",{className:"border-t border-white/10 bg-white/[0.03] px-6 py-3 text-center text-xs text-cyan-100/60",children:"Cần hỗ trợ thêm? Liên hệ trung tâm Ocean Edu để được giải đáp."})]})]})]})]})}function v({icon:n,value:a,label:i}){return t("div",{className:"flex items-center justify-center gap-3 rounded-2xl bg-[#0000001c] px-2 py-4",children:[e("span",{className:"flex h-12 w-12 flex-none items-center justify-center rounded-full bg-[#00bdff1a] text-white",children:n}),t("div",{className:"flex flex-col items-start leading-tight",children:[e("div",{className:"text-2xl font-black text-white md:text-3xl",children:a}),e("div",{className:"text-xs font-bold text-white/90 md:text-sm",children:i})]})]})}function N({onClick:n,isStarting:l,showCountdown:s,autoStartCountdown:r}){return s?e("div",{className:"inline-flex h-14 w-48 items-center justify-center rounded-full bg-yellow-400 text-2xl font-black text-[#1a3a6e]",children:r}):t("button",{onClick:n,disabled:l,className:"group relative mt-5 inline-flex cursor-pointer items-center gap-3 rounded-full bg-gradient-to-b from-[#ffd54a] via-[#ffb733] to-[#ff8a1f] py-2.5 pl-8 pr-10 shadow-[0_6px_0_0_#c46410,0_10px_18px_rgba(0,0,0,0.4)] ring-2 ring-orange-300/60 transition-all duration-150 hover:-translate-y-0.5 hover:brightness-110 hover:shadow-[0_8px_0_0_#c46410,0_14px_22px_rgba(0,0,0,0.45)] active:translate-y-1.5 active:shadow-[0_1px_0_0_#c46410,0_2px_6px_rgba(0,0,0,0.3)] disabled:cursor-not-allowed disabled:opacity-70",children:[l?e(i,{className:"h-7 w-7 animate-spin text-white"}):e(a,{src:b,alt:"",width:36,height:36,unoptimized:!0}),e("span",{className:"text-xl font-black text-white",style:{color:"#685030"},children:"Bắt đầu"})]})}
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as n}from"react";import a from"next/image";import{Loader2 as i,Clock as l,Trophy as s,Layers as r,Target as c,HelpCircle as o,ChevronDown as h,X as m}from"lucide-react";import{PartRow as d,groupPartsByCategory as x}from"./cambridge-yle-waiting-parts";import p from"../../../../components/themes/cambridge-yle/assets/images/background-ocean-edu-2.png";import g from"../../../../components/themes/cambridge-yle/assets/images/frame.png";import u from"../../../../components/themes/cambridge-yle/assets/images/bg-title.png";import b from"../../../../components/themes/cambridge-yle/assets/images/close.png";import f from"../../../../components/themes/cambridge-yle/assets/images/rocket.png";const w=[{q:"Bài test này kéo dài bao lâu?",a:"Thời gian làm bài sẽ được hiển thị trên màn hình. Hãy theo dõi đồng hồ để phân bổ thời gian hợp lý."},{q:"Em có cần hoàn thành tất cả câu hỏi không?",a:"Để kết quả phản ánh chính xác nhất năng lực hiện tại, em cố gắng hoàn thành toàn bộ câu hỏi trong thời gian quy định."},{q:"Nếu mất mạng giữa chừng thì sao?",a:"Trong một số trường hợp, hệ thống có thể tự động lưu tiến trình làm bài. Hãy kết nối lại internet sớm nhất có thể. Tuy nhiên để tránh gián đoạn, em nên sử dụng kết nối internet ổn định trong suốt quá trình làm bài."},{q:"Em không nghe được audio thì phải làm sao?",a:"Em hãy kiểm tra loa, tai nghe và âm lượng thiết bị trước. Nếu vẫn gặp lỗi, hãy thử tải lại trang hoặc đổi sang trình duyệt khác để tiếp tục làm bài."},{q:"Trang web bị lag hoặc không tải được câu hỏi?",a:"Em có thể thử làm mới trang, kiểm tra lại kết nối internet hoặc đổi trình duyệt/thiết bị khác. Nếu tình trạng vẫn tiếp diễn, hãy liên hệ trung tâm để được hỗ trợ nhanh nhất."},{q:"Em có thể xem lại đáp án sau khi nộp bài không?",a:"Sau khi nộp bài, sẽ có phiếu kết quả AI chấm điểm trả về, phân tích từng câu hỏi em đã làm."},{q:"Nếu em nộp nhầm thì sao?",a:"Sau khi nộp bài, em sẽ không thể chỉnh sửa câu trả lời. Em có thể liên hệ thầy cô ở trung tâm để hỗ trợ làm lại bài khác."},{q:"Em có được dùng từ điển hoặc tài liệu không?",a:"Để kết quả phản ánh đúng năng lực hiện tại, em nên làm bài trong điều kiện tương tự một bài kiểm tra thực tế và hạn chế sử dụng tài liệu hỗ trợ."},{q:"Em cần chuẩn bị gì trước khi bắt đầu?",a:"Em nên chuẩn bị thiết bị có kết nối internet ổn định, tai nghe (nếu có phần Listening), không gian yên tĩnh và dành đủ thời gian để hoàn thành bài test liên tục."},{q:"Em nên làm gì nếu gặp lỗi hệ thống?",a:"Nếu gặp lỗi trong quá trình làm bài, em hãy chụp lại màn hình lỗi (nếu có) và liên hệ trung tâm để được hỗ trợ xử lý nhanh nhất."}];function v({className:t="",size:n=18}){return e("svg",{width:n,height:n,viewBox:"0 0 24 24",className:t,fill:"currentColor",children:e("path",{d:"M12 0l2.4 9.6L24 12l-9.6 2.4L12 24l-2.4-9.6L0 12l9.6-2.4L12 0z"})})}export function CambridgeYleWaitingRoom({room:i,onStart:f,isStarting:k,showCountdown:_,autoStartCountdown:C,closeRedirectUrl:z,onClose:j}){const q=i.exam?.name||"",S=i.contest?.name||"",E=i.exam?.parts??[],I=E.length>0?E.length:i.exam?.numberOfParts||1,B=i.exam?.durationMinutes||45,L=i.exam?.totalScore||100,T=i.exam?.passScore||0,W=i.exam?.level?.trim()||"",[P,$]=n(!1),[H,O]=n(0);return t("div",{className:"fixed inset-0 z-50 flex items-center justify-center overflow-hidden",children:[e("div",{className:"absolute inset-0 scale-105 bg-cover bg-center",style:{backgroundImage:`url(${p.src})`,filter:"blur(2px) brightness(0.8) saturate(0.9)"}}),e("div",{className:"absolute inset-0 bg-gradient-to-b from-blue-950/50 via-blue-900/40 to-blue-950/60"}),e(v,{className:"absolute left-[8%] top-[14%] text-yellow-300 drop-shadow-[0_0_8px_rgba(255,255,150,0.8)]",size:22}),e(v,{className:"absolute right-[10%] top-[10%] text-yellow-200 drop-shadow-[0_0_8px_rgba(255,255,150,0.8)]",size:16}),e(v,{className:"absolute left-[15%] bottom-[18%] text-white/80",size:14}),e(v,{className:"absolute right-[6%] bottom-[24%] text-yellow-300 drop-shadow-[0_0_8px_rgba(255,255,150,0.8)]",size:20}),e(v,{className:"absolute left-[45%] top-[8%] text-white/70",size:12}),e("div",{className:"relative z-10",style:{width:"min(98vw, calc(98vh * 1552 / 672), 1800px)"},children:t("div",{className:"relative aspect-[1552/672] w-full",children:[e(a,{src:g,alt:"",fill:!0,className:"object-contain",priority:!0,unoptimized:!0}),e("div",{className:"absolute left-1/2 top-0 z-20 max-w-[min(92%,720px,calc(100%-7rem))] -translate-x-1/2 -translate-y-1/2",children:e("div",{className:"relative flex h-[clamp(52px,7vw,72px)] min-w-[240px] max-w-full items-center justify-center px-6 pt-0.5 drop-shadow-xl sm:px-15",style:{borderStyle:"solid",borderColor:"transparent",borderWidth:0,borderImageSource:`url(${u.src})`,borderImageSlice:"10 85 fill",borderImageWidth:"0 calc(clamp(52px, 7vw, 72px) / 2)",borderImageRepeat:"stretch"},children:e("span",{className:"relative z-10 whitespace-nowrap text-center text-sm font-extrabold uppercase tracking-[0.12em] text-white drop-shadow sm:text-base sm:tracking-[0.15em]",children:S})})}),e("button",{onClick:()=>{j?j():z&&(window.location.href=z)},className:"absolute right-[7%] top-[-2%] z-30 cursor-pointer transition-transform hover:scale-110 active:scale-95","aria-label":"Close",children:e(a,{src:b,alt:"Close",width:56,height:56,unoptimized:!0})}),t("div",{className:"absolute inset-0 z-10 overflow-hidden px-[9%] pt-[4%] pb-[calc(7%+1.75rem)]",children:[t("div",{className:"flex h-full min-h-0 items-stretch gap-4",children:[t("div",{className:"mx-auto flex h-full w-full max-w-[560px] min-h-0 flex-[0_0_46%] flex-col gap-1",children:[e("h1",{className:"shrink-0 text-center text-2xl font-black uppercase tracking-wide text-white sm:text-3xl md:text-4xl lg:text-5xl 2xl:text-5xl",style:{fontWeight:900,margin:"0.1em 0",textShadow:["0 1px 0 #cfe3ff","0 2px 0 #a8c8ee","0 3px 0 #6f9cd4","0 4px 0 #4a7cb8","0 5px 0 #2f5e9c","0 6px 0 #1a4480","0 8px 12px rgba(0,0,0,0.45)","0 0 22px rgba(120,180,255,0.55)"].join(", ")},children:i.name}),W?e("div",{className:"flex w-full min-w-0 shrink-0 flex-col items-center gap-1 px-1",children:e("span",{className:"rounded-full bg-cyan-400/30 px-3 py-0.5 text-[11px] font-black uppercase tracking-wider text-cyan-100 ring-1 ring-cyan-300/60 shadow-sm backdrop-blur-xs",children:W})}):null,e("p",{className:"mt-0.5 hidden shrink-0 text-center text-sm font-bold text-[#21cffb] md:text-base 2xl:block 2xl:text-lg",children:"Đánh giá năng lực • Xác định lộ trình • Bứt phá tương lai"}),e("p",{className:"mx-auto mt-0.5 hidden max-w-2xl shrink-0 text-center text-xs font-medium text-cyan-50/90 drop-shadow-sm md:text-sm 2xl:block",children:"Bài thi giúp bạn biết chính xác trình độ hiện tại và được Ocean Edu tư vấn lộ trình học tập phù hợp nhất."}),t("div",{className:"mt-1.5 hidden shrink-0 items-center justify-center gap-2 2xl:flex",children:[e("span",{className:"h-px w-10 bg-white"}),e(v,{className:"text-white",size:12}),e("span",{className:"text-xs font-extrabold uppercase tracking-[0.3em] text-white md:text-sm",children:"Bài thi bao gồm"}),e(v,{className:"text-white",size:12}),e("span",{className:"h-px w-10 bg-white"})]}),t("div",{className:"mt-1.5 grid shrink-0 grid-cols-3 gap-2",children:[e(y,{icon:e(r,{className:"h-5 w-5"}),value:I,label:"Phần thi"}),e(y,{icon:e(l,{className:"h-5 w-5"}),value:B,label:"Phút"}),e(y,{icon:e(s,{className:"h-5 w-5"}),value:L,label:"Tổng điểm"})]}),E.length>0?t("div",{className:"mt-2 flex min-h-0 flex-1 flex-col overflow-hidden",children:[q?t("div",{className:"mb-2 flex w-full shrink-0 flex-col items-center py-1",title:q,children:[e("span",{className:"text-[11px] font-black uppercase tracking-[0.25em] text-cyan-300/90",children:"ĐỀ THI"}),e("h2",{className:"w-full truncate text-center text-base font-black uppercase tracking-wide text-white drop-shadow-sm sm:text-lg md:text-xl",children:q})]}):null,t("div",{className:"mb-2 flex shrink-0 items-center justify-between px-1",children:[e("span",{className:"text-xs font-black uppercase tracking-[0.2em] text-cyan-100 sm:text-sm",children:"Cấu trúc bài thi"}),T>0&&t("span",{className:"text-xs font-bold text-white/90 sm:text-sm",children:["Điểm đạt:"," ",t("span",{className:"font-black text-yellow-300",children:[T,"/",L]})]})]}),e("div",{className:"cambridge-scrollbar min-h-0 flex-1 overflow-y-auto pr-1 pb-2",children:e("div",{className:"space-y-2.5 pb-8",children:x(E).map(n=>t("div",{className:"space-y-1.5",children:[t("div",{className:"flex items-center gap-2 px-1",children:[e("span",{className:"flex-none text-[11px] font-extrabold uppercase tracking-[0.14em] text-cyan-200",children:n.label}),e("span",{className:"h-px flex-1 bg-white/15"}),n.totalPoints>0&&t("span",{className:"flex-none text-[11px] font-bold text-white/75",children:[n.totalPoints," điểm"]})]}),n.parts.map((t,a)=>e(d,{part:t,showSkill:!1},t.id||`${n.key}-${a}`))]},n.key))})})]}):T>0&&t("div",{className:"mt-1.5 flex shrink-0 items-center gap-3 rounded-xl bg-[#0000001c] px-3 py-2.5",children:[e("span",{className:"flex h-9 w-9 flex-none items-center justify-center rounded-full bg-[#00000021] text-white",children:e(c,{className:"h-4 w-4"})}),e("span",{className:"text-sm font-bold text-white md:text-base",children:"Điểm tối thiểu cần đạt"}),t("span",{className:"ml-auto text-sm font-black text-yellow-300 md:text-lg",children:[T,"/",L]})]})]}),e("div",{className:"relative hidden flex-[0_0_42%] md:block",children:e("div",{className:"absolute left-0 top-[4%] z-20 max-w-[60%]",children:t("div",{className:"relative rounded-2xl bg-white px-3 py-2 text-center text-[11px] font-semibold text-sky-900 shadow-xl ring-2 ring-sky-200 md:text-xs",children:["Cùng mình khám phá trình độ của bạn nhé!",e("span",{className:"absolute -bottom-1.5 right-6 h-3 w-3 rotate-45 bg-white ring-2 ring-sky-200"})]})})})]}),e("div",{className:"pointer-events-none absolute inset-x-[9%] bottom-[6%] z-20 flex justify-center",children:e("div",{className:"pointer-events-auto",children:e(N,{onClick:f,isStarting:k,showCountdown:_,autoStartCountdown:C})})})]})]})}),t("button",{type:"button",onClick:()=>$(!0),"aria-label":"Câu hỏi thường gặp",className:"group fixed bottom-5 right-5 z-40 inline-flex cursor-pointer items-center gap-2 rounded-full bg-gradient-to-b from-cyan-300 via-sky-500 to-sky-700 px-4 py-3 text-sm font-bold text-white shadow-[0_6px_0_0_#0c4a6e,0_10px_22px_rgba(14,165,233,0.45)] ring-2 ring-cyan-200/50 transition-all duration-150 hover:-translate-y-0.5 hover:brightness-110 active:translate-y-1 active:shadow-[0_1px_0_0_#0c4a6e,0_3px_8px_rgba(14,165,233,0.3)]",children:[e(o,{className:"h-5 w-5",strokeWidth:2.5}),e("span",{className:"hidden sm:inline",style:{textShadow:"0 1px 0 rgba(12,74,110,0.5)"},children:"Câu hỏi thường gặp"})]}),P&&t("div",{className:"fixed inset-0 z-[60] flex items-center justify-center p-4",role:"dialog","aria-modal":"true","aria-label":"Câu hỏi thường gặp",children:[e("div",{className:"absolute inset-0 bg-blue-950/70 backdrop-blur-sm",onClick:()=>$(!1)}),t("div",{className:"relative z-10 flex max-h-[85vh] w-full max-w-2xl flex-col overflow-hidden rounded-3xl bg-gradient-to-br from-cyan-300/20 via-white/5 to-white/0 p-px shadow-[0_20px_60px_-15px_rgba(10,75,140,0.7)] backdrop-blur-xl",children:[e("div",{className:"pointer-events-none absolute -left-12 -top-12 h-40 w-40 rounded-full bg-cyan-400/30 blur-3xl"}),e("div",{className:"pointer-events-none absolute -right-12 -bottom-12 h-40 w-40 rounded-full bg-sky-500/25 blur-3xl"}),t("div",{className:"relative flex max-h-[85vh] flex-col overflow-hidden rounded-[calc(1.5rem-1px)] bg-gradient-to-b from-[#0e3d70]/95 via-[#0a4b8c]/95 to-[#0a3866]/95 ring-1 ring-cyan-300/20",children:[t("div",{className:"flex items-center gap-3 px-6 py-5",children:[e("div",{className:"flex h-12 w-12 flex-none items-center justify-center rounded-full bg-gradient-to-br from-cyan-300 to-sky-600 shadow-[0_6px_18px_-4px_rgba(34,211,238,0.6)] ring-4 ring-cyan-300/20",children:e(o,{className:"h-6 w-6 text-white",strokeWidth:2.5})}),t("div",{className:"flex-1",children:[e("h2",{className:"text-lg font-extrabold tracking-tight text-white drop-shadow-md",children:"Câu hỏi thường gặp"}),e("p",{className:"mt-0.5 text-xs font-medium text-cyan-100/70",children:"Những điều cần biết trước khi làm bài"})]}),e("button",{type:"button",onClick:()=>$(!1),"aria-label":"Đóng",className:"flex h-9 w-9 flex-none cursor-pointer items-center justify-center rounded-full bg-white/10 text-white/80 ring-1 ring-white/15 transition-all duration-150 hover:bg-white/20 hover:text-white",children:e(m,{className:"h-5 w-5"})})]}),e("div",{className:"mx-6 h-px bg-gradient-to-r from-transparent via-cyan-300/25 to-transparent"}),e("div",{className:"flex-1 overflow-y-auto px-4 py-4 sm:px-6",children:e("ul",{className:"space-y-2",children:w.map((n,a)=>{const i=H===a;return t("li",{className:"overflow-hidden rounded-2xl ring-1 transition-colors duration-200 "+(i?"bg-white/[0.08] ring-cyan-300/30":"bg-white/[0.04] ring-white/10 hover:bg-white/[0.06]"),children:[t("button",{type:"button",onClick:()=>O(i?null:a),className:"flex w-full cursor-pointer items-center gap-3 px-4 py-3 text-left","aria-expanded":i,children:[e("span",{className:"flex h-7 w-7 flex-none items-center justify-center rounded-full text-xs font-black transition-colors "+(i?"bg-gradient-to-br from-yellow-300 to-orange-500 text-white":"bg-white/10 text-cyan-100"),children:a+1}),e("span",{className:"flex-1 text-sm font-bold text-white",children:n.q}),e(h,{className:"h-5 w-5 flex-none text-cyan-200 transition-transform duration-200 "+(i?"rotate-180":"")})]}),e("div",{className:"grid transition-all duration-200 "+(i?"grid-rows-[1fr] opacity-100":"grid-rows-[0fr] opacity-0"),children:e("div",{className:"overflow-hidden",children:e("p",{className:"px-4 pb-4 pl-14 text-sm leading-relaxed text-cyan-50/90",children:n.a})})})]},a)})})}),e("div",{className:"border-t border-white/10 bg-white/[0.03] px-6 py-3 text-center text-xs text-cyan-100/60",children:"Cần hỗ trợ thêm? Liên hệ trung tâm Ocean Edu để được giải đáp."})]})]})]})]})}function y({icon:n,value:a,label:i}){return t("div",{className:"flex items-center justify-center gap-2 rounded-2xl bg-black/25 px-2 py-2 ring-1 ring-white/10 shadow-inner",children:[e("span",{className:"flex h-8 w-8 flex-none items-center justify-center rounded-full bg-cyan-400/20 text-cyan-200 ring-1 ring-cyan-300/30 md:h-9 md:w-9",children:n}),t("div",{className:"flex flex-col items-start leading-tight",children:[e("div",{className:"text-xl font-black text-white md:text-2xl",children:a}),e("div",{className:"text-[11px] font-extrabold text-cyan-100/95 md:text-xs",children:i})]})]})}function N({onClick:n,isStarting:l,showCountdown:s,autoStartCountdown:r}){return s?e("div",{className:"inline-flex h-14 w-48 items-center justify-center rounded-full bg-yellow-400 text-2xl font-black text-[#1a3a6e]",children:r}):t("button",{onClick:n,disabled:l,className:"group relative inline-flex cursor-pointer items-center gap-3 rounded-full bg-gradient-to-b from-[#ffd54a] via-[#ffb733] to-[#ff8a1f] py-2.5 pl-8 pr-10 shadow-[0_6px_0_0_#c46410,0_10px_18px_rgba(0,0,0,0.4)] ring-2 ring-orange-300/60 transition-all duration-150 hover:-translate-y-0.5 hover:brightness-110 hover:shadow-[0_8px_0_0_#c46410,0_14px_22px_rgba(0,0,0,0.45)] active:translate-y-1.5 active:shadow-[0_1px_0_0_#c46410,0_2px_6px_rgba(0,0,0,0.3)] disabled:cursor-not-allowed disabled:opacity-70",children:[l?e(i,{className:"h-7 w-7 animate-spin text-white"}):e(a,{src:f,alt:"",width:36,height:36,unoptimized:!0}),e("span",{className:"text-xl font-black text-white",style:{color:"#685030"},children:"Bắt đầu"})]})}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { StudentExamPartSummary } from '../../../../shared/types/student.types';
|
|
2
|
+
export type PartCategoryGroup = {
|
|
3
|
+
/** Uppercase key used for React keys / de-duping */
|
|
4
|
+
key: string;
|
|
5
|
+
/** Display label, e.g. "Reading & Writing" */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Sum of points across parts in this category */
|
|
8
|
+
totalPoints: number;
|
|
9
|
+
parts: StudentExamPartSummary[];
|
|
10
|
+
};
|
|
11
|
+
/** Groups parts by their `category` (falling back to skill), preserving first-seen order. */
|
|
12
|
+
export declare function groupPartsByCategory(parts: StudentExamPartSummary[]): PartCategoryGroup[];
|
|
13
|
+
export declare function PartRow({ part, showSkill, }: {
|
|
14
|
+
part: StudentExamPartSummary;
|
|
15
|
+
index?: number;
|
|
16
|
+
/** Hide the inline skill label when the parent already shows a category header. */
|
|
17
|
+
showSkill?: boolean;
|
|
18
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import{BookOpen as n,Mic as a,Headphones as r,PenLine as s,MessageSquareText as o}from"lucide-react";const l={READING:{label:"Reading",Icon:n,iconWrap:"bg-emerald-400/20 text-emerald-200 ring-emerald-300/30"},WRITING:{label:"Writing",Icon:s,iconWrap:"bg-orange-400/20 text-orange-200 ring-orange-300/30"},LISTENING:{label:"Listening",Icon:r,iconWrap:"bg-sky-400/20 text-sky-200 ring-sky-300/30"},SPEAKING:{label:"Speaking",Icon:a,iconWrap:"bg-fuchsia-400/20 text-fuchsia-200 ring-fuchsia-300/30"}},i={label:"",Icon:o,iconWrap:"bg-white/15 text-white ring-white/20"};function c(e){const t=e?.trim();return t?t.replace(/_/g," ").toLowerCase().replace(/\band\b/g,"&").replace(/\s+/g," ").trim().replace(/\b\w/g,e=>e.toUpperCase()):"Khác"}export function groupPartsByCategory(e){const t=[],n=new Map;for(const a of e){const e=a.category||a.skill||"OTHER",r=e.toUpperCase();let s=n.get(r);s||(s={key:r,label:c(e),totalPoints:0,parts:[]},n.set(r,s),t.push(r)),s.parts.push(a),a.points>0&&(s.totalPoints+=a.points)}return t.map(e=>n.get(e))}export function PartRow({part:n,showSkill:a=!0}){const r=function(e){const t=(e.skill||"").toUpperCase();if(l[t])return l[t];const n=`${e.skill??""} ${e.category??""}`.toUpperCase();for(const e of Object.keys(l))if(n.includes(e))return l[e];return i}(n),{Icon:s}=r,o=r.label,c=n.questionCount>0?`${n.questionCount} câu`:"";return t("div",{className:"flex items-center gap-3.5 rounded-xl bg-white/[0.08] px-3.5 py-2 ring-1 ring-white/15 transition-colors hover:bg-white/[0.14]",children:[e("span",{className:`flex h-9 w-9 flex-none items-center justify-center rounded-full ring-1.5 ${r.iconWrap}`,children:e(s,{className:"h-5 w-5",strokeWidth:2.5})}),t("div",{className:"min-w-0 flex-1 truncate text-base leading-snug",children:[e("span",{className:"font-black text-white",children:n.name}),a&&o&&t("span",{className:"font-bold text-cyan-100/80",children:[" · ",o]}),c&&t("span",{className:"font-bold text-yellow-200/90",children:[" · ",c]})]}),n.points>0&&t("div",{className:"flex flex-none items-baseline gap-1 rounded-lg bg-black/20 px-2 py-0.5 ring-1 ring-yellow-400/20",children:[e("span",{className:"text-lg font-black text-yellow-300 md:text-xl",children:n.points}),e("span",{className:"text-xs font-black uppercase tracking-wider text-yellow-100",children:"ĐIỂM"})]})]})}
|