@tinyweb_dev/oe-exam-sdk 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/components/exams/take/ExamTakingPageContainer.js +1 -1
  2. package/dist/components/exams/take/components/speaking/renderers/SpeakingConversationRenderer.js +1 -1
  3. package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.js +1 -1
  4. package/dist/components/exams/take/components/speaking/renderers/SpeakingInfoExchangeRenderer.js +1 -1
  5. package/dist/components/exams/take/components/speaking/renderers/SpeakingReadDisplayedContentRenderer.js +1 -1
  6. package/dist/components/exams/take/hooks/useSpeakingRecorder.js +1 -1
  7. package/dist/components/themes/index.d.ts +1 -3
  8. package/dist/components/themes/index.js +1 -1
  9. package/dist/shared/lib/hooks/usePresignedFileUrl.d.ts +9 -1
  10. package/dist/shared/lib/hooks/usePresignedFileUrl.js +1 -1
  11. package/dist/shared/types/common.types.d.ts +0 -1
  12. package/dist/shared/types/common.types.js +1 -1
  13. package/package.json +2 -2
  14. package/dist/components/themes/spaceship/SpaceshipAudioPlayer.d.ts +0 -8
  15. package/dist/components/themes/spaceship/SpaceshipAudioPlayer.js +0 -1
  16. package/dist/components/themes/spaceship/SpaceshipLayout.d.ts +0 -2
  17. package/dist/components/themes/spaceship/SpaceshipLayout.js +0 -1
  18. package/dist/components/themes/spaceship/assets/images/X-sunset.png +0 -0
  19. package/dist/components/themes/spaceship/assets/images/X.webp +0 -0
  20. package/dist/components/themes/spaceship/assets/images/audio-bar.webp +0 -0
  21. package/dist/components/themes/spaceship/assets/images/background.webp +0 -0
  22. package/dist/components/themes/spaceship/assets/images/bg_sunset.png +0 -0
  23. package/dist/components/themes/spaceship/assets/images/big-blue-badge.png +0 -0
  24. package/dist/components/themes/spaceship/assets/images/big-blue-badge.webp +0 -0
  25. package/dist/components/themes/spaceship/assets/images/bingo.webp +0 -0
  26. package/dist/components/themes/spaceship/assets/images/blue-badge.png +0 -0
  27. package/dist/components/themes/spaceship/assets/images/blue-wrapper.webp +0 -0
  28. package/dist/components/themes/spaceship/assets/images/board_red.png +0 -0
  29. package/dist/components/themes/spaceship/assets/images/button_feedback_vi.png +0 -0
  30. package/dist/components/themes/spaceship/assets/images/circle-btn-right-sunset.png +0 -0
  31. package/dist/components/themes/spaceship/assets/images/circle-btn-right.png +0 -0
  32. package/dist/components/themes/spaceship/assets/images/circle-btn-sunset.png +0 -0
  33. package/dist/components/themes/spaceship/assets/images/circle-btn.webp +0 -0
  34. package/dist/components/themes/spaceship/assets/images/focus-vector.webp +0 -0
  35. package/dist/components/themes/spaceship/assets/images/head-phone_red.png +0 -0
  36. package/dist/components/themes/spaceship/assets/images/ic-mute-sunset.png +0 -0
  37. package/dist/components/themes/spaceship/assets/images/ic-mute.png +0 -0
  38. package/dist/components/themes/spaceship/assets/images/ic-play-sunset.png +0 -0
  39. package/dist/components/themes/spaceship/assets/images/ic-play-violet.webp +0 -0
  40. package/dist/components/themes/spaceship/assets/images/ic-play.webp +0 -0
  41. package/dist/components/themes/spaceship/assets/images/micro.png +0 -0
  42. package/dist/components/themes/spaceship/assets/images/next-sunset.png +0 -0
  43. package/dist/components/themes/spaceship/assets/images/next.webp +0 -0
  44. package/dist/components/themes/spaceship/assets/images/purple-circle.webp +0 -0
  45. package/dist/components/themes/spaceship/assets/images/question-badge-sunset.png +0 -0
  46. package/dist/components/themes/spaceship/assets/images/question-badge.webp +0 -0
  47. package/dist/components/themes/spaceship/assets/images/red-badge.webp +0 -0
  48. package/dist/components/themes/spaceship/assets/images/red-wrapper.webp +0 -0
  49. package/dist/components/themes/spaceship/assets/images/sound_red.png +0 -0
  50. package/dist/components/themes/spaceship/assets/images/student-avatar.png +0 -0
  51. package/dist/components/themes/spaceship/assets/images/teacher-play.webp +0 -0
  52. package/dist/components/themes/spaceship/assets/images/timer-badge.png +0 -0
  53. package/dist/components/themes/spaceship/assets/styles/SpaceshipLayout.module.css +0 -347
  54. package/dist/components/themes/spaceship/assets/styles/SpaceshipWaitingRoom.module.css +0 -395
  55. /package/dist/components/themes/{spaceship → summer-sky}/assets/images/big-blue-badge-sunset.png +0 -0
  56. /package/dist/components/themes/{spaceship → summer-sky}/assets/images/blue-badge-sunset.png +0 -0
  57. /package/dist/components/themes/{spaceship → summer-sky}/assets/images/blue-wrapper-sunset.png +0 -0
  58. /package/dist/components/themes/{spaceship → summer-sky}/assets/images/next-small.webp +0 -0
  59. /package/dist/components/themes/{spaceship → summer-sky}/assets/images/red-badge-sunset.png +0 -0
  60. /package/dist/components/themes/{spaceship → summer-sky}/assets/images/red-wrapper-sunset.png +0 -0
  61. /package/dist/components/themes/{spaceship → summer-sky}/assets/images/robot-avatar.png +0 -0
  62. /package/dist/components/themes/{spaceship → summer-sky}/assets/images/teacher-play-sunset.png +0 -0
@@ -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:H,onSubmitted:j}){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=["SPACESHIP","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),j?.({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,He=re[$e];if(!He)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:He,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?He.questions.length-1:0,skipTeacherVideo:z.playedIntroParts.has($e)||he!==H,onTeacherIntroPlayed:()=>be($e)},`${He.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:He?.name||(He?.partNo?`PART ${He.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"===He?.questionType||"SPONTANEOUS_QA"===He?.questionType||"SPEAKING_CUE_CARD"===He?.questionType||"READ_DISPLAYED_CONTENT"===He?.questionType),a=Ve[ne],o=r&&a?.partIndex===$e?a.indexInPart:void 0;return t(n,{...s,children:[e(i,{partName:He?.name||(He?.partNo?`PART ${He.partNo}`:void 0),children:e(q,{part:He,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?He?.questions.length-1:0,skipTeacherVideo:z.playedIntroParts.has($e)||he!==H,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 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 +1 @@
1
- "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as a}from"react";import s from"next/image";import{Pause as n,Play as r}from"lucide-react";import{ResolvedImage as i}from"../../../../../../components/common/ResolvedImage";import{useSpeakingRendererSetup as l}from"../../../hooks/useSpeakingRendererSetup";import{useSpeakingConversationAudio as o}from"../../../hooks/useSpeakingConversationAudio";import{getSpeakingLayout as c}from"../../../../../../components/themes";import d from"../../../../../../components/themes/spaceship/assets/styles/SpaceshipLayout.module.css";import p from"../../../../../../components/themes/spaceship/assets/images/big-blue-badge-sunset.png";import m from"../../../../../../components/themes/spaceship/assets/images/teacher-play-sunset.png";import h from"../../../../../../components/themes/spaceship/assets/images/question-badge-sunset.png";import u from"../../../../../../components/themes/spaceship/assets/images/red-badge-sunset.png";import x from"../../../../../../components/themes/spaceship/assets/images/blue-badge-sunset.png";import g from"../../../../../../components/themes/spaceship/assets/images/red-wrapper-sunset.png";import f from"../../../../../../components/themes/spaceship/assets/images/blue-wrapper-sunset.png";import N from"../../../../../../components/themes/spaceship/assets/images/robot-avatar.png";import v from"../../../../../../components/themes/spaceship/assets/images/student-avatar.png";import y from"../../../../../../components/themes/spaceship/assets/images/next-small.webp";function b(e){if(!isFinite(e)||e<0)return"0:00";return`${Math.floor(e/60)}:${Math.floor(e%60).toString().padStart(2,"0")}`}function w({phase:a,isPlaying:i,togglePlayPause:l,partNumber:o,partnerName:c,currentTime:h,duration:u}){const x="playing-partner"===a?c||"Bạn thi":`PART ${o}`,g=u>0?h/u*100:0;return e("div",{className:d.examAudioContainer,children:t("div",{className:d.bigBlueBadge,children:[e(s,{src:p,alt:"Audio Badge",className:d.bigBlueBadgeBg,priority:!0}),e("div",{className:d.audioBarContent,children:t("div",{className:d.audioBarInner,children:[e("span",{className:d.partLabel,children:x}),t("div",{className:d.teacherAvatarContainer,onClick:l,title:i?"Tạm dừng":"Phát",children:[e("img",{src:m.src,alt:"Speaker",className:d.teacherPlayIcon}),e("div",{className:"absolute inset-0 flex items-center justify-center",children:i?e(n,{className:"h-5 w-5 text-white drop-shadow-md",fill:"currentColor"}):e(r,{className:"h-5 w-5 text-white drop-shadow-md ml-0.5",fill:"currentColor"})})]}),t("div",{className:d.audioControlsWrapper,children:[t("span",{className:d.audioTime,children:["idle"===a&&"0:00 / 0:00",i&&`${b(h)} / ${b(u)}`,"ready"===a&&`${b(u)} / ${b(u)}`]}),e("div",{className:d.sliderTrack,children:e("div",{className:d.sliderFill,style:{width:`${g}%`,transition:"width 0.25s linear"}})})]})]})})]})})}function P({text:n}){const[r,i]=a(!0);return n?e("div",{className:"flex flex-col items-center w-full",style:{maxWidth:"882px"},children:t("div",r?{className:"relative flex flex-col justify-center items-center",style:{width:"882px",maxWidth:"90%",paddingLeft:"77px",paddingRight:"77px",paddingTop:"26px",paddingBottom:"26px",backgroundColor:"rgba(232, 136, 154, 0.15)",borderRadius:"20px"},children:[t("div",{className:"absolute cursor-pointer",style:{top:"-19px"},onClick:()=>i(!1),children:[e(s,{src:h,alt:"",style:{width:"169px",height:"38px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center select-none",children:e("span",{className:"font-normal text-center leading-5 text-white",style:{fontSize:"18px"},children:"Ấn câu hỏi"})})]}),e("p",{className:"text-black font-bold leading-[26px] text-center m-0",style:{fontSize:"18px",fontFamily:'"Open Sans", sans-serif'},children:n})]}:{className:"relative cursor-pointer",onClick:()=>i(!0),children:[e(s,{src:h,alt:"",style:{width:"169px",height:"38px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center select-none",children:e("span",{className:"font-normal text-center leading-5 text-white",style:{fontSize:"18px"},children:"Hiện câu hỏi"})})]})}):null}function S({images:a}){if(!a||0===a.length)return null;const s=1===a.length,n=s?"grid-cols-1":2===a.length||4===a.length?"grid-cols-2":"grid-cols-3";return e("div",{className:`grid ${n} gap-4 w-full`,style:{maxWidth:s?"650px":"800px",margin:"0 auto"},children:a.map(a=>t("div",{className:"flex flex-col items-center gap-2",children:[e("div",{className:`relative w-full ${s?"":"aspect-square"} flex justify-center items-center rounded-xl overflow-hidden border-2 border-white/40 shadow-md bg-white/20`,children:e(i,{src:a.url,alt:a.label||"Image",className:"object-contain pointer-events-none "+(s?"max-h-[350px] w-auto":"w-full h-full p-1"),draggable:!1})}),a.label&&e("span",{className:"text-center font-bold",style:{fontSize:"14px",color:"#333"},children:a.label})]},a.id))})}function C({partnerName:a,partnerAvatarUrl:n,studentName:r,activeCharacter:l,isPartnerQuestion:o}){const c="partner"===l,d="student"===l;return t("div",{className:"flex justify-between select-none",style:{width:"990px",maxWidth:"95%",paddingBottom:"10px",paddingLeft:"20px",paddingRight:"20px"},children:[t("div",{className:"relative select-none",style:{opacity:c?1:.55},children:[t("div",{className:"relative flex",children:[e(s,{src:u,alt:"",style:{height:"57px",width:"258px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center",style:{paddingTop:"12px"},children:e("p",{className:"m-0 truncate select-none text-white font-normal text-center leading-5",style:{fontSize:"18px",paddingLeft:"60px",paddingRight:"60px"},children:a||"Bạn thi"})})]}),t("div",{className:"absolute",style:{top:"7px",right:"-58px"},children:[e(s,{src:g,alt:"",className:"relative",style:{width:"115px",height:"84px",zIndex:0}}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:t("div",{className:"relative",style:{width:"68px",height:"68px"},children:[n?e(i,{src:n,alt:a||"Partner",className:"object-cover rounded-full select-none",style:{width:"68px",height:"68px"},draggable:!1}):e(s,{src:N,alt:a||"Partner",width:68,height:68,className:"object-cover rounded-full select-none",draggable:!1}),c&&e("div",{className:"absolute inset-0 rounded-full border-4 border-yellow-400 shadow-[0_0_12px_4px_rgba(250,204,21,0.6)]"})]})})]})]}),t("div",{className:"relative select-none",style:{opacity:d||!o?1:.55},children:[t("div",{className:"relative flex",children:[e(s,{src:x,alt:"",style:{height:"57px",width:"258px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center",style:{paddingTop:"12px"},children:e("p",{className:"m-0 truncate select-none text-white font-normal text-center leading-5",style:{fontSize:"18px",paddingLeft:"60px",paddingRight:"60px"},children:r||"Bạn"})})]}),t("div",{className:"absolute",style:{top:"7px",left:"-58px"},children:[e(s,{src:f,alt:"",className:"relative",style:{width:"115px",height:"84px",zIndex:0}}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:t("div",{className:"relative",style:{width:"68px",height:"68px"},children:[e(s,{src:v,alt:r||"Bạn",width:68,height:68,className:"object-cover rounded-full select-none",draggable:!1}),d&&e("div",{className:"absolute inset-0 rounded-full border-4 border-sky-400 shadow-[0_0_12px_4px_rgba(56,189,248,0.6)]"})]})})]})]})]})}function A({audioReady:a,onNext:n}){return a?e("div",{className:"flex flex-col items-center text-center",style:{maxWidth:"291px",marginTop:"-10px",marginBottom:"10px"},children:t("div",{className:"flex items-center gap-1",children:[e("p",{className:"m-0",style:{color:"#333",fontSize:"13px"},children:"Ấn nút"}),e("div",{className:"cursor-pointer",onClick:n,children:e(s,{src:y,alt:"next",width:30,height:30})}),e("p",{className:"m-0",style:{color:"#333",fontSize:"13px"},children:"để tiếp tục."})]})}):null}export function SpeakingConversationRenderer(s){const[n,r]=a(!1),i=l({...s,maxDurationMs:3e4,hasMic:!0}),d=c("SPACESHIP"),p=i.currentQuestion?.content,m=i.currentQuestion?.questionGroup?.payload,h="PARTNER"===p?.responder,u=o({interlocutorAudioUrl:p?.interlocutorAudioUrl,partnerAudioUrl:p?.partnerAudioUrl,onSequenceComplete:()=>r(!0)});if(!i.currentQuestion||!p)return null;const x="playing-interlocutor"===u.phase?"interlocutor":"playing-partner"===u.phase||h?"partner":n?"student":"none",g=()=>{r(!1),i.handleNext()};return e(d,{onExit:s.onExit,partName:s.part.name||`Part ${s.part.partNo}`,instruction:s.part.instructions||"SPEAKING CONVERSATION",audioUrl:"",questionNumber:i.nav.questionNumberInPart,onPrev:()=>{r(!1),i.handlePrev()},onNext:g,showPrev:i.nav.showPrev,showNext:i.nav.showNext,canGoPrev:i.nav.canGoPrev,canGoNext:i.nav.canGoNext,onAudioPlayingChange:i.onAudioPlayingChange,recorder:s.isReviewMode||h?null:i.recorder,showExistingBadge:!h&&i.showExistingBadge,teacherVideoUrl:s.teacherVideoUrl,onTeacherVideoEnded:s.onTeacherIntroPlayed,skipTeacherVideo:s.skipTeacherVideo,hideAudioBar:!0,hideFooterTitle:h,children:t("div",{className:"w-full h-full flex flex-col items-center relative",style:{paddingBottom:h?"0":"50px"},children:[e(w,{phase:u.phase,isPlaying:u.isPlaying,togglePlayPause:u.togglePlayPause,partNumber:i.nav.currentPartNo,partnerName:m?.partnerName,currentTime:u.currentTime,duration:u.duration}),e(P,{text:p.questionText}),m?.images&&m.images.length>0&&e("div",{className:"mt-4 w-full flex justify-center",children:e(S,{images:m.images})}),e("div",{className:"flex-1"}),h&&e(A,{audioReady:n,onNext:g}),e(C,{partnerName:m?.partnerName,partnerAvatarUrl:m?.partnerAvatarUrl,activeCharacter:x,isPartnerQuestion:h})]},i.currentQuestion.id)})}
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as s}from"react";import a from"next/image";import{Pause as r,Play as n}from"lucide-react";import{ResolvedImage as i}from"../../../../../../components/common/ResolvedImage";import{useSpeakingRendererSetup as l}from"../../../hooks/useSpeakingRendererSetup";import{useSpeakingConversationAudio as o}from"../../../hooks/useSpeakingConversationAudio";import{getSpeakingLayout as c}from"../../../../../../components/themes";import d from"../../../../../../components/themes/summer-sky/assets/styles/SummerSkyLayout.module.css";import m from"../../../../../../components/themes/summer-sky/assets/images/big-blue-badge-sunset.png";import p from"../../../../../../components/themes/summer-sky/assets/images/teacher-play-sunset.png";import u from"../../../../../../components/themes/summer-sky/assets/images/question-badge-sunset.png";import h from"../../../../../../components/themes/summer-sky/assets/images/red-badge-sunset.png";import x from"../../../../../../components/themes/summer-sky/assets/images/blue-badge-sunset.png";import g from"../../../../../../components/themes/summer-sky/assets/images/red-wrapper-sunset.png";import f from"../../../../../../components/themes/summer-sky/assets/images/blue-wrapper-sunset.png";import N from"../../../../../../components/themes/summer-sky/assets/images/robot-avatar.png";import y from"../../../../../../components/themes/summer-sky/assets/images/student-avatar.png";import v from"../../../../../../components/themes/summer-sky/assets/images/next-small.webp";function b(e){if(!isFinite(e)||e<0)return"0:00";return`${Math.floor(e/60)}:${Math.floor(e%60).toString().padStart(2,"0")}`}function w({phase:s,isPlaying:i,togglePlayPause:l,partNumber:o,partnerName:c,currentTime:u,duration:h}){const x="playing-partner"===s?c||"Bạn thi":`PART ${o}`,g=h>0?u/h*100:0;return e("div",{className:d.examAudioContainer,children:t("div",{className:d.bigBlueBadge,children:[e(a,{src:m,alt:"Audio Badge",className:d.bigBlueBadgeBg,priority:!0}),e("div",{className:d.audioBarContent,children:t("div",{className:d.audioBarInner,children:[e("span",{className:d.partLabel,children:x}),t("div",{className:d.teacherAvatarContainer,onClick:l,title:i?"Tạm dừng":"Phát",children:[e("img",{src:p.src,alt:"Speaker",className:d.teacherPlayIcon}),e("div",{className:"absolute inset-0 flex items-center justify-center",children:i?e(r,{className:"h-5 w-5 text-white drop-shadow-md",fill:"currentColor"}):e(n,{className:"h-5 w-5 text-white drop-shadow-md ml-0.5",fill:"currentColor"})})]}),t("div",{className:d.audioControlsWrapper,children:[t("span",{className:d.audioTime,children:["idle"===s&&"0:00 / 0:00",i&&`${b(u)} / ${b(h)}`,"ready"===s&&`${b(h)} / ${b(h)}`]}),e("div",{className:d.sliderTrack,children:e("div",{className:d.sliderFill,style:{width:`${g}%`,transition:"width 0.25s linear"}})})]})]})})]})})}function P({text:r}){const[n,i]=s(!0);return r?e("div",{className:"flex flex-col items-center w-full",style:{maxWidth:"882px"},children:t("div",n?{className:"relative flex flex-col justify-center items-center",style:{width:"882px",maxWidth:"90%",paddingLeft:"77px",paddingRight:"77px",paddingTop:"26px",paddingBottom:"26px",backgroundColor:"rgba(232, 136, 154, 0.15)",borderRadius:"20px"},children:[t("div",{className:"absolute cursor-pointer",style:{top:"-19px"},onClick:()=>i(!1),children:[e(a,{src:u,alt:"",style:{width:"169px",height:"38px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center select-none",children:e("span",{className:"font-normal text-center leading-5 text-white",style:{fontSize:"18px"},children:"Ấn câu hỏi"})})]}),e("p",{className:"text-black font-bold leading-[26px] text-center m-0",style:{fontSize:"18px",fontFamily:'"Open Sans", sans-serif'},children:r})]}:{className:"relative cursor-pointer",onClick:()=>i(!0),children:[e(a,{src:u,alt:"",style:{width:"169px",height:"38px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center select-none",children:e("span",{className:"font-normal text-center leading-5 text-white",style:{fontSize:"18px"},children:"Hiện câu hỏi"})})]})}):null}function k({images:s}){if(!s||0===s.length)return null;const a=1===s.length,r=a?"grid-cols-1":2===s.length||4===s.length?"grid-cols-2":"grid-cols-3";return e("div",{className:`grid ${r} gap-4 w-full`,style:{maxWidth:a?"650px":"800px",margin:"0 auto"},children:s.map(s=>t("div",{className:"flex flex-col items-center gap-2",children:[e("div",{className:`relative w-full ${a?"":"aspect-square"} flex justify-center items-center rounded-xl overflow-hidden border-2 border-white/40 shadow-md bg-white/20`,children:e(i,{src:s.url,alt:s.label||"Image",className:"object-contain pointer-events-none "+(a?"max-h-[350px] w-auto":"w-full h-full p-1"),draggable:!1})}),s.label&&e("span",{className:"text-center font-bold",style:{fontSize:"14px",color:"#333"},children:s.label})]},s.id))})}function S({partnerName:s,partnerAvatarUrl:r,studentName:n,activeCharacter:l,isPartnerQuestion:o}){const c="partner"===l,d="student"===l;return t("div",{className:"flex justify-between select-none",style:{width:"990px",maxWidth:"95%",paddingBottom:"10px",paddingLeft:"20px",paddingRight:"20px"},children:[t("div",{className:"relative select-none",style:{opacity:c?1:.55},children:[t("div",{className:"relative flex",children:[e(a,{src:h,alt:"",style:{height:"57px",width:"258px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center",style:{paddingTop:"12px"},children:e("p",{className:"m-0 truncate select-none text-white font-normal text-center leading-5",style:{fontSize:"18px",paddingLeft:"60px",paddingRight:"60px"},children:s||"Bạn thi"})})]}),t("div",{className:"absolute",style:{top:"7px",right:"-58px"},children:[e(a,{src:g,alt:"",className:"relative",style:{width:"115px",height:"84px",zIndex:0}}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:t("div",{className:"relative",style:{width:"68px",height:"68px"},children:[r?e(i,{src:r,alt:s||"Partner",className:"object-cover rounded-full select-none",style:{width:"68px",height:"68px"},draggable:!1}):e(a,{src:N,alt:s||"Partner",width:68,height:68,className:"object-cover rounded-full select-none",draggable:!1}),c&&e("div",{className:"absolute inset-0 rounded-full border-4 border-yellow-400 shadow-[0_0_12px_4px_rgba(250,204,21,0.6)]"})]})})]})]}),t("div",{className:"relative select-none",style:{opacity:d||!o?1:.55},children:[t("div",{className:"relative flex",children:[e(a,{src:x,alt:"",style:{height:"57px",width:"258px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center",style:{paddingTop:"12px"},children:e("p",{className:"m-0 truncate select-none text-white font-normal text-center leading-5",style:{fontSize:"18px",paddingLeft:"60px",paddingRight:"60px"},children:n||"Bạn"})})]}),t("div",{className:"absolute",style:{top:"7px",left:"-58px"},children:[e(a,{src:f,alt:"",className:"relative",style:{width:"115px",height:"84px",zIndex:0}}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:t("div",{className:"relative",style:{width:"68px",height:"68px"},children:[e(a,{src:y,alt:n||"Bạn",width:68,height:68,className:"object-cover rounded-full select-none",draggable:!1}),d&&e("div",{className:"absolute inset-0 rounded-full border-4 border-sky-400 shadow-[0_0_12px_4px_rgba(56,189,248,0.6)]"})]})})]})]})]})}function B({audioReady:s,onNext:r}){return s?e("div",{className:"flex flex-col items-center text-center",style:{maxWidth:"291px",marginTop:"-10px",marginBottom:"10px"},children:t("div",{className:"flex items-center gap-1",children:[e("p",{className:"m-0",style:{color:"#333",fontSize:"13px"},children:"Ấn nút"}),e("div",{className:"cursor-pointer",onClick:r,children:e(a,{src:v,alt:"next",width:30,height:30})}),e("p",{className:"m-0",style:{color:"#333",fontSize:"13px"},children:"để tiếp tục."})]})}):null}export function SpeakingConversationRenderer(a){const[r,n]=s(!1),i=l({...a,maxDurationMs:3e4,hasMic:!0}),d=c("SUMMER_SKY"),m=i.currentQuestion?.content,p=i.currentQuestion?.questionGroup?.payload,u="PARTNER"===m?.responder,h=o({interlocutorAudioUrl:m?.interlocutorAudioUrl,partnerAudioUrl:m?.partnerAudioUrl,onSequenceComplete:()=>n(!0)});if(!i.currentQuestion||!m)return null;const x="playing-interlocutor"===h.phase?"interlocutor":"playing-partner"===h.phase||u?"partner":r?"student":"none",g=()=>{n(!1),i.handleNext()};return e(d,{onExit:a.onExit,partName:a.part.name||`Part ${a.part.partNo}`,instruction:a.part.instructions||"SPEAKING CONVERSATION",audioUrl:"",questionNumber:i.nav.questionNumberInPart,onPrev:()=>{n(!1),i.handlePrev()},onNext:g,showPrev:i.nav.showPrev,showNext:i.nav.showNext,canGoPrev:i.nav.canGoPrev,canGoNext:i.nav.canGoNext,onAudioPlayingChange:i.onAudioPlayingChange,recorder:a.isReviewMode||u?null:i.recorder,showExistingBadge:!u&&i.showExistingBadge,teacherVideoUrl:a.teacherVideoUrl,onTeacherVideoEnded:a.onTeacherIntroPlayed,skipTeacherVideo:a.skipTeacherVideo,hideAudioBar:!0,hideFooterTitle:u,children:t("div",{className:"w-full h-full flex flex-col items-center relative",style:{paddingBottom:u?"0":"50px"},children:[e(w,{phase:h.phase,isPlaying:h.isPlaying,togglePlayPause:h.togglePlayPause,partNumber:i.nav.currentPartNo,partnerName:p?.partnerName,currentTime:h.currentTime,duration:h.duration}),e(P,{text:m.questionText}),p?.images&&p.images.length>0&&e("div",{className:"mt-4 w-full flex justify-center",children:e(k,{images:p.images})}),e("div",{className:"flex-1"}),u&&e(B,{audioReady:r,onNext:g}),e(S,{partnerName:p?.partnerName,partnerAvatarUrl:p?.partnerAvatarUrl,activeCharacter:x,isPartnerQuestion:u})]},i.currentQuestion.id)})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as i,useEffect as s,useRef as n,useCallback as a,useMemo as r}from"react";import l from"next/image";import{usePresignedFileUrl as o}from"../../../../../../shared/lib/hooks";import{useSpeakingRendererSetup as c}from"../../../hooks/useSpeakingRendererSetup";import{getSpeakingLayout as d}from"../../../../../../components/themes";import p from"../../../../../../components/themes/spaceship/assets/images/question-badge-sunset.png";import h from"../../../../../../components/themes/spaceship/assets/images/red-badge-sunset.png";import m from"../../../../../../components/themes/spaceship/assets/images/blue-badge-sunset.png";import u from"../../../../../../components/themes/spaceship/assets/images/red-wrapper-sunset.png";import x from"../../../../../../components/themes/spaceship/assets/images/blue-wrapper-sunset.png";import f from"../../../../../../components/themes/spaceship/assets/images/robot-avatar.png";import g from"../../../../../../components/themes/spaceship/assets/images/student-avatar.png";import y from"../../../../../../components/themes/spaceship/assets/images/ic-play-sunset.png";import v from"../../../../../../components/themes/spaceship/assets/images/ic-play-violet.webp";import w from"../../../../../../components/themes/spaceship/assets/images/next-small.webp";function N({total:t,currentIndex:i,answeredIds:s,questionIds:n,virtualIndices:a}){return e("div",{className:"flex items-center gap-1.5 flex-wrap justify-center",children:Array.from({length:t},(t,r)=>{const l=r===i,o=s.has(n[r]),c=a.has(r);return e("div",{className:"h-2.5 w-2.5 rounded-full border-2 transition-all "+(l?"scale-125 border-yellow-300 bg-yellow-400 shadow-lg":o?"border-green-400 bg-green-400":c?"border-white/30 bg-white/10":"border-white/50 bg-white/20"),title:c?"Câu HS ảo":`Câu ${r+1}`},r)})})}export function SpeakingGNInterviewRenderer(b){const[S,R]=i(!0),[j,I]=i(!1),P=n(null),T=b.part.groupPayload,k=T?.virtualStudentName||"Học sinh AI",W=r(()=>{const e=new Set;return b.part.questions.forEach((t,i)=>{const s=t.content;"VIRTUAL"===s?.targetCandidate&&e.add(i)}),e},[b.part.questions]),q=c({...b,maxDurationMs:6e4,hasMic:!0}),A=d("SPACESHIP"),z=q.currentQuestion?.content,C="VIRTUAL"===z?.targetCandidate,U=!C,{previewUrl:E}=o(z?.virtualAnswer?.audioUrl??""),{previewUrl:B}=o(z?.imageUrl??""),L=!!z?.imageUrl&&!!B;s(()=>{P.current&&(P.current.pause(),P.current.currentTime=0),I(!1)},[q.currentQuestion?.id]);const V=a(()=>{if(E){if(j&&P.current)return P.current.pause(),void I(!1);P.current?P.current.src=E:(P.current=new Audio(E),P.current.onended=()=>I(!1),P.current.onerror=()=>I(!1)),P.current.play(),I(!0)}},[E,j]);s(()=>()=>{P.current&&(P.current.pause(),P.current=null)},[]);const H=a(()=>{if(!C||!E)return;const e=setTimeout(()=>{V()},1e3);return()=>clearTimeout(e)},[C,E,V]);if(!q.currentQuestion||!z)return null;const F=new Set(b.part.questions.map(e=>e.id).filter(e=>!!b.answers[e])),Y=b.part.questions.map(e=>e.id),D=e(N,{total:b.part.questions.length,currentIndex:q.nav.currentIndex,answeredIds:F,questionIds:Y,virtualIndices:W});return t(A,{onExit:b.onExit,partName:b.part.name||`Part ${b.part.partNo}`,instruction:b.part.instructions||"LISTEN AND ANSWER",audioUrl:z.audioUrl??"",questionNumber:q.nav.questionNumberInPart,onPrev:q.handlePrev,onNext:q.handleNext,showPrev:q.nav.showPrev,showNext:q.nav.showNext,canGoPrev:q.nav.canGoPrev,canGoNext:q.nav.canGoNext,onAudioPlayingChange:q.onAudioPlayingChange,recorder:b.isReviewMode||C?null:q.recorder,showExistingBadge:U&&q.showExistingBadge,teacherVideoUrl:b.teacherVideoUrl,onTeacherVideoEnded:b.onTeacherIntroPlayed,skipTeacherVideo:b.skipTeacherVideo,headerRight:D,onAudioEnded:H,children:[t("div",{className:"w-full h-full flex flex-col items-center relative",children:[e("div",{className:"w-full flex-1",style:{minHeight:0},children:e("div",{className:"mx-auto",style:{width:"850px",maxWidth:"90%",height:L?"auto":"calc(100% - 100px)"},children:t("div",{className:`w-full ${L?"":"h-full"} flex flex-col items-center`,style:L?{}:{paddingTop:"30px"},children:[S&&z.questionText&&t("div",{className:"relative flex flex-col justify-center items-center",style:{width:"882px",maxWidth:"90%",maxHeight:"80%",paddingLeft:"77px",paddingRight:"77px",paddingTop:"26px",paddingBottom:"26px",backgroundColor:"rgba(232, 136, 154, 0.15)",borderRadius:"20px"},children:[t("div",{className:"absolute cursor-pointer",style:{top:"-19px"},onClick:()=>R(!1),children:[e(l,{src:p,alt:"",style:{width:"169px",height:"38px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center select-none",children:e("span",{className:"font-normal text-center leading-5 text-white",style:{fontSize:"18px"},children:"Ẩn câu hỏi"})})]}),e("div",{className:"max-w-full",children:e("div",{className:"text-black font-bold leading-[26px] text-center max-w-full",style:{fontSize:"18px",fontFamily:'"Open Sans", sans-serif'},children:e("p",{children:z.questionText})})})]}),!S&&t("div",{className:"cursor-pointer",onClick:()=>R(!0),children:[e(l,{src:p,alt:"",style:{width:"169px",height:"38px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center select-none",style:{position:"relative",top:"-30px"},children:e("span",{className:"font-normal text-center leading-5 text-white",style:{fontSize:"18px"},children:"Hiện câu hỏi"})})]}),L&&e("div",{className:"flex justify-center",style:{marginTop:"12px"},children:e("div",{className:"relative overflow-hidden",style:{maxWidth:"100%",borderRadius:"16px",border:"3px solid rgba(230, 99, 93, 0.3)",boxShadow:"0 4px 15px rgba(0,0,0,0.08)"},children:e("img",{src:B,alt:"Booklet",style:{width:"100%",height:"100%",objectFit:"cover"}})})})]})})}),t("div",{className:"flex justify-between select-none items-end",style:{width:"990px",maxWidth:"95%",paddingBottom:"40px",paddingLeft:"20px",paddingRight:"20px"},children:[t("div",{className:"relative select-none transition-opacity duration-300 "+(C?"opacity-100":"opacity-50 grayscale"),children:[e("div",{children:t("div",{className:"relative flex",children:[e(l,{src:h,alt:"",style:{height:"57px",width:"258px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center",style:{paddingTop:"12px"},children:e("div",{className:"text-white leading-5 font-normal text-center m-0 w-full select-none",children:e("p",{className:"m-0 truncate select-none",style:{fontSize:"18px",paddingLeft:"60px",paddingRight:"60px"},children:k})})})]})}),t("div",{className:"absolute",style:{top:"7px",right:"-58px"},children:[e(l,{src:u,alt:"",className:"relative",style:{width:"115px",height:"84px",zIndex:0}}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:t("div",{className:"relative",style:{width:"68px",height:"68px"},children:[e(l,{src:f,alt:k,width:68,height:68,className:"object-cover rounded-full select-none",style:{width:"68px",height:"68px"},draggable:!1}),e("div",{className:"flex items-center justify-center absolute w-full h-full top-0 rounded-full text-white cursor-pointer",onClick:C?V:void 0,children:e(l,{src:y,alt:"play",width:16,height:16,className:"opacity-80"})})]})})]}),j&&e("div",{className:"absolute pointer-events-none",style:{top:"0px",right:"-130px",width:"70px",height:"84px",display:"flex",alignItems:"center"},children:t("div",{className:"relative",style:{width:"70px",height:"70px"},children:[e("div",{style:{position:"absolute",left:"0px",top:"50%",transform:"translateY(-50%)",width:"20px",height:"34px",borderRight:"3px solid rgba(30, 64, 175, 0.95)",borderRadius:"0 50% 50% 0",animation:"soundWavePulse 1s ease-in-out infinite",animationDelay:"0s"}}),e("div",{style:{position:"absolute",left:"12px",top:"50%",transform:"translateY(-50%)",width:"28px",height:"50px",borderRight:"3px solid rgba(30, 64, 175, 0.7)",borderRadius:"0 50% 50% 0",animation:"soundWavePulse 1s ease-in-out infinite",animationDelay:"0.2s"}}),e("div",{style:{position:"absolute",left:"24px",top:"50%",transform:"translateY(-50%)",width:"36px",height:"66px",borderRight:"3px solid rgba(30, 64, 175, 0.45)",borderRadius:"0 50% 50% 0",animation:"soundWavePulse 1s ease-in-out infinite",animationDelay:"0.4s"}})]})})]}),j&&e("div",{className:"flex-1 flex justify-center items-center text-center",style:{paddingLeft:"40px",paddingRight:"40px",paddingBottom:"40px"},children:t("p",{className:"m-0 select-none",style:{fontSize:"16px",fontWeight:700,fontStyle:"italic",color:"#1a1a2e",lineHeight:"1.5",fontFamily:'"Open Sans", sans-serif'},children:["Người chơi khác đang trả lời.",e("br",{}),"Vui lòng nghe xong để tiếp tục."]})}),C&&!j&&t("div",{className:"flex-1 flex flex-col justify-center items-center text-center",style:{paddingLeft:"40px",paddingRight:"40px",paddingBottom:"40px"},children:[t("p",{className:"m-0 whitespace-nowrap",style:{color:"#1a1a2e",fontSize:"16px",fontWeight:700,fontStyle:"italic",fontFamily:'"Open Sans", sans-serif'},children:["Ấn biểu tượng"," ",e(l,{src:v,alt:"",width:20,height:20,className:"inline-block"})," ","trên avatar để nghe lại."]}),t("div",{className:"flex items-center",style:{gap:"4px"},children:[e("p",{className:"m-0",style:{color:"#1a1a2e",fontSize:"16px",fontWeight:700,fontStyle:"italic",fontFamily:'"Open Sans", sans-serif'},children:"Ấn nút"}),e(l,{src:w,alt:"next",width:34,height:34}),e("p",{className:"m-0",style:{color:"#1a1a2e",fontSize:"16px",fontWeight:700,fontStyle:"italic",fontFamily:'"Open Sans", sans-serif'},children:"để tiếp tục."})]})]}),t("div",{className:"relative select-none transition-opacity duration-300 "+(U?"opacity-100":"opacity-50 grayscale"),children:[e("div",{children:t("div",{className:"relative flex",children:[e(l,{src:m,alt:"",style:{height:"57px",width:"258px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center",style:{paddingTop:"12px"},children:e("div",{className:"text-white leading-5 font-normal text-center m-0 w-full select-none",children:e("p",{className:"m-0 truncate select-none",style:{fontSize:"18px",paddingLeft:"60px",paddingRight:"60px"},children:"Bạn"})})})]})}),t("div",{className:"absolute",style:{top:"7px",left:"-58px"},children:[e(l,{src:x,alt:"",className:"relative",style:{width:"115px",height:"84px",zIndex:0}}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:e("div",{className:"relative",style:{width:"68px",height:"68px"},children:e(l,{src:g,alt:"Bạn",width:68,height:68,className:"object-cover rounded-full select-none",style:{width:"68px",height:"68px"},draggable:!1})})})]})]})]})]}),e("style",{jsx:!0,children:"\n @keyframes soundWavePulse {\n 0% {\n opacity: 0.2;\n transform: translateY(-50%) scaleX(0.7);\n }\n 50% {\n opacity: 1;\n transform: translateY(-50%) scaleX(1);\n }\n 100% {\n opacity: 0.2;\n transform: translateY(-50%) scaleX(0.7);\n }\n }\n "})]})}
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as s,useEffect as i,useRef as n,useCallback as a,useMemo as r}from"react";import l from"next/image";import{usePresignedFileUrl as o}from"../../../../../../shared/lib/hooks";import{useSpeakingRendererSetup as c}from"../../../hooks/useSpeakingRendererSetup";import{getSpeakingLayout as d}from"../../../../../../components/themes";import p from"../../../../../../components/themes/summer-sky/assets/images/question-badge-sunset.png";import m from"../../../../../../components/themes/summer-sky/assets/images/red-badge-sunset.png";import h from"../../../../../../components/themes/summer-sky/assets/images/blue-badge-sunset.png";import u from"../../../../../../components/themes/summer-sky/assets/images/red-wrapper-sunset.png";import x from"../../../../../../components/themes/summer-sky/assets/images/blue-wrapper-sunset.png";import f from"../../../../../../components/themes/summer-sky/assets/images/robot-avatar.png";import g from"../../../../../../components/themes/summer-sky/assets/images/student-avatar.png";import y from"../../../../../../components/themes/summer-sky/assets/images/ic-play-sunset.png";import v from"../../../../../../components/themes/summer-sky/assets/images/ic-play-violet.webp";import w from"../../../../../../components/themes/summer-sky/assets/images/next-small.webp";function N({total:t,currentIndex:s,answeredIds:i,questionIds:n,virtualIndices:a}){return e("div",{className:"flex items-center gap-1.5 flex-wrap justify-center",children:Array.from({length:t},(t,r)=>{const l=r===s,o=i.has(n[r]),c=a.has(r);return e("div",{className:"h-2.5 w-2.5 rounded-full border-2 transition-all "+(l?"scale-125 border-yellow-300 bg-yellow-400 shadow-lg":o?"border-green-400 bg-green-400":c?"border-white/30 bg-white/10":"border-white/50 bg-white/20"),title:c?"Câu HS ảo":`Câu ${r+1}`},r)})})}export function SpeakingGNInterviewRenderer(b){const[S,k]=s(!0),[R,j]=s(!1),I=n(null),T=b.part.groupPayload,P=T?.virtualStudentName||"Học sinh AI",W=r(()=>{const e=new Set;return b.part.questions.forEach((t,s)=>{const i=t.content;"VIRTUAL"===i?.targetCandidate&&e.add(s)}),e},[b.part.questions]),q=c({...b,maxDurationMs:6e4,hasMic:!0}),U=d("SUMMER_SKY"),z=q.currentQuestion?.content,A="VIRTUAL"===z?.targetCandidate,C=!A,{previewUrl:E}=o(z?.virtualAnswer?.audioUrl??""),{previewUrl:B}=o(z?.imageUrl??""),L=!!z?.imageUrl&&!!B;i(()=>{I.current&&(I.current.pause(),I.current.currentTime=0),j(!1)},[q.currentQuestion?.id]);const V=a(()=>{if(E){if(R&&I.current)return I.current.pause(),void j(!1);I.current?I.current.src=E:(I.current=new Audio(E),I.current.onended=()=>j(!1),I.current.onerror=()=>j(!1)),I.current.play(),j(!0)}},[E,R]);i(()=>()=>{I.current&&(I.current.pause(),I.current=null)},[]);const Y=a(()=>{if(!A||!E)return;const e=setTimeout(()=>{V()},1e3);return()=>clearTimeout(e)},[A,E,V]);if(!q.currentQuestion||!z)return null;const F=new Set(b.part.questions.map(e=>e.id).filter(e=>!!b.answers[e])),H=b.part.questions.map(e=>e.id),D=e(N,{total:b.part.questions.length,currentIndex:q.nav.currentIndex,answeredIds:F,questionIds:H,virtualIndices:W});return t(U,{onExit:b.onExit,partName:b.part.name||`Part ${b.part.partNo}`,instruction:b.part.instructions||"LISTEN AND ANSWER",audioUrl:z.audioUrl??"",questionNumber:q.nav.questionNumberInPart,onPrev:q.handlePrev,onNext:q.handleNext,showPrev:q.nav.showPrev,showNext:q.nav.showNext,canGoPrev:q.nav.canGoPrev,canGoNext:q.nav.canGoNext,onAudioPlayingChange:q.onAudioPlayingChange,recorder:b.isReviewMode||A?null:q.recorder,showExistingBadge:C&&q.showExistingBadge,teacherVideoUrl:b.teacherVideoUrl,onTeacherVideoEnded:b.onTeacherIntroPlayed,skipTeacherVideo:b.skipTeacherVideo,headerRight:D,onAudioEnded:Y,children:[t("div",{className:"w-full h-full flex flex-col items-center relative",children:[e("div",{className:"w-full flex-1",style:{minHeight:0},children:e("div",{className:"mx-auto",style:{width:"850px",maxWidth:"90%",height:L?"auto":"calc(100% - 100px)"},children:t("div",{className:`w-full ${L?"":"h-full"} flex flex-col items-center`,style:L?{}:{paddingTop:"30px"},children:[S&&z.questionText&&t("div",{className:"relative flex flex-col justify-center items-center",style:{width:"882px",maxWidth:"90%",maxHeight:"80%",paddingLeft:"77px",paddingRight:"77px",paddingTop:"26px",paddingBottom:"26px",backgroundColor:"rgba(232, 136, 154, 0.15)",borderRadius:"20px"},children:[t("div",{className:"absolute cursor-pointer",style:{top:"-19px"},onClick:()=>k(!1),children:[e(l,{src:p,alt:"",style:{width:"169px",height:"38px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center select-none",children:e("span",{className:"font-normal text-center leading-5 text-white",style:{fontSize:"18px"},children:"Ẩn câu hỏi"})})]}),e("div",{className:"max-w-full",children:e("div",{className:"text-black font-bold leading-[26px] text-center max-w-full",style:{fontSize:"18px",fontFamily:'"Open Sans", sans-serif'},children:e("p",{children:z.questionText})})})]}),!S&&t("div",{className:"cursor-pointer",onClick:()=>k(!0),children:[e(l,{src:p,alt:"",style:{width:"169px",height:"38px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center select-none",style:{position:"relative",top:"-30px"},children:e("span",{className:"font-normal text-center leading-5 text-white",style:{fontSize:"18px"},children:"Hiện câu hỏi"})})]}),L&&e("div",{className:"flex justify-center",style:{marginTop:"12px"},children:e("div",{className:"relative overflow-hidden",style:{maxWidth:"100%",borderRadius:"16px",border:"3px solid rgba(230, 99, 93, 0.3)",boxShadow:"0 4px 15px rgba(0,0,0,0.08)"},children:e("img",{src:B,alt:"Booklet",style:{width:"100%",height:"100%",objectFit:"cover"}})})})]})})}),t("div",{className:"flex justify-between select-none items-end",style:{width:"990px",maxWidth:"95%",paddingBottom:"40px",paddingLeft:"20px",paddingRight:"20px"},children:[t("div",{className:"relative select-none transition-opacity duration-300 "+(A?"opacity-100":"opacity-50 grayscale"),children:[e("div",{children:t("div",{className:"relative flex",children:[e(l,{src:m,alt:"",style:{height:"57px",width:"258px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center",style:{paddingTop:"12px"},children:e("div",{className:"text-white leading-5 font-normal text-center m-0 w-full select-none",children:e("p",{className:"m-0 truncate select-none",style:{fontSize:"18px",paddingLeft:"60px",paddingRight:"60px"},children:P})})})]})}),t("div",{className:"absolute",style:{top:"7px",right:"-58px"},children:[e(l,{src:u,alt:"",className:"relative",style:{width:"115px",height:"84px",zIndex:0}}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:t("div",{className:"relative",style:{width:"68px",height:"68px"},children:[e(l,{src:f,alt:P,width:68,height:68,className:"object-cover rounded-full select-none",style:{width:"68px",height:"68px"},draggable:!1}),e("div",{className:"flex items-center justify-center absolute w-full h-full top-0 rounded-full text-white cursor-pointer",onClick:A?V:void 0,children:e(l,{src:y,alt:"play",width:16,height:16,className:"opacity-80"})})]})})]}),R&&e("div",{className:"absolute pointer-events-none",style:{top:"0px",right:"-130px",width:"70px",height:"84px",display:"flex",alignItems:"center"},children:t("div",{className:"relative",style:{width:"70px",height:"70px"},children:[e("div",{style:{position:"absolute",left:"0px",top:"50%",transform:"translateY(-50%)",width:"20px",height:"34px",borderRight:"3px solid rgba(30, 64, 175, 0.95)",borderRadius:"0 50% 50% 0",animation:"soundWavePulse 1s ease-in-out infinite",animationDelay:"0s"}}),e("div",{style:{position:"absolute",left:"12px",top:"50%",transform:"translateY(-50%)",width:"28px",height:"50px",borderRight:"3px solid rgba(30, 64, 175, 0.7)",borderRadius:"0 50% 50% 0",animation:"soundWavePulse 1s ease-in-out infinite",animationDelay:"0.2s"}}),e("div",{style:{position:"absolute",left:"24px",top:"50%",transform:"translateY(-50%)",width:"36px",height:"66px",borderRight:"3px solid rgba(30, 64, 175, 0.45)",borderRadius:"0 50% 50% 0",animation:"soundWavePulse 1s ease-in-out infinite",animationDelay:"0.4s"}})]})})]}),R&&e("div",{className:"flex-1 flex justify-center items-center text-center",style:{paddingLeft:"40px",paddingRight:"40px",paddingBottom:"40px"},children:t("p",{className:"m-0 select-none",style:{fontSize:"16px",fontWeight:700,fontStyle:"italic",color:"#1a1a2e",lineHeight:"1.5",fontFamily:'"Open Sans", sans-serif'},children:["Người chơi khác đang trả lời.",e("br",{}),"Vui lòng nghe xong để tiếp tục."]})}),A&&!R&&t("div",{className:"flex-1 flex flex-col justify-center items-center text-center",style:{paddingLeft:"40px",paddingRight:"40px",paddingBottom:"40px"},children:[t("p",{className:"m-0 whitespace-nowrap",style:{color:"#1a1a2e",fontSize:"16px",fontWeight:700,fontStyle:"italic",fontFamily:'"Open Sans", sans-serif'},children:["Ấn biểu tượng"," ",e(l,{src:v,alt:"",width:20,height:20,className:"inline-block"})," ","trên avatar để nghe lại."]}),t("div",{className:"flex items-center",style:{gap:"4px"},children:[e("p",{className:"m-0",style:{color:"#1a1a2e",fontSize:"16px",fontWeight:700,fontStyle:"italic",fontFamily:'"Open Sans", sans-serif'},children:"Ấn nút"}),e(l,{src:w,alt:"next",width:34,height:34}),e("p",{className:"m-0",style:{color:"#1a1a2e",fontSize:"16px",fontWeight:700,fontStyle:"italic",fontFamily:'"Open Sans", sans-serif'},children:"để tiếp tục."})]})]}),t("div",{className:"relative select-none transition-opacity duration-300 "+(C?"opacity-100":"opacity-50 grayscale"),children:[e("div",{children:t("div",{className:"relative flex",children:[e(l,{src:h,alt:"",style:{height:"57px",width:"258px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center",style:{paddingTop:"12px"},children:e("div",{className:"text-white leading-5 font-normal text-center m-0 w-full select-none",children:e("p",{className:"m-0 truncate select-none",style:{fontSize:"18px",paddingLeft:"60px",paddingRight:"60px"},children:"Bạn"})})})]})}),t("div",{className:"absolute",style:{top:"7px",left:"-58px"},children:[e(l,{src:x,alt:"",className:"relative",style:{width:"115px",height:"84px",zIndex:0}}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:e("div",{className:"relative",style:{width:"68px",height:"68px"},children:e(l,{src:g,alt:"Bạn",width:68,height:68,className:"object-cover rounded-full select-none",style:{width:"68px",height:"68px"},draggable:!1})})})]})]})]})]}),e("style",{jsx:!0,children:"\n @keyframes soundWavePulse {\n 0% {\n opacity: 0.2;\n transform: translateY(-50%) scaleX(0.7);\n }\n 50% {\n opacity: 1;\n transform: translateY(-50%) scaleX(1);\n }\n 100% {\n opacity: 0.2;\n transform: translateY(-50%) scaleX(0.7);\n }\n }\n "})]})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import{ResolvedImage as i}from"../../../../../../components/common/ResolvedImage";import{useSpeakingRendererSetup as n}from"../../../hooks/useSpeakingRendererSetup";import{getSpeakingLayout as r}from"../../../../../../components/themes";import t from"../SpeakingInfoExchange.module.css";import s from"../SpeakingInfoExchangeSummerSky.module.css";export function SpeakingInfoExchangeRenderer(l){const d=n({...l,maxDurationMs:3e4}),c=r(l.speakingTheme),m="SUMMER_SKY"===l.speakingTheme,h=m?s:t,f=d.currentQuestion?.content,u=d.currentQuestion?.questionGroup?.payload;if(!d.currentQuestion||!f)return null;const g=f.audioUrl??"",p=u?.title??"",N=u?.imageUrl??"",v=u?.candidateFields??[],x=u?.examinerFields??[];return e(c,{onExit:l.onExit,partName:l.part.name||`Part ${l.part.partNo}`,instruction:l.part.instructions||"INFORMATION EXCHANGE",audioUrl:g,questionNumber:d.nav.questionNumberInPart,onPrev:d.handlePrev,onNext:d.handleNext,showPrev:d.nav.showPrev,showNext:d.nav.showNext,canGoPrev:d.nav.canGoPrev,canGoNext:d.nav.canGoNext,onAudioPlayingChange:d.onAudioPlayingChange,recorder:l.isReviewMode?null:d.recorder,showExistingBadge:d.showExistingBadge,teacherVideoUrl:l.teacherVideoUrl,onTeacherVideoEnded:l.onTeacherIntroPlayed,skipTeacherVideo:l.skipTeacherVideo,contentClassName:"!gap-2",children:e("div",{className:"w-full h-full",children:e("div",{className:h.part2Container,children:a("div",{className:h.questionContainer,children:[N&&a("div",m?{className:h.imageWrapper,children:[d.showExistingBadge&&a("div",{className:h.recordedBadge,children:[e("span",{className:h.recordedBadgeDot}),"Đã ghi âm"]}),e("div",{className:h.imageFrame,children:e(i,{src:N,alt:p||"Info Exchange",className:"object-contain h-full w-full pointer-events-none",draggable:!1})})]}:{className:"relative h-full flex items-center justify-center",children:[d.showExistingBadge&&a("div",{className:"absolute right-4 top-4 z-10 rounded-full bg-green-500 px-4 py-1 flex items-center gap-2 text-sm font-bold text-white shadow-md border-2 border-white",children:[e("span",{className:"h-2.5 w-2.5 rounded-full bg-white animate-pulse"}),"Đã ghi âm"]}),e("div",{className:t.imageBorder,children:e(i,{src:N,alt:p||"Info Exchange",className:"object-cover h-full w-full pointer-events-none",draggable:!1})})]}),a("div",{className:h.infoContainer,children:[e(o,{heading:"Candidate's Copy",title:p,fields:v,styles:h,isSummerSky:m}),e(o,{heading:"Examiner's Copy",title:p,fields:x,styles:h,isSummerSky:m})]})]})})})})}function o({heading:i,title:n,fields:r,styles:t,isSummerSky:s}){const o=r.map((i,n)=>{const r=!i.answer||"___"===i.answer||"?"===i.answer;return a("div",s?{className:t.infoDetailItem,children:[e("div",{className:t.infoDetailLabel,children:i.key}),e("div",{className:t.infoDetailDivide}),e("div",{className:[t.infoDetailValue,r?t.infoDetailValueBlank:""].join(" "),children:r?"?":i.answer})]}:{className:t.infoDetailItem,children:[e("div",{className:t.infoDetailItemValue,style:{textAlign:"right",flex:1,minWidth:0,wordBreak:"break-word",paddingRight:"10px",color:"#fff",fontSize:"18px",fontWeight:700},children:i.key}),e("div",{className:t.infoDetailItemDivide}),e("div",{className:t.infoDetailItemValue,style:{textAlign:"left",flex:1,minWidth:0,wordBreak:"break-word",paddingLeft:"10px",color:r?"#a8a29e":"#fff",fontStyle:r?"italic":"normal",fontSize:"18px",fontWeight:r?"normal":700},children:r?"?":i.answer})]},n)});return a("div",s?{className:t.infoItem,children:[e("div",{className:t.infoHeader,children:i}),a("div",{className:t.infoItemInner,children:[n&&e("div",{className:t.infoName,children:n}),o]})]}:{className:t.infoItem,children:[e("div",{className:t.infoHeader,children:i}),n&&e("div",{className:t.infoName,children:n}),o]})}
1
+ "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import{ResolvedImage as i}from"../../../../../../components/common/ResolvedImage";import{useSpeakingRendererSetup as n}from"../../../hooks/useSpeakingRendererSetup";import{getSpeakingLayout as r}from"../../../../../../components/themes";import t from"../SpeakingInfoExchange.module.css";import s from"../SpeakingInfoExchangeSummerSky.module.css";export function SpeakingInfoExchangeRenderer(l){const d=n({...l,maxDurationMs:3e4}),c=r(l.speakingTheme),m="SUMMER_SKY"===l.speakingTheme,h=m?s:t,f=d.currentQuestion?.content,u=d.currentQuestion?.questionGroup?.payload;if(!d.currentQuestion||!f)return null;const g=f.audioUrl??"",p=u?.title??"",N=u?.imageUrl??"",v=u?.candidateFields??[],x=u?.examinerFields??[];return e(c,{onExit:l.onExit,partName:l.part.name||`Part ${l.part.partNo}`,instruction:l.part.instructions||"INFORMATION EXCHANGE",audioUrl:g,questionNumber:d.nav.questionNumberInPart,onPrev:d.handlePrev,onNext:d.handleNext,showPrev:d.nav.showPrev,showNext:d.nav.showNext,canGoPrev:d.nav.canGoPrev,canGoNext:d.nav.canGoNext,onAudioPlayingChange:d.onAudioPlayingChange,recorder:l.isReviewMode?null:d.recorder,showExistingBadge:d.showExistingBadge,teacherVideoUrl:l.teacherVideoUrl,onTeacherVideoEnded:l.onTeacherIntroPlayed,skipTeacherVideo:l.skipTeacherVideo,contentClassName:"!gap-2",children:e("div",{className:"w-full h-full",children:e("div",{className:h.part2Container,children:a("div",{className:h.questionContainer,children:[N&&a("div",m?{className:h.imageWrapper,children:[d.showExistingBadge&&a("div",{className:h.recordedBadge,children:[e("span",{className:h.recordedBadgeDot}),"Đã ghi âm"]}),e("div",{className:h.imageFrame,children:e(i,{src:N,alt:p||"Info Exchange",className:"object-contain h-full w-full pointer-events-none",draggable:!1})})]}:{className:"relative h-full flex items-center justify-center",children:[d.showExistingBadge&&a("div",{className:"absolute right-4 top-4 z-10 rounded-full bg-green-500 px-4 py-1 flex items-center gap-2 text-sm font-bold text-white shadow-md border-2 border-white",children:[e("span",{className:"h-2.5 w-2.5 rounded-full bg-white animate-pulse"}),"Đã ghi âm"]}),e("div",{className:t.imageBorder,children:e(i,{src:N,alt:p||"Info Exchange",className:"object-cover h-full w-full pointer-events-none",draggable:!1})})]}),a("div",{className:h.infoContainer,children:[e(o,{heading:"Candidate's Copy",title:p,fields:v,styles:h,isSummerSky:m}),e(o,{heading:"Examiner's Copy",title:p,fields:x,styles:h,isSummerSky:m})]})]})})})})}function o({heading:i,title:n,fields:r,styles:t,isSummerSky:s}){const o=r.map((i,n)=>{const r=!i.answer||"___"===i.answer||"?"===i.answer;return a("div",s?{className:t.infoDetailItem,children:[e("div",{className:t.infoDetailLabel,children:i.key}),e("div",{className:t.infoDetailDivide}),e("div",{className:[t.infoDetailValue,r?t.infoDetailValueBlank:""].join(" "),children:r?"?":i.answer})]}:{className:t.infoDetailItem,children:[e("div",{className:t.infoDetailItemValue,style:{textAlign:"right",flex:1,minWidth:0,wordBreak:"break-word",paddingRight:"10px",color:"#fff",fontSize:"18px",fontWeight:700},children:i.key}),e("div",{className:t.infoDetailItemDivide}),e("div",{className:t.infoDetailItemValue,style:{textAlign:"left",flex:1,minWidth:0,wordBreak:"break-word",paddingLeft:"10px",color:r?"#a8a29e":"#fff",fontStyle:r?"italic":"normal",fontSize:"18px",fontWeight:r?"normal":700},children:r?"?":i.answer})]},n)});return a("div",s?{className:t.infoItem,children:[e("div",{className:t.infoHeader,children:i}),a("div",{className:t.infoItemInner,children:[n&&e("div",{className:t.infoName,children:n}),o]})]}:{className:t.infoItem,children:[e("div",{className:t.infoHeader,children:i}),n&&e("div",{className:t.infoName,children:n}),o]})}
@@ -1 +1 @@
1
- "use client";import{jsxs as e,jsx as r}from"react/jsx-runtime";import{useEffect as t,useRef as i,useState as n}from"react";import{useSpeakingRendererSetup as s}from"../../../hooks/useSpeakingRendererSetup";import{getSpeakingLayout as a}from"../../../../../../components/themes";import l from"../../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import o from"next/image";import d from"../../../../../../components/themes/summer-sky/assets/images/mic_ver2_icon.png";import c from"../../../../../../components/themes/summer-sky/assets/images/stop_audio_ver2_icon.png";import m from"../../../../../../components/themes/summer-sky/assets/images/audio_ver2_icon.png";import u from"../../../../../../components/themes/summer-sky/assets/images/pause_audio_ver2_icon.png";import p from"../SpeakingReadDisplayedContent.module.css";import{SpeakingAudioPlayer as h}from"../../../../../../components/shared/audio/SpeakingAudioPlayer";function f(e){switch(e){case"BASIC_PHONICS":return p.difficultyBasicPhonics;case"DAILY_ROUTINE":return p.difficultyDailyRoutine;case"DESCRIPTIVE_EMOTIONAL":return p.difficultyDescriptiveEmotional;default:return""}}function x(e){switch(e){case"BASIC_PHONICS":return"📖 Basic Phonics";case"DAILY_ROUTINE":return"🕐 Daily Routine & Time";case"DESCRIPTIVE_EMOTIONAL":return"🌄 Descriptive & Emotional";default:return""}}function g({total:t,currentIndex:i,answeredIds:n,questionIds:s,isSpaceship:a}){return e("div",{className:p.taskIndicator,style:a?{color:"#78350f",textShadow:"none",fontWeight:800}:void 0,children:[e("span",{children:["Question ",i+1,"/ ",t]}),r("div",{className:"flex gap-2",children:Array.from({length:t},(e,t)=>{const a=t===i,l=n.has(s[t]);return r("div",{className:`${p.taskDot} ${a?p.taskDotActive:""} ${l&&!a?p.taskDotCompleted:""}`},t)})})]})}function v({total:t,currentIndex:i,answeredIds:n,questionIds:s}){return e("div",{className:"flex items-center gap-2 font-bold text-[#78350f] font-['Quicksand'] z-10",children:[e("span",{className:"text-sm",children:["Question ",i+1,"/ ",t]}),r("div",{className:"flex gap-1.5",children:Array.from({length:t},(e,t)=>{const a=t===i,l=n.has(s[t]);return r("div",{className:"w-2.5 h-2.5 rounded-full "+(a?"bg-[#FF9900] scale-125 shadow-sm":l?"bg-[#16CA3B]":"bg-white/60")},t)})})]})}export function SpeakingReadDisplayedContentRenderer(w){const N=s({...w,maxDurationMs:3e4}),y=i(null),[b,k]=n(!1);t(()=>{const e=y.current;if(!e)return;const r=()=>{k(!0),N.onAudioPlayingChange?.(!0)},t=()=>{k(!1),N.onAudioPlayingChange?.(!1)},i=()=>{k(!1),N.onAudioPlayingChange?.(!1)};return e.addEventListener("play",r),e.addEventListener("pause",t),e.addEventListener("ended",i),()=>{e.removeEventListener("play",r),e.removeEventListener("pause",t),e.removeEventListener("ended",i),N.onAudioPlayingChange?.(!1)}},[N.recorder?.previewUrl,N.onAudioPlayingChange]);const S=a(w.speakingTheme),E="SPACESHIP"===w.speakingTheme||"SUMMER_SKY"===w.speakingTheme,I=N.currentQuestion?.content;if(!N.currentQuestion||!I)return null;const C=I.referenceText??"",A=I.modelAudioUrl??"",P=I.difficultyTag,_=C.length>700?"clamp(15px, 1.6vw, 19px)":C.length>400?"clamp(18px, 2vw, 24px)":"clamp(22px, 2.2vw, 30px)",T=new Set(w.part.questions.map(e=>e.id).filter(e=>!!w.answers[e])),F=w.part.questions.map(e=>e.id);if(w.speakingTheme&&"CAMBRIDGE_YLE"!==w.speakingTheme){const t=r(g,{total:w.part.questions.length,currentIndex:N.nav.currentIndex,answeredIds:T,questionIds:F,isSpaceship:E}),i=A?e("div",{className:p.modelAudioSection,children:[r("span",{className:p.modelAudioLabel,children:"🔊 Model pronunciation:"}),r(h,{audioUrl:A})]}):null;return r(S,{onExit:w.onExit,partName:w.part.name||`Part ${w.part.partNo}`,instruction:w.part.instructions||"READ THE PASSAGE ALOUD",audioUrl:E&&A||"",questionNumber:N.nav.questionNumberInPart,onPrev:N.handlePrev,onNext:N.handleNext,showPrev:N.nav.showPrev,showNext:N.nav.showNext,canGoPrev:N.nav.canGoPrev,canGoNext:N.nav.canGoNext,onAudioPlayingChange:N.onAudioPlayingChange,recorder:w.isReviewMode?null:N.recorder,showExistingBadge:N.showExistingBadge,headerRight:t,audioBarRight:E?null:i,teacherVideoUrl:w.teacherVideoUrl,waitForTeacherVideo:w.waitForTeacherVideo,onTeacherVideoEnded:w.onTeacherIntroPlayed,skipTeacherVideo:w.skipTeacherVideo,children:E?r("div",{className:"w-full h-full flex flex-col items-center relative",children:r("div",{className:"w-full flex-1",style:{minHeight:0},children:r("div",{className:"mx-auto",style:{width:"900px",maxWidth:"95%",height:"calc(100% - 100px)"},children:r("div",{className:"w-full h-full flex flex-col items-center justify-center",style:{paddingTop:"10px"},children:e("div",{className:"relative flex flex-col justify-center items-center",style:{width:"100%",paddingLeft:"60px",paddingRight:"60px",paddingTop:"20px",paddingBottom:"20px"},children:[N.showExistingBadge&&e("div",{className:"absolute right-12 top-12 z-10 rounded-full bg-green-500 px-4 py-1.5 flex items-center gap-2 text-sm font-bold text-white shadow-md border-2 border-white",children:[r("span",{className:"h-2.5 w-2.5 rounded-full bg-white animate-pulse"}),"Đã ghi âm"]}),r("div",{className:"max-w-full",children:r("div",{className:"text-center max-w-full",style:{fontSize:"40px",fontFamily:'"SVN-Volte Rounded", sans-serif',fontWeight:600,lineHeight:"52px",letterSpacing:"-0.01em",color:"#2C38B6"},children:r("p",{className:"m-0 break-words whitespace-pre-wrap",children:`"${C}"`})})})]})})})})}):e("div",{className:"flex flex-col items-center justify-center h-full w-full gap-4 px-4",children:[P&&r("div",{className:`${p.difficultyBadge} ${f(P)}`,children:x(P)}),e("div",{className:p.referenceTextCard,children:[N.showExistingBadge&&e("div",{className:"absolute right-4 top-4 z-10 rounded-full bg-green-500 px-4 py-1 flex items-center gap-2 text-sm font-bold text-white shadow-md border-2 border-white",children:[r("span",{className:"h-2.5 w-2.5 rounded-full bg-white animate-pulse"}),"Đã ghi âm"]}),r("p",{className:p.referenceText,children:`"${C}"`})]})]})})}return e("div",{className:"flex flex-col w-full h-full relative",style:{background:"linear-gradient(180deg, #E6F3FF 0%, #FFFFFF 100%)"},children:[e("div",{className:"relative w-full flex justify-between items-start pt-6 px-6 z-20 shrink-0",children:[r("div",{className:"flex-1"}),r("div",{className:"flex-none drop-shadow-md",children:r(l,{partNumber:w.part.partNo,questionCount:w.part.questions.length,partName:w.part.name||`Part ${w.part.partNo}`})}),r("div",{className:"flex-1 flex justify-end mt-2 z-20",children:r(v,{total:w.part.questions.length,currentIndex:N.nav.currentIndex,answeredIds:T,questionIds:F})})]}),e("div",{className:"flex-1 w-full flex flex-col items-center min-h-0 px-4 pb-6 pt-5",children:[w.part.instructions&&e("div",{className:"shrink-0 w-full max-w-[760px] flex items-center gap-3 rounded-2xl px-5 py-3 mb-4",style:{background:"rgba(255, 255, 255, 0.9)",border:"2px solid #FCD34D",boxShadow:"0 3px 12px rgba(180, 130, 20, 0.12)"},children:[r("div",{className:"shrink-0 flex items-center justify-center rounded-full",style:{width:42,height:42,background:"#FEF3C7"},children:r("span",{style:{fontSize:22,lineHeight:1},children:"💡"})}),r("div",{className:"flex flex-col text-left min-w-0",children:r("p",{className:"m-0",style:{color:"#78350F",fontSize:16,fontWeight:600,lineHeight:1.35,fontFamily:'"Quicksand", sans-serif'},children:w.part.instructions})})]}),P&&r("div",{className:"shrink-0 mb-3",children:r("div",{className:`${p.difficultyBadge} ${f(P)}`,children:x(P)})}),r("div",{className:"flex-1 w-full flex flex-col items-center justify-center min-h-0 relative mb-8",children:e("div",{className:"w-full max-w-[850px] max-h-full relative bg-white/60 backdrop-blur-md rounded-2xl shadow-[0_2px_15px_rgba(0,0,0,0.04)] border border-blue-50 p-8 flex flex-col min-h-0",children:[N.showExistingBadge&&e("div",{className:"absolute right-4 top-0 z-10 rounded-full bg-green-500 px-4 py-1.5 flex items-center gap-2 text-sm font-bold text-white shadow-lg border-2 border-white transform -translate-y-1/2",children:[r("span",{className:"h-2.5 w-2.5 rounded-full bg-white animate-pulse"}),"Đã ghi âm"]}),r("div",{className:"w-full min-h-0 overflow-y-auto",children:r("p",{className:"text-center break-words whitespace-pre-wrap m-0",style:{fontSize:_,fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',fontWeight:600,lineHeight:1.4,letterSpacing:"-0.01em",color:"#2C38B6"},children:`"${C}"`})}),A&&e("div",{className:"mt-6 flex items-center justify-center gap-2 shrink-0",children:[r("span",{className:"text-sm font-semibold text-[#283593] font-['Quicksand']",children:"🔊 Model pronunciation:"}),r(h,{audioUrl:A})]})]})}),N.recorder&&!w.isReviewMode&&e("div",{className:"shrink-0 flex flex-col items-center z-50 gap-3",children:[r("div",{className:"bg-white rounded-[100px] shadow-[0_4px_10px_rgba(0,0,0,0.1)] whitespace-nowrap flex items-center justify-center",style:{padding:"10px 30px",color:"recording"===N.recorder.status?"#FF4D4D":["recorded","uploading","uploaded"].includes(N.recorder.status)?"#16CA3B":"#343C55",fontSize:"18px",fontFamily:'"Quicksand", sans-serif',fontWeight:700,lineHeight:"100%",letterSpacing:"-0.01em"},children:"recording"===N.recorder.status?"Ấn lần nữa để lưu kết quả":["recorded","uploading","uploaded"].includes(N.recorder.status)?"Câu trả lời đã được ghi nhận !":"Ấn biểu tượng Micro để trả lời"}),r("div",{className:"relative flex flex-col items-center",children:"recording"===N.recorder.status?e("div",{className:"relative flex flex-col justify-center items-center cursor-pointer drop-shadow-[0_0_15px_rgba(255,100,100,0.8)] transition-transform hover:scale-[1.05] active:scale-[0.95]",onClick:N.recorder.stopRecording,children:[r(o,{src:c,alt:"stop audio",className:"animate-pulse",style:{width:"120px",height:"120px"}}),e("span",{className:"absolute text-white text-[16px] font-bold font-['Quicksand']",style:{bottom:"30px"},children:[Math.floor(N.recorder.remainingSeconds/60),":",(N.recorder.remainingSeconds%60).toString().padStart(2,"0")]})]}):r(o,{src:["recorded","uploading","uploaded"].includes(N.recorder.status)?b?u:m:d,alt:"micro",className:"transition-transform cursor-pointer hover:scale-[1.05] active:scale-[0.95]",style:{width:"120px",height:"120px"},onClick:()=>{if("recording"===N.recorder?.status)N.recorder.stopRecording();else if("idle"===N.recorder?.status||"error"===N.recorder?.status)N.recorder.startRecording();else if("uploaded"===N.recorder?.status||"recorded"===N.recorder?.status){const e=y.current;e&&(b?e.pause():e.play().catch(console.error))}}})}),N.recorder.previewUrl&&r("audio",{ref:y,src:N.recorder.previewUrl})]})]})]})}
1
+ "use client";import{jsxs as e,jsx as r}from"react/jsx-runtime";import{useEffect as t,useRef as i,useState as n}from"react";import{useSpeakingRendererSetup as s}from"../../../hooks/useSpeakingRendererSetup";import{getSpeakingLayout as a}from"../../../../../../components/themes";import l from"../../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import o from"next/image";import d from"../../../../../../components/themes/summer-sky/assets/images/mic_ver2_icon.png";import c from"../../../../../../components/themes/summer-sky/assets/images/stop_audio_ver2_icon.png";import m from"../../../../../../components/themes/summer-sky/assets/images/audio_ver2_icon.png";import u from"../../../../../../components/themes/summer-sky/assets/images/pause_audio_ver2_icon.png";import p from"../SpeakingReadDisplayedContent.module.css";import{SpeakingAudioPlayer as h}from"../../../../../../components/shared/audio/SpeakingAudioPlayer";function f(e){switch(e){case"BASIC_PHONICS":return p.difficultyBasicPhonics;case"DAILY_ROUTINE":return p.difficultyDailyRoutine;case"DESCRIPTIVE_EMOTIONAL":return p.difficultyDescriptiveEmotional;default:return""}}function g(e){switch(e){case"BASIC_PHONICS":return"📖 Basic Phonics";case"DAILY_ROUTINE":return"🕐 Daily Routine & Time";case"DESCRIPTIVE_EMOTIONAL":return"🌄 Descriptive & Emotional";default:return""}}function x({total:t,currentIndex:i,answeredIds:n,questionIds:s,isSpeakingShell:a}){return e("div",{className:p.taskIndicator,style:a?{color:"#78350f",textShadow:"none",fontWeight:800}:void 0,children:[e("span",{children:["Question ",i+1,"/ ",t]}),r("div",{className:"flex gap-2",children:Array.from({length:t},(e,t)=>{const a=t===i,l=n.has(s[t]);return r("div",{className:`${p.taskDot} ${a?p.taskDotActive:""} ${l&&!a?p.taskDotCompleted:""}`},t)})})]})}function v({total:t,currentIndex:i,answeredIds:n,questionIds:s}){return e("div",{className:"flex items-center gap-2 font-bold text-[#78350f] font-['Quicksand'] z-10",children:[e("span",{className:"text-sm",children:["Question ",i+1,"/ ",t]}),r("div",{className:"flex gap-1.5",children:Array.from({length:t},(e,t)=>{const a=t===i,l=n.has(s[t]);return r("div",{className:"w-2.5 h-2.5 rounded-full "+(a?"bg-[#FF9900] scale-125 shadow-sm":l?"bg-[#16CA3B]":"bg-white/60")},t)})})]})}export function SpeakingReadDisplayedContentRenderer(w){const N=s({...w,maxDurationMs:3e4}),y=i(null),[b,k]=n(!1);t(()=>{const e=y.current;if(!e)return;const r=()=>{k(!0),N.onAudioPlayingChange?.(!0)},t=()=>{k(!1),N.onAudioPlayingChange?.(!1)},i=()=>{k(!1),N.onAudioPlayingChange?.(!1)};return e.addEventListener("play",r),e.addEventListener("pause",t),e.addEventListener("ended",i),()=>{e.removeEventListener("play",r),e.removeEventListener("pause",t),e.removeEventListener("ended",i),N.onAudioPlayingChange?.(!1)}},[N.recorder?.previewUrl,N.onAudioPlayingChange]);const S=a(w.speakingTheme),E="SUMMER_SKY"===w.speakingTheme,I=N.currentQuestion?.content;if(!N.currentQuestion||!I)return null;const C=I.referenceText??"",A=I.modelAudioUrl??"",_=I.difficultyTag,P=C.length>700?"clamp(15px, 1.6vw, 19px)":C.length>400?"clamp(18px, 2vw, 24px)":"clamp(22px, 2.2vw, 30px)",T=new Set(w.part.questions.map(e=>e.id).filter(e=>!!w.answers[e])),F=w.part.questions.map(e=>e.id);if(w.speakingTheme&&"CAMBRIDGE_YLE"!==w.speakingTheme){const t=r(x,{total:w.part.questions.length,currentIndex:N.nav.currentIndex,answeredIds:T,questionIds:F,isSpeakingShell:E}),i=A?e("div",{className:p.modelAudioSection,children:[r("span",{className:p.modelAudioLabel,children:"🔊 Model pronunciation:"}),r(h,{audioUrl:A})]}):null;return r(S,{onExit:w.onExit,partName:w.part.name||`Part ${w.part.partNo}`,instruction:w.part.instructions||"READ THE PASSAGE ALOUD",audioUrl:E&&A||"",questionNumber:N.nav.questionNumberInPart,onPrev:N.handlePrev,onNext:N.handleNext,showPrev:N.nav.showPrev,showNext:N.nav.showNext,canGoPrev:N.nav.canGoPrev,canGoNext:N.nav.canGoNext,onAudioPlayingChange:N.onAudioPlayingChange,recorder:w.isReviewMode?null:N.recorder,showExistingBadge:N.showExistingBadge,headerRight:t,audioBarRight:E?null:i,teacherVideoUrl:w.teacherVideoUrl,waitForTeacherVideo:w.waitForTeacherVideo,onTeacherVideoEnded:w.onTeacherIntroPlayed,skipTeacherVideo:w.skipTeacherVideo,children:E?r("div",{className:"w-full h-full flex flex-col items-center relative",children:r("div",{className:"w-full flex-1",style:{minHeight:0},children:r("div",{className:"mx-auto",style:{width:"900px",maxWidth:"95%",height:"calc(100% - 100px)"},children:r("div",{className:"w-full h-full flex flex-col items-center justify-center",style:{paddingTop:"10px"},children:e("div",{className:"relative flex flex-col justify-center items-center",style:{width:"100%",paddingLeft:"60px",paddingRight:"60px",paddingTop:"20px",paddingBottom:"20px"},children:[N.showExistingBadge&&e("div",{className:"absolute right-12 top-12 z-10 rounded-full bg-green-500 px-4 py-1.5 flex items-center gap-2 text-sm font-bold text-white shadow-md border-2 border-white",children:[r("span",{className:"h-2.5 w-2.5 rounded-full bg-white animate-pulse"}),"Đã ghi âm"]}),r("div",{className:"max-w-full",children:r("div",{className:"text-center max-w-full",style:{fontSize:"40px",fontFamily:'"SVN-Volte Rounded", sans-serif',fontWeight:600,lineHeight:"52px",letterSpacing:"-0.01em",color:"#2C38B6"},children:r("p",{className:"m-0 break-words whitespace-pre-wrap",children:`"${C}"`})})})]})})})})}):e("div",{className:"flex flex-col items-center justify-center h-full w-full gap-4 px-4",children:[_&&r("div",{className:`${p.difficultyBadge} ${f(_)}`,children:g(_)}),e("div",{className:p.referenceTextCard,children:[N.showExistingBadge&&e("div",{className:"absolute right-4 top-4 z-10 rounded-full bg-green-500 px-4 py-1 flex items-center gap-2 text-sm font-bold text-white shadow-md border-2 border-white",children:[r("span",{className:"h-2.5 w-2.5 rounded-full bg-white animate-pulse"}),"Đã ghi âm"]}),r("p",{className:p.referenceText,children:`"${C}"`})]})]})})}return e("div",{className:"flex flex-col w-full h-full relative",style:{background:"linear-gradient(180deg, #E6F3FF 0%, #FFFFFF 100%)"},children:[e("div",{className:"relative w-full flex justify-between items-start pt-6 px-6 z-20 shrink-0",children:[r("div",{className:"flex-1"}),r("div",{className:"flex-none drop-shadow-md",children:r(l,{partNumber:w.part.partNo,questionCount:w.part.questions.length,partName:w.part.name||`Part ${w.part.partNo}`})}),r("div",{className:"flex-1 flex justify-end mt-2 z-20",children:r(v,{total:w.part.questions.length,currentIndex:N.nav.currentIndex,answeredIds:T,questionIds:F})})]}),e("div",{className:"flex-1 w-full flex flex-col items-center min-h-0 px-4 pb-6 pt-5",children:[w.part.instructions&&e("div",{className:"shrink-0 w-full max-w-[760px] flex items-center gap-3 rounded-2xl px-5 py-3 mb-4",style:{background:"rgba(255, 255, 255, 0.9)",border:"2px solid #FCD34D",boxShadow:"0 3px 12px rgba(180, 130, 20, 0.12)"},children:[r("div",{className:"shrink-0 flex items-center justify-center rounded-full",style:{width:42,height:42,background:"#FEF3C7"},children:r("span",{style:{fontSize:22,lineHeight:1},children:"💡"})}),r("div",{className:"flex flex-col text-left min-w-0",children:r("p",{className:"m-0",style:{color:"#78350F",fontSize:16,fontWeight:600,lineHeight:1.35,fontFamily:'"Quicksand", sans-serif'},children:w.part.instructions})})]}),_&&r("div",{className:"shrink-0 mb-3",children:r("div",{className:`${p.difficultyBadge} ${f(_)}`,children:g(_)})}),r("div",{className:"flex-1 w-full flex flex-col items-center justify-center min-h-0 relative mb-8",children:e("div",{className:"w-full max-w-[850px] max-h-full relative bg-white/60 backdrop-blur-md rounded-2xl shadow-[0_2px_15px_rgba(0,0,0,0.04)] border border-blue-50 p-8 flex flex-col min-h-0",children:[N.showExistingBadge&&e("div",{className:"absolute right-4 top-0 z-10 rounded-full bg-green-500 px-4 py-1.5 flex items-center gap-2 text-sm font-bold text-white shadow-lg border-2 border-white transform -translate-y-1/2",children:[r("span",{className:"h-2.5 w-2.5 rounded-full bg-white animate-pulse"}),"Đã ghi âm"]}),r("div",{className:"w-full min-h-0 overflow-y-auto",children:r("p",{className:"text-center break-words whitespace-pre-wrap m-0",style:{fontSize:P,fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',fontWeight:600,lineHeight:1.4,letterSpacing:"-0.01em",color:"#2C38B6"},children:`"${C}"`})}),A&&e("div",{className:"mt-6 flex items-center justify-center gap-2 shrink-0",children:[r("span",{className:"text-sm font-semibold text-[#283593] font-['Quicksand']",children:"🔊 Model pronunciation:"}),r(h,{audioUrl:A})]})]})}),N.recorder&&!w.isReviewMode&&e("div",{className:"shrink-0 flex flex-col items-center z-50 gap-3",children:[r("div",{className:"bg-white rounded-[100px] shadow-[0_4px_10px_rgba(0,0,0,0.1)] whitespace-nowrap flex items-center justify-center",style:{padding:"10px 30px",color:"recording"===N.recorder.status?"#FF4D4D":["recorded","uploading","uploaded"].includes(N.recorder.status)?"#16CA3B":"#343C55",fontSize:"18px",fontFamily:'"Quicksand", sans-serif',fontWeight:700,lineHeight:"100%",letterSpacing:"-0.01em"},children:"recording"===N.recorder.status?"Ấn lần nữa để lưu kết quả":["recorded","uploading","uploaded"].includes(N.recorder.status)?"Câu trả lời đã được ghi nhận !":"Ấn biểu tượng Micro để trả lời"}),r("div",{className:"relative flex flex-col items-center",children:"recording"===N.recorder.status?e("div",{className:"relative flex flex-col justify-center items-center cursor-pointer drop-shadow-[0_0_15px_rgba(255,100,100,0.8)] transition-transform hover:scale-[1.05] active:scale-[0.95]",onClick:N.recorder.stopRecording,children:[r(o,{src:c,alt:"stop audio",className:"animate-pulse",style:{width:"120px",height:"120px"}}),e("span",{className:"absolute text-white text-[16px] font-bold font-['Quicksand']",style:{bottom:"30px"},children:[Math.floor(N.recorder.remainingSeconds/60),":",(N.recorder.remainingSeconds%60).toString().padStart(2,"0")]})]}):r(o,{src:["recorded","uploading","uploaded"].includes(N.recorder.status)?b?u:m:d,alt:"micro",className:"transition-transform cursor-pointer hover:scale-[1.05] active:scale-[0.95]",style:{width:"120px",height:"120px"},onClick:()=>{if("recording"===N.recorder?.status)N.recorder.stopRecording();else if("idle"===N.recorder?.status||"error"===N.recorder?.status)N.recorder.startRecording();else if("uploaded"===N.recorder?.status||"recorded"===N.recorder?.status){const e=y.current;e&&(b?e.pause():e.play().catch(console.error))}}})}),N.recorder.previewUrl&&r("audio",{ref:y,src:N.recorder.previewUrl})]})]})]})}
@@ -1 +1 @@
1
- import{useState as r,useRef as e,useEffect as n,useCallback as t}from"react";import{usePresignedFileUrl as u}from"../../../../shared/lib/hooks";import{useExamTakingApi as o}from"../ExamTakingApiContext";export function useSpeakingRecorder(i){const c=i.maxDurationMs??3e4,a=Math.floor(c/1e3),d=o(),s=e(d);s.current=d;const l=e(i.onRecordingComplete),p=e(i.onError);l.current=i.onRecordingComplete,p.current=i.onError;const g=e(i.attemptId),m=e(i.questionId);g.current=i.attemptId,m.current=i.questionId;const[h,y]=r("idle"),[w,f]=r(a),[A,v]=r(0),[R,T]=r(null),[E,x]=r(null),[I,b]=r(null),[K,M]=r(!1),k=e(null),P=e(null),D=e([]),S=e(null),U=e(null),O=e(""),_=e(0),q=e(null),L=e(void 0),B=e(0),V=e(!0),C=e(""),G="undefined"!=typeof MediaRecorder,{previewUrl:j}=u(i.existingAnswerKey),N=t(()=>{S.current&&(clearInterval(S.current),S.current=null)},[]),F=t(()=>{U.current&&(U.current.startsWith("blob:")&&URL.revokeObjectURL(U.current),U.current=null)},[]),W=t(()=>{P.current&&(P.current.getTracks().forEach(r=>r.stop()),P.current=null)},[]),X=t(async(r,e,n,t)=>{if(!V.current)return;const u=t||C.current||m.current;m.current===u&&y("uploading");const o=g.current;if("mock-attempt-speaking"===o){if(await new Promise(r=>setTimeout(r,500)),!V.current)return;const r=`mock-audio-key-${u}`;return m.current===u&&(y("uploaded"),x(r)),l.current(r,u),q.current=null,void(L.current=void 0)}try{if(!s.current.uploadAudioAnswer)throw new Error("uploadAudioAnswer is not implemented by the provided API adapter.");const n=(i=await s.current.uploadAudioAnswer({attemptId:o,questionId:u,audioBlob:r,durationMs:e}))&&"object"==typeof i&&"data"in i?i.data:i;if(!V.current)return;const t=n.audioKey??"";m.current===u&&(y("uploaded"),x(t)),l.current(t,u),q.current=null,L.current=void 0,B.current=0,s.current.realtimeGradeSingle?.({attemptId:o,questionId:u,audioKey:t}).catch(r=>{console.debug("[Realtime Grading] Skipped or failed:",r?.response?.status??r?.message)})}catch(u){if(!V.current)return;const o=u,i=o?.response?.data?.code;if("ATTEMPT_EXPIRED"===i||"ATTEMPT_NOT_IN_PROGRESS"===i){const r="ATTEMPT_EXPIRED"===i?"Bài thi đã hết giờ":"Bài thi đã được nộp.";return y("error"),b(r),M(!0),void p.current?.(r)}if("AUDIO_FILE_TOO_LARGE"===i){const r="Bài ghi âm quá dài. Vui lòng ghi âm ngắn hơn.";return y("error"),b(r),void p.current?.(r)}if(n<3){const u=1e3*Math.pow(2,n);if(await new Promise(r=>setTimeout(r,u)),!V.current)return;B.current=n+1,await X(r,e,n+1,t)}else{const r="Tải lên bản ghi âm thất bại. Vui lòng thử lại.";y("error"),b(r),p.current?.(r)}}var i},[]),z=t(async(r,e,n)=>{q.current=r,L.current=e,B.current=0,await X(r,e,0,n)},[X]),$=t(async()=>{if(i.existingAnswerKey)return y("uploaded"),void x(i.existingAnswerKey);if(!G){const r="Trình duyệt này không hỗ trợ ghi âm. Vui lòng dùng Chrome, Firefox hoặc Edge.";return y("error"),b(r),void p.current?.(r)}const r=function(){if("undefined"==typeof MediaRecorder)return null;const r=["audio/webm;codecs=opus","audio/webm","audio/mp4","audio/ogg;codecs=opus","audio/ogg"];for(const e of r)if(MediaRecorder.isTypeSupported(e))return e;return null}();if(!r){const r="Trình duyệt không hỗ trợ định dạng ghi âm.";return y("error"),b(r),void p.current?.(r)}try{const e=await navigator.mediaDevices.getUserMedia({audio:!0});P.current=e,O.current=r;const n=new MediaRecorder(e,{mimeType:r});k.current=n,D.current=[],n.ondataavailable=r=>{r.data.size>0&&D.current.push(r.data)},n.onstop=()=>{const r=Date.now()-_.current,e=new Blob(D.current,{type:O.current}),n=URL.createObjectURL(e),t=C.current;F(),U.current=n,T(n),y("recorded"),z(e,r,t)},n.start(),_.current=Date.now(),C.current=m.current,y("recording"),v(0),f(a),b(null),x(null),T(null),M(!1),S.current=setInterval(()=>{v(r=>r+1),f(r=>{const e=Math.max(0,r-1);return 0===e&&(N(),k.current&&"recording"===k.current.state&&k.current.stop(),W()),e})},1e3)}catch(r){W();const e=r instanceof DOMException&&("NotAllowedError"===r.name||"PermissionDeniedError"===r.name)?"Vui lòng cấp quyền truy cập microphone trong trình duyệt.":"Không thể truy cập microphone. Vui lòng thử lại.";y("error"),b(e),p.current?.(e)}},[G,a,i.existingAnswerKey,N,W,z,F]),H=t(()=>{N(),k.current&&"recording"===k.current.state&&k.current.stop(),W()},[N,W]),J=t(()=>{N(),W(),k.current&&"recording"===k.current.state&&k.current.stop(),k.current=null,D.current=[],q.current=null,L.current=void 0,B.current=0,F(),T(null),x(null),v(0),f(a),b(null),y("idle"),M(!1)},[N,W,F,a]),Q=t(async()=>{if(i.existingAnswerKey)return y("uploaded"),void x(i.existingAnswerKey);J(),await $()},[i.existingAnswerKey,J,$]),Y=t(async()=>{const r=q.current;r&&(B.current=0,await X(r,L.current,0,C.current||void 0))},[X]);n(()=>{J()},[i.questionId]),n(()=>{"idle"===h&&j&&i.existingAnswerKey&&!R&&(T(j),U.current=j,x(i.existingAnswerKey),y("uploaded"))},[h,j,i.existingAnswerKey,R]),n(()=>(V.current=!0,()=>{V.current=!1,N(),k.current&&"recording"===k.current.state&&k.current.stop(),W(),F()}),[]);return{status:h,remainingSeconds:w,isWarning:w<=5&&"recording"===h,durationSeconds:A,previewUrl:R,uploadedKey:E,error:I,isSupported:G,isAttemptExpired:K,liveTranscript:null,startRecording:$,stopRecording:H,resetRecording:J,reRecord:Q,retryUpload:Y}}
1
+ import{useState as r,useRef as e,useEffect as n,useCallback as t}from"react";import{usePresignedFileUrl as u}from"../../../../shared/lib/hooks";import{useExamTakingApiOptional as o}from"../ExamTakingApiContext";export function useSpeakingRecorder(i){const c=i.maxDurationMs??3e4,a=Math.floor(c/1e3),d=o(),s=e(d);s.current=d;const l=e(i.onRecordingComplete),p=e(i.onError);l.current=i.onRecordingComplete,p.current=i.onError;const g=e(i.attemptId),m=e(i.questionId);g.current=i.attemptId,m.current=i.questionId;const[h,y]=r("idle"),[w,f]=r(a),[A,v]=r(0),[R,T]=r(null),[E,x]=r(null),[I,b]=r(null),[K,M]=r(!1),k=e(null),P=e(null),D=e([]),S=e(null),U=e(null),O=e(""),_=e(0),q=e(null),L=e(void 0),B=e(0),V=e(!0),C=e(""),G="undefined"!=typeof MediaRecorder,{previewUrl:j}=u(i.existingAnswerKey),N=t(()=>{S.current&&(clearInterval(S.current),S.current=null)},[]),F=t(()=>{U.current&&(U.current.startsWith("blob:")&&URL.revokeObjectURL(U.current),U.current=null)},[]),W=t(()=>{P.current&&(P.current.getTracks().forEach(r=>r.stop()),P.current=null)},[]),X=t(async(r,e,n,t)=>{if(!V.current)return;const u=t||C.current||m.current;m.current===u&&y("uploading");const o=g.current;if("mock-attempt-speaking"===o){if(await new Promise(r=>setTimeout(r,500)),!V.current)return;const r=`mock-audio-key-${u}`;return m.current===u&&(y("uploaded"),x(r)),l.current(r,u),q.current=null,void(L.current=void 0)}try{if(!s.current?.uploadAudioAnswer)throw new Error("uploadAudioAnswer is not implemented by the provided API adapter.");const n=(i=await s.current.uploadAudioAnswer({attemptId:o,questionId:u,audioBlob:r,durationMs:e}))&&"object"==typeof i&&"data"in i?i.data:i;if(!V.current)return;const t=n.audioKey??"";m.current===u&&(y("uploaded"),x(t)),l.current(t,u),q.current=null,L.current=void 0,B.current=0,s.current.realtimeGradeSingle?.({attemptId:o,questionId:u,audioKey:t}).catch(r=>{console.debug("[Realtime Grading] Skipped or failed:",r?.response?.status??r?.message)})}catch(u){if(!V.current)return;const o=u,i=o?.response?.data?.code;if("ATTEMPT_EXPIRED"===i||"ATTEMPT_NOT_IN_PROGRESS"===i){const r="ATTEMPT_EXPIRED"===i?"Bài thi đã hết giờ":"Bài thi đã được nộp.";return y("error"),b(r),M(!0),void p.current?.(r)}if("AUDIO_FILE_TOO_LARGE"===i){const r="Bài ghi âm quá dài. Vui lòng ghi âm ngắn hơn.";return y("error"),b(r),void p.current?.(r)}if(n<3){const u=1e3*Math.pow(2,n);if(await new Promise(r=>setTimeout(r,u)),!V.current)return;B.current=n+1,await X(r,e,n+1,t)}else{const r="Tải lên bản ghi âm thất bại. Vui lòng thử lại.";y("error"),b(r),p.current?.(r)}}var i},[]),z=t(async(r,e,n)=>{q.current=r,L.current=e,B.current=0,await X(r,e,0,n)},[X]),$=t(async()=>{if(i.existingAnswerKey)return y("uploaded"),void x(i.existingAnswerKey);if(!G){const r="Trình duyệt này không hỗ trợ ghi âm. Vui lòng dùng Chrome, Firefox hoặc Edge.";return y("error"),b(r),void p.current?.(r)}const r=function(){if("undefined"==typeof MediaRecorder)return null;const r=["audio/webm;codecs=opus","audio/webm","audio/mp4","audio/ogg;codecs=opus","audio/ogg"];for(const e of r)if(MediaRecorder.isTypeSupported(e))return e;return null}();if(!r){const r="Trình duyệt không hỗ trợ định dạng ghi âm.";return y("error"),b(r),void p.current?.(r)}try{const e=await navigator.mediaDevices.getUserMedia({audio:!0});P.current=e,O.current=r;const n=new MediaRecorder(e,{mimeType:r});k.current=n,D.current=[],n.ondataavailable=r=>{r.data.size>0&&D.current.push(r.data)},n.onstop=()=>{const r=Date.now()-_.current,e=new Blob(D.current,{type:O.current}),n=URL.createObjectURL(e),t=C.current;F(),U.current=n,T(n),y("recorded"),z(e,r,t)},n.start(),_.current=Date.now(),C.current=m.current,y("recording"),v(0),f(a),b(null),x(null),T(null),M(!1),S.current=setInterval(()=>{v(r=>r+1),f(r=>{const e=Math.max(0,r-1);return 0===e&&(N(),k.current&&"recording"===k.current.state&&k.current.stop(),W()),e})},1e3)}catch(r){W();const e=r instanceof DOMException&&("NotAllowedError"===r.name||"PermissionDeniedError"===r.name)?"Vui lòng cấp quyền truy cập microphone trong trình duyệt.":"Không thể truy cập microphone. Vui lòng thử lại.";y("error"),b(e),p.current?.(e)}},[G,a,i.existingAnswerKey,N,W,z,F]),H=t(()=>{N(),k.current&&"recording"===k.current.state&&k.current.stop(),W()},[N,W]),J=t(()=>{N(),W(),k.current&&"recording"===k.current.state&&k.current.stop(),k.current=null,D.current=[],q.current=null,L.current=void 0,B.current=0,F(),T(null),x(null),v(0),f(a),b(null),y("idle"),M(!1)},[N,W,F,a]),Q=t(async()=>{if(i.existingAnswerKey)return y("uploaded"),void x(i.existingAnswerKey);J(),await $()},[i.existingAnswerKey,J,$]),Y=t(async()=>{const r=q.current;r&&(B.current=0,await X(r,L.current,0,C.current||void 0))},[X]);n(()=>{J()},[i.questionId]),n(()=>{"idle"===h&&j&&i.existingAnswerKey&&!R&&(T(j),U.current=j,x(i.existingAnswerKey),y("uploaded"))},[h,j,i.existingAnswerKey,R]),n(()=>(V.current=!0,()=>{V.current=!1,N(),k.current&&"recording"===k.current.state&&k.current.stop(),W(),F()}),[]);return{status:h,remainingSeconds:w,isWarning:w<=5&&"recording"===h,durationSeconds:A,previewUrl:R,uploadedKey:E,error:I,isSupported:G,isAttemptExpired:K,liveTranscript:null,startRecording:$,stopRecording:H,resetRecording:J,reRecord:Q,retryUpload:Y}}
@@ -2,14 +2,12 @@ import type { ComponentType } from 'react';
2
2
  import type { SpeakingLayoutProps, StandardExamLayoutProps, StandardQuestionCardProps } from './types';
3
3
  export * from './cambridge-yle';
4
4
  export * from './english-certification';
5
- export * from './spaceship/SpaceshipLayout';
6
- export * from './spaceship/SpaceshipAudioPlayer';
7
5
  export * from './summer-sky/SummerSkyAudioPlayer';
8
6
  export * from './summer-sky/SummerSkyLayout';
9
7
  export * from './summer-sky/SummerSkySubmitModal';
10
8
  export * from './summer-sky/SummerSkyWaitingRoom';
11
9
  export type * from './types';
12
- export type SpeakingThemeId = 'SPACESHIP' | 'SUMMER_SKY' | string;
10
+ export type SpeakingThemeId = 'SUMMER_SKY' | string;
13
11
  export declare function getSpeakingLayout(themeId?: SpeakingThemeId): ComponentType<SpeakingLayoutProps>;
14
12
  export interface StandardThemeEntry {
15
13
  Layout: ComponentType<StandardExamLayoutProps>;
@@ -1 +1 @@
1
- import{SpaceshipLayout as r}from"./spaceship/SpaceshipLayout";import{SummerSkyLayout as e}from"./summer-sky/SummerSkyLayout";import{CambridgeYleExamLayout as m}from"./cambridge-yle/CambridgeYleExamLayout";import o from"./cambridge-yle/CambridgeYleQuestionCard";export*from"./cambridge-yle";export*from"./english-certification";export*from"./spaceship/SpaceshipLayout";export*from"./spaceship/SpaceshipAudioPlayer";export*from"./summer-sky/SummerSkyAudioPlayer";export*from"./summer-sky/SummerSkyLayout";export*from"./summer-sky/SummerSkySubmitModal";export*from"./summer-sky/SummerSkyWaitingRoom";const t={SPACESHIP:r,SUMMER_SKY:e},a="SUMMER_SKY";export function getSpeakingLayout(r){return t[r||a]||t[a]}const i={CAMBRIDGE_YLE:{Layout:m,QuestionCard:o}},p="CAMBRIDGE_YLE";export function getStandardExamTheme(r){return i[r||p]||i[p]}
1
+ import{SummerSkyLayout as r}from"./summer-sky/SummerSkyLayout";import{CambridgeYleExamLayout as m}from"./cambridge-yle/CambridgeYleExamLayout";import e from"./cambridge-yle/CambridgeYleQuestionCard";export*from"./cambridge-yle";export*from"./english-certification";export*from"./summer-sky/SummerSkyAudioPlayer";export*from"./summer-sky/SummerSkyLayout";export*from"./summer-sky/SummerSkySubmitModal";export*from"./summer-sky/SummerSkyWaitingRoom";const o={SUMMER_SKY:r},t="SUMMER_SKY";export function getSpeakingLayout(r){return o[r||t]||o[t]}const u={CAMBRIDGE_YLE:{Layout:m,QuestionCard:e}},a="CAMBRIDGE_YLE";export function getStandardExamTheme(r){return u[r||a]||u[a]}
@@ -3,8 +3,16 @@ export interface PresignedUrlResponse {
3
3
  key: string;
4
4
  expiresIn?: number;
5
5
  }
6
+ /**
7
+ * Resolve a storage reference to a displayable URL.
8
+ *
9
+ * - Empty/undefined → empty string.
10
+ * - Already a URL (http/https/blob/data) → returned unchanged.
11
+ * - An S3 storage key (e.g. `exams/:id/audio/x.wav`) → resolved to a presigned
12
+ * URL via the host API (`/api/v1/exam-storage/:key`).
13
+ */
6
14
  export declare function usePresignedFileUrl(fileKey: string | undefined): {
7
15
  previewUrl: string;
8
16
  isLoading: boolean;
9
- error: any;
17
+ error: Error;
10
18
  };
@@ -1 +1 @@
1
- import{useMemo as r}from"react";export function usePresignedFileUrl(e){return{previewUrl:r(()=>e||"",[e]),isLoading:!1,error:null}}
1
+ import{useEffect as t,useMemo as r,useState as e}from"react";const n=(process.env.NEXT_PUBLIC_API_URL??"").replace(/\/+$/,"");const s=new Map,i=new Map;export function usePresignedFileUrl(o){const a="string"==typeof o?o:"",l=r(()=>{return a&&((t=a).startsWith("http://")||t.startsWith("https://")||t.startsWith("blob:")||t.startsWith("data:"))?a:"";var t},[a]),[c,u]=e(()=>l||s.get(a)||""),[f,d]=e(!1),[p,g]=e(null);return t(()=>{if(!a||l)return u(l),d(!1),void g(null);const t=s.get(a);if(t)return u(t),d(!1),void g(null);let r=!0;return d(!0),g(null),async function(t){const r=s.get(t);if(r)return r;const e=i.get(t);if(e)return e;const o=(async()=>{if(!n)return t;const r=await fetch(`${n}/api/v1/exam-storage/${encodeURIComponent(t)}`,{credentials:"include"});if(!r.ok)throw new Error(`Failed to resolve file URL (${r.status})`);const e=await r.json(),i="data"in e?e.data?.url:e.url;if(!i)throw new Error("Presigned URL missing in response");return s.set(t,i),i})().finally(()=>{i.delete(t)});return i.set(t,o),o}(a).then(t=>{r&&(u(t),d(!1))}).catch(t=>{r&&(g(t instanceof Error?t:new Error(String(t))),u(""),d(!1))}),()=>{r=!1}},[a,l]),{previewUrl:c,isLoading:f,error:p}}
@@ -42,7 +42,6 @@ export declare enum SkillEnum {
42
42
  export declare enum ExamTemplateTheme {
43
43
  CAMBRIDGE_YLE = "CAMBRIDGE_YLE",
44
44
  FLYER_WOODEN = "FLYER_WOODEN",
45
- SPACESHIP = "SPACESHIP",
46
45
  SUMMER_SKY = "SUMMER_SKY",
47
46
  IELTS_LRW = "IELTS_LRW"
48
47
  }
@@ -1 +1 @@
1
- export var UserRole;!function(E){E.SYSTEM_ADMIN="SYSTEM_ADMIN",E.ADMIN="ADMIN",E.TEACHER="TEACHER",E.STUDENT="STUDENT"}(UserRole||(UserRole={}));export var Gender;!function(E){E.MALE="male",E.FEMALE="female",E.OTHER="other"}(Gender||(Gender={}));export var RoomType;!function(E){E.CONTEST="CONTEST",E.PRACTICE_TEST="PRACTICE_TEST"}(RoomType||(RoomType={}));export var ExamRoomStatus;!function(E){E.SCHEDULED="SCHEDULED",E.IN_PROGRESS="IN_PROGRESS",E.COMPLETED="COMPLETED"}(ExamRoomStatus||(ExamRoomStatus={}));export var StudentSelectionType;!function(E){E.ALL="ALL",E.SPECIFIC="SPECIFIC"}(StudentSelectionType||(StudentSelectionType={}));export var SkillEnum;!function(E){E.LISTENING="LISTENING",E.SPEAKING="SPEAKING",E.READING="READING",E.WRITING="WRITING"}(SkillEnum||(SkillEnum={}));export var ExamTemplateTheme;!function(E){E.CAMBRIDGE_YLE="CAMBRIDGE_YLE",E.FLYER_WOODEN="FLYER_WOODEN",E.SPACESHIP="SPACESHIP",E.SUMMER_SKY="SUMMER_SKY",E.IELTS_LRW="IELTS_LRW"}(ExamTemplateTheme||(ExamTemplateTheme={}));
1
+ export var UserRole;!function(E){E.SYSTEM_ADMIN="SYSTEM_ADMIN",E.ADMIN="ADMIN",E.TEACHER="TEACHER",E.STUDENT="STUDENT"}(UserRole||(UserRole={}));export var Gender;!function(E){E.MALE="male",E.FEMALE="female",E.OTHER="other"}(Gender||(Gender={}));export var RoomType;!function(E){E.CONTEST="CONTEST",E.PRACTICE_TEST="PRACTICE_TEST"}(RoomType||(RoomType={}));export var ExamRoomStatus;!function(E){E.SCHEDULED="SCHEDULED",E.IN_PROGRESS="IN_PROGRESS",E.COMPLETED="COMPLETED"}(ExamRoomStatus||(ExamRoomStatus={}));export var StudentSelectionType;!function(E){E.ALL="ALL",E.SPECIFIC="SPECIFIC"}(StudentSelectionType||(StudentSelectionType={}));export var SkillEnum;!function(E){E.LISTENING="LISTENING",E.SPEAKING="SPEAKING",E.READING="READING",E.WRITING="WRITING"}(SkillEnum||(SkillEnum={}));export var ExamTemplateTheme;!function(E){E.CAMBRIDGE_YLE="CAMBRIDGE_YLE",E.FLYER_WOODEN="FLYER_WOODEN",E.SUMMER_SKY="SUMMER_SKY",E.IELTS_LRW="IELTS_LRW"}(ExamTemplateTheme||(ExamTemplateTheme={}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinyweb_dev/oe-exam-sdk",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Reusable OceanEdu question components.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -21,7 +21,7 @@
21
21
  "build:compile": "tsc -p tsconfig.build.json",
22
22
  "build:alias": "tsc-alias -p tsconfig.build.json",
23
23
  "build:ts": "npm run build:compile && npm run build:assets && npm run build:alias",
24
- "build:assets": "for d in cambridge-yle english-certification summer-sky spaceship; do [ -d src/components/themes/$d/assets ] && cp -R src/components/themes/$d/assets dist/components/themes/$d/ || true; done; [ -d src/components/shared/audio/assets ] && cp -R src/components/shared/audio/assets dist/components/shared/audio/ || true; [ -d src/components/results/report/assets ] && mkdir -p dist/components/results/report && cp -R src/components/results/report/assets dist/components/results/report/ || true; (cd src && find . -name '*.module.css' -exec cp --parents {} ../dist/ \\;); cp src/global.d.ts dist/global.d.ts",
24
+ "build:assets": "for d in cambridge-yle english-certification summer-sky; do [ -d src/components/themes/$d/assets ] && cp -R src/components/themes/$d/assets dist/components/themes/$d/ || true; done; [ -d src/components/shared/audio/assets ] && cp -R src/components/shared/audio/assets dist/components/shared/audio/ || true; [ -d src/components/results/report/assets ] && mkdir -p dist/components/results/report && cp -R src/components/results/report/assets dist/components/results/report/ || true; (cd src && find . -name '*.module.css' -exec cp --parents {} ../dist/ \\;); cp src/global.d.ts dist/global.d.ts",
25
25
  "minify:js": "find dist -name '*.js' -type f -exec sh -c 'for f do terser \"$f\" --compress directives=false --mangle --module --comments false --output \"$f\"; done' sh {} +",
26
26
  "build": "npm run clean && npm run build:ts && npm run minify:js",
27
27
  "pack:local": "npm pack",
@@ -1,8 +0,0 @@
1
- interface SpaceshipAudioPlayerProps {
2
- audioUrl: string;
3
- partName?: string;
4
- onEnded?: () => void;
5
- onPlayingChange?: (isPlaying: boolean) => void;
6
- }
7
- export declare function SpaceshipAudioPlayer({ audioUrl, partName, onEnded, onPlayingChange }: SpaceshipAudioPlayerProps): import("react").JSX.Element;
8
- export {};
@@ -1 +0,0 @@
1
- "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useRef as a,useState as r,useEffect as n}from"react";import s from"next/image";import{Pause as i,Play as l,VolumeX as o}from"lucide-react";import{usePresignedFileUrl as d}from"../../../shared/lib/hooks/usePresignedFileUrl";import c from"./assets/styles/SpaceshipLayout.module.css";import u from"./assets/images/big-blue-badge-sunset.png";import m from"./assets/images/teacher-play-sunset.png";import p from"./assets/images/ic-mute-sunset.png";function v(e){if(isNaN(e)||!isFinite(e))return"0:00";const t=Math.floor(e/60),a=Math.floor(e%60);return`${t}:${String(a).padStart(2,"0")}`}export function SpaceshipAudioPlayer({audioUrl:h,partName:f="Part 1 - Phase 2",onEnded:g,onPlayingChange:N}){const w=a(null),[y,b]=r(!1),[L,E]=r(0),[x,k]=r(0),[C,B]=r(100),{previewUrl:P}=d(h||void 0);n(()=>{const e=w.current;if(!e)return;const t=()=>{e.duration&&!isNaN(e.duration)&&isFinite(e.duration)&&k(e.duration)},a=()=>{E(e.currentTime),t()},r=()=>{b(!0),N?.(!0)},n=()=>{b(!1),N?.(!1)},s=()=>{b(!1),E(0),N?.(!1),g?.()};return t(),e.addEventListener("loadedmetadata",t),e.addEventListener("durationchange",t),e.addEventListener("canplay",t),e.addEventListener("timeupdate",a),e.addEventListener("play",r),e.addEventListener("pause",n),e.addEventListener("ended",s),()=>{e.removeEventListener("loadedmetadata",t),e.removeEventListener("durationchange",t),e.removeEventListener("canplay",t),e.removeEventListener("timeupdate",a),e.removeEventListener("play",r),e.removeEventListener("pause",n),e.removeEventListener("ended",s)}},[P,g]),n(()=>{b(!1),E(0),k(0)},[P]),n(()=>{const e=w.current;if(!e||!P)return;let t=!1;const a=()=>{t||e.play().catch(()=>{if(t)return;const a=()=>{t||(e.play().catch(()=>{}),document.removeEventListener("click",a),document.removeEventListener("keydown",a))};document.addEventListener("click",a,{once:!0}),document.addEventListener("keydown",a,{once:!0})})};return e.readyState>=3?a():e.addEventListener("canplay",a,{once:!0}),()=>{t=!0,e.removeEventListener("canplay",a)}},[P]);const F=x>0?L/x*100:0;return t("div",{className:c.examAudioContainer,children:[e("audio",{ref:w,...P?{src:P}:{},preload:"metadata"}),t("div",{className:c.bigBlueBadge,children:[e(s,{src:u,alt:"Audio Badge",className:c.bigBlueBadgeBg,priority:!0}),e("div",{className:c.audioBarContent,children:t("div",{className:c.audioBarInner,children:[e("span",{className:c.partLabel,children:f}),t("div",{className:c.teacherAvatarContainer,onClick:P?()=>{const e=w.current;e&&(e.paused?e.play().catch(()=>{}):e.pause())}:void 0,children:[e("img",{src:m.src,alt:"Play",className:c.teacherPlayIcon}),e("div",{className:"absolute inset-0 flex items-center justify-center",children:y?e(i,{className:"h-5 w-5 text-white drop-shadow-md",fill:"currentColor"}):e(l,{className:"h-5 w-5 text-white drop-shadow-md ml-1",fill:"currentColor"})})]}),t("div",{className:c.audioControlsWrapper,children:[t("span",{className:c.audioTime,children:[v(L)," / ",v(x)]}),t("div",{className:c.sliderTrack,children:[e("div",{className:c.sliderFill,style:{width:`${F}%`}}),e("input",{type:"range",min:"0",max:x||0,step:"0.1",value:L,onChange:e=>{const t=w.current;if(!t)return;const a=parseFloat(e.target.value);t.currentTime=a,E(a)},className:"absolute inset-0 w-full h-full opacity-0 cursor-pointer disabled:cursor-not-allowed",disabled:!P})]}),t("div",{className:c.volumeContainer,children:[e("div",{className:c.volumeIcon,onClick:()=>{const e=w.current;e&&(C>0?(e.volume=0,B(0)):(e.volume=1,B(100)))},children:0===C?e(o,{className:"text-white w-full h-full"}):e(s,{src:p,alt:"volume",className:"w-full h-full"})}),e("div",{className:"flex-grow items-center flex",style:{width:"60px"},children:e("input",{type:"range",min:"0",max:"100",value:C,onChange:e=>{const t=w.current;if(!t)return;const a=parseFloat(e.target.value);t.volume=a/100,B(a)},className:"w-full h-[3px] appearance-none bg-white/50 rounded cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-2.5 [&::-webkit-slider-thumb]:h-2.5 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white"})})]})]})]})})]})]})}
@@ -1,2 +0,0 @@
1
- import type { SpeakingLayoutProps } from '../types';
2
- export declare function SpaceshipLayout({ onExit, partName, headerRight, onPrev, onNext, canGoPrev, canGoNext, audioUrl, onAudioEnded, recorder, children, contentClassName, hideAudioBar, onAudioPlayingChange, }: SpeakingLayoutProps): import("react").JSX.Element;
@@ -1 +0,0 @@
1
- "use client";import{jsx as e,jsxs as t,Fragment as s}from"react/jsx-runtime";import a from"next/image";import r from"./assets/styles/SpaceshipLayout.module.css";import{SpaceshipAudioPlayer as i}from"./SpaceshipAudioPlayer";import n from"./assets/images/circle-btn-right-sunset.png";import l from"./assets/images/circle-btn-sunset.png";import c from"./assets/images/next-sunset.png";import o from"./assets/images/X-sunset.png";import m from"./assets/images/button_feedback_vi.png";import d from"./assets/images/blue-wrapper-sunset.png";import p from"./assets/images/timer-badge.png";import h from"./assets/images/micro.png";export function SpaceshipLayout({onExit:g,partName:u,headerRight:f,onPrev:x,onNext:v,canGoPrev:N,canGoNext:b,audioUrl:y,onAudioEnded:B,recorder:w,children:C,contentClassName:S="",hideAudioBar:k,onAudioPlayingChange:I}){return t("div",{id:"exam-main-scroll-area",className:r.pageContainer,children:[e("div",{className:r.examContainer,children:t("div",{className:r.examMainBoard,children:[e("div",{className:r.headerTitleWrapper,children:e("div",{className:r.exitButtonWrapper,children:t("div",{className:r.circleBtn,tabIndex:0,onClick:g,children:[e(a,{src:n,alt:"btn",className:r.circleBtnBg}),e("div",{className:r.circleBtnInner,children:e(a,{src:o,alt:"X",className:r.exitIcon})})]})})}),N&&e("div",{className:r.controlLeft,children:t("div",{className:r.circleBtn,onClick:x,children:[e(a,{src:n,alt:"btn",className:r.circleBtnBg}),e("div",{className:r.circleBtnInner,children:e(a,{src:c,alt:"prev",className:`${r.nextPrevIcon} ${r.rotate}`})})]})}),t("div",{className:r.examContentMainContainer,children:[!k&&e(i,{audioUrl:y,partName:u,onEnded:B,onPlayingChange:I}),t("div",{className:r.examContentSpace,children:[f&&e("div",{className:"absolute top-2 right-6 z-50",children:f}),e("div",{className:`w-full h-full flex flex-col items-center justify-center ${S}`,children:C})]}),w&&t(s,{children:[e("p",{className:"absolute left-1/2 -translate-x-1/2 text-center whitespace-nowrap text-black font-bold m-0",style:{bottom:"115px",fontSize:"16px",fontFamily:'"Open Sans", sans-serif'},children:"uploaded"===w.status?"Đã ghi nhận câu trả lời":"Ấn biểu tượng micro để trả lời"}),e("div",{className:`absolute left-1/2 -translate-x-1/2 flex flex-col items-center z-10 transition-transform ${"recording"===w.status?"scale-[1.05]":"hover:scale-[1.02] active:scale-[0.98]"} ${"uploaded"===w.status?"opacity-80 grayscale-[20%] pointer-events-none":""}`,style:{bottom:"-40px",overflow:"visible"},children:t("div",{className:"block relative",style:{overflow:"visible"},children:[e(a,{src:d,alt:"wrapper",className:"z-0 "+("recording"===w.status?"animate-pulse":""),style:{width:"158px",height:"116px"}}),"uploaded"!==w.status&&t("div",{className:"absolute left-1/2 -translate-x-1/2 z-20",style:{top:"-32px"},children:[e(a,{src:p,alt:"timer",style:{width:"104px",height:"45px"}}),e("div",{className:"absolute inset-0 flex items-center justify-center",children:t("p",{className:"text-white text-center text-[20px] font-normal m-0",style:{margin:0},children:[Math.floor(w.remainingSeconds/60),":",(w.remainingSeconds%60).toString().padStart(2,"0")]})})]}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:e(a,{src:h,alt:"micro",className:"cursor-pointer "+("recording"===w.status?"drop-shadow-[0_0_15px_rgba(0,255,255,0.8)]":""),style:{width:"51px",height:"51px"},onClick:"recording"===w.status?w.stopRecording:"idle"===w.status||"error"===w.status?w.startRecording:void 0})})]})})]})]}),b&&e("div",{className:r.controlRight,children:t("div",{className:r.circleBtn,onClick:v,children:[e(a,{src:l,alt:"btn",className:r.circleBtnBg}),e("div",{className:r.circleBtnInner,children:e(a,{src:c,alt:"next",className:r.nextPrevIcon})})]})})]})}),e("div",{className:r.feedbackButton,children:e("a",{target:"_blank",href:"https://forms.gle/DxdZqfgSirYzf1vW8",rel:"noopener noreferrer",children:e(a,{alt:"feedback",src:m})})})]})}