@tinyweb_dev/oe-exam-sdk 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/api/exam-entry.d.ts +1 -1
  2. package/dist/api/exam-entry.types.d.ts +14 -0
  3. package/dist/api/exam-taking.types.d.ts +2 -0
  4. package/dist/components/exams/entry/StudentExamEntryPageContainer.d.ts +4 -2
  5. package/dist/components/exams/entry/StudentExamEntryPageContainer.js +1 -1
  6. package/dist/components/exams/take/ExamTakingPageContainer.d.ts +4 -2
  7. package/dist/components/exams/take/ExamTakingPageContainer.js +1 -1
  8. package/dist/components/exams/take/components/question-renderers/MoversWritingRenderer.js +1 -1
  9. package/dist/components/exams/take/exam-taking.utils.d.ts +8 -2
  10. package/dist/components/exams/take/exam-taking.utils.js +1 -1
  11. package/dist/components/exams/take/utils/question-transformers.d.ts +4 -0
  12. package/dist/components/exams/take/utils/question-transformers.js +1 -1
  13. package/dist/components/features/exam-entry/themed/CambridgeYleWaitingRoom.js +1 -1
  14. package/dist/components/features/exam-entry/themed/cambridge-yle-waiting-parts.d.ts +18 -0
  15. package/dist/components/features/exam-entry/themed/cambridge-yle-waiting-parts.js +1 -0
  16. package/dist/components/features/exam-entry/themed/index.d.ts +3 -0
  17. package/dist/components/features/exam-entry/themed/index.js +1 -1
  18. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +1 -1
  19. package/dist/components/results/ResultReviewPageContainer.js +1 -1
  20. package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.d.ts +2 -0
  21. package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.js +1 -1
  22. package/dist/components/themes/english-certification/EcAnswerTheQuestion.js +1 -1
  23. package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +1 -1
  24. package/dist/components/themes/english-certification/EcWordFillParagraph.js +1 -1
  25. package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -1
  26. package/dist/components/themes/english-certification/EcWritingTask.js +1 -1
  27. package/dist/components/themes/english-certification/EnglishCertificationExamLayout.js +1 -1
  28. package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +1 -1
  29. package/dist/components/themes/english-certification/EnglishCertificationInstructionBanner.d.ts +17 -0
  30. package/dist/components/themes/english-certification/EnglishCertificationInstructionBanner.js +1 -0
  31. package/dist/components/themes/english-certification/EnglishCertificationPartHeader.d.ts +24 -0
  32. package/dist/components/themes/english-certification/EnglishCertificationPartHeader.js +1 -0
  33. package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.d.ts +3 -1
  34. package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +1 -1
  35. package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -1
  36. package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +1 -1
  37. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.d.ts +0 -2
  38. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +1 -1
  39. package/dist/components/themes/english-certification/english-cert-scroll.d.ts +32 -0
  40. package/dist/components/themes/english-certification/english-cert-scroll.js +1 -0
  41. package/dist/components/themes/english-certification/index.d.ts +4 -1
  42. package/dist/components/themes/english-certification/index.js +1 -1
  43. package/dist/shared/lib/html-content.d.ts +14 -0
  44. package/dist/shared/lib/html-content.js +1 -0
  45. package/dist/shared/types/exam-taking.types.d.ts +2 -0
  46. package/dist/shared/types/student.types.d.ts +14 -0
  47. package/package.json +1 -1
@@ -1 +1,4 @@
1
1
  export { ThemedWaitingRoom } from './ThemedWaitingRoom';
2
+ export { CambridgeYleWaitingRoom } from './CambridgeYleWaitingRoom';
3
+ export { PartRow, groupPartsByCategory } from './cambridge-yle-waiting-parts';
4
+ export type { PartCategoryGroup } from './cambridge-yle-waiting-parts';
@@ -1 +1 @@
1
- export{ThemedWaitingRoom}from"./ThemedWaitingRoom";
1
+ export{ThemedWaitingRoom}from"./ThemedWaitingRoom";export{CambridgeYleWaitingRoom}from"./CambridgeYleWaitingRoom";export{PartRow,groupPartsByCategory}from"./cambridge-yle-waiting-parts";
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as r,Fragment as t}from"react/jsx-runtime";import{useState as a,useEffect as s,useMemo as i}from"react";import{Textarea as d}from"../../../../components/ui/textarea";import{cn as l}from"../../../../shared/lib/utils";import{FileText as n,PenLine as o,Check as c,AlertCircle as m,BookOpen as g,Lightbulb as h,ImageIcon as b}from"lucide-react";import{usePresignedFileUrl as x}from"../../../../shared/lib/hooks/usePresignedFileUrl";function f({imageKey:t}){const{previewUrl:a}=x(t);return e("div",a?{className:"mx-auto w-full max-w-sm overflow-hidden rounded-lg border border-gray-200 bg-white shadow-sm",children:e("img",{src:a,alt:"Ảnh hướng dẫn",className:"h-auto w-full object-contain",onError:e=>{e.target.src="/images/placeholder-image.svg"}})}:{className:"flex aspect-[4/3] w-full items-center justify-center rounded-lg border border-gray-200 bg-gray-50",children:r("div",{className:"flex flex-col items-center gap-2 text-gray-400",children:[e(b,{className:"h-8 w-8"}),e("span",{className:"text-xs",children:"Đang tải..."})]})})}export function WriteAShortLetterClient({questionData:x,onSubmit:u,isReviewMode:p=!1,userAnswer:w,explanation:v}){const{informations:N,minWords:y,maxWords:j,instructions:k,guideImages:B}=x,$=k?.mainInstruction||"",[C,T]=a("string"==typeof w?w:"");s(()=>{void 0!==w&&"string"==typeof w&&T(w)},[w]);const M=i(()=>{const e="string"==typeof C?C:"";return e.trim()?e.trim().split(/\s+/).filter(e=>e.length>0).length:0},[C]),W=i(()=>!(M<y)&&!(j&&M>j),[M,y,j]),q=i(()=>j&&M>j,[M,j]),A=i(()=>{const e=y;return Math.min(M/e*100,100)},[M,y]);return r("div",{className:"space-y-5",children:[$&&e("div",{className:"overflow-hidden rounded-xl border border-blue-200 bg-gradient-to-r from-blue-50 to-indigo-50 shadow-sm",children:r("div",{className:"flex items-center gap-3 px-5 py-4",children:[e("div",{className:"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-blue-500 to-indigo-600 text-white shadow-sm",children:e(g,{className:"h-5 w-5"})}),r("div",{children:[e("h3",{className:"text-sm font-semibold text-blue-900",children:"Hướng dẫn"}),e("p",{className:"text-sm text-blue-700",children:$})]})]})}),B&&B.length>0&&r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center gap-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-5 py-3",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-violet-500 to-purple-600 text-white shadow-sm",children:e(b,{className:"h-4 w-4"})}),e("span",{className:"text-sm font-medium text-gray-700",children:"Ảnh hướng dẫn"})]}),e("div",{className:"p-5",children:e("div",{className:"flex flex-col gap-4",children:B.map((r,t)=>e(f,{imageKey:r},`${r}-${t}`))})})]}),N&&N.filter(e=>e?.trim()).length>0&&r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center gap-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-5 py-3",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-emerald-500 to-teal-600 text-white shadow-sm",children:e(n,{className:"h-4 w-4"})}),r("span",{className:"text-sm font-medium text-gray-700",children:["Thông tin cần bao gồm (",N.length,")"]})]}),e("div",{className:"p-5",children:e("div",{className:"space-y-3",children:N.filter(e=>e?.trim()).map((t,a)=>r("div",{className:"flex items-start gap-3 rounded-lg border border-gray-100 bg-gradient-to-r from-white to-gray-50 p-3 transition-all hover:border-gray-200 hover:shadow-sm",children:[e("div",{className:"flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-gradient-to-br from-emerald-400 to-teal-500 text-xs font-bold text-white shadow-sm",children:a+1}),e("p",{className:"text-sm text-gray-700 leading-relaxed pt-0.5",children:t})]},a))})})]}),r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-5 py-3",children:[r("div",{className:"flex items-center gap-3",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-purple-500 to-violet-600 text-white shadow-sm",children:e(o,{className:"h-4 w-4"})}),e("span",{className:"text-sm font-medium text-gray-700",children:"Viết thư của bạn"})]}),r("div",{className:l("flex items-center gap-2 rounded-full px-3 py-1.5 text-xs font-semibold transition-all",q?"bg-red-100 text-red-700":W?"bg-green-100 text-green-700":"bg-amber-100 text-amber-700"),children:[W&&!q&&e(c,{className:"h-3.5 w-3.5"}),q&&e(m,{className:"h-3.5 w-3.5"}),r("span",{children:[M," / ",y,j?` - ${j}`:"+"," từ"]})]})]}),r("div",{className:"p-5 space-y-4",children:[!p&&r("div",{className:"space-y-2",children:[r("div",{className:"flex items-center justify-between text-xs text-gray-500",children:[e("span",{children:"Tiến độ viết"}),r("span",{children:[Math.round(A),"%"]})]}),e("div",{className:"h-2 w-full overflow-hidden rounded-full bg-gray-100",children:e("div",{className:l("h-full transition-all duration-300 ease-out rounded-full",q?"bg-gradient-to-r from-red-400 to-rose-500":W?"bg-gradient-to-r from-green-400 to-emerald-500":"bg-gradient-to-r from-amber-400 to-orange-500"),style:{width:`${A}%`}})})]}),r("div",{className:"relative",children:[e(d,{id:"writing-answer",value:C,onChange:e=>{return r=e.target.value,void(p||(T(r),u?.(r)));var r},placeholder:"Bắt đầu viết thư của bạn tại đây...",className:l("min-h-[280px] resize-none rounded-xl border-2 p-4 text-base leading-relaxed transition-all","focus:ring-2 focus:ring-offset-1",p?"bg-gray-50 cursor-not-allowed":"bg-white hover:border-gray-300",q?"border-red-300 focus:border-red-400 focus:ring-red-100":W?"border-green-300 focus:border-green-400 focus:ring-green-100":"border-gray-200 focus:border-purple-400 focus:ring-purple-100"),rows:12,disabled:p}),e("div",{className:"absolute bottom-3 right-3 pointer-events-none",children:e("div",{className:"flex items-center gap-1 text-gray-300",children:e(o,{className:"h-4 w-4"})})})]}),!p&&e("div",{className:l("rounded-xl border p-4 transition-all",q?"border-red-200 bg-gradient-to-r from-red-50 to-rose-50":W?"border-green-200 bg-gradient-to-r from-green-50 to-emerald-50":"border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50"),children:r("div",{className:"flex items-start gap-3",children:[e("div",{className:l("flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg text-white shadow-sm",q?"bg-gradient-to-br from-red-500 to-rose-600":W?"bg-gradient-to-br from-green-500 to-emerald-600":"bg-gradient-to-br from-amber-500 to-orange-600"),children:e(q?m:W?c:m,{className:"h-4 w-4"})}),r("div",{className:"flex-1",children:[e("p",{className:l("text-sm font-semibold",q?"text-red-800":W?"text-green-800":"text-amber-800"),children:q?"Vượt quá số từ cho phép!":W?"Tuyệt vời! Đã đủ số từ yêu cầu":"Chưa đủ số từ yêu cầu"}),e("p",{className:l("text-xs mt-0.5",q?"text-red-600":W?"text-green-600":"text-amber-600"),children:r(t,q?{children:["Bạn đã viết ",M," từ. Tối đa ",j," từ."]}:W?{children:["Bạn đã viết ",M," từ. Yêu cầu: ",y,j?` - ${j}`:"+"," từ."]}:{children:["Bạn đã viết ",M," từ. Cần ít nhất ",y," từ."]})})]})]})}),p&&C&&r("div",{className:"rounded-xl border border-gray-200 bg-gradient-to-r from-slate-50 to-gray-50 p-4",children:[r("div",{className:"flex items-center gap-2 mb-3 pb-3 border-b border-gray-200",children:[e("div",{className:"flex h-6 w-6 items-center justify-center rounded-lg bg-gray-200",children:e(n,{className:"h-3.5 w-3.5 text-gray-600"})}),e("span",{className:"text-sm font-medium text-gray-600",children:"Bài viết đã nộp"}),r("span",{className:l("ml-auto text-xs font-semibold px-2 py-1 rounded-full",W?"bg-green-100 text-green-700":"bg-amber-100 text-amber-700"),children:[M," từ"]})]}),e("p",{className:"text-sm text-gray-700 whitespace-pre-wrap leading-relaxed",children:C})]}),p&&v&&e("div",{className:"rounded-xl bg-gradient-to-r from-blue-50 to-indigo-50 p-4 border border-blue-200",children:r("div",{className:"flex items-start gap-3",children:[e("div",{className:"flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-blue-500 text-white",children:e(h,{className:"h-3.5 w-3.5"})}),r("div",{className:"flex-1",children:[e("span",{className:"text-xs font-semibold text-blue-700 uppercase tracking-wider",children:"Giải thích"}),e("p",{className:"mt-1 text-sm text-gray-700 leading-relaxed",children:v})]})]})})]})]})]})}
1
+ "use client";import{jsx as e,jsxs as r,Fragment as t}from"react/jsx-runtime";import{useState as a,useEffect as s,useMemo as i}from"react";import{Textarea as d}from"../../../../components/ui/textarea";import{cn as l}from"../../../../shared/lib/utils";import{HtmlOrText as n}from"../../../../shared/lib/html-content";import{FileText as o,PenLine as m,Check as c,AlertCircle as g,BookOpen as h,Lightbulb as b,ImageIcon as x}from"lucide-react";import{usePresignedFileUrl as f}from"../../../../shared/lib/hooks/usePresignedFileUrl";function u({imageKey:t}){const{previewUrl:a}=f(t);return e("div",a?{className:"mx-auto w-full max-w-sm overflow-hidden rounded-lg border border-gray-200 bg-white shadow-sm",children:e("img",{src:a,alt:"Ảnh hướng dẫn",className:"h-auto w-full object-contain",onError:e=>{e.target.src="/images/placeholder-image.svg"}})}:{className:"flex aspect-[4/3] w-full items-center justify-center rounded-lg border border-gray-200 bg-gray-50",children:r("div",{className:"flex flex-col items-center gap-2 text-gray-400",children:[e(x,{className:"h-8 w-8"}),e("span",{className:"text-xs",children:"Đang tải..."})]})})}export function WriteAShortLetterClient({questionData:f,onSubmit:p,isReviewMode:v=!1,userAnswer:w,explanation:N}){const{informations:y,minWords:j,maxWords:k,instructions:B,guideImages:$}=f,C=B?.mainInstruction||"",[T,M]=a("string"==typeof w?w:"");s(()=>{void 0!==w&&"string"==typeof w&&M(w)},[w]);const W=i(()=>{const e="string"==typeof T?T:"";return e.trim()?e.trim().split(/\s+/).filter(e=>e.length>0).length:0},[T]),q=i(()=>!(W<j)&&!(k&&W>k),[W,j,k]),A=i(()=>k&&W>k,[W,k]),F=i(()=>{const e=j;return Math.min(W/e*100,100)},[W,j]);return r("div",{className:"space-y-5",children:[C&&e("div",{className:"overflow-hidden rounded-xl border border-blue-200 bg-gradient-to-r from-blue-50 to-indigo-50 shadow-sm",children:r("div",{className:"flex items-center gap-3 px-5 py-4",children:[e("div",{className:"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-blue-500 to-indigo-600 text-white shadow-sm",children:e(h,{className:"h-5 w-5"})}),r("div",{children:[e("h3",{className:"text-sm font-semibold text-blue-900",children:"Hướng dẫn"}),e(n,{value:C,className:"text-sm text-blue-700"})]})]})}),$&&$.length>0&&r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center gap-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-5 py-3",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-violet-500 to-purple-600 text-white shadow-sm",children:e(x,{className:"h-4 w-4"})}),e("span",{className:"text-sm font-medium text-gray-700",children:"Ảnh hướng dẫn"})]}),e("div",{className:"p-5",children:e("div",{className:"flex flex-col gap-4",children:$.map((r,t)=>e(u,{imageKey:r},`${r}-${t}`))})})]}),y&&y.filter(e=>e?.trim()).length>0&&r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center gap-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-5 py-3",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-emerald-500 to-teal-600 text-white shadow-sm",children:e(o,{className:"h-4 w-4"})}),r("span",{className:"text-sm font-medium text-gray-700",children:["Thông tin cần bao gồm (",y.length,")"]})]}),e("div",{className:"p-5",children:e("div",{className:"space-y-3",children:y.filter(e=>e?.trim()).map((t,a)=>r("div",{className:"flex items-start gap-3 rounded-lg border border-gray-100 bg-gradient-to-r from-white to-gray-50 p-3 transition-all hover:border-gray-200 hover:shadow-sm",children:[e("div",{className:"flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-gradient-to-br from-emerald-400 to-teal-500 text-xs font-bold text-white shadow-sm",children:a+1}),e(n,{value:t,className:"text-sm text-gray-700 leading-relaxed pt-0.5"})]},a))})})]}),r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-5 py-3",children:[r("div",{className:"flex items-center gap-3",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-purple-500 to-violet-600 text-white shadow-sm",children:e(m,{className:"h-4 w-4"})}),e("span",{className:"text-sm font-medium text-gray-700",children:"Viết thư của bạn"})]}),r("div",{className:l("flex items-center gap-2 rounded-full px-3 py-1.5 text-xs font-semibold transition-all",A?"bg-red-100 text-red-700":q?"bg-green-100 text-green-700":"bg-amber-100 text-amber-700"),children:[q&&!A&&e(c,{className:"h-3.5 w-3.5"}),A&&e(g,{className:"h-3.5 w-3.5"}),r("span",{children:[W," / ",j,k?` - ${k}`:"+"," từ"]})]})]}),r("div",{className:"p-5 space-y-4",children:[!v&&r("div",{className:"space-y-2",children:[r("div",{className:"flex items-center justify-between text-xs text-gray-500",children:[e("span",{children:"Tiến độ viết"}),r("span",{children:[Math.round(F),"%"]})]}),e("div",{className:"h-2 w-full overflow-hidden rounded-full bg-gray-100",children:e("div",{className:l("h-full transition-all duration-300 ease-out rounded-full",A?"bg-gradient-to-r from-red-400 to-rose-500":q?"bg-gradient-to-r from-green-400 to-emerald-500":"bg-gradient-to-r from-amber-400 to-orange-500"),style:{width:`${F}%`}})})]}),r("div",{className:"relative",children:[e(d,{id:"writing-answer",value:T,onChange:e=>{return r=e.target.value,void(v||(M(r),p?.(r)));var r},placeholder:"Bắt đầu viết thư của bạn tại đây...",className:l("min-h-[280px] resize-none rounded-xl border-2 p-4 text-base leading-relaxed transition-all","focus:ring-2 focus:ring-offset-1",v?"bg-gray-50 cursor-not-allowed":"bg-white hover:border-gray-300",A?"border-red-300 focus:border-red-400 focus:ring-red-100":q?"border-green-300 focus:border-green-400 focus:ring-green-100":"border-gray-200 focus:border-purple-400 focus:ring-purple-100"),rows:12,disabled:v}),e("div",{className:"absolute bottom-3 right-3 pointer-events-none",children:e("div",{className:"flex items-center gap-1 text-gray-300",children:e(m,{className:"h-4 w-4"})})})]}),!v&&e("div",{className:l("rounded-xl border p-4 transition-all",A?"border-red-200 bg-gradient-to-r from-red-50 to-rose-50":q?"border-green-200 bg-gradient-to-r from-green-50 to-emerald-50":"border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50"),children:r("div",{className:"flex items-start gap-3",children:[e("div",{className:l("flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg text-white shadow-sm",A?"bg-gradient-to-br from-red-500 to-rose-600":q?"bg-gradient-to-br from-green-500 to-emerald-600":"bg-gradient-to-br from-amber-500 to-orange-600"),children:e(A?g:q?c:g,{className:"h-4 w-4"})}),r("div",{className:"flex-1",children:[e("p",{className:l("text-sm font-semibold",A?"text-red-800":q?"text-green-800":"text-amber-800"),children:A?"Vượt quá số từ cho phép!":q?"Tuyệt vời! Đã đủ số từ yêu cầu":"Chưa đủ số từ yêu cầu"}),e("p",{className:l("text-xs mt-0.5",A?"text-red-600":q?"text-green-600":"text-amber-600"),children:r(t,A?{children:["Bạn đã viết ",W," từ. Tối đa ",k," từ."]}:q?{children:["Bạn đã viết ",W," từ. Yêu cầu: ",j,k?` - ${k}`:"+"," từ."]}:{children:["Bạn đã viết ",W," từ. Cần ít nhất ",j," từ."]})})]})]})}),v&&T&&r("div",{className:"rounded-xl border border-gray-200 bg-gradient-to-r from-slate-50 to-gray-50 p-4",children:[r("div",{className:"flex items-center gap-2 mb-3 pb-3 border-b border-gray-200",children:[e("div",{className:"flex h-6 w-6 items-center justify-center rounded-lg bg-gray-200",children:e(o,{className:"h-3.5 w-3.5 text-gray-600"})}),e("span",{className:"text-sm font-medium text-gray-600",children:"Bài viết đã nộp"}),r("span",{className:l("ml-auto text-xs font-semibold px-2 py-1 rounded-full",q?"bg-green-100 text-green-700":"bg-amber-100 text-amber-700"),children:[W," từ"]})]}),e("p",{className:"text-sm text-gray-700 whitespace-pre-wrap leading-relaxed",children:T})]}),v&&N&&e("div",{className:"rounded-xl bg-gradient-to-r from-blue-50 to-indigo-50 p-4 border border-blue-200",children:r("div",{className:"flex items-start gap-3",children:[e("div",{className:"flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-blue-500 text-white",children:e(b,{className:"h-3.5 w-3.5"})}),r("div",{className:"flex-1",children:[e("span",{className:"text-xs font-semibold text-blue-700 uppercase tracking-wider",children:"Giải thích"}),e("p",{className:"mt-1 text-sm text-gray-700 leading-relaxed",children:N})]})]})})]})]})]})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,Fragment as t,jsxs as r}from"react/jsx-runtime";import{useCallback as n,useEffect as o,useMemo as i,useState as a}from"react";import{ChevronLeft as s,Download as l,Loader2 as c,Sparkles as d}from"lucide-react";import{ResultTemplateType as m}from"../../api/result-review";import{useToast as u}from"../../shared/lib/hooks/useToast";import{ReviewQuestionRenderer as p}from"./ReviewQuestionRenderer";import{useResultReviewPolling as f}from"./hooks/useResultReviewPolling";import{BadgeTitle as g}from"./report/BadgeTitle";import{OceanEduExamReport as x}from"./report/OceanEduExamReport";import{OverallAssessmentSection as h}from"./report/OverallAssessmentSection";import{ResultErrorState as b}from"./report/ResultErrorState";import{ResultLoadingState as w}from"./report/ResultLoadingState";import{ResultNotPublicState as S}from"./report/ResultNotPublicState";import{SpeakingRubricSection as v}from"./report/SpeakingRubricSection";import{SpeakingReviewResult as N}from"./speaking/SpeakingReviewResult";import{transformResultAnswersForReview as R}from"./review-data";import{isResultNotPublic as P,setPdfReady as k}from"./review-status.utils";import{unwrap as E}from"./result-review.utils";import{formatTotalScore as y}from"./utils/review-score.utils";import{transformSpeakingResultForReview as A}from"./utils/transform-speaking-review";export var PartRubricTemplateCode;!function(e){e.KINDY_VER3="PLACEMENT_TEST_KINDY_VER3",e.PRESCHOOL="PLACEMENT_TEST_PRESCHOOL"}(PartRubricTemplateCode||(PartRubricTemplateCode={}));const T=new Set(Object.values(PartRubricTemplateCode));export function ResultReviewPageContainer({attemptId:s,token:l,api:c,isPrintMode:d=!1,canExportPdf:p=!1,reviewUrl:g,assetBaseUrl:y,loginHref:B,onBack:U,onNavigate:F,topActionsSlot:O,beforeReportSlot:I,afterReportSlot:_}){const{error:j,success:Q}=u(),[$,M]=a(null),[H,G]=a(null),[K,V]=a(!0),[q,W]=a(null),[X,Y]=a(!1),z=n(async e=>{e&&V(!0);try{const[e,t]=await Promise.all([c.getDetailedResult(s,l),c.getAttempt?.(s,l)]);M(E(e)),G(t?E(t):null),W(null)}catch(e){W(e),P(e,Boolean(l))||j({message:"Không thể tải kết quả",description:e instanceof Error?e.message:void 0})}finally{e&&V(!1)}},[c,s,l,j]);o(()=>{z(!0)},[z]);const J=n(()=>{z(!1)},[z]),{hasPendingQuestions:Z,hasPendingLlm:ee,hasFailedLlm:te,retryLlm:re}=f({detail:$,isPrintMode:d,isLoading:K,onRefetch:J});o(()=>{if(!d||K)return;const e=requestAnimationFrame(()=>k(!0));return()=>{cancelAnimationFrame(e),k(!1)}},[d,K]);const ne=H?.exam?.template,oe=ne?.parts,ie=H?.studentName??"Học sinh",ae=H?.studentUsername??null,se=H?.branchName??"Chưa tham gia chi nhánh",le=function(e){const t=e?new Date(e):new Date;return Number.isNaN(t.getTime())?(new Date).toLocaleDateString("vi-VN"):t.toLocaleDateString("vi-VN")}($?.submittedAt),ce=i(()=>function(e,t){const r=e??("undefined"!=typeof window?window.location.href:void 0);if(!r||!t)return r;try{const e=new URL(r,"undefined"!=typeof window?window.location.origin:void 0);return e.searchParams.set("token",t),e.toString()}catch{return r}}(g,l??H?.verificationToken),[g,l,H?.verificationToken]),de=i(()=>R($?.answers??[],oe),[$?.answers,oe]),me=i(()=>$&&ne?.type===m.SPEAKING?A($,ie,oe):null,[$,ie,ne?.type,oe]),ue=!!$?.templateCode&&T.has($.templateCode),pe=i(()=>function(e){const t={};return e?.speakingRubric?.criteria?.forEach(e=>{const r=/^C(\d+)$/.exec(e.code);if(!r)return;const n=null!=e.weightedScore&&null!=e.maxScore;t[Number(r[1])]=n?{score:e.weightedScore,maxScore:e.maxScore,weighted:n}:{score:e.score,maxScore:5,weighted:n}}),t}($),[$?.speakingRubric]),fe=n(()=>{if(U)return U();F?F(H?.contestId?`/student/contests/${H.contestId}/rooms`:"/student/results"):"undefined"!=typeof window&&window.history.back()},[H?.contestId,U,F]),ge=async()=>{if($&&c.exportPdf){Y(!0);try{const{blob:e,filename:t}=await c.exportPdf(s,ne?.type);!function(e,t){const r=URL.createObjectURL(e),n=document.createElement("a");n.href=r,n.download=t,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(r)}(e,t),Q({message:"Xuất PDF thành công"})}catch(e){j({message:"Không xuất được PDF",description:e instanceof Error?e.message:void 0})}finally{Y(!1)}}};return K?e(w,{}):P(q,Boolean(l))?e(S,{loginHref:B,assetBaseUrl:y,onLogin:F}):$?me?e(N,{reviewData:me,studentName:ie,studentCode:ae,branchName:se,examDateText:le,examTitle:ne?.title,showDetailedResults:$.showDetailedResults,speakingRubric:$.speakingRubric,reviewUrl:ce,assetBaseUrl:y,canExportPdf:p&&Boolean(c.exportPdf),isExporting:X,hasPendingQuestions:Z,onBack:fe,onExportPdf:ge,topActionsSlot:O,beforeReportSlot:I,afterReportSlot:_}):e("div",{className:"min-h-screen bg-[#e0e0e0] py-4 md:py-6",children:r("div",{className:"mx-auto flex w-full max-w-[1160px] flex-col gap-4 px-0 sm:px-4",children:[e(D,{onBack:fe,onExport:ge,canExport:p&&Boolean(c.exportPdf),isExporting:X,topActionsSlot:O}),Z?e(L,{}):null,I,e(x,{studentName:ie,studentCode:ae,branchName:se,examDateText:le,totalScore:$.totalScore,maxScore:$.maxScore,isPendingGrading:Boolean($.isPendingGrading||Z),examSubTitle:$.roomName,examTitle:ne?.title,reviewUrl:ce,assetBaseUrl:y,readingScore:$.readingScore,maxReadingScore:$.maxReadingScore,listeningScore:$.listeningScore,maxListeningScore:$.maxListeningScore,writingScore:$.writingScore,maxWritingScore:$.maxWritingScore,speakingScore:$.speakingScore,maxSpeakingScore:$.maxSpeakingScore,overallAssessmentSlot:r(t,{children:[e(h,{isPending:ee,isFailed:te,onRetry:re,llmOverallAssessment:$.llmOverallAssessment,llmSkillAssessment:$.llmSkillAssessment,correctAnswers:$.correctAnswers,totalQuestions:$.totalQuestions}),$.speakingRubric?.criteria?.length?e(v,{rubric:$.speakingRubric}):null]}),children:!1!==$.showDetailedResults?e(C,{reviewData:de,hidePerQuestionGrading:ue,rubricScores:pe}):null}),_]})}):e(b,{error:q,onBack:fe})}function D({onBack:t,onExport:n,canExport:o,isExporting:i,topActionsSlot:a}){return r("div",{className:"flex items-center justify-between gap-3 px-3 print:hidden sm:px-0",children:[r("button",{type:"button",onClick:t,className:"inline-flex items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-sm font-semibold text-slate-700 shadow-sm transition hover:bg-slate-50",children:[e(s,{className:"h-4 w-4"}),"Quay lại"]}),r("div",{className:"flex items-center gap-3",children:[o?r("button",{type:"button",onClick:()=>{n()},disabled:i,className:"inline-flex items-center gap-2 rounded-xl bg-gradient-to-r from-[#00AEEF] to-[#0099D6] px-5 py-2.5 text-sm font-bold text-white shadow-lg disabled:opacity-50",children:[i?e(c,{className:"h-4 w-4 animate-spin"}):e(l,{className:"h-4 w-4"}),i?"Đang xuất...":"Xuất PDF"]}):null,a]})]})}function L(){return r("div",{className:"mx-3 flex items-center gap-3 rounded-2xl border border-[#b3dfff] bg-gradient-to-r from-[#e8f6ff] to-[#f0f8ff] px-5 py-4 shadow-sm sm:mx-0",children:[e("div",{className:"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[#d0edff]",children:e(d,{className:"h-5 w-5 animate-pulse text-[#00AEEF]"})}),r("div",{children:[e("p",{className:"text-sm font-bold text-[#0054A6]",children:"AI đang chấm điểm..."}),e("p",{className:"text-xs text-[#0078c8]",children:"Trang sẽ tự động cập nhật cho đến khi hoàn tất."})]})]})}function C({reviewData:t,hidePerQuestionGrading:n,rubricScores:o}){return e("div",{className:"space-y-6",children:t.parts.map((i,a)=>{const s=n?o[i.partNo]:void 0,l=t.partScoresMap[a],c=s?`${s.weighted?Number(s.score.toFixed(1)):Math.round(s.score)} / ${Math.round(s.maxScore)}`:l?`${y(l.score)} / ${y(l.maxScore)}`:null;return r("section",{className:"relative rounded-[20px] border-2 border-[#00AEEF] bg-white px-5 pb-6 pt-11 md:px-8",children:[e(g,{number:String(i.partNo),title:i.name||`PHẦN ${i.partNo}`}),r("div",{className:"mb-6 flex flex-col gap-4",children:[c?e("div",{className:"flex justify-end",children:r("div",{className:"rounded-full bg-[#0054A6] px-4 py-2 text-sm font-bold text-white",children:["Điểm: ",c]})}):null,i.instructions?e(B,{value:i.instructions}):null]}),e(p,{part:i,reviewData:t,hidePerQuestionGrading:n})]},`${i.partId}-${a}`)})})}function B({value:t}){return/<[a-z][\s\S]*>/i.test(t)?e("div",{className:"text-[17px] font-bold leading-relaxed text-[#0054A6] [&_p]:mb-2 [&_p:last-child]:mb-0",dangerouslySetInnerHTML:{__html:t}}):e("h3",{className:"text-[17px] font-bold leading-relaxed text-[#0054A6]",children:t})}
1
+ "use client";import{jsx as e,Fragment as t,jsxs as r}from"react/jsx-runtime";import{useCallback as n,useEffect as o,useMemo as i,useState as a}from"react";import{ChevronLeft as s,Download as l,Loader2 as c,Sparkles as d}from"lucide-react";import{ResultTemplateType as m}from"../../api/result-review";import{useToast as u}from"../../shared/lib/hooks/useToast";import{ReviewQuestionRenderer as p}from"./ReviewQuestionRenderer";import{useResultReviewPolling as f}from"./hooks/useResultReviewPolling";import{BadgeTitle as g}from"./report/BadgeTitle";import{OceanEduExamReport as x}from"./report/OceanEduExamReport";import{OverallAssessmentSection as h}from"./report/OverallAssessmentSection";import{ResultErrorState as w}from"./report/ResultErrorState";import{ResultLoadingState as b}from"./report/ResultLoadingState";import{ResultNotPublicState as S}from"./report/ResultNotPublicState";import{SpeakingRubricSection as v}from"./report/SpeakingRubricSection";import{SpeakingReviewResult as N}from"./speaking/SpeakingReviewResult";import{transformResultAnswersForReview as R}from"./review-data";import{isResultNotPublic as E,setPdfReady as P}from"./review-status.utils";import{unwrap as y}from"./result-review.utils";import{formatTotalScore as k}from"./utils/review-score.utils";import{transformSpeakingResultForReview as A}from"./utils/transform-speaking-review";const L="/student/contests/my-contests";export var PartRubricTemplateCode;!function(e){e.KINDY_VER3="PLACEMENT_TEST_KINDY_VER3",e.PRESCHOOL="PLACEMENT_TEST_PRESCHOOL"}(PartRubricTemplateCode||(PartRubricTemplateCode={}));const T=new Set(Object.values(PartRubricTemplateCode));export function ResultReviewPageContainer({attemptId:s,token:l,api:c,isPrintMode:d=!1,canExportPdf:p=!1,reviewUrl:g,assetBaseUrl:k,loginHref:U,onBack:F,onNavigate:O,topActionsSlot:_,beforeReportSlot:j,afterReportSlot:Q}){const{error:M,success:$}=u(),[H,I]=a(null),[G,K]=a(null),[V,q]=a(!0),[W,X]=a(null),[Y,z]=a(!1),J=n(async e=>{e&&q(!0);try{const[e,t]=await Promise.all([c.getDetailedResult(s,l),c.getAttempt?.(s,l)]);I(y(e)),K(t?y(t):null),X(null)}catch(e){X(e),E(e,Boolean(l))||M({message:"Không thể tải kết quả",description:e instanceof Error?e.message:void 0})}finally{e&&q(!1)}},[c,s,l,M]);o(()=>{J(!0)},[J]);const Z=n(()=>{J(!1)},[J]),{hasPendingQuestions:ee,hasPendingLlm:te,hasFailedLlm:re,retryLlm:ne}=f({detail:H,isPrintMode:d,isLoading:V,onRefetch:Z});o(()=>{if(!d||V)return;const e=requestAnimationFrame(()=>P(!0));return()=>{cancelAnimationFrame(e),P(!1)}},[d,V]);const oe=G?.exam?.template,ie=oe?.parts,ae=G?.studentName??"Học sinh",se=G?.studentUsername??null,le=G?.branchName??"Chưa tham gia chi nhánh",ce=function(e){const t=e?new Date(e):new Date;return Number.isNaN(t.getTime())?(new Date).toLocaleDateString("vi-VN"):t.toLocaleDateString("vi-VN")}(H?.submittedAt),de=i(()=>function(e,t){const r=e??("undefined"!=typeof window?window.location.href:void 0);if(!r||!t)return r;try{const e=new URL(r,"undefined"!=typeof window?window.location.origin:void 0);return e.searchParams.set("token",t),e.toString()}catch{return r}}(g,l??G?.verificationToken),[g,l,G?.verificationToken]),me=i(()=>R(H?.answers??[],ie),[H?.answers,ie]),ue=i(()=>H&&oe?.type===m.SPEAKING?A(H,ae,ie):null,[H,ae,oe?.type,ie]),pe=!!H?.templateCode&&T.has(H.templateCode),fe=i(()=>function(e){const t={};return e?.speakingRubric?.criteria?.forEach(e=>{const r=/^C(\d+)$/.exec(e.code);if(!r)return;const n=null!=e.weightedScore&&null!=e.maxScore;t[Number(r[1])]=n?{score:e.weightedScore,maxScore:e.maxScore,weighted:n}:{score:e.score,maxScore:5,weighted:n}}),t}(H),[H?.speakingRubric]);o(()=>{if("undefined"==typeof window)return;window.history.pushState(null,"",window.location.href);const e=()=>{F?F():O?O(L):window.location.replace(L)};return window.addEventListener("popstate",e),()=>{window.removeEventListener("popstate",e)}},[F,O]);const ge=n(()=>{if(F)return F();O?O(L):"undefined"!=typeof window&&(window.location.href=L)},[F,O]),xe=async()=>{if(H&&c.exportPdf){z(!0);try{const{blob:e,filename:t}=await c.exportPdf(s,oe?.type);!function(e,t){const r=URL.createObjectURL(e),n=document.createElement("a");n.href=r,n.download=t,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(r)}(e,t),$({message:"Xuất PDF thành công"})}catch(e){M({message:"Không xuất được PDF",description:e instanceof Error?e.message:void 0})}finally{z(!1)}}};return V?e(b,{}):E(W,Boolean(l))?e(S,{loginHref:U,assetBaseUrl:k,onLogin:O}):H?ue?e(N,{reviewData:ue,studentName:ae,studentCode:se,branchName:le,examDateText:ce,examTitle:oe?.title,showDetailedResults:H.showDetailedResults,speakingRubric:H.speakingRubric,reviewUrl:de,assetBaseUrl:k,canExportPdf:p&&Boolean(c.exportPdf),isExporting:Y,hasPendingQuestions:ee,onBack:ge,onExportPdf:xe,topActionsSlot:_,beforeReportSlot:j,afterReportSlot:Q}):e("div",{className:"min-h-screen bg-[#e0e0e0] py-4 md:py-6",children:r("div",{className:"mx-auto flex w-full max-w-[1160px] flex-col gap-4 px-0 sm:px-4",children:[e(D,{onBack:ge,onExport:xe,canExport:p&&Boolean(c.exportPdf),isExporting:Y,topActionsSlot:_}),ee?e(C,{}):null,j,e(x,{studentName:ae,studentCode:se,branchName:le,examDateText:ce,totalScore:H.totalScore,maxScore:H.maxScore,isPendingGrading:Boolean(H.isPendingGrading||ee),examSubTitle:H.roomName,examTitle:oe?.title,reviewUrl:de,assetBaseUrl:k,readingScore:H.readingScore,maxReadingScore:H.maxReadingScore,listeningScore:H.listeningScore,maxListeningScore:H.maxListeningScore,writingScore:H.writingScore,maxWritingScore:H.maxWritingScore,speakingScore:H.speakingScore,maxSpeakingScore:H.maxSpeakingScore,overallAssessmentSlot:r(t,{children:[e(h,{isPending:te,isFailed:re,onRetry:ne,llmOverallAssessment:H.llmOverallAssessment,llmSkillAssessment:H.llmSkillAssessment,correctAnswers:H.correctAnswers,totalQuestions:H.totalQuestions}),H.speakingRubric?.criteria?.length?e(v,{rubric:H.speakingRubric}):null]}),children:!1!==H.showDetailedResults?e(B,{reviewData:me,hidePerQuestionGrading:pe,rubricScores:fe}):null}),Q]})}):e(w,{error:W,onBack:ge})}function D({onBack:t,onExport:n,canExport:o,isExporting:i,topActionsSlot:a}){return r("div",{className:"flex items-center justify-between gap-3 px-3 print:hidden sm:px-0",children:[r("button",{type:"button",onClick:t,className:"inline-flex items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-sm font-semibold text-slate-700 shadow-sm transition hover:bg-slate-50",children:[e(s,{className:"h-4 w-4"}),"Quay lại"]}),r("div",{className:"flex items-center gap-3",children:[o?r("button",{type:"button",onClick:()=>{n()},disabled:i,className:"inline-flex items-center gap-2 rounded-xl bg-gradient-to-r from-[#00AEEF] to-[#0099D6] px-5 py-2.5 text-sm font-bold text-white shadow-lg disabled:opacity-50",children:[i?e(c,{className:"h-4 w-4 animate-spin"}):e(l,{className:"h-4 w-4"}),i?"Đang xuất...":"Xuất PDF"]}):null,a]})]})}function C(){return r("div",{className:"mx-3 flex items-center gap-3 rounded-2xl border border-[#b3dfff] bg-gradient-to-r from-[#e8f6ff] to-[#f0f8ff] px-5 py-4 shadow-sm sm:mx-0",children:[e("div",{className:"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[#d0edff]",children:e(d,{className:"h-5 w-5 animate-pulse text-[#00AEEF]"})}),r("div",{children:[e("p",{className:"text-sm font-bold text-[#0054A6]",children:"AI đang chấm điểm..."}),e("p",{className:"text-xs text-[#0078c8]",children:"Trang sẽ tự động cập nhật cho đến khi hoàn tất."})]})]})}function B({reviewData:t,hidePerQuestionGrading:n,rubricScores:o}){return e("div",{className:"space-y-6",children:t.parts.map((i,a)=>{const s=n?o[i.partNo]:void 0,l=t.partScoresMap[a],c=s?`${s.weighted?Number(s.score.toFixed(1)):Math.round(s.score)} / ${Math.round(s.maxScore)}`:l?`${k(l.score)} / ${k(l.maxScore)}`:null;return r("section",{className:"relative rounded-[20px] border-2 border-[#00AEEF] bg-white px-5 pb-6 pt-11 md:px-8",children:[e(g,{number:String(i.partNo),title:i.name||`PHẦN ${i.partNo}`}),r("div",{className:"mb-6 flex flex-col gap-4",children:[c?e("div",{className:"flex justify-end",children:r("div",{className:"rounded-full bg-[#0054A6] px-4 py-2 text-sm font-bold text-white",children:["Điểm: ",c]})}):null,i.instructions?e(U,{value:i.instructions}):null]}),e(p,{part:i,reviewData:t,hidePerQuestionGrading:n})]},`${i.partId}-${a}`)})})}function U({value:t}){return/<[a-z][\s\S]*>/i.test(t)?e("div",{className:"text-[17px] font-bold leading-relaxed text-[#0054A6] [&_p]:mb-2 [&_p:last-child]:mb-0",dangerouslySetInnerHTML:{__html:t}}):e("h3",{className:"text-[17px] font-bold leading-relaxed text-[#0054A6]",children:t})}
@@ -3,6 +3,8 @@ export interface SidebarPart {
3
3
  partNo: number;
4
4
  name?: string;
5
5
  category?: string;
6
+ /** Max points for this part from template (shown as "X điểm") */
7
+ points?: number;
6
8
  totalQuestions: number;
7
9
  answeredCount: number;
8
10
  }
@@ -1 +1 @@
1
- import{jsx as e,jsxs as t}from"react/jsx-runtime";import{cn as r}from"../../../shared/lib/utils";import s from"next/image";import l from"./assets/images/phao.png";import a from"./assets/images/sanho.png";import n from"./assets/images/sao.png";import i from"./assets/images/vooc.png";const o=[l,a,n,i];export function CambridgeYleSidebar({parts:l,questions:a,currentQuestionGlobalIndex:n,onPartClick:i,onQuestionClick:d,isNavDisabled:c,className:p}){const m=a[n],h=m?m.partIndex:0;return t("div",{className:r("flex flex-col w-full h-full pb-4",p),children:[t("div",{className:"flex-1 overflow-y-auto custom-scrollbar p-4 lg:p-6 pb-2",children:[t("div",{className:"flex items-center gap-2 mb-4 justify-center uppercase tracking-widest text-[16px]",children:[e("div",{className:"flex items-center justify-center p-1.5 bg-gradient-to-br from-blue-400 to-blue-600 rounded-xl text-white",children:t("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",children:[e("polygon",{points:"12 2 2 7 12 12 22 7 12 2"}),e("polyline",{points:"2 17 12 22 22 17"}),e("polyline",{points:"2 12 12 17 22 12"})]})}),e("span",{className:"font-black bg-gradient-to-r from-blue-700 to-blue-500 bg-clip-text text-transparent",children:"Parts"})]}),e("div",{className:"flex flex-col gap-2.5",children:l.map((a,n)=>{const d=n===h,p=o[n%o.length],m=n>0?l[n-1].category:null,b=a.category&&a.category!==m;return t("div",{className:"flex flex-col",children:[b&&t("div",{className:"flex items-center gap-2 mt-5 mb-3 px-1",children:[e("div",{className:"h-[4px] w-4 rounded-full bg-blue-500"}),e("span",{className:"text-[14px] font-black uppercase tracking-[0.15em] text-blue-800",children:a.category?.replace(/_/g," ")}),e("div",{className:"h-[2px] flex-1 rounded-full bg-blue-100"})]}),t("button",{type:"button",onClick:()=>i(n),disabled:c,className:r("flex items-center justify-between p-2 px-[15px] rounded-[15px] transition-all border font-medium shadow-sm",d?"bg-blue-600 text-white border-blue-600":"bg-white text-slate-800 border-transparent",d||c?"":"hover:border-blue-200",c?"opacity-50 cursor-not-allowed":"cursor-pointer"),children:[t("div",{className:"flex items-center gap-3",children:[e("div",{className:"flex items-center justify-center w-8 h-8 shrink-0",children:e(s,{src:p,alt:`part icon ${n}`,className:"w-[30px] h-auto object-contain"})}),e("span",{className:"font-black text-[15px]",children:a.name||`Part ${a.partNo}`})]}),t("span",{className:r("text-[13px] font-bold tracking-wide",d?"text-blue-100":"text-blue-900/60"),children:[a.answeredCount,"/",a.totalQuestions]})]})]},n)})})]}),e("div",{className:"px-6",children:e("hr",{className:"border-t-2 border-dashed border-blue-100"})}),t("div",{className:"flex-1 p-4 lg:p-6 pt-4 flex flex-col min-h-0",children:[t("div",{className:"flex items-center gap-2 mb-4 justify-center uppercase tracking-widest text-[16px] shrink-0",children:[e("div",{className:"flex items-center justify-center p-1.5 bg-gradient-to-br from-blue-400 to-blue-600 rounded-xl text-white",children:t("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",children:[e("rect",{width:"8",height:"4",x:"8",y:"2",rx:"1",ry:"1"}),e("path",{d:"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"}),e("path",{d:"M12 11h4"}),e("path",{d:"M12 16h4"}),e("path",{d:"M8 11h.01"}),e("path",{d:"M8 16h.01"})]})}),e("span",{className:"font-black bg-gradient-to-r from-blue-700 to-blue-500 bg-clip-text text-transparent",children:"Question List"})]}),e("div",{className:"flex-1 overflow-y-auto custom-scrollbar pr-1",children:e("div",{className:"grid grid-cols-5 gap-2",children:a.map(t=>{const s=t.globalIndex===n,l=t.isAnswered;let a="bg-white text-slate-800 shadow-sm border-transparent";return s?a="bg-blue-600 text-white border-blue-600 shadow-md":l&&(a="bg-[#4ade80] text-white border-transparent shadow-sm"),s||c||(a+=" hover:shadow-md hover:text-blue-600"),a+=c?" opacity-50 cursor-not-allowed":" cursor-pointer",e("button",{type:"button",onClick:()=>d(t.globalIndex),disabled:c,className:r("h-[44px] w-full rounded-[10px] flex items-center justify-center font-bold text-[15px] transition-all border",a),children:t.questionNumber},t.globalIndex)})})}),e("div",{className:"shrink-0 mt-4 pt-4 border-t border-blue-200/50",children:t("div",{className:"flex items-center justify-between text-[11px] xl:text-[11.5px] font-bold text-gray-700",children:[t("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"w-3.5 h-3.5 rounded-full bg-blue-600 shadow-sm"}),e("span",{children:"Current"})]}),t("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"w-3.5 h-3.5 rounded-full bg-green-500 shadow-sm"}),e("span",{children:"Answered"})]}),t("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"w-3.5 h-3.5 rounded-full bg-[#f4f9ff] border border-blue-200 shadow-sm"}),e("span",{children:"Not answered"})]})]})})]})]})}
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import{cn as r}from"../../../shared/lib/utils";import s from"next/image";import{useEffect as l,useRef as a}from"react";import n from"./assets/images/phao.png";import o from"./assets/images/sanho.png";import i from"./assets/images/sao.png";import c from"./assets/images/vooc.png";const d=[n,o,i,c];export function CambridgeYleSidebar({parts:n,questions:o,currentQuestionGlobalIndex:i,onPartClick:c,onQuestionClick:p,isNavDisabled:m,className:h}){const u=o[i],b=u?u.partIndex:0,x=a(null),f=a([]);return l(()=>{const e=x.current,t=f.current[b];if(!e||!t)return;const r=e.getBoundingClientRect(),s=t.getBoundingClientRect(),l=s.top<r.top,a=s.bottom>r.bottom;(l||a)&&t.scrollIntoView({block:"nearest",behavior:"smooth"})},[b]),t("div",{className:r("flex flex-col w-full h-full pb-4",h),children:[t("div",{ref:x,className:"flex-1 overflow-y-auto custom-scrollbar p-4 lg:p-6 pb-2",children:[t("div",{className:"flex items-center gap-2 mb-4 justify-center uppercase tracking-widest text-[16px]",children:[e("div",{className:"flex items-center justify-center p-1.5 bg-gradient-to-br from-blue-400 to-blue-600 rounded-xl text-white",children:t("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",children:[e("polygon",{points:"12 2 2 7 12 12 22 7 12 2"}),e("polyline",{points:"2 17 12 22 22 17"}),e("polyline",{points:"2 12 12 17 22 12"})]})}),e("span",{className:"font-black bg-gradient-to-r from-blue-700 to-blue-500 bg-clip-text text-transparent",children:"Parts"})]}),e("div",{className:"flex flex-col gap-2.5",children:n.map((l,a)=>{const o=a===b,i=d[a%d.length],p=a>0?n[a-1].category:null,h=l.category&&l.category!==p;return t("div",{ref:e=>{f.current[a]=e},className:"flex flex-col",children:[h&&t("div",{className:"flex items-center gap-2 mt-5 mb-3 px-1",children:[e("div",{className:"h-[4px] w-4 rounded-full bg-blue-500"}),e("span",{className:"text-[14px] font-black uppercase tracking-[0.15em] text-blue-800",children:l.category?.replace(/_/g," ")}),e("div",{className:"h-[2px] flex-1 rounded-full bg-blue-100"})]}),t("button",{type:"button",onClick:()=>c(a),disabled:m,className:r("flex items-center justify-between p-2 px-[15px] rounded-[15px] transition-all border font-medium shadow-sm",o?"bg-blue-600 text-white border-blue-600":"bg-white text-slate-800 border-transparent",o||m?"":"hover:border-blue-200",m?"opacity-50 cursor-not-allowed":"cursor-pointer"),children:[t("div",{className:"flex items-center gap-3",children:[e("div",{className:"flex items-center justify-center w-8 h-8 shrink-0",children:e(s,{src:i,alt:`part icon ${a}`,className:"w-[30px] h-auto object-contain"})}),e("span",{className:"font-black text-[15px]",children:l.name||`Part ${l.partNo}`})]}),t("div",{className:"flex items-center gap-2 shrink-0",children:[null!=l.points&&l.points>0&&t("span",{className:r("text-[12px] font-black tracking-wide whitespace-nowrap",o?"text-yellow-200":"text-amber-500"),children:[l.points," điểm"]}),t("span",{className:r("text-[13px] font-bold tracking-wide",o?"text-blue-100":"text-blue-900/60"),children:[l.answeredCount,"/",l.totalQuestions]})]})]})]},a)})})]}),e("div",{className:"px-6",children:e("hr",{className:"border-t-2 border-dashed border-blue-100"})}),t("div",{className:"flex-1 p-4 lg:p-6 pt-4 flex flex-col min-h-0",children:[t("div",{className:"flex items-center gap-2 mb-4 justify-center uppercase tracking-widest text-[16px] shrink-0",children:[e("div",{className:"flex items-center justify-center p-1.5 bg-gradient-to-br from-blue-400 to-blue-600 rounded-xl text-white",children:t("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",children:[e("rect",{width:"8",height:"4",x:"8",y:"2",rx:"1",ry:"1"}),e("path",{d:"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"}),e("path",{d:"M12 11h4"}),e("path",{d:"M12 16h4"}),e("path",{d:"M8 11h.01"}),e("path",{d:"M8 16h.01"})]})}),e("span",{className:"font-black bg-gradient-to-r from-blue-700 to-blue-500 bg-clip-text text-transparent",children:"Question List"})]}),e("div",{className:"flex-1 overflow-y-auto custom-scrollbar pr-1",children:e("div",{className:"grid grid-cols-5 gap-2",children:o.map(t=>{const s=t.globalIndex===i,l=t.isAnswered;let a="bg-white text-slate-800 shadow-sm border-transparent";return s?a="bg-blue-600 text-white border-blue-600 shadow-md":l&&(a="bg-[#4ade80] text-white border-transparent shadow-sm"),s||m||(a+=" hover:shadow-md hover:text-blue-600"),a+=m?" opacity-50 cursor-not-allowed":" cursor-pointer",e("button",{type:"button",onClick:()=>p(t.globalIndex),disabled:m,className:r("h-[44px] w-full rounded-[10px] flex items-center justify-center font-bold text-[15px] transition-all border",a),children:t.questionNumber},t.globalIndex)})})}),e("div",{className:"shrink-0 mt-4 pt-4 border-t border-blue-200/50",children:t("div",{className:"flex items-center justify-between text-[11px] xl:text-[11.5px] font-bold text-gray-700",children:[t("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"w-3.5 h-3.5 rounded-full bg-blue-600 shadow-sm"}),e("span",{children:"Current"})]}),t("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"w-3.5 h-3.5 rounded-full bg-green-500 shadow-sm"}),e("span",{children:"Answered"})]}),t("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"w-3.5 h-3.5 rounded-full bg-[#f4f9ff] border border-blue-200 shadow-sm"}),e("span",{children:"Not answered"})]})]})})]})]})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{useMemo as t}from"react";import{ResolvedImage as r}from"../../../components/common/ResolvedImage";import{cn as a}from"../../../shared/lib/utils";import{transformAnswerTheQuestion as n}from"../../../components/exams/take/exam-taking.utils";export function EcAnswerTheQuestion({part:i,answers:l,onAnswerChange:d,isReviewMode:o=!1}){const{questions:c,instruction:m,imageUrl:x,title:p,groupContent:f}=t(()=>n(i.questions),[i.questions]);return s("div",{className:"flex flex-col gap-4",children:[m&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:m}),x&&e("div",{className:"flex items-center justify-center",children:e(r,{src:x,alt:p||"Group image",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),e("div",{className:"flex flex-col gap-3",children:c.map(t=>{const n=l[t.id]?.answer??t.exampleAnswer??"";return e("div",{id:`question-${t.id}`,className:a("rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",t.isExample&&"opacity-90"),children:s("div",{className:"flex items-start gap-3",children:[e("span",{className:"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:t.questionNumber}),s("div",{className:"min-w-0 flex-1 space-y-2",children:[t.imageUrl&&e(r,{src:t.imageUrl,alt:`Question ${t.questionNumber}`,className:"max-h-28 w-auto rounded object-contain"}),e("p",{className:"text-sm text-[#0f1730]",children:t.question}),s("div",{className:"flex flex-wrap items-center gap-2",children:[t.prefixText&&e("span",{className:"text-sm text-[#64748b]",children:t.prefixText}),t.isExample?e("span",{className:"rounded-lg border border-[#b9edc8] bg-[#ddf8e7] px-3 py-1.5 text-sm font-semibold text-[#15803d]",children:t.exampleAnswer}):e("input",{type:"text",value:n,disabled:o,placeholder:"Nhập câu trả lời…",onChange:e=>{return s=t.id,r=e.target.value,void d(s,{answer:r});var s,r},className:a("min-w-[200px] flex-1 rounded-lg border-2 border-[#9cc4f5] bg-white px-3 py-2 text-sm font-medium text-[#0f1730] outline-none transition-all focus:border-[#1167e8]",o&&"cursor-not-allowed opacity-70")}),t.suffixText&&e("span",{className:"text-sm text-[#64748b]",children:t.suffixText})]}),t.suggestedAnswers&&t.suggestedAnswers.length>0&&e("div",{className:"flex flex-wrap gap-1.5",children:t.suggestedAnswers.map((s,r)=>e("span",{className:"rounded-full border border-[#e2ecf8] bg-[#f4f9ff] px-2.5 py-0.5 text-xs text-[#0b57d0]",children:s},`${t.id}-sa-${r}`))})]})]})},t.id)})})]})}
1
+ "use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{useMemo as t}from"react";import{ResolvedImage as r}from"../../../components/common/ResolvedImage";import{cn as a}from"../../../shared/lib/utils";import{transformAnswerTheQuestion as i}from"../../../components/exams/take/exam-taking.utils";import{englishCertQuestionDomId as n}from"./english-cert-scroll";export function EcAnswerTheQuestion({part:l,answers:o,onAnswerChange:d,isReviewMode:c=!1}){const{questions:m,instruction:x,imageUrl:p,title:f,groupContent:u}=t(()=>i(l.questions),[l.questions]);return s("div",{className:"flex flex-col gap-4",children:[x&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:x}),p&&e("div",{className:"flex items-center justify-center",children:e(r,{src:p,alt:f||"Group image",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),e("div",{className:"flex flex-col gap-3",children:m.map(t=>{const i=o[t.id]?.answer??t.exampleAnswer??"";return e("div",{id:n(t.id),className:a("scroll-mt-24 rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",t.isExample&&"opacity-90"),children:s("div",{className:"flex items-start gap-3",children:[e("span",{className:"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:t.questionNumber}),s("div",{className:"min-w-0 flex-1 space-y-2",children:[t.imageUrl&&e(r,{src:t.imageUrl,alt:`Question ${t.questionNumber}`,className:"max-h-28 w-auto rounded object-contain"}),e("p",{className:"text-sm text-[#0f1730]",children:t.question}),s("div",{className:"flex flex-wrap items-center gap-2",children:[t.prefixText&&e("span",{className:"text-sm text-[#64748b]",children:t.prefixText}),t.isExample?e("span",{className:"rounded-lg border border-[#b9edc8] bg-[#ddf8e7] px-3 py-1.5 text-sm font-semibold text-[#15803d]",children:t.exampleAnswer}):e("input",{type:"text",value:i,disabled:c,placeholder:"Nhập câu trả lời…",onChange:e=>{return s=t.id,r=e.target.value,void d(s,{answer:r});var s,r},className:a("min-w-[200px] flex-1 rounded-lg border-2 border-[#9cc4f5] bg-white px-3 py-2 text-sm font-medium text-[#0f1730] outline-none transition-all focus:border-[#1167e8]",c&&"cursor-not-allowed opacity-70")}),t.suffixText&&e("span",{className:"text-sm text-[#64748b]",children:t.suffixText})]}),t.suggestedAnswers&&t.suggestedAnswers.length>0&&e("div",{className:"flex flex-wrap gap-1.5",children:t.suggestedAnswers.map((s,r)=>e("span",{className:"rounded-full border border-[#e2ecf8] bg-[#f4f9ff] px-2.5 py-0.5 text-xs text-[#0b57d0]",children:s},`${t.id}-sa-${r}`))})]})]})},t.id)})})]})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ResolvedImage as n}from"../../../components/common/ResolvedImage";import{cn as s}from"../../../shared/lib/utils";import{transformMatchByWritingAnswer as a}from"../../../components/exams/take/exam-taking.utils";const o="ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),i={empty:"bg-[#eef3fb] text-[#94a3b8] border border-[#dbe5f2]",filled:"bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-white border border-transparent",correct:"bg-[#16a34a] text-white border border-transparent",wrong:"bg-[#ef4444] text-white border border-transparent"};function d({letter:t,tone:r}){return e("span",{className:s("flex h-9 w-9 shrink-0 items-center justify-center rounded-xl text-base font-bold transition-colors",i[r]),children:t||"—"})}export function EcMatchByWritingAnswer({part:i,answers:l,onAnswerChange:c,isReviewMode:m=!1}){const{questions:f,options:b,instruction:p,groupImageUrl:x}=r(()=>a(i.questions),[i.questions]),u=r(()=>{const e=new Map;return b.forEach((t,r)=>{e.set(t.answer,o[r]??String(r+1))}),e},[b]),g=e=>l[e.id]?.answer??e.exampleAnswer??"",h=r(()=>{const e=new Set;return f.forEach(t=>{const r=g(t),n=u.get(r);n&&e.add(n)}),e},[f,l,u]);return t("div",{className:"flex flex-col gap-4",children:[p&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:p}),x&&e("div",{className:"flex items-center justify-center",children:e(n,{src:x,alt:"Group image",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),b.length>0&&t("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:[e("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-[#64748b]",children:"ANSWER OPTIONS"}),e("div",{className:"mt-2 grid grid-cols-1 gap-2 sm:grid-cols-2",children:b.map((r,a)=>{const i=o[a]??String(a+1),d=!m&&h.has(i);return t("div",{className:s("flex items-start gap-2.5 rounded-xl border border-[#e2ecf8] bg-[#f4f9ff] px-3 py-2 transition-opacity",d&&"opacity-50"),children:[t("span",{className:"relative flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:[i,d&&e("span",{className:"absolute -right-1 -top-1 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-[#16a34a] text-[8px] text-white",children:"✓"})]}),t("div",{className:"min-w-0 text-sm text-[#0f1730]",children:[r.imageUrl&&e(n,{src:r.imageUrl,alt:r.answer,className:"mb-1 max-h-24 w-auto rounded object-contain"}),e("span",{className:"font-medium",children:r.content||r.answer})]})]},`${r.answer}-${a}`)})})]}),e("div",{className:"flex flex-col gap-3",children:f.map(r=>{const a=g(r),i=u.get(a)??"",l=m&&r.isExample?a===(r.exampleAnswer??""):void 0,f=!0===l?"border-[#bbf7d0] bg-[#f0fdf4]":!1===l?"border-[#fecaca] bg-[#fef2f2]":"border-[#d9e4f2] bg-white/90",p=!0===l?"correct":!1===l?"wrong":i?"filled":"empty";return t("div",{id:`question-${r.id}`,className:s("flex items-center gap-3 rounded-xl border p-3 shadow-sm transition-colors",f,r.isExample&&"opacity-90"),children:[e("span",{className:"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:r.questionNumber}),t("div",{className:"min-w-0 flex-1",children:[r.imageUrl&&e(n,{src:r.imageUrl,alt:`Question ${r.questionNumber}`,className:"mb-2 max-h-28 w-auto rounded object-contain"}),e("p",{className:"text-sm text-[#0f1730]",children:r.question})]}),t("div",{className:"flex shrink-0 items-center gap-2",children:[e(d,{letter:i,tone:p}),r.isExample?e("span",{className:"rounded-lg border border-[#b9edc8] bg-[#ddf8e7] px-3 py-1.5 text-sm font-semibold text-[#15803d]",children:r.exampleAnswer}):t("select",{value:a,disabled:m,onChange:e=>{return t=r.id,n=e.target.value,void c(t,{answer:n});var t,n},className:s("h-9 min-w-[150px] rounded-lg border-2 border-[#9cc4f5] bg-white px-3 text-sm font-semibold text-[#0f1730] outline-none transition-all focus:border-[#1167e8]",m&&"cursor-not-allowed opacity-70"),children:[e("option",{value:"",children:"—"}),b.map((t,n)=>{const s=o[n]??String(n+1),a=t.content||t.answer;return e("option",{value:t.answer,children:a?`${s} — ${a}`:s},`${r.id}-${n}`)})]})]})]},r.id)})})]})}
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ResolvedImage as n}from"../../../components/common/ResolvedImage";import{cn as s}from"../../../shared/lib/utils";import{transformMatchByWritingAnswer as a}from"../../../components/exams/take/exam-taking.utils";import{englishCertQuestionDomId as o}from"./english-cert-scroll";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),d={empty:"bg-[#eef3fb] text-[#94a3b8] border border-[#dbe5f2]",filled:"bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-white border border-transparent",correct:"bg-[#16a34a] text-white border border-transparent",wrong:"bg-[#ef4444] text-white border border-transparent"};function l({letter:t,tone:r}){return e("span",{className:s("flex h-9 w-9 shrink-0 items-center justify-center rounded-xl text-base font-bold transition-colors",d[r]),children:t||"—"})}export function EcMatchByWritingAnswer({part:d,answers:c,onAnswerChange:m,isReviewMode:f=!1}){const{questions:b,options:p,instruction:x,groupImageUrl:u}=r(()=>a(d.questions),[d.questions]),g=r(()=>{const e=new Map;return p.forEach((t,r)=>{e.set(t.answer,i[r]??String(r+1))}),e},[p]),h=e=>c[e.id]?.answer??e.exampleAnswer??"",w=r(()=>{const e=new Set;return b.forEach(t=>{const r=h(t),n=g.get(r);n&&e.add(n)}),e},[b,c,g]);return t("div",{className:"flex flex-col gap-4",children:[x&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:x}),u&&e("div",{className:"flex items-center justify-center",children:e(n,{src:u,alt:"Group image",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),p.length>0&&t("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:[e("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-[#64748b]",children:"ANSWER OPTIONS"}),e("div",{className:"mt-2 grid grid-cols-1 gap-2 sm:grid-cols-2",children:p.map((r,a)=>{const o=i[a]??String(a+1),d=!f&&w.has(o);return t("div",{className:s("flex items-start gap-2.5 rounded-xl border border-[#e2ecf8] bg-[#f4f9ff] px-3 py-2 transition-opacity",d&&"opacity-50"),children:[t("span",{className:"relative flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:[o,d&&e("span",{className:"absolute -right-1 -top-1 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-[#16a34a] text-[8px] text-white",children:"✓"})]}),t("div",{className:"min-w-0 text-sm text-[#0f1730]",children:[r.imageUrl&&e(n,{src:r.imageUrl,alt:r.answer,className:"mb-1 max-h-24 w-auto rounded object-contain"}),e("span",{className:"font-medium",children:r.content||r.answer})]})]},`${r.answer}-${a}`)})})]}),e("div",{className:"flex flex-col gap-3",children:b.map(r=>{const a=h(r),d=g.get(a)??"",c=f&&r.isExample?a===(r.exampleAnswer??""):void 0,b=!0===c?"border-[#bbf7d0] bg-[#f0fdf4]":!1===c?"border-[#fecaca] bg-[#fef2f2]":"border-[#d9e4f2] bg-white/90",x=!0===c?"correct":!1===c?"wrong":d?"filled":"empty";return t("div",{id:o(r.id),className:s("scroll-mt-24 flex items-center gap-3 rounded-xl border p-3 shadow-sm transition-colors",b,r.isExample&&"opacity-90"),children:[e("span",{className:"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:r.questionNumber}),t("div",{className:"min-w-0 flex-1",children:[r.imageUrl&&e(n,{src:r.imageUrl,alt:`Question ${r.questionNumber}`,className:"mb-2 max-h-28 w-auto rounded object-contain"}),e("p",{className:"text-sm text-[#0f1730]",children:r.question})]}),t("div",{className:"flex shrink-0 items-center gap-2",children:[e(l,{letter:d,tone:x}),r.isExample?e("span",{className:"rounded-lg border border-[#b9edc8] bg-[#ddf8e7] px-3 py-1.5 text-sm font-semibold text-[#15803d]",children:r.exampleAnswer}):t("select",{value:a,disabled:f,onChange:e=>{return t=r.id,n=e.target.value,void m(t,{answer:n});var t,n},className:s("h-9 min-w-[150px] rounded-lg border-2 border-[#9cc4f5] bg-white px-3 text-sm font-semibold text-[#0f1730] outline-none transition-all focus:border-[#1167e8]",f&&"cursor-not-allowed opacity-70"),children:[e("option",{value:"",children:"—"}),p.map((t,n)=>{const s=i[n]??String(n+1),a=t.content||t.answer;return e("option",{value:t.answer,children:a?`${s} — ${a}`:s},`${r.id}-${n}`)})]})]})]},r.id)})})]})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ResolvedImage as a}from"../../../components/common/ResolvedImage";import{cn as n}from"../../../shared/lib/utils";import{transformWordFillParagraph as o}from"../../../components/exams/take/exam-taking.utils";export function EcWordFillParagraph({part:l,answers:s,onAnswerChange:i,isReviewMode:d=!1}){const c=r(()=>o(l.questions),[l.questions]),{questionId:m,paragraph:p,title:x,imageUrl:b,wordBank:f,viewMode:h,instruction:u}=c,g=s[m]||[],w=r(()=>p.split(/(\{\d+\})/),[p]),N="WITH_WORD_BANK"===h,v=new Set(g.filter(Boolean)),y=(e,t)=>{if(d)return;const r=[...g];r[e]=t,i(m,r)};return t("div",{className:"flex flex-col gap-4",children:[u&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:u}),b&&e("div",{className:"flex items-center justify-center",children:e(a,{src:b,alt:x||"Illustration",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),N&&f.length>0&&t("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:[e("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-[#64748b]",children:"Word bank"}),e("div",{className:"mt-2 flex flex-wrap gap-2",children:f.map((t,r)=>{const a=v.has(t.word);return e("span",{className:n("rounded-full border px-3 py-1 text-sm font-semibold transition-all",t.isExample?"border-[#b9edc8] bg-[#ddf8e7] text-[#15803d]":a?"border-[#d9e4f2] bg-[#f4f9ff] text-[#94a3b8] line-through":"border-[#9cc4f5] bg-white text-[#0b57d0]"),children:t.word},`${t.word}-${r}`)})})]}),e("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-5 text-base leading-loose text-[#0f1730] shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:w.map((r,a)=>{const o=r.match(/^\{(\d+)\}$/);if(!o)return e("span",{children:r},a);const l=parseInt(o[1],10),s=g[l]||"";return t("span",N?{className:"mx-1 inline-flex items-baseline gap-1 align-baseline",children:[t("span",{className:"text-[11px] font-bold text-[#1f7cff]",children:["(",l+1,")"]}),t("select",{value:s,disabled:d,onChange:e=>y(l,e.target.value),className:n("rounded-lg border-2 px-2 py-1 text-sm font-semibold outline-none transition-all",s?"border-[#1167e8] text-[#0b57d0]":"border-[#9cc4f5] text-[#64748b]",d&&"cursor-not-allowed opacity-70"),children:[e("option",{value:"",children:"———"}),f.filter(e=>!e.isExample).map((t,r)=>e("option",{value:t.word,children:t.word},`${l}-${r}`))]})]}:{className:"mx-1 inline-flex items-baseline gap-1 align-baseline",children:[t("span",{className:"text-[11px] font-bold text-[#1f7cff]",children:["(",l+1,")"]}),e("input",{type:"text",value:s,disabled:d,placeholder:"···",onChange:e=>y(l,e.target.value),style:{width:`${Math.max(4,s.length+1)}ch`},className:n("inline-block min-w-[4ch] max-w-[16ch] border-b-2 bg-transparent px-1 text-center text-sm font-semibold outline-none transition-colors",s?"border-[#1167e8] text-[#0b57d0]":"border-[#9cc4f5] text-[#64748b]",d&&"cursor-not-allowed opacity-70")})]},a)})})]})}
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ResolvedImage as a}from"../../../components/common/ResolvedImage";import{cn as n}from"../../../shared/lib/utils";import{transformWordFillParagraph as o}from"../../../components/exams/take/exam-taking.utils";import{englishCertQuestionDomId as l}from"./english-cert-scroll";export function EcWordFillParagraph({part:s,answers:i,onAnswerChange:d,isReviewMode:c=!1}){const m=r(()=>o(s.questions),[s.questions]),{questionId:p,paragraph:x,title:b,imageUrl:f,wordBank:h,viewMode:u,instruction:g}=m,w=i[p]||[],N=r(()=>x.split(/(\{\d+\})/),[x]),v="WITH_WORD_BANK"===u,y=new Set(w.filter(Boolean)),_=(e,t)=>{if(c)return;const r=[...w];r[e]=t,d(p,r)};return t("div",{id:l(p),className:"scroll-mt-24 flex flex-col gap-4",children:[g&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:g}),f&&e("div",{className:"flex items-center justify-center",children:e(a,{src:f,alt:b||"Illustration",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),v&&h.length>0&&t("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:[e("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-[#64748b]",children:"Word bank"}),e("div",{className:"mt-2 flex flex-wrap gap-2",children:h.map((t,r)=>{const a=y.has(t.word);return e("span",{className:n("rounded-full border px-3 py-1 text-sm font-semibold transition-all",t.isExample?"border-[#b9edc8] bg-[#ddf8e7] text-[#15803d]":a?"border-[#d9e4f2] bg-[#f4f9ff] text-[#94a3b8] line-through":"border-[#9cc4f5] bg-white text-[#0b57d0]"),children:t.word},`${t.word}-${r}`)})})]}),e("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-5 text-base leading-loose text-[#0f1730] shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:N.map((r,a)=>{const o=r.match(/^\{(\d+)\}$/);if(!o)return e("span",{children:r},a);const l=parseInt(o[1],10),s=w[l]||"";return t("span",v?{className:"mx-1 inline-flex items-baseline gap-1 align-baseline",children:[t("span",{className:"text-[11px] font-bold text-[#1f7cff]",children:["(",l+1,")"]}),t("select",{value:s,disabled:c,onChange:e=>_(l,e.target.value),className:n("rounded-lg border-2 px-2 py-1 text-sm font-semibold outline-none transition-all",s?"border-[#1167e8] text-[#0b57d0]":"border-[#9cc4f5] text-[#64748b]",c&&"cursor-not-allowed opacity-70"),children:[e("option",{value:"",children:"———"}),h.filter(e=>!e.isExample).map((t,r)=>e("option",{value:t.word,children:t.word},`${l}-${r}`))]})]}:{className:"mx-1 inline-flex items-baseline gap-1 align-baseline",children:[t("span",{className:"text-[11px] font-bold text-[#1f7cff]",children:["(",l+1,")"]}),e("input",{type:"text",value:s,disabled:c,placeholder:"···",onChange:e=>_(l,e.target.value),style:{width:`${Math.max(4,s.length+1)}ch`},className:n("inline-block min-w-[4ch] max-w-[16ch] border-b-2 bg-transparent px-1 text-center text-sm font-semibold outline-none transition-colors",s?"border-[#1167e8] text-[#0b57d0]":"border-[#9cc4f5] text-[#64748b]",c&&"cursor-not-allowed opacity-70")})]},a)})})]})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useRef as r,useEffect as n,useMemo as s,useCallback as a,memo as i}from"react";import{ResolvedImage as o}from"../../../components/common/ResolvedImage";import{cn as l}from"../../../shared/lib/utils";import{transformWordFillStructuredForm as d}from"../../../components/exams/take/exam-taking.utils";function c(e){const t=Number(e);return Number.isFinite(t)?String(t+1):e}function b(e,t){const r=e.trim();return t?r:r.toLowerCase()}function u(e,t){const r=Object.keys(e).map(e=>Number(e)).filter(e=>Number.isFinite(e)).sort((e,t)=>e-t);if(0===r.length)return`Question ${t}`;const n=r[0]+1,s=r[r.length-1]+1;return n===s?`Question ${n}`:`Questions ${n}–${s}`}const m={},p=i(function({question:a,initialAnswers:i,onBlankChange:d,isReviewMode:u}){const m=r(null),p=r(d);p.current=d;const f=r(!1),x=r(i),h=s(()=>a.content.replace(/\{([\w\d]+)\}/g,(e,t)=>`\n <span class="ec-blank-wrapper" data-blank-wrapper="${t}">\n <span class="ec-blank-number" data-blank-number="${t}">${c(t)}</span>\n <input type="text" data-blank-key="${t}" class="ec-blank-input" />\n </span>\n `),[a.content]);return n(()=>{const e=m.current;if(!e)return;f.current||(e.innerHTML=h,f.current=!0);const t=e.querySelectorAll("input.ec-blank-input"),r=[];return t.forEach(t=>{const n=t.getAttribute("data-blank-key")||"",s=e.querySelector(`[data-blank-wrapper="${n}"]`),i=x.current[n]||"",o=a.answers[n]||"",d=i.trim().length>0,m=d&&b(i,a.caseSensitive)===b(o,a.caseSensitive),f=u&&!m&&o.trim().length>0;t.value=f?`${d?i:"(empty)"} → ${o}`:i,t.disabled=u,t.className=l("ec-blank-input inline-block w-[110px] border-0 border-b-2 border-dashed bg-transparent px-1 py-0 text-base font-semibold leading-tight align-middle outline-none transition-colors",u?m?"border-[#22c55e] text-[#15803d]":d?"border-[#ef4444] text-red-700":"border-[#f97316] text-[#c2410c]":"border-[#1167e8] text-[#0f1730] hover:border-[#0b57d0] focus:border-[#0b57d0]");const h=e.querySelector(`[data-blank-number="${n}"]`);h&&(h.textContent=c(n),h.className=l("ec-blank-number mr-1 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full px-1 text-[11px] font-bold leading-none text-white align-middle",u?m?"bg-[#22c55e]":d?"bg-[#ef4444]":"bg-[#f97316]":"bg-[#0b57d0]")),s&&(s.className=l("ec-blank-wrapper inline-flex items-center whitespace-nowrap align-middle",u?"mx-1":"mx-0.5"));const g=e=>{const t=e.target;p.current(n,t.value)};t.addEventListener("input",g),r.push({el:t,handler:g})}),()=>{r.forEach(({el:e,handler:t})=>{e.removeEventListener("input",t)})}},[h,u]),t("div",{className:"space-y-3",children:[a.title&&e("h3",{className:"text-base font-semibold text-[#0f1730]",children:a.title}),a.imageUrl&&e("div",{className:"flex justify-center",children:e("div",{className:"overflow-hidden rounded-lg border border-[#d9e4f2]",children:e(o,{src:a.imageUrl,alt:a.title||"Question image",className:"max-h-56 w-auto object-contain"})})}),e("div",{ref:m,className:"ec-structured-content w-full overflow-x-auto rounded-xl border border-[#d9e4f2] bg-[#f4f9ff] p-5 text-base leading-relaxed text-[#0f1730] [&_table]:w-full [&_table]:border-collapse [&_td]:border [&_td]:border-[#d9e4f2] [&_td]:px-4 [&_td]:py-3 [&_td]:align-top [&_th]:border [&_th]:border-[#d9e4f2] [&_th]:bg-[#e9f3ff] [&_th]:px-4 [&_th]:py-3 [&_th]:text-left [&_th]:font-semibold"}),u&&Object.keys(a.answers).length>0&&t("div",{className:"rounded-xl border border-[#d9e4f2] bg-white/70 p-3",children:[e("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-[#64748b]",children:"Correct answers"}),e("div",{className:"mt-1 flex flex-wrap gap-1.5",children:Object.entries(a.answers).map(([e,r])=>t("span",{className:"rounded border border-[#b9edc8] bg-[#ddf8e7] px-2 py-0.5 text-xs font-semibold text-[#15803d]",children:[e,": ",r]},e))})]})]})});export function EcWordFillStructuredForm({part:n,answers:i,onAnswerChange:l,isReviewMode:c=!1}){const{questions:b,instruction:f,groupTitle:x,groupContent:h,groupImageUrl:g}=s(()=>d(n.questions),[n.questions]),w=r(i);w.current=i;const N=r(l);N.current=l;const v=a((e,t,r)=>{const n=w.current[e]||{};N.current(e,{...n,[t]:r})},[]),k=s(()=>{const e={};return b.forEach(t=>{e[t.id]=(e,r)=>v(t.id,e,r)}),e},[b,v]);return t("div",{className:"flex flex-col gap-4",children:[f&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:f}),x&&e("h2",{className:"text-center text-lg font-bold uppercase text-[#0b57d0]",children:x}),g&&e("div",{className:"flex items-center justify-center",children:e(o,{src:g,alt:x||"Group image",className:"max-h-[300px] rounded-lg object-contain shadow-md"})}),e("div",{className:"flex flex-col gap-4",children:b.map(r=>t("div",{id:`question-${r.id}`,className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)] backdrop-blur-md",children:[e("div",{className:"mb-2 flex items-center gap-2",children:e("span",{className:"inline-flex items-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] px-3 py-1 text-xs font-bold text-white shadow-sm",children:u(r.answers,r.questionNumber)})}),e(p,{question:r,initialAnswers:i[r.id]||m,onBlankChange:k[r.id],isReviewMode:c})]},r.id))})]})}
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useRef as r,useEffect as n,useMemo as s,useCallback as a,memo as o}from"react";import{ResolvedImage as i}from"../../../components/common/ResolvedImage";import{cn as l}from"../../../shared/lib/utils";import{transformWordFillStructuredForm as d}from"../../../components/exams/take/exam-taking.utils";import{englishCertQuestionDomId as c}from"./english-cert-scroll";function b(e){const t=Number(e);return Number.isFinite(t)?String(t+1):e}function u(e,t){const r=e.trim();return t?r:r.toLowerCase()}function m(e,t){const r=Object.keys(e).map(e=>Number(e)).filter(e=>Number.isFinite(e)).sort((e,t)=>e-t);if(0===r.length)return`Question ${t}`;const n=r[0]+1,s=r[r.length-1]+1;return n===s?`Question ${n}`:`Questions ${n}–${s}`}const p={},f=o(function({question:a,initialAnswers:o,onBlankChange:d,isReviewMode:c}){const m=r(null),p=r(d);p.current=d;const f=r(!1),x=r(o),h=s(()=>a.content.replace(/\{([\w\d]+)\}/g,(e,t)=>`\n <span class="ec-blank-wrapper" data-blank-wrapper="${t}">\n <span class="ec-blank-number" data-blank-number="${t}">${b(t)}</span>\n <input type="text" data-blank-key="${t}" class="ec-blank-input" />\n </span>\n `),[a.content]);return n(()=>{const e=m.current;if(!e)return;f.current||(e.innerHTML=h,f.current=!0);const t=e.querySelectorAll("input.ec-blank-input"),r=[];return t.forEach(t=>{const n=t.getAttribute("data-blank-key")||"",s=e.querySelector(`[data-blank-wrapper="${n}"]`),o=x.current[n]||"",i=a.answers[n]||"",d=o.trim().length>0,m=d&&u(o,a.caseSensitive)===u(i,a.caseSensitive),f=c&&!m&&i.trim().length>0;t.value=f?`${d?o:"(empty)"} → ${i}`:o,t.disabled=c,t.className=l("ec-blank-input inline-block w-[110px] border-0 border-b-2 border-dashed bg-transparent px-1 py-0 text-base font-semibold leading-tight align-middle outline-none transition-colors",c?m?"border-[#22c55e] text-[#15803d]":d?"border-[#ef4444] text-red-700":"border-[#f97316] text-[#c2410c]":"border-[#1167e8] text-[#0f1730] hover:border-[#0b57d0] focus:border-[#0b57d0]");const h=e.querySelector(`[data-blank-number="${n}"]`);h&&(h.textContent=b(n),h.className=l("ec-blank-number mr-1 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full px-1 text-[11px] font-bold leading-none text-white align-middle",c?m?"bg-[#22c55e]":d?"bg-[#ef4444]":"bg-[#f97316]":"bg-[#0b57d0]")),s&&(s.className=l("ec-blank-wrapper inline-flex items-center whitespace-nowrap align-middle",c?"mx-1":"mx-0.5"));const g=e=>{const t=e.target;p.current(n,t.value)};t.addEventListener("input",g),r.push({el:t,handler:g})}),()=>{r.forEach(({el:e,handler:t})=>{e.removeEventListener("input",t)})}},[h,c]),t("div",{className:"space-y-3",children:[a.title&&e("h3",{className:"text-base font-semibold text-[#0f1730]",children:a.title}),a.imageUrl&&e("div",{className:"flex justify-center",children:e("div",{className:"overflow-hidden rounded-lg border border-[#d9e4f2]",children:e(i,{src:a.imageUrl,alt:a.title||"Question image",className:"max-h-56 w-auto object-contain"})})}),e("div",{ref:m,className:"ec-structured-content w-full overflow-x-auto rounded-xl border border-[#d9e4f2] bg-[#f4f9ff] p-5 text-base leading-relaxed text-[#0f1730] [&_table]:w-full [&_table]:border-collapse [&_td]:border [&_td]:border-[#d9e4f2] [&_td]:px-4 [&_td]:py-3 [&_td]:align-top [&_th]:border [&_th]:border-[#d9e4f2] [&_th]:bg-[#e9f3ff] [&_th]:px-4 [&_th]:py-3 [&_th]:text-left [&_th]:font-semibold"}),c&&Object.keys(a.answers).length>0&&t("div",{className:"rounded-xl border border-[#d9e4f2] bg-white/70 p-3",children:[e("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-[#64748b]",children:"Correct answers"}),e("div",{className:"mt-1 flex flex-wrap gap-1.5",children:Object.entries(a.answers).map(([e,r])=>t("span",{className:"rounded border border-[#b9edc8] bg-[#ddf8e7] px-2 py-0.5 text-xs font-semibold text-[#15803d]",children:[e,": ",r]},e))})]})]})});export function EcWordFillStructuredForm({part:n,answers:o,onAnswerChange:l,isReviewMode:b=!1}){const{questions:u,instruction:x,groupTitle:h,groupContent:g,groupImageUrl:w}=s(()=>d(n.questions),[n.questions]),N=r(o);N.current=o;const v=r(l);v.current=l;const k=a((e,t,r)=>{const n=N.current[e]||{};v.current(e,{...n,[t]:r})},[]),y=s(()=>{const e={};return u.forEach(t=>{e[t.id]=(e,r)=>k(t.id,e,r)}),e},[u,k]);return t("div",{className:"flex flex-col gap-4",children:[x&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:x}),h&&e("h2",{className:"text-center text-lg font-bold uppercase text-[#0b57d0]",children:h}),w&&e("div",{className:"flex items-center justify-center",children:e(i,{src:w,alt:h||"Group image",className:"max-h-[300px] rounded-lg object-contain shadow-md"})}),e("div",{className:"flex flex-col gap-4",children:u.map(r=>t("div",{id:c(r.id),className:"scroll-mt-24 rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)] backdrop-blur-md",children:[e("div",{className:"mb-2 flex items-center gap-2",children:e("span",{className:"inline-flex items-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] px-3 py-1 text-xs font-bold text-white shadow-sm",children:m(r.answers,r.questionNumber)})}),e(f,{question:r,initialAnswers:o[r.id]||p,onBlankChange:y[r.id],isReviewMode:b})]},r.id))})]})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ResolvedImage as s}from"../../../components/common/ResolvedImage";import{cn as i}from"../../../shared/lib/utils";import{transformWriteShortLetter as a}from"../../../components/exams/take/exam-taking.utils";export function EcWritingTask({part:n,answers:l,onAnswerChange:d,isReviewMode:o=!1}){const c=n.questions[0],m=r(()=>a(c),[c]);if(!c)return null;const{prompt:x,requirements:p,minWords:f,maxWords:u,guideImages:b}=m,h=l[c.id]||"",g=function(e){const t=e.trim();return t?t.split(/\s+/).length:0}(h),w=!f||g>=f,N=!u||g<=u;return t("div",{className:"flex flex-col gap-4",children:[n.instructions&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:n.instructions}),x&&e("div",{className:"whitespace-pre-line rounded-2xl border border-[#d9e4f2] bg-white/90 p-5 text-base leading-relaxed text-[#0f1730] shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:x}),p&&p.length>0&&t("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/70 p-4",children:[e("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-[#64748b]",children:"Yêu cầu"}),e("ul",{className:"mt-2 list-inside list-disc space-y-1 text-sm text-[#0f1730]",children:p.map((t,r)=>e("li",{children:t},r))})]}),b&&b.length>0&&e("div",{className:"flex flex-col items-center justify-center gap-4 py-4",children:b.map((t,r)=>e(s,{src:t,alt:`Guide ${r+1}`,className:"w-full max-w-3xl rounded-xl bg-white object-contain shadow-sm"},r))}),t("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:[e("textarea",{value:h,disabled:o,placeholder:"Viết bài của bạn ở đây…",onChange:e=>d(c.id,e.target.value),rows:12,className:i("w-full resize-y rounded-xl border-2 border-[#9cc4f5] bg-[#f4f9ff] px-4 py-3 text-sm leading-relaxed text-[#0f1730] outline-none transition-all focus:border-[#1167e8]",o&&"cursor-not-allowed opacity-80")}),t("div",{className:"mt-2 flex items-center justify-between text-xs",children:[t("span",{className:i("font-semibold",w&&N?"text-[#15803d]":"text-[#ef4444]"),children:[g," từ"]}),(f||u)&&t("span",{className:"text-[#64748b]",children:[f?`Tối thiểu ${f}`:"",f&&u?" · ":"",u?`Tối đa ${u}`:""]})]})]})]})}
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ListChecks as s,PenLine as l,CheckCircle2 as a,AlertCircle as d}from"lucide-react";import{ResolvedImage as i}from"../../../components/common/ResolvedImage";import{HtmlOrText as o}from"../../../shared/lib/html-content";import{cn as n}from"../../../shared/lib/utils";import{transformWriteShortLetter as c}from"../../../components/exams/take/utils/question-transformers";import{englishCertQuestionDomId as m}from"./english-cert-scroll";export function EcWritingTask({part:f,answers:x,onAnswerChange:p,isReviewMode:u=!1}){const b=f.questions[0],h=r(()=>b?c(b):null,[b]),g=h?.minWords,w=h?.maxWords,v=b&&x[b.id]||"",N=function(e){const t=e.trim();return t?t.split(/\s+/).length:0}(v),y=r(()=>{if(g&&N<g){const e=g-N;return{text:`Add ${e} more word${1===e?"":"s"} to reach the minimum`,ok:!1}}if(w&&N>w){const e=N-w;return{text:`${e} word${1===e?"":"s"} over the maximum limit`,ok:!1}}return g||w?{text:"Word count requirement met",ok:!0}:null},[N,g,w]);if(!b||!h)return null;const{prompt:k,requirements:$,guideImages:j}=h,W=(!g||N>=g)&&(!w||N<=w),_=w||g||0,q=_?Math.min(100,Math.round(N/_*100)):0;return t("div",{id:m(b.id),className:"scroll-mt-24 flex flex-col gap-5",children:[t("div",{className:"flex flex-col gap-5",children:[t("div",{className:"overflow-hidden rounded-2xl border border-[#cfe0f7] bg-white shadow-[0_18px_40px_rgba(13,71,161,0.10)]",children:[k&&e(o,{value:k,as:"div",className:"whitespace-pre-line px-5 pb-4 pt-5 text-base leading-relaxed text-[#0f1730]"}),$&&$.length>0&&e("div",{className:n("px-5 pb-4",!k&&"pt-5"),children:t("div",{className:"rounded-xl border border-[#e3edfb] bg-[#f6faff] p-4",children:[t("div",{className:"flex items-center gap-1.5 text-[11px] font-bold uppercase tracking-wider text-[#0b57d0]",children:[e(s,{className:"h-3.5 w-3.5"}),"Requirements"]}),e("ul",{className:"mt-2 list-inside list-disc space-y-1.5 text-sm text-[#0f1730]",children:$.map((t,r)=>e("li",{children:e(o,{value:t,as:"span"})},r))})]})}),g&&t("div",{className:"border-t border-[#e3edfb] bg-[#f9fbfe] px-5 py-3 text-sm font-semibold text-[#0f1730]",children:["Write at least ",g," words."]})]}),j&&j.length>0&&e("div",{className:"flex flex-col items-center justify-center gap-4 rounded-2xl border border-[#d9e4f2] bg-white/60 p-4",children:j.map((t,r)=>e(i,{src:t,alt:`Guide ${r+1}`,className:"w-full max-w-3xl rounded-xl bg-white object-contain shadow-sm"},r))})]}),t("div",{className:"overflow-hidden rounded-2xl border border-[#cfe0f7] bg-white shadow-[0_18px_40px_rgba(13,71,161,0.10)]",children:[t("div",{className:"flex items-center gap-1.5 border-b border-[#e3edfb] bg-[#f6faff] px-4 py-2.5 text-xs font-bold uppercase tracking-wider text-[#0b57d0]",children:[e(l,{className:"h-3.5 w-3.5"}),"Your answer"]}),e("textarea",{value:v,disabled:u,placeholder:"Write your essay here…",onChange:e=>p(b.id,e.target.value),rows:14,className:n("w-full resize-y border-0 bg-white px-5 py-4 text-sm leading-relaxed text-[#0f1730] outline-none transition-all placeholder:text-[#9aa9c2] focus:bg-[#fbfdff]",u&&"cursor-not-allowed opacity-80")}),t("div",{className:"flex flex-col gap-2 border-t border-[#e3edfb] bg-[#f9fbfe] px-4 py-3",children:[t("div",{className:"flex items-center justify-between text-xs",children:[t("span",{className:n("inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 font-semibold",W?"bg-[#ddf8e7] text-[#15803d]":"bg-[#fde8e8] text-[#ef4444]"),children:[N," words"]}),(g||w)&&t("span",{className:"font-medium text-[#64748b]",children:[g?`Min ${g}`:"",g&&w?" · ":"",w?`Max ${w}`:""]})]}),_>0&&e("div",{className:"h-1.5 w-full overflow-hidden rounded-full bg-[#e3edfb]",children:e("div",{className:n("h-full rounded-full transition-all",W?"bg-[#15803d]":"bg-[#1167e8]"),style:{width:`${q}%`}})}),y&&t("div",{className:n("flex items-center gap-1.5 text-xs font-medium",y.ok?"text-[#15803d]":"text-[#64748b]"),children:[y.ok?e(a,{className:"h-3.5 w-3.5 shrink-0"}):e(d,{className:"h-3.5 w-3.5 shrink-0"}),y.text]})]})]})]})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as i}from"react";import{List as r}from"lucide-react";import{Sheet as o,SheetContent as l,SheetHeader as n,SheetTitle as a}from"../../../components/ui/sheet";import{EnglishCertificationHeader as s}from"./EnglishCertificationHeader";import{EnglishCertificationNavigationPanel as d}from"./EnglishCertificationNavigationPanel";import{EnglishCertificationFooterBar as c}from"./EnglishCertificationFooterBar";import{ENGLISH_CERT_APP_BACKGROUND as h,ENGLISH_CERT_PRIMARY_GRADIENT as m}from"./english-certification-theme";export function EnglishCertificationExamLayout({children:f,headerProps:x,navigationProps:p,footerProps:b}){const[g,w]=i(!0),[u,v]=i(!1);return t("div",{className:"flex h-screen flex-col overflow-hidden text-[#0f1730]",style:{background:h},children:[e(s,{...x}),t("div",{className:"flex flex-1 gap-4 overflow-hidden px-4 py-4 lg:px-6",children:[e("main",{id:"exam-main-scroll-area",className:"min-w-0 flex-1 overflow-y-auto",children:f}),g&&t("aside",{className:"hidden w-[360px] shrink-0 flex-col overflow-hidden rounded-xl border border-[#d9e4f2] bg-white/90 shadow-[0_14px_35px_rgba(13,71,161,0.12)] backdrop-blur-md lg:flex","aria-label":"Answer sheet navigation",children:[t("div",{className:"flex h-14 items-center justify-between px-5 text-white",style:{background:m},children:[e("h3",{className:"text-[18px] font-black tracking-[0.1em]",children:"ANSWER SHEET"}),e("button",{type:"button",onClick:()=>w(!1),className:"text-sm font-bold text-white/90 hover:text-white",children:"Hide ≪"})]}),e("div",{className:"flex-1 overflow-hidden",children:e(d,{...p})})]}),!g&&e("button",{type:"button",onClick:()=>w(!0),className:"fixed right-0 top-24 z-30 hidden rounded-l-lg border border-r-0 border-[#d9e4f2] bg-white px-2 py-3 text-sm font-bold text-[#0b57d0] shadow-sm hover:bg-blue-50 lg:block","aria-label":"Show answer sheet",children:"≫"})]}),b&&e(c,{...b}),e("button",{type:"button",onClick:()=>v(!0),className:"fixed bottom-24 right-4 z-30 flex h-12 w-12 items-center justify-center rounded-full text-white shadow-lg lg:hidden",style:{background:m},"aria-label":"Open answer sheet",children:e(r,{className:"h-5 w-5"})}),e(o,{open:u,onOpenChange:v,children:t(l,{side:"bottom",className:"h-[78vh] p-0",children:[e(n,{className:"flex h-14 flex-row items-center px-5 text-white",style:{background:m},children:e(a,{className:"text-[18px] font-black tracking-[0.1em] text-white",children:"ANSWER SHEET"})}),e("div",{className:"h-[calc(78vh-3.5rem)] overflow-hidden",children:e(d,{...p})})]})})]})}
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as i}from"react";import{List as r}from"lucide-react";import{Sheet as o,SheetContent as l,SheetHeader as n,SheetTitle as a}from"../../../components/ui/sheet";import{EnglishCertificationHeader as s}from"./EnglishCertificationHeader";import{EnglishCertificationNavigationPanel as c}from"./EnglishCertificationNavigationPanel";import{EnglishCertificationFooterBar as d}from"./EnglishCertificationFooterBar";import{ENGLISH_CERT_APP_BACKGROUND as h,ENGLISH_CERT_PRIMARY_GRADIENT as m}from"./english-certification-theme";export function EnglishCertificationExamLayout({children:f,headerProps:x,navigationProps:p,footerProps:b}){const[g,u]=i(!0),[w,k]=i(!1),v={...p,onQuestionClick:e=>{p.onQuestionClick(e),k(!1)},onPartClick:e=>{p.onPartClick(e),k(!1)}};return t("div",{className:"flex h-screen flex-col overflow-hidden text-[#0f1730]",style:{background:h},children:[e(s,{...x}),t("div",{className:"flex flex-1 gap-4 overflow-hidden px-4 py-4 lg:px-6",children:[e("main",{id:"exam-main-scroll-area",className:"min-w-0 flex-1 overflow-y-auto",children:f}),g&&t("aside",{className:"hidden w-[360px] shrink-0 flex-col overflow-hidden rounded-xl border border-[#d9e4f2] bg-white/90 shadow-[0_14px_35px_rgba(13,71,161,0.12)] backdrop-blur-md lg:flex","aria-label":"Answer sheet navigation",children:[t("div",{className:"flex h-14 items-center justify-between px-5 text-white",style:{background:m},children:[e("h3",{className:"text-[18px] font-black tracking-[0.1em]",children:"ANSWER SHEET"}),e("button",{type:"button",onClick:()=>u(!1),className:"text-sm font-bold text-white/90 hover:text-white",children:"Hide ≪"})]}),e("div",{className:"flex-1 overflow-hidden",children:e(c,{...v})})]}),!g&&e("button",{type:"button",onClick:()=>u(!0),className:"fixed right-0 top-24 z-30 hidden rounded-l-lg border border-r-0 border-[#d9e4f2] bg-white px-2 py-3 text-sm font-bold text-[#0b57d0] shadow-sm hover:bg-blue-50 lg:block","aria-label":"Show answer sheet",children:"≫"})]}),b&&e(d,{...b}),e("button",{type:"button",onClick:()=>k(!0),className:"fixed bottom-24 right-4 z-30 flex h-12 w-12 items-center justify-center rounded-full text-white shadow-lg lg:hidden",style:{background:m},"aria-label":"Open answer sheet",children:e(r,{className:"h-5 w-5"})}),e(o,{open:w,onOpenChange:k,children:t(l,{side:"bottom",className:"h-[78vh] p-0",children:[e(n,{className:"flex h-14 flex-row items-center px-5 text-white",style:{background:m},children:e(a,{className:"text-[18px] font-black tracking-[0.1em] text-white",children:"ANSWER SHEET"})}),e("div",{className:"h-[calc(78vh-3.5rem)] overflow-hidden",children:e(c,{...v})})]})})]})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{FileText as a,Headphones as t,Info as r}from"lucide-react";import{EnglishCertificationQuestionCard as i}from"./EnglishCertificationQuestionCard";import{EnglishCertificationPassagePanel as n}from"./EnglishCertificationPassagePanel";import{EnglishCertificationReadingSection as l}from"./EnglishCertificationReadingSection";import{EnglishCertificationAudioPlayer as o}from"./EnglishCertificationAudioPlayer";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as d}from"./english-certification-theme";import{isHtmlContent as c,stripInstruction as p}from"./grouped-question-utils";export function EnglishCertificationGroupedQuestion({part:g,partConfig:u,answers:m,flaggedQuestions:f,onAnswerChange:h,onToggleFlag:x,isReviewMode:b=!1,isListeningPart:w=!1,partAudioUrl:N}){const v=u.startIndex??0,q=function(e,s){const a=e.questions[0];return(a?.questionGroup?.payload?.instructions??(s?.trim()||void 0)??a?.content?.question??"").trim()}(g,g.instructions??u.instructions),I=g.sections?.length?[(()=>{const e=g.questions[0]?.questionGroup?.payload??{},s=e.content??e.passage??"",a=p(s,q),t=e.imageUrl??e.passageImageUrl??"";return{groupId:g.partId,questions:g.questions,passage:a,passageTitle:e.passageTitle??e.title??"",passageSubtitle:e.subtitle??"",passageImageUrl:t,hasPassageContent:Boolean(a.trim())||Boolean(t)}})()]:function(e,s){const a=[],t=new Map;return e.questions.forEach(e=>{const s=e.group_id??e.id;t.has(s)||(t.set(s,[]),a.push(s)),t.get(s).push(e)}),a.map(e=>{const a=t.get(e),r=a[0]?.questionGroup?.payload??{},i=r.content??r.passage??"",n=p(i,s),l=r.imageUrl??r.passageImageUrl??"";return{groupId:e,questions:a,passage:n,passageTitle:r.passageTitle??r.title??"",passageSubtitle:r.subtitle??"",passageImageUrl:l,hasPassageContent:Boolean(n.trim())||Boolean(l)}})}(g,q);if(!I.length)return e("div",{className:"flex h-full items-center justify-center rounded-xl border border-red-200 bg-red-50 p-8 text-red-600",children:"No questions found for this part"});const y=w&&Boolean(N),_=s=>g.sections?.length?e("div",{className:"flex-1 space-y-6 px-4 py-4",children:g.sections.map((a,t)=>{const r=s.questions.filter(e=>{const s=g.questions.indexOf(e);return s>=a.startIndex-v&&s<=a.endIndex-v});return r.length?e(l,{part:g,section:a,questions:r,startIndex:v,answers:m,flaggedQuestions:f,onAnswerChange:h,onToggleFlag:x,isReviewMode:b},`${s.groupId}-section-${t}`):null})}):e("div",{className:"flex-1 space-y-3 px-4 py-4",children:s.questions.map(s=>{const a=g.questions.indexOf(s)+1;return e(i,{question:s,globalQuestionNumber:v+a,answer:m[s.id],isFlagged:f.has(s.id),sharedInstruction:q,onAnswerChange:h,onToggleFlag:x,isReviewMode:b},s.id)})});return s("div",{className:"flex h-full flex-col gap-6 overflow-y-auto pb-4",children:[y&&e("div",{className:`${d} w-full self-center`,children:e(o,{audioUrl:N,partNumber:g.partNo})}),q&&e("div",{className:`${d} w-full self-center`,children:s("div",{className:"flex items-start gap-3 rounded-xl border border-[#bfd8f8] bg-gradient-to-r from-[#eef5ff] to-[#f7fbff] px-5 py-4 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md",children:[e("span",{className:"mt-0.5 grid h-6 w-6 shrink-0 place-items-center rounded-full bg-[#1167e8] text-white",children:e(w?t:r,{className:"h-3.5 w-3.5"})}),s("div",{className:"min-w-0",children:[g.name&&e("div",{className:"mb-1 text-xs font-black uppercase tracking-wide text-[#0b57d0]",children:g.name}),e("p",{className:"text-base font-semibold leading-relaxed text-[#0f1730]",children:q})]})]})}),I.map(t=>{const i=g.questions.indexOf(t.questions[0])+v+1,l=g.questions.indexOf(t.questions[t.questions.length-1])+v+1,o=c(t.passage);return t.hasPassageContent?s("div",{className:"flex flex-col gap-3",children:[e("div",{className:"flex flex-wrap items-center gap-3 rounded-xl border border-[#d9e4f2] bg-white/85 px-4 py-3 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md",children:s("div",{className:"flex items-center gap-2.5 rounded-md border border-[#bfd8f8] bg-white/70 px-3 py-1.5 text-base font-bold text-[#0b57d0]",children:[e("span",{className:"grid h-[18px] w-[18px] place-items-center rounded-full bg-[#1167e8] text-white",children:e(r,{className:"h-3 w-3"})}),"Questions ",i,"–",l," refer to the following passage."]})}),s("div",{className:"grid gap-4",style:{gridTemplateColumns:"minmax(0, 1fr) minmax(0, 1fr)"},children:[e("div",{className:"max-h-[calc(100vh-220px)] min-h-0 overflow-y-auto",children:e(n,{passage:t.passage,passageTitle:t.passageTitle,passageSubtitle:t.passageSubtitle,passageImageUrl:t.passageImageUrl,passageIsHtml:o,partName:g.name??""})}),e("section",{className:"flex max-h-[calc(100vh-220px)] min-h-0 flex-col overflow-y-auto rounded-xl border border-[#d9e4f2] bg-white/90 shadow-[0_14px_35px_rgba(13,71,161,0.12)] backdrop-blur-md",children:_(t)})]})]},t.groupId):s("div",{className:`${d} flex w-full flex-col gap-3 self-center`,children:[s("div",{className:"flex items-center gap-4 rounded-xl border border-[#d9e4f2] bg-white/90 px-5 py-4 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md",children:[e("span",{className:"grid h-12 w-12 shrink-0 place-items-center rounded-xl bg-[#eaf2ff] text-[#1167e8]",children:e(a,{className:"h-6 w-6"})}),s("div",{className:"min-w-0 flex-1",children:[s("span",{className:"inline-flex items-center gap-1.5 rounded-md border border-[#bfd8f8] bg-[#eaf2ff] px-2.5 py-1 text-xs font-bold text-[#0b57d0]",children:["Questions ",i,"–",l]}),t.passageTitle&&e("p",{className:"mt-2 text-lg font-bold leading-tight text-[#0f1730]",children:t.passageTitle}),t.passageSubtitle&&e("p",{className:"mt-1 text-[15px] font-medium text-[#475569]",children:t.passageSubtitle})]}),t.passageImageUrl&&e("img",{src:t.passageImageUrl,alt:t.passageTitle||"Illustration",className:"h-20 w-32 shrink-0 rounded-lg object-contain"})]}),e("section",{className:"flex flex-col overflow-hidden rounded-xl border border-[#d9e4f2] bg-white/90 shadow-[0_14px_35px_rgba(13,71,161,0.12)] backdrop-blur-md",children:_(t)})]},t.groupId)})]})}
1
+ "use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{FileText as a,Headphones as t,Info as r}from"lucide-react";import{EnglishCertificationQuestionCard as i}from"./EnglishCertificationQuestionCard";import{EnglishCertificationPassagePanel as n}from"./EnglishCertificationPassagePanel";import{EnglishCertificationReadingSection as l}from"./EnglishCertificationReadingSection";import{EnglishCertificationAudioPlayer as o}from"./EnglishCertificationAudioPlayer";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as d}from"./english-certification-theme";import{ENGLISH_CERT_STICKY_AUDIO_ATTR as c,englishCertQuestionDomId as p}from"./english-cert-scroll";import{isHtmlContent as g,stripInstruction as m}from"./grouped-question-utils";export function EnglishCertificationGroupedQuestion({part:u,partConfig:f,answers:h,flaggedQuestions:x,onAnswerChange:b,onToggleFlag:w,isReviewMode:N=!1,isListeningPart:v=!1,partAudioUrl:q}){const I=f.startIndex??0,y=function(e,s){const a=e.questions[0];return(a?.questionGroup?.payload?.instructions??(s?.trim()||void 0)??a?.content?.question??"").trim()}(u,u.instructions??f.instructions),_=u.sections?.length?[(()=>{const e=u.questions[0]?.questionGroup?.payload??{},s=e.content??e.passage??"",a=m(s,y),t=e.imageUrl??e.passageImageUrl??"";return{groupId:u.partId,questions:u.questions,passage:a,passageTitle:e.passageTitle??e.title??"",passageSubtitle:e.subtitle??"",passageImageUrl:t,hasPassageContent:Boolean(a.trim())||Boolean(t)}})()]:function(e,s){const a=[],t=new Map;return e.questions.forEach(e=>{const s=e.group_id??e.id;t.has(s)||(t.set(s,[]),a.push(s)),t.get(s).push(e)}),a.map(e=>{const a=t.get(e),r=a[0]?.questionGroup?.payload??{},i=r.content??r.passage??"",n=m(i,s),l=r.imageUrl??r.passageImageUrl??"";return{groupId:e,questions:a,passage:n,passageTitle:r.passageTitle??r.title??"",passageSubtitle:r.subtitle??"",passageImageUrl:l,hasPassageContent:Boolean(n.trim())||Boolean(l)}})}(u,y);if(!_.length)return e("div",{className:"flex h-full items-center justify-center rounded-xl border border-red-200 bg-red-50 p-8 text-red-600",children:"No questions found for this part"});const C=v&&Boolean(q),T=s=>u.sections?.length?e("div",{className:"flex-1 space-y-6 px-4 py-4",children:u.sections.map((a,t)=>{const r=s.questions.filter(e=>{const s=u.questions.indexOf(e);return s>=a.startIndex-I&&s<=a.endIndex-I});return r.length?e(l,{part:u,section:a,questions:r,startIndex:I,answers:h,flaggedQuestions:x,onAnswerChange:b,onToggleFlag:w,isReviewMode:N},`${s.groupId}-section-${t}`):null})}):e("div",{className:"flex-1 space-y-3 px-4 py-4",children:s.questions.map(s=>{const a=u.questions.indexOf(s)+1;return e(i,{question:s,globalQuestionNumber:I+a,answer:h[s.id],isFlagged:x.has(s.id),sharedInstruction:y,onAnswerChange:b,onToggleFlag:w,isReviewMode:N,domId:p(s.id)},s.id)})});return s("div",{className:"flex h-full flex-col gap-6 overflow-y-auto pb-4",children:[C&&e("div",{[c]:"",className:`sticky top-0 z-20 ${d} w-full self-center`,children:e(o,{audioUrl:q,partNumber:u.partNo})}),y&&e("div",{className:`${d} w-full self-center`,children:s("div",{className:"flex items-start gap-3 rounded-xl border border-[#bfd8f8] bg-gradient-to-r from-[#eef5ff] to-[#f7fbff] px-5 py-4 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md",children:[e("span",{className:"mt-0.5 grid h-6 w-6 shrink-0 place-items-center rounded-full bg-[#1167e8] text-white",children:e(v?t:r,{className:"h-3.5 w-3.5"})}),s("div",{className:"min-w-0",children:[u.name&&e("div",{className:"mb-1 text-xs font-black uppercase tracking-wide text-[#0b57d0]",children:u.name}),e("p",{className:"text-base font-semibold leading-relaxed text-[#0f1730]",children:y})]})]})}),_.map(t=>{const i=u.questions.indexOf(t.questions[0])+I+1,l=u.questions.indexOf(t.questions[t.questions.length-1])+I+1,o=g(t.passage);return t.hasPassageContent?s("div",{className:"flex flex-col gap-3",children:[e("div",{className:"flex flex-wrap items-center gap-3 rounded-xl border border-[#d9e4f2] bg-white/85 px-4 py-3 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md",children:s("div",{className:"flex items-center gap-2.5 rounded-md border border-[#bfd8f8] bg-white/70 px-3 py-1.5 text-base font-bold text-[#0b57d0]",children:[e("span",{className:"grid h-[18px] w-[18px] place-items-center rounded-full bg-[#1167e8] text-white",children:e(r,{className:"h-3 w-3"})}),"Questions ",i,"–",l," refer to the following passage."]})}),s("div",{className:"grid gap-4",style:{gridTemplateColumns:"minmax(0, 1fr) minmax(0, 1fr)"},children:[e("div",{className:"max-h-[calc(100vh-220px)] min-h-0 overflow-y-auto",children:e(n,{passage:t.passage,passageTitle:t.passageTitle,passageSubtitle:t.passageSubtitle,passageImageUrl:t.passageImageUrl,passageIsHtml:o,partName:u.name??""})}),e("section",{className:"flex max-h-[calc(100vh-220px)] min-h-0 flex-col overflow-y-auto rounded-xl border border-[#d9e4f2] bg-white/90 shadow-[0_14px_35px_rgba(13,71,161,0.12)] backdrop-blur-md",children:T(t)})]})]},t.groupId):s("div",{className:`${d} flex w-full flex-col gap-3 self-center`,children:[s("div",{className:"flex items-center gap-4 rounded-xl border border-[#d9e4f2] bg-white/90 px-5 py-4 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md",children:[e("span",{className:"grid h-12 w-12 shrink-0 place-items-center rounded-xl bg-[#eaf2ff] text-[#1167e8]",children:e(a,{className:"h-6 w-6"})}),s("div",{className:"min-w-0 flex-1",children:[s("span",{className:"inline-flex items-center gap-1.5 rounded-md border border-[#bfd8f8] bg-[#eaf2ff] px-2.5 py-1 text-xs font-bold text-[#0b57d0]",children:["Questions ",i,"–",l]}),t.passageTitle&&e("p",{className:"mt-2 text-lg font-bold leading-tight text-[#0f1730]",children:t.passageTitle}),t.passageSubtitle&&e("p",{className:"mt-1 text-[15px] font-medium text-[#475569]",children:t.passageSubtitle})]}),t.passageImageUrl&&e("img",{src:t.passageImageUrl,alt:t.passageTitle||"Illustration",className:"h-20 w-32 shrink-0 rounded-lg object-contain"})]}),e("section",{className:"flex flex-col overflow-hidden rounded-xl border border-[#d9e4f2] bg-white/90 shadow-[0_14px_35px_rgba(13,71,161,0.12)] backdrop-blur-md",children:T(t)})]},t.groupId)})]})}
@@ -0,0 +1,17 @@
1
+ interface EnglishCertificationInstructionBannerProps {
2
+ instruction: string;
3
+ isListeningPart?: boolean;
4
+ isFullWidth?: boolean;
5
+ }
6
+ /**
7
+ * Premium branded "Directions" callout block.
8
+ *
9
+ * Design:
10
+ * - Gradient header strip with icon + "DIRECTIONS" label — clear visual anchor.
11
+ * - Cream-white body with generous padding for readability.
12
+ * - HTML instructions rendered as rich prose with "Example:" sections styled
13
+ * as an inset callout for TOEIC-style worked examples.
14
+ * - Plain-text instructions get the same header but a simple prose paragraph.
15
+ */
16
+ export declare function EnglishCertificationInstructionBanner({ instruction, isListeningPart, isFullWidth, }: EnglishCertificationInstructionBannerProps): import("react").JSX.Element;
17
+ export {};
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as n}from"react/jsx-runtime";import{Headphones as t,Info as i}from"lucide-react";import{ENGLISH_CERT_COLORS as r,ENGLISH_CERT_CONTENT_WIDTH_CLASS as l,ENGLISH_CERT_PRIMARY_GRADIENT as s}from"./english-certification-theme";import{isHtmlContent as a}from"./grouped-question-utils";export function EnglishCertificationInstructionBanner({instruction:o,isListeningPart:c=!1,isFullWidth:d=!1}){if(!o)return null;const p=c?t:i,m=a(o),h=m?o:(f=o).replace(/^\s*directions\s*[:.\\-–]?\s*/i,"").trim()||f;var f;return n("div",{className:d?"w-full":`${l} w-full self-center`,children:[n("div",{className:"overflow-hidden rounded-2xl",style:{boxShadow:"0 4px 6px -1px rgba(11,87,208,0.08), 0 12px_28px rgba(11,87,208,0.10)",border:`1px solid ${r.blue600}26`},children:[n("div",{className:"flex items-center gap-3 px-5 py-3",style:{background:s},children:[e("span",{className:"grid h-8 w-8 shrink-0 place-items-center rounded-lg",style:{background:"rgba(255,255,255,0.18)"},children:e(p,{className:"h-4 w-4 text-white",strokeWidth:2.5})}),e("span",{className:"text-[11px] font-black uppercase tracking-[0.22em] text-white/90",children:"Directions"}),e("div",{className:"ml-auto flex items-center gap-1","aria-hidden":!0,children:[.5,.35,.2].map((n,t)=>e("span",{className:"h-1.5 w-1.5 rounded-full bg-white",style:{opacity:n}},t))})]}),e("div",{className:"px-6 py-5",style:{background:"linear-gradient(160deg, #f8fbff 0%, #eef5ff 100%)"},children:m?e("div",{className:"ec-instruction-html text-[15px] leading-[1.8] text-[#0f1730]",dangerouslySetInnerHTML:{__html:h}}):e("p",{className:"text-[15px] font-semibold leading-[1.8] text-[#0f1730]",children:h})})]}),e("style",{children:`\n /* Base paragraphs */\n .ec-instruction-html p {\n margin-bottom: 0.5rem;\n font-size: 15px;\n font-weight: 600;\n color: #0f1730;\n }\n .ec-instruction-html p:last-child {\n margin-bottom: 0;\n }\n\n /* Bold labels ("Directions:", "Example:") */\n .ec-instruction-html strong {\n font-weight: 700;\n color: ${r.blue700};\n }\n\n /* "Example:" paragraph — inset callout block */\n .ec-instruction-html p:has(> strong:first-child):not(:first-child) {\n margin-top: 1rem;\n padding: 0.7rem 1rem;\n background: rgba(11, 87, 208, 0.06);\n border-left: 3px solid ${r.blue600};\n border-radius: 0 8px 8px 0;\n }\n\n /* Lines that follow inside an inset callout */\n .ec-instruction-html p:has(> strong:first-child) ~ p {\n padding-left: 1rem;\n font-size: 14.5px;\n font-weight: 500;\n color: #1e2d4d;\n }\n `})]})}
@@ -0,0 +1,24 @@
1
+ interface EnglishCertificationPartHeaderProps {
2
+ /** e.g. "Part 2" or "PART 2" — displayed as the primary label. */
3
+ partName?: string;
4
+ /** e.g. 2 — used to render the large decorative number. */
5
+ partNo?: number;
6
+ /** Skill category to pick the right icon and accent colour. */
7
+ skill?: 'LISTENING' | 'READING' | 'WRITING' | 'SPEAKING' | string;
8
+ /** Optional subtitle, e.g. "Question Responses" */
9
+ subtitle?: string;
10
+ /** Whether to span the full width of the container (used for split views). */
11
+ isFullWidth?: boolean;
12
+ }
13
+ /**
14
+ * Premium standalone Part title header for English Certification exams.
15
+ *
16
+ * Design decisions:
17
+ * - Full-bleed gradient card matching the brand palette (never plain text).
18
+ * - Large ghost number in the background gives spatial identity.
19
+ * - Skill badge + icon communicate exam section at a glance.
20
+ * - Decorative wave SVG and a thin accent bar at the bottom tie it
21
+ * to the footer / audio-player language.
22
+ */
23
+ export declare function EnglishCertificationPartHeader({ partName, partNo, skill, subtitle, isFullWidth, }: EnglishCertificationPartHeaderProps): import("react").JSX.Element;
24
+ export {};
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import{BookOpen as l,Headphones as t,Pencil as r,Mic as n}from"lucide-react";import{ENGLISH_CERT_COLORS as i,ENGLISH_CERT_CONTENT_WIDTH_CLASS as c,ENGLISH_CERT_PRIMARY_GRADIENT as s}from"./english-certification-theme";export function EnglishCertificationPartHeader({partName:o,partNo:d,skill:p,subtitle:h,isFullWidth:u=!1}){if(!o&&void 0===d)return null;const{Icon:b,label:x}=function(e){switch((e??"").toUpperCase()){case"LISTENING":return{Icon:t,label:"Listening",color:"#0b57d0"};case"READING":return{Icon:l,label:"Reading",color:"#0f6cbf"};case"WRITING":return{Icon:r,label:"Writing",color:"#1255a0"};case"SPEAKING":return{Icon:n,label:"Speaking",color:"#0d4fa3"};default:return{Icon:l,label:null,color:i.blue700}}}(p),g=o?o.replace(/^part\s*/i,"").toUpperCase():String(d??""),m=d??o?.match(/\d+/)?.[0]??"";return e("div",{className:u?"w-full":`${c} w-full self-center`,children:a("div",{className:"relative overflow-hidden rounded-2xl",style:{background:s,boxShadow:"0 8px 32px rgba(11,87,208,0.28), 0 2px 8px rgba(11,87,208,0.16)"},children:[e("span",{"aria-hidden":!0,className:"pointer-events-none absolute -right-4 -top-3 select-none font-black leading-none text-white/10",style:{fontSize:"clamp(80px, 12vw, 110px)"},children:m}),e("div",{"aria-hidden":!0,className:"pointer-events-none absolute -left-12 -top-12 h-48 w-48 rounded-full",style:{background:"radial-gradient(circle, rgba(255,255,255,0.12) 0%, transparent 70%)"}}),a("div",{className:"relative flex items-center gap-5 px-7 py-5",children:[e("div",{className:"grid h-14 w-14 shrink-0 place-items-center rounded-2xl shadow-[0_4px_16px_rgba(0,0,0,0.20)]",style:{background:"rgba(255,255,255,0.18)",backdropFilter:"blur(8px)"},children:e(b,{className:"h-6 w-6 text-white",strokeWidth:2})}),a("div",{className:"min-w-0 flex-1",children:[x&&e("span",{className:"mb-1.5 inline-flex items-center gap-1.5 rounded-full px-3 py-0.5 text-[10px] font-black uppercase tracking-[0.2em]",style:{background:"rgba(255,255,255,0.20)",color:"rgba(255,255,255,0.90)"},children:x}),a("p",{className:"text-2xl font-black leading-none tracking-tight text-white drop-shadow-sm",children:["Part"," ",e("span",{className:"rounded-lg px-2.5 py-0.5 text-[22px] font-black",style:{background:"rgba(255,255,255,0.22)"},children:g})]}),h&&e("p",{className:"mt-1 text-[13px] font-medium text-white/75",children:h})]})]}),e("svg",{"aria-hidden":!0,className:"block w-full",height:"18",viewBox:"0 0 940 18",preserveAspectRatio:"none",fill:"none",children:e("path",{d:"M0 8C160 0 300 16 470 8C640 0 780 16 940 8V18H0V8Z",fill:"rgba(255,255,255,0.10)"})})]})})}
@@ -9,6 +9,8 @@ interface EnglishCertificationQuestionCardProps {
9
9
  onAnswerChange: (questionId: string, answer: any) => void;
10
10
  onToggleFlag: (questionId: string) => void;
11
11
  isReviewMode?: boolean;
12
+ /** Optional DOM id used by the Answer Sheet to scroll the card into view. */
13
+ domId?: string;
12
14
  }
13
15
  /**
14
16
  * Single MCQ rendered as a standalone Ocean Edu white card.
@@ -16,5 +18,5 @@ interface EnglishCertificationQuestionCardProps {
16
18
  * Replaces the former shared-section/divider layout so each question matches the
17
19
  * target mockup (own card, number chip, flag button, compact options).
18
20
  */
19
- export declare function EnglishCertificationQuestionCard({ question, globalQuestionNumber, answer, isFlagged, sharedInstruction, onAnswerChange, onToggleFlag, isReviewMode, }: EnglishCertificationQuestionCardProps): import("react").JSX.Element;
21
+ export declare function EnglishCertificationQuestionCard({ question, globalQuestionNumber, answer, isFlagged, sharedInstruction, onAnswerChange, onToggleFlag, isReviewMode, domId, }: EnglishCertificationQuestionCardProps): import("react").JSX.Element;
20
22
  export {};
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{EnglishCertificationOptionSelector as t}from"./EnglishCertificationOptionSelector";import{EnglishCertificationFlagButton as n}from"./EnglishCertificationFlagButton";export function EnglishCertificationQuestionCard({question:o,globalQuestionNumber:r,answer:s,isFlagged:a,sharedInstruction:l,onAnswerChange:d,onToggleFlag:c,isReviewMode:g=!1}){const m=o.content||{},f=m.options||[],p=m.question?.trim()??"",u=p.length>0&&p!==l;return e("article",{className:"rounded-xl border border-[#d9e4f2] bg-white/90 px-4 py-4 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md transition-colors",children:i("div",{className:"grid grid-cols-[44px_1fr_32px] gap-1",children:[e("div",{className:"grid h-9 w-9 place-items-center rounded-full bg-[#eef5ff] text-base font-black leading-none text-[#0b57d0]",children:r}),i("div",{className:"min-w-0",children:[u&&e("div",{className:"mb-2 text-base font-black leading-snug text-[#10172f]",children:p}),e(t,{options:f.map((e,i)=>({id:e?.id||String.fromCharCode(65+i),label:e?.id||String.fromCharCode(65+i),text:e?.text||String(e??"")})),selectedOptionId:s?.optionId??null,onSelect:e=>d(o.id,{optionId:e}),isReviewMode:g,disabled:g,variant:"compact"})]}),e(n,{isFlagged:a,onToggle:()=>c(o.id),size:"sm",className:"self-start justify-self-end"})]})})}
1
+ "use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{EnglishCertificationOptionSelector as t}from"./EnglishCertificationOptionSelector";import{EnglishCertificationFlagButton as n}from"./EnglishCertificationFlagButton";export function EnglishCertificationQuestionCard({question:o,globalQuestionNumber:r,answer:s,isFlagged:a,sharedInstruction:d,onAnswerChange:l,onToggleFlag:c,isReviewMode:g=!1,domId:m}){const f=o.content||{},p=f.options||[],u=f.question?.trim()??"",b=u.length>0&&u!==d;return e("article",{id:m,className:"scroll-mt-24 rounded-xl border border-[#d9e4f2] bg-white/90 px-4 py-4 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md transition-colors",children:i("div",{className:"grid grid-cols-[44px_1fr_32px] gap-1",children:[e("div",{className:"grid h-9 w-9 place-items-center rounded-full bg-[#eef5ff] text-base font-black leading-none text-[#0b57d0]",children:r}),i("div",{className:"min-w-0",children:[b&&e("div",{className:"mb-2 text-base font-black leading-snug text-[#10172f]",children:u}),e(t,{options:p.map((e,i)=>({id:e?.id||String.fromCharCode(65+i),label:e?.id||String.fromCharCode(65+i),text:e?.text||String(e??"")})),selectedOptionId:s?.optionId??null,onSelect:e=>l(o.id,{optionId:e}),isReviewMode:g,disabled:g,variant:"compact"})]}),e(n,{isFlagged:a,onToggle:()=>c(o.id),size:"sm",className:"self-start justify-self-end"})]})})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{SkillEnum as i}from"../../../shared/types/common.types";import{EnglishCertificationSingleQuestionList as n}from"./EnglishCertificationSingleQuestionList";import{EnglishCertificationGroupedQuestion as o}from"./EnglishCertificationGroupedQuestion";import{EnglishCertificationAudioPlayer as s}from"./EnglishCertificationAudioPlayer";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as t}from"./english-certification-theme";import{EcWordFillStructuredForm as a}from"./EcWordFillStructuredForm";import{EcMatchByWritingAnswer as l}from"./EcMatchByWritingAnswer";import{EcAnswerTheQuestion as d}from"./EcAnswerTheQuestion";import{EcWordFillParagraph as c}from"./EcWordFillParagraph";import{EcWritingTask as u}from"./EcWritingTask";const g=new Set(["CHOOSE_THE_CORRECT_ANSWER"]);export function EnglishCertificationQuestionRenderer({part:p,partConfig:m,answers:f,flaggedQuestions:h,onAnswerChange:w,onToggleFlag:R,isReviewMode:A=!1,isAudioPlayed:E=!1,onAudioFirstPlay:C}){if(!p.questions.length)return e("div",{className:"flex h-full items-center justify-center rounded-xl border border-red-200 bg-red-50 p-8 text-red-600",children:"No questions found for this part"});const T=m.category===i.LISTENING,N=T?p.audioUrl??m.audioUrl??"":void 0,_=p.questionType,v=Boolean(p.isGroup)&&"DOCUMENT"===p.group?.type,x=m.isGroup&&g.has(_),y=Boolean(p.sections?.length);if(v||x||y)return e("div",{className:"h-full",children:e(o,{part:p,partConfig:m,answers:f,flaggedQuestions:h,onAnswerChange:w,onToggleFlag:R,isReviewMode:A,isListeningPart:T,partAudioUrl:N})});if(g.has(_))return e(n,{part:p,partConfig:m,answers:f,flaggedQuestions:h,onAnswerChange:w,onToggleFlag:R,isReviewMode:A,isListeningPart:T,partAudioUrl:N});return r("div",{className:"flex flex-col items-center gap-5 pb-4",children:[T&&e("div",{className:t,children:e(s,{audioUrl:N??"",partNumber:p.partNo,isLocked:!A&&E,onFirstPlay:C})}),e("div",{className:`${t} w-full`,children:(()=>{switch(_){case"WORD_FILL_STRUCTURED_FORM":return e(a,{part:p,answers:f,onAnswerChange:w,isReviewMode:A});case"MATCH_BY_WRITING_ANSWER":return e(l,{part:p,answers:f,onAnswerChange:w,isReviewMode:A});case"ANSWER_THE_QUESTION":return e(d,{part:p,answers:f,onAnswerChange:w,isReviewMode:A});case"WORD_FILL_PARAGRAPH":return e(c,{part:p,answers:f,onAnswerChange:w,isReviewMode:A});case"WRITE_A_SHORT_LETTER":return e(u,{part:p,answers:f,onAnswerChange:w,isReviewMode:A});default:return r("div",{className:"rounded-xl border border-amber-200 bg-amber-50 p-6 text-sm text-amber-700",children:['Loại câu hỏi "',_,'" chưa được hỗ trợ trong giao diện này.']})}})()})]})}
1
+ "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{SkillEnum as i}from"../../../shared/types/common.types";import{EnglishCertificationSingleQuestionList as t}from"./EnglishCertificationSingleQuestionList";import{EnglishCertificationGroupedQuestion as n}from"./EnglishCertificationGroupedQuestion";import{EnglishCertificationAudioPlayer as o}from"./EnglishCertificationAudioPlayer";import{EnglishCertificationPartHeader as s}from"./EnglishCertificationPartHeader";import{EnglishCertificationInstructionBanner as a}from"./EnglishCertificationInstructionBanner";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as l}from"./english-certification-theme";import{ENGLISH_CERT_STICKY_AUDIO_ATTR as c}from"./english-cert-scroll";import{EcWordFillStructuredForm as d}from"./EcWordFillStructuredForm";import{EcMatchByWritingAnswer as u}from"./EcMatchByWritingAnswer";import{EcAnswerTheQuestion as g}from"./EcAnswerTheQuestion";import{EcWordFillParagraph as m}from"./EcWordFillParagraph";import{EcWritingTask as p}from"./EcWritingTask";const f=new Set(["CHOOSE_THE_CORRECT_ANSWER"]);export function EnglishCertificationQuestionRenderer({part:h,partConfig:w,answers:E,flaggedQuestions:R,onAnswerChange:A,onToggleFlag:C,isReviewMode:N=!1,isAudioPlayed:T=!1,onAudioFirstPlay:_}){if(!h.questions.length)return e("div",{className:"flex h-full items-center justify-center rounded-xl border border-red-200 bg-red-50 p-8 text-red-600",children:"No questions found for this part"});const v=w.category===i.LISTENING,y=v?h.audioUrl??w.audioUrl??"":void 0,x=h.questionType,L=Boolean(h.isGroup)&&"DOCUMENT"===h.group?.type,M=w.isGroup&&f.has(x),b=Boolean(h.sections?.length);if(L||M||b)return e("div",{className:"h-full",children:e(n,{part:h,partConfig:w,answers:E,flaggedQuestions:R,onAnswerChange:A,onToggleFlag:C,isReviewMode:N,isListeningPart:v,partAudioUrl:y})});if(f.has(x))return e(t,{part:h,partConfig:w,answers:E,flaggedQuestions:R,onAnswerChange:A,onToggleFlag:C,isReviewMode:N,isListeningPart:v,partAudioUrl:y});const F=(h.questions[0]?.questionGroup?.payload?.instructions??h.instructions??w.instructions??"").trim(),P=!N&&T;return r("div",{className:"flex flex-col items-center gap-6 pb-4",children:[e(s,{partName:h.name??w.name,partNo:h.partNo,skill:w.category}),e(a,{instruction:F,isListeningPart:v}),v&&e("div",{[c]:"",className:`sticky top-0 z-20 ${l}`,children:e(o,{audioUrl:y??"",partNumber:h.partNo,isLocked:P,onFirstPlay:_})}),e("div",{className:`${l} w-full`,children:(()=>{switch(x){case"WORD_FILL_STRUCTURED_FORM":return e(d,{part:h,answers:E,onAnswerChange:A,isReviewMode:N});case"MATCH_BY_WRITING_ANSWER":return e(u,{part:h,answers:E,onAnswerChange:A,isReviewMode:N});case"ANSWER_THE_QUESTION":return e(g,{part:h,answers:E,onAnswerChange:A,isReviewMode:N});case"WORD_FILL_PARAGRAPH":return e(m,{part:h,answers:E,onAnswerChange:A,isReviewMode:N});case"WRITE_A_SHORT_LETTER":return e(p,{part:h,answers:E,onAnswerChange:A,isReviewMode:N});default:return r("div",{className:"rounded-xl border border-amber-200 bg-amber-50 p-6 text-sm text-amber-700",children:['Loại câu hỏi "',x,'" chưa được hỗ trợ trong giao diện này.']})}})()})]})}
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{EnglishCertificationOptionSelector as t}from"./EnglishCertificationOptionSelector";import{EnglishCertificationFlagButton as n}from"./EnglishCertificationFlagButton";import{EcWordFillStructuredForm as r}from"./EcWordFillStructuredForm";import{EcMatchByWritingAnswer as s}from"./EcMatchByWritingAnswer";import{EcAnswerTheQuestion as o}from"./EcAnswerTheQuestion";import{EcWordFillParagraph as a}from"./EcWordFillParagraph";import{EcWritingTask as d}from"./EcWritingTask";function l(e){return e.map((e,i)=>{const t=String.fromCharCode(65+i);return"string"==typeof e?{id:e,label:t,text:e}:{id:String(e?.id||t),label:String(e?.id||t),text:String(e?.text??e?.value??e??"")}})}export function EnglishCertificationReadingSection({part:c,section:m,questions:u,startIndex:p,answers:g,flaggedQuestions:f,onAnswerChange:x,onToggleFlag:h,isReviewMode:w=!1}){if(!u.length)return null;const R=(m.instructions||m.name||"").trim();if("CHOOSE_THE_CORRECT_ANSWER"===m.questionType)return i("div",{className:"flex flex-col gap-3",children:[R&&e("p",{className:"text-sm font-semibold leading-relaxed text-[#0b57d0]",children:R}),e("div",{className:"divide-y divide-[#e8eef7]",children:u.map(r=>{const s=c.questions.indexOf(r)+p+1,o=r.content||{},a=Array.isArray(o.options)?o.options:m.defaultValue??[],d=o.question?.trim()??"",u=g[r.id];return i("article",{className:"grid grid-cols-[44px_1fr_32px] gap-1 py-4",children:[i("div",{className:"text-[18px] font-black leading-snug text-[#0b57d0]",children:[s,"."]}),i("div",{className:"min-w-0",children:[d&&e("div",{className:"mb-2 text-[15px] font-black leading-snug text-[#10172f]",children:d}),e(t,{options:l(a),selectedOptionId:u?.optionId??null,onSelect:e=>x(r.id,{optionId:e}),isReviewMode:w,disabled:w,variant:"compact"})]}),e(n,{isFlagged:f.has(r.id),onToggle:()=>h(r.id),size:"sm",className:"self-start justify-self-end"})]},r.id)})})]});const v={...c,questionType:m.questionType,questions:u,instructions:R||c.instructions,isGroup:!1,group:void 0,sections:void 0,viewMode:m.viewMode,wordBankConfig:m.wordBankConfig,startIndex:m.startIndex,endIndex:m.endIndex};return i("div",{className:"flex flex-col gap-3",children:[R&&e("p",{className:"text-sm font-semibold leading-relaxed text-[#0b57d0]",children:R}),(()=>{switch(m.questionType){case"WORD_FILL_STRUCTURED_FORM":return e(r,{part:v,answers:g,onAnswerChange:x,isReviewMode:w});case"MATCH_BY_WRITING_ANSWER":return e(s,{part:v,answers:g,onAnswerChange:x,isReviewMode:w});case"ANSWER_THE_QUESTION":return e(o,{part:v,answers:g,onAnswerChange:x,isReviewMode:w});case"WORD_FILL_PARAGRAPH":return e(a,{part:v,answers:g,onAnswerChange:x,isReviewMode:w});case"WRITE_A_SHORT_LETTER":return e(d,{part:v,answers:g,onAnswerChange:x,isReviewMode:w});default:return i("div",{className:"rounded-xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-700",children:['Loại câu hỏi "',m.questionType,'" chưa được hỗ trợ.']})}})()]})}
1
+ "use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{EnglishCertificationOptionSelector as t}from"./EnglishCertificationOptionSelector";import{EnglishCertificationFlagButton as n}from"./EnglishCertificationFlagButton";import{EcWordFillStructuredForm as r}from"./EcWordFillStructuredForm";import{EcMatchByWritingAnswer as s}from"./EcMatchByWritingAnswer";import{EcAnswerTheQuestion as o}from"./EcAnswerTheQuestion";import{EcWordFillParagraph as a}from"./EcWordFillParagraph";import{EcWritingTask as d}from"./EcWritingTask";import{englishCertQuestionDomId as l}from"./english-cert-scroll";function c(e){return e.map((e,i)=>{const t=String.fromCharCode(65+i);return"string"==typeof e?{id:e,label:t,text:e}:{id:String(e?.id||t),label:String(e?.id||t),text:String(e?.text??e?.value??e??"")}})}export function EnglishCertificationReadingSection({part:m,section:p,questions:u,startIndex:g,answers:f,flaggedQuestions:x,onAnswerChange:h,onToggleFlag:w,isReviewMode:R=!1}){if(!u.length)return null;const v=(p.instructions||p.name||"").trim();if("CHOOSE_THE_CORRECT_ANSWER"===p.questionType)return i("div",{className:"flex flex-col gap-3",children:[v&&e("p",{className:"text-sm font-semibold leading-relaxed text-[#0b57d0]",children:v}),e("div",{className:"divide-y divide-[#e8eef7]",children:u.map(r=>{const s=m.questions.indexOf(r)+g+1,o=r.content||{},a=Array.isArray(o.options)?o.options:p.defaultValue??[],d=o.question?.trim()??"",u=f[r.id];return i("article",{id:l(r.id),className:"scroll-mt-24 grid grid-cols-[44px_1fr_32px] gap-1 py-4",children:[i("div",{className:"text-[18px] font-black leading-snug text-[#0b57d0]",children:[s,"."]}),i("div",{className:"min-w-0",children:[d&&e("div",{className:"mb-2 text-[15px] font-black leading-snug text-[#10172f]",children:d}),e(t,{options:c(a),selectedOptionId:u?.optionId??null,onSelect:e=>h(r.id,{optionId:e}),isReviewMode:R,disabled:R,variant:"compact"})]}),e(n,{isFlagged:x.has(r.id),onToggle:()=>w(r.id),size:"sm",className:"self-start justify-self-end"})]},r.id)})})]});const T={...m,questionType:p.questionType,questions:u,instructions:v||m.instructions,isGroup:!1,group:void 0,sections:void 0,viewMode:p.viewMode,wordBankConfig:p.wordBankConfig,startIndex:p.startIndex,endIndex:p.endIndex};return i("div",{className:"flex flex-col gap-3",children:[v&&e("p",{className:"text-sm font-semibold leading-relaxed text-[#0b57d0]",children:v}),(()=>{switch(p.questionType){case"WORD_FILL_STRUCTURED_FORM":return e(r,{part:T,answers:f,onAnswerChange:h,isReviewMode:R});case"MATCH_BY_WRITING_ANSWER":return e(s,{part:T,answers:f,onAnswerChange:h,isReviewMode:R});case"ANSWER_THE_QUESTION":return e(o,{part:T,answers:f,onAnswerChange:h,isReviewMode:R});case"WORD_FILL_PARAGRAPH":return e(a,{part:T,answers:f,onAnswerChange:h,isReviewMode:R});case"WRITE_A_SHORT_LETTER":return e(d,{part:T,answers:f,onAnswerChange:h,isReviewMode:R});default:return i("div",{className:"rounded-xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-700",children:['Loại câu hỏi "',p.questionType,'" chưa được hỗ trợ.']})}})()]})}
@@ -13,8 +13,6 @@ interface EnglishCertificationSingleQuestionListProps {
13
13
  /** Part-level audio URL (shown once at the top for listening parts). */
14
14
  partAudioUrl?: string;
15
15
  }
16
- /** Stable DOM id for a question card, used for Answer-Sheet scroll-to. */
17
- export declare function englishCertQuestionDomId(questionId: string): string;
18
16
  /**
19
17
  * Renders every question of a single-question part (or section) on one screen.
20
18
  *
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{EnglishCertificationAudioPlayer as n}from"./EnglishCertificationAudioPlayer";import{EnglishCertificationQuestionItem as t}from"./EnglishCertificationQuestionItem";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as o}from"./english-certification-theme";export function englishCertQuestionDomId(e){return`ec-question-${e}`}export function EnglishCertificationSingleQuestionList({part:r,partConfig:s,answers:a,flaggedQuestions:u,onAnswerChange:l,onToggleFlag:g,isReviewMode:d=!1,isListeningPart:m=!1,partAudioUrl:f}){const c=s.startIndex??0,p=Array.isArray(s.questionConfig)?s.questionConfig:[],h=s.defaultQuestion,C=m&&Boolean(f);return i("div",{className:"flex flex-col items-center gap-5 pb-4",children:[C&&e("div",{className:o,children:e(n,{audioUrl:f,partNumber:r.partNo})}),r.questions.map((i,n)=>{const o=i.audio_url?Array.from(new Set([...p,"audioUrl"])):p;return e(t,{domId:englishCertQuestionDomId(i.id),question:i,questionNumber:c+n+1,questionConfig:o,defaultQuestion:h,isListeningPart:m,answer:a[i.id],isFlagged:u.has(i.id),onAnswerChange:l,onToggleFlag:g,isReviewMode:d},i.id)})]})}
1
+ "use client";import{jsx as i,jsxs as e}from"react/jsx-runtime";import{EnglishCertificationAudioPlayer as t}from"./EnglishCertificationAudioPlayer";import{EnglishCertificationQuestionItem as o}from"./EnglishCertificationQuestionItem";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as n}from"./english-certification-theme";import{ENGLISH_CERT_STICKY_AUDIO_ATTR as r,englishCertQuestionDomId as s}from"./english-cert-scroll";export function EnglishCertificationSingleQuestionList({part:a,partConfig:l,answers:u,flaggedQuestions:g,onAnswerChange:d,onToggleFlag:m,isReviewMode:f=!1,isListeningPart:c=!1,partAudioUrl:p}){const h=l.startIndex??0,C=Array.isArray(l.questionConfig)?l.questionConfig:[],w=l.defaultQuestion,x=c&&Boolean(p);return e("div",{className:"flex flex-col items-center gap-5 pb-4",children:[x&&i("div",{[r]:"",className:`sticky top-0 z-20 ${n}`,children:i(t,{audioUrl:p,partNumber:a.partNo})}),a.questions.map((e,t)=>{const n=e.audio_url?Array.from(new Set([...C,"audioUrl"])):C;return i(o,{domId:s(e.id),question:e,questionNumber:h+t+1,questionConfig:n,defaultQuestion:w,isListeningPart:c,answer:u[e.id],isFlagged:g.has(e.id),onAnswerChange:d,onToggleFlag:m,isReviewMode:f},e.id)})]})}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Scroll helpers for English Certification Answer Sheet navigation.
3
+ *
4
+ * Question cards use a stable DOM id (`ec-question-{id}`) so the sidebar can
5
+ * jump to the chosen question after `goToQuestion` re-renders the active part.
6
+ *
7
+ * Listening parts pin the audio bar with `position: sticky`. Manual scroll must
8
+ * subtract that bar's height so the target card is not hidden underneath it.
9
+ */
10
+ /** Stable DOM id for a question card / row, used for Answer-Sheet scroll-to. */
11
+ export declare function englishCertQuestionDomId(questionId: string): string;
12
+ /** Marker on sticky audio wrappers so scroll offset can be measured at runtime. */
13
+ export declare const ENGLISH_CERT_STICKY_AUDIO_ATTR = "data-ec-sticky-audio";
14
+ /** Nearest ancestor that actually scrolls (falls back to document scrolling element). */
15
+ export declare function findScrollableParent(el: HTMLElement): HTMLElement;
16
+ /**
17
+ * Scroll `el` into view inside its nearest scrollable ancestor.
18
+ * Prefer parent-relative scroll so nested columns (Reading split-view) work.
19
+ * When a sticky Listening audio bar is present, leave room under it.
20
+ */
21
+ export declare function scrollElementIntoView(el: HTMLElement, options?: {
22
+ behavior?: ScrollBehavior;
23
+ block?: ScrollLogicalPosition;
24
+ }): void;
25
+ /**
26
+ * Find the question anchor by id and scroll it into view.
27
+ * Retries briefly so cross-part navigation can wait for React to mount the card.
28
+ */
29
+ export declare function scrollToEnglishCertQuestion(questionId: string, options?: {
30
+ behavior?: ScrollBehavior;
31
+ block?: ScrollLogicalPosition;
32
+ }): void;
@@ -0,0 +1 @@
1
+ export function englishCertQuestionDomId(t){return`ec-question-${t}`}export const ENGLISH_CERT_STICKY_AUDIO_ATTR="data-ec-sticky-audio";const t=[0,50,120,250,400];function e(t){const e=window.getComputedStyle(t).overflowY;return("auto"===e||"scroll"===e||"overlay"===e)&&t.scrollHeight>t.clientHeight+1}export function findScrollableParent(t){let n=t.parentElement;for(;n;){if(e(n))return n;n=n.parentElement}return document.scrollingElement??document.documentElement}export function scrollElementIntoView(t,e){const n=e?.behavior??"smooth",o=e?.block??"start",i=findScrollableParent(t),l=function(t,e){const n=t.querySelectorAll("[data-ec-sticky-audio]");if(!n.length)return 0;let o=0;return n.forEach(n=>{if(n===e||n.contains(e))return;if(!t.contains(n))return;const i=n.getBoundingClientRect().height;i>o&&(o=i)}),o>0?o+12:0}(i,t),r=i.getBoundingClientRect(),c=t.getBoundingClientRect(),s=i.scrollTop,u=c.top-r.top+s;let a=u;if("center"===o)a=u-i.clientHeight/2+c.height/2;else if("end"===o)a=u-i.clientHeight+c.height;else if("nearest"===o){const t=s+l,e=s+i.clientHeight,n=u+c.height;if(u>=t&&n<=e)return;a=u<t?u-l:n-i.clientHeight}else a=u-l;"start"===o&&0===l&&(a=Math.max(0,a-12)),i.scrollTo({top:Math.max(0,a),behavior:n})}export function scrollToEnglishCertQuestion(e,n){if("undefined"==typeof document||!e)return;const o=englishCertQuestionDomId(e);let i=0;const l=()=>{const e=document.getElementById(o);e?scrollElementIntoView(e,n):(i+=1,i<t.length&&window.setTimeout(l,t[i]))};window.setTimeout(l,t[0])}