@tinyweb_dev/oe-exam-sdk 0.1.23 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/dist/components/exams/take/components/question-renderers/MoversWordFillStructuredFormRenderer.js +1 -1
- package/dist/components/exams/take/utils/question-transformers.d.ts +3 -1
- package/dist/components/exams/take/utils/question-transformers.js +1 -1
- package/dist/components/questions/_shared/types/word-fill-structured-form.type.d.ts +18 -9
- package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +1 -1
- package/dist/components/questions/types/choose-the-correct-answer/transform.js +1 -1
- package/dist/components/questions/types/word-fill-structured-form/WfsfWordBankEditor.d.ts +14 -0
- package/dist/components/questions/types/word-fill-structured-form/WfsfWordBankEditor.js +1 -0
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.d.ts +1 -1
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -1
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.d.ts +1 -1
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +1 -1
- package/dist/components/questions/types/word-fill-structured-form/register.js +1 -1
- package/dist/components/questions/types/word-fill-structured-form/transform.d.ts +5 -2
- package/dist/components/questions/types/word-fill-structured-form/transform.js +1 -1
- package/dist/components/questions/types/word-fill-structured-form/wfsf-word-bank.utils.d.ts +24 -0
- package/dist/components/questions/types/word-fill-structured-form/wfsf-word-bank.utils.js +1 -0
- package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1 -1
- package/dist/shared/lib/i18n/messages/en/admin.d.ts +0 -3
- package/dist/shared/lib/i18n/messages/en/admin.js +1 -1
- package/dist/shared/lib/i18n/messages/en.d.ts +0 -3
- package/dist/shared/lib/i18n/messages/vi/admin.d.ts +0 -3
- package/dist/shared/lib/i18n/messages/vi/admin.js +1 -1
- package/dist/shared/lib/i18n/messages/vi.d.ts +0 -3
- package/package.json +169 -163
- package/dist/mcp/config.d.ts +0 -12
- package/dist/mcp/config.js +0 -1
- package/dist/mcp/http-client.d.ts +0 -6
- package/dist/mcp/http-client.js +0 -1
- package/dist/mcp/index.d.ts +0 -6
- package/dist/mcp/index.js +0 -2
- package/dist/mcp/tools/_helpers.d.ts +0 -4
- package/dist/mcp/tools/_helpers.js +0 -1
- package/dist/mcp/tools/exams.d.ts +0 -2
- package/dist/mcp/tools/exams.js +0 -1
- package/dist/mcp/tools/index.d.ts +0 -2
- package/dist/mcp/tools/index.js +0 -1
- package/dist/mcp/tools/results.d.ts +0 -2
- package/dist/mcp/tools/results.js +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @tinyweb_dev/oe-exam-sdk
|
|
2
2
|
|
|
3
|
-
SDK tái sử dụng cho hệ thống OE Exam: màn tạo đề, quản lý câu hỏi, làm bài, xem kết
|
|
3
|
+
SDK tái sử dụng cho hệ thống OE Exam: màn tạo đề, quản lý câu hỏi, làm bài, xem kết quả và theme giao diện.
|
|
4
4
|
|
|
5
5
|
## Cài đặt
|
|
6
6
|
|
|
@@ -91,7 +91,6 @@ export function ResultReviewPage({ attemptId, token, router }) {
|
|
|
91
91
|
@tinyweb_dev/oe-exam-sdk # export tổng hợp thường dùng
|
|
92
92
|
@tinyweb_dev/oe-exam-sdk/api # API adapters, constants, types
|
|
93
93
|
@tinyweb_dev/oe-exam-sdk/shared # shared constants/types/helpers
|
|
94
|
-
@tinyweb_dev/oe-exam-sdk/mcp # MCP server entry và tools
|
|
95
94
|
@tinyweb_dev/oe-exam-sdk/components # shared UI components
|
|
96
95
|
@tinyweb_dev/oe-exam-sdk/components/exams # màn tạo đề / câu hỏi / làm bài / vào phòng
|
|
97
96
|
@tinyweb_dev/oe-exam-sdk/components/exams/entry # màn vào phòng (entry) + state machine
|
|
@@ -238,16 +237,16 @@ Các report shell, renderer, transform helper, polling/status helper và result-
|
|
|
238
237
|
|
|
239
238
|
## MCP server
|
|
240
239
|
|
|
241
|
-
|
|
240
|
+
MCP đã tách sang package riêng:
|
|
242
241
|
|
|
243
242
|
```bash
|
|
244
|
-
oe-exam-mcp
|
|
243
|
+
npm install @tinyweb_dev/oe-exam-mcp-server
|
|
245
244
|
```
|
|
246
245
|
|
|
247
246
|
Chạy bằng PAT/API token. Nếu token có dạng `oeexam_...`, MCP tự gửi qua `X-API-Key`; token khác sẽ gửi qua `Authorization: Bearer`.
|
|
248
247
|
|
|
249
248
|
```bash
|
|
250
|
-
OE_API_URL=http://localhost:3000 OE_API_TOKEN=... npx oe-exam-mcp
|
|
249
|
+
OE_API_URL=http://localhost:3000 OE_API_TOKEN=... npx @tinyweb_dev/oe-exam-mcp-server
|
|
251
250
|
```
|
|
252
251
|
|
|
253
252
|
Tools hiện có:
|
|
@@ -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 a,useCallback as l,memo as s}from"react";import{ResolvedImage as i}from"../../../../../components/common/ResolvedImage";import o from"../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import d from"../../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner";import c from"../../../../../components/themes/cambridge-yle/CambridgeYleAudioPlayer";import{cn as u}from"../../../../../shared/lib/utils";function m(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function p(e,t){return e.replace(/\{([\w\d]+)\}/g,(e,r)=>{const n=function(e,t){if(!e?.length)return null;const r=Number(t),n=Number.isFinite(r)&&r>=0&&r<e.length?e[r]:null;return null!=n&&"options"in n&&n.options?.length&&n.options.length>=2?n.options:null}(t,r);if(n){return`\n <span class="structured-blank-wrapper" data-blank-wrapper="${r}">\n <select data-blank-key="${r}" class="structured-blank-input structured-blank-select">${['<option value="">—</option>',...n.map(e=>`<option value="${m(e)}">${m(e)}</option>`)].join("")}</select>\n <span class="structured-blank-hint" data-blank-hint="${r}"></span>\n </span>\n `}return`\n <span class="structured-blank-wrapper" data-blank-wrapper="${r}">\n <input type="text" data-blank-key="${r}" placeholder="" class="structured-blank-input" />\n <span class="structured-blank-hint" data-blank-hint="${r}"></span>\n </span>\n `})}function b(e,t){const r=e.trim();return t?r:r.toLowerCase()}const g={},x=s(function({question:l,initialAnswers:s,onBlankChange:o,isReviewMode:d}){const c=r(null),m=r(o);m.current=o;const g=r(!1),x=r(s),h=a(()=>p(l.content,l.wordBank),[l.content,l.wordBank]);return n(()=>{const e=c.current;if(!e)return;g.current||(e.innerHTML=h,g.current=!0);const t=e.querySelectorAll("input.structured-blank-input, select.structured-blank-input"),r=[];return t.forEach(t=>{const n=t.getAttribute("data-blank-key")||"",a=e.querySelector(`[data-blank-wrapper="${n}"]`),s=e.querySelector(`[data-blank-hint="${n}"]`),i=x.current[n]||"",o=l.answers[n]||"",c=i.trim().length>0,p=c&&b(i,l.caseSensitive)===b(o,l.caseSensitive),g=d&&!p&&o.trim().length>0;t.value=g?`${c?i:"(trống)"} → ${o}`:i,t.disabled=d;const h="SELECT"===t.tagName,f=l.blankStyle||"word",w="letter"===f,y="phrase"===f;w&&!h&&"maxLength"in t&&(t.maxLength=Math.max(1,(o||" ").trim().length||1)),t.className=u("structured-blank-input inline-block bg-slate-50/40 text-sm font-semibold outline-none transition-all align-baseline hover:bg-slate-100/60 focus:bg-teal-50/60 focus:ring-0",h?"min-w-[
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useRef as r,useEffect as n,useMemo as a,useCallback as l,memo as s}from"react";import{ResolvedImage as i}from"../../../../../components/common/ResolvedImage";import o from"../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import d from"../../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner";import c from"../../../../../components/themes/cambridge-yle/CambridgeYleAudioPlayer";import{cn as u}from"../../../../../shared/lib/utils";function m(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function p(e,t){return e.replace(/\{([\w\d]+)\}/g,(e,r)=>{const n=function(e,t){if(!e?.length)return null;const r=Number(t),n=Number.isFinite(r)&&r>=0&&r<e.length?e[r]:null;return null!=n&&"options"in n&&n.options?.length&&n.options.length>=2?n.options:null}(t,r);if(n){return`\n <span class="structured-blank-wrapper" data-blank-wrapper="${r}">\n <select data-blank-key="${r}" class="structured-blank-input structured-blank-select">${['<option value="">—</option>',...n.map(e=>`<option value="${m(e)}">${m(e)}</option>`)].join("")}</select>\n <span class="structured-blank-hint" data-blank-hint="${r}"></span>\n </span>\n `}return`\n <span class="structured-blank-wrapper" data-blank-wrapper="${r}">\n <input type="text" data-blank-key="${r}" placeholder="" class="structured-blank-input" />\n <span class="structured-blank-hint" data-blank-hint="${r}"></span>\n </span>\n `})}function b(e,t){const r=e.trim();return t?r:r.toLowerCase()}const g={},x=s(function({question:l,initialAnswers:s,onBlankChange:o,isReviewMode:d}){const c=r(null),m=r(o);m.current=o;const g=r(!1),x=r(s),h=a(()=>p(l.content,l.wordBank),[l.content,l.wordBank]);return n(()=>{const e=c.current;if(!e)return;g.current||(e.innerHTML=h,g.current=!0);const t=e.querySelectorAll("input.structured-blank-input, select.structured-blank-input"),r=[];return t.forEach(t=>{const n=t.getAttribute("data-blank-key")||"",a=e.querySelector(`[data-blank-wrapper="${n}"]`),s=e.querySelector(`[data-blank-hint="${n}"]`),i=x.current[n]||"",o=l.answers[n]||"",c=i.trim().length>0,p=c&&b(i,l.caseSensitive)===b(o,l.caseSensitive),g=d&&!p&&o.trim().length>0;t.value=g?`${c?i:"(trống)"} → ${o}`:i,t.disabled=d;const h="SELECT"===t.tagName,f=l.blankStyle||"word",w="letter"===f,y="phrase"===f;w&&!h&&"maxLength"in t&&(t.maxLength=Math.max(1,(o||" ").trim().length||1)),t.className=u("structured-blank-input inline-block bg-slate-50/40 text-sm font-semibold outline-none transition-all align-baseline hover:bg-slate-100/60 focus:bg-teal-50/60 focus:ring-0",h?"min-w-[5.5rem] max-w-[10rem] rounded border px-2 py-1 text-center":w?"h-7 w-7 rounded border-2 px-0 text-center uppercase":y?"min-w-[9rem] max-w-[18rem] w-[14ch] rounded-t border-b-2 px-2 py-0.5 text-center":"min-w-[4.5rem] max-w-[7.5rem] w-[8ch] rounded-t border-b-2 px-1 py-0.5 text-center",d?p?"border-emerald-500 bg-emerald-50 text-emerald-800 font-bold":c?"border-rose-500 bg-rose-50 text-rose-800 font-bold":"border-amber-500 bg-amber-50 text-amber-800 font-bold":"border-slate-400 text-slate-800 focus:border-teal-600"),h||w||!("size"in t)||(t.size=y?18:10),w&&(t.style.display="inline-block",t.style.width="1.75rem",t.style.height="1.75rem",t.style.minWidth="1.75rem",t.style.maxWidth="1.75rem",t.style.padding="0",t.style.margin="0 2px",t.style.borderWidth="2px",t.style.borderStyle="solid",t.style.borderRadius="4px",t.style.textAlign="center",t.style.fontWeight="700",t.style.textTransform="uppercase",t.style.boxSizing="border-box",t.style.verticalAlign="baseline"),a&&(a.className=u("structured-blank-wrapper inline-flex items-baseline align-baseline mx-1 my-0.5",d&&"mx-1 my-0.5")),s&&(s.textContent="",s.className="structured-blank-hint hidden");const k=e=>{const t=e.target;m.current(n,t.value)},v=h?"change":"input";t.addEventListener(v,k),r.push({el:t,handler:k,eventName:v})}),()=>{r.forEach(({el:e,handler:t,eventName:r})=>{e.removeEventListener(r,t)})}},[h,d]),t("div",{className:"space-y-3",children:[l.title&&e("h3",{className:"text-base font-semibold text-gray-800",children:l.title}),l.imageUrl&&e("div",{className:"flex justify-center",children:e("div",{className:"overflow-hidden rounded-lg border border-gray-200",children:e(i,{src:l.imageUrl,alt:l.title||"Question image",className:"max-h-48 w-auto object-contain"})})}),e("div",{ref:c,className:u("structured-form-content rounded-lg border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4 text-sm leading-relaxed text-gray-800","[&_.structured-blank-wrapper]:inline-flex [&_.structured-blank-wrapper]:align-baseline [&_.structured-blank-wrapper]:items-baseline [&_.structured-blank-hint]:max-w-[180px]","[&_table.dialogue]:w-full [&_table.dialogue]:border-collapse [&_table.dialogue]:table-fixed","[&_table.dialogue_td.speaker]:w-[1%] [&_table.dialogue_td.speaker]:whitespace-nowrap","[&_table.dialogue_td.speaker]:align-top [&_table.dialogue_td.speaker]:pr-3","[&_table.dialogue_td.speaker]:font-semibold [&_table.dialogue_td.speaker]:text-slate-900","[&_table.dialogue_td]:align-top [&_table.dialogue_td]:py-1.5")}),d&&t("div",{className:"space-y-2 rounded-lg border border-slate-200 bg-slate-50 p-3",children:[t("div",{className:"flex flex-wrap gap-2 text-[11px] font-medium",children:[t("span",{className:"inline-flex items-center gap-1 rounded-full bg-green-100 px-2 py-1 text-green-700",children:[e("span",{className:"h-2 w-2 rounded-full bg-green-500"}),"Đúng"]}),t("span",{className:"inline-flex items-center gap-1 rounded-full bg-red-100 px-2 py-1 text-red-700",children:[e("span",{className:"h-2 w-2 rounded-full bg-red-500"}),"Sai"]}),t("span",{className:"inline-flex items-center gap-1 rounded-full bg-amber-100 px-2 py-1 text-amber-700",children:[e("span",{className:"h-2 w-2 rounded-full bg-amber-500"}),"Chưa trả lời"]})]}),t("div",{children:[e("span",{className:"text-[10px] font-medium uppercase tracking-wider text-slate-500",children:"Đáp án đúng"}),e("div",{className:"mt-1 flex flex-wrap gap-1.5",children:Object.entries(l.answers).map(([e,r])=>t("span",{className:"rounded border border-green-300 bg-green-100 px-2 py-0.5 text-xs font-semibold text-green-800",children:[e,": ",r]},e))})]})]})]})});export function MoversWordFillStructuredFormRenderer({partNumber:n,partName:s,questionCount:u,instruction:m,audioUrl:p,groupTitle:b,groupContent:h,groupImageUrl:f,questions:w,answers:y,onAnswerChange:k,isReviewMode:v=!1}){const N=r(y);N.current=y;const _=r(k);_.current=k;const $=l((e,t,r)=>{const n=N.current[e]||{};_.current(e,{...n,[t]:r})},[]),C=a(()=>{const e={};return w.forEach(t=>{e[t.id]=(e,r)=>$(t.id,e,r)}),e},[w,$]);return t("div",{className:"flex flex-col h-full gap-4 sm:gap-6 overflow-y-auto custom-scrollbar",children:[t("div",{className:"flex flex-col gap-4 p-3 sm:px-6 sm:pt-2",children:[e(o,{partNumber:n,questionCount:u,partName:s,isReviewMode:v}),e(d,{instruction:m,isReviewMode:v}),b&&e("h2",{className:"text-center text-xl font-bold uppercase text-coral-500",children:b}),p&&e(c,{audioSrc:p,compact:!0}),f&&e("div",{className:"flex items-center justify-center",children:e(i,{src:f,alt:b||"Group image",className:"max-h-[300px] rounded-lg object-contain shadow-md"})}),h&&e("div",{className:"article-content rounded-lg bg-amber-50 p-4 text-sm leading-relaxed text-gray-700 max-h-[500px] overflow-y-auto pr-2 custom-scrollbar",dangerouslySetInnerHTML:{__html:h}})]}),w.length>0&&e("div",{className:"px-3 sm:px-6",children:e("hr",{className:"border-t border-slate-200/60 my-1"})}),e("div",{className:"grid grid-cols-1 gap-4 sm:gap-5 p-3 sm:px-6 sm:pb-6",children:w.map(r=>t("div",{id:`question-${r.id}`,className:"rounded-xl border border-gray-200 bg-white p-4 shadow-sm transition-all hover:border-indigo-200 hover:shadow-md",children:[e("div",{className:"mb-2 flex items-center gap-2",children:e("span",{className:"flex h-7 w-7 items-center justify-center rounded-full bg-gradient-to-br from-indigo-500 to-violet-600 text-xs font-bold text-white shadow-sm",children:r.questionNumber})}),e(x,{question:r,initialAnswers:y[r.id]||g,onBlankChange:C[r.id],isReviewMode:v})]},r.id))})]})}
|
|
@@ -140,7 +140,9 @@ export declare function transformWriteCorrectVerbForm(questions: ApiQuestion[]):
|
|
|
140
140
|
title: string;
|
|
141
141
|
instruction: string;
|
|
142
142
|
};
|
|
143
|
-
export declare function transformChooseCorrectAnswer(questions: ApiQuestion[]
|
|
143
|
+
export declare function transformChooseCorrectAnswer(questions: ApiQuestion[], optionsConfig?: {
|
|
144
|
+
shuffleOptions?: boolean;
|
|
145
|
+
}): {
|
|
144
146
|
questions: ChooseBestAnswerQuestion[];
|
|
145
147
|
example?: import('../types').ChooseBestAnswerExample;
|
|
146
148
|
imageUrl?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function groupQuestionsByPart(t,e){const n=new Map,o=new Map;for(const e of t){const t=o.get(e.part_id)||[];t.push(e),o.set(e.part_id,t)}for(const[t,r]of o.entries()){const o=[...r].sort((t,e)=>t.question_number-e.question_number),i=o[0];if(!i)continue;const s=e?.find(e=>String(e.id)===String(t)),a=void 0!==s?.id?Number(s.id):void 0,u=s?.name?.match(/\d+/),l=u?parseInt(u[0],10):i.part_no,c=s?.group,m=Boolean(s?.isGroup)&&"DOCUMENT"===c?.type,p=s?.sections??[],d=new Set(p.map(t=>t.questionType).filter(Boolean)),g=p.length>1&&d.size>1;if(m||g){const e=`${t}_part`;n.set(e,{partId:t,partNo:l,questionType:i.question_type,questions:o,name:s?.name,instructions:s?.instructions,audioUrl:s?.audioUrl,templateOrder:a,category:s?.category,points:s?.points,isGroup:!0,group:c,sections:s?.sections,startIndex:s?.startIndex,endIndex:s?.endIndex});continue}if(!s?.sections?.length){const e=`${t}_part`;n.set(e,{partId:t,partNo:l,questionType:i.question_type,questions:o,name:s?.name,instructions:s?.instructions,audioUrl:s?.audioUrl,templateOrder:a,category:s?.category,points:s?.points,isGroup:s?.isGroup,optionMode:s?.optionMode,optionCount:s?.optionCount,viewMode:s?.viewMode,defaultValue:s?.defaultValue,multipleAnswers:s?.multipleAnswers,questionConfig:s?.questionConfig,wordBankConfig:s?.wordBankConfig,group:s?.group,startIndex:s?.startIndex,endIndex:s?.endIndex});continue}for(const[e,r]of s.sections.entries()){const i=o.filter(t=>{const e=t.question_number-1;return e>=r.startIndex&&e<=r.endIndex});if(!i.length)continue;const u=`${t}_section_${e}`,c=Boolean(r.isGroup||r.group?.type);n.set(u,{partId:t,partNo:l,questionType:r.questionType||i[0].question_type,questions:i,name:s.name,instructions:r.instructions||r.name||s.instructions,audioUrl:s.audioUrl,templateOrder:a,category:s.category,points:s.points,sectionId:r.sectionId,isGroup:c,optionMode:r.optionMode,optionCount:r.optionCount,viewMode:r.viewMode,defaultValue:r.defaultValue,multipleAnswers:r.multipleAnswers,questionConfig:r.questionConfig,wordBankConfig:r.wordBankConfig,group:r.group,startIndex:r.startIndex,endIndex:r.endIndex})}}return Array.from(n.values()).sort((t,e)=>{const n=void 0===t.templateOrder||isNaN(t.templateOrder)?1/0:t.templateOrder,o=void 0===e.templateOrder||isNaN(e.templateOrder)?1/0:e.templateOrder;return n!==o?n-o:(t.questions[0]?.question_number||0)-(e.questions[0]?.question_number||0)})}export function transformFillInBlank(t){const e=t[0],n=e?.content,o=e?.questionGroup?.payload,r=[],i=t=>t.replace(/\*\*/g,"");for(const e of t){const t=e.content,n=e.is_example||!1,o=t.question||t.blanks?.[0]?.text||"";if([...o.matchAll(/\{(\d+)\}/g)].length>1){const s=o.split("\n").filter(t=>t.trim());for(const o of s){const s=o.match(/\{(\d+)\}/);if(!s)continue;const a=parseInt(s[1],10),u=o.split(/\{\d+\}/),l=i(u[0]?.trim()||""),c=i(u[1]?.trim()||"");r.push({id:`${e.id}-blank-${a}`,questionNumber:e.question_number,textBefore:l,textAfter:c,imageUrl:t.imageUrl,hints:t.hints,isExample:n,correctAnswer:n?e.correct_answer?.answers?.[a]:void 0})}}else{const s=o.match(/^(.*?)\{0\}(.*)$/),a=i(s?s[1].trim():o),u=i(s?s[2].trim():"");r.push({id:e.id,questionNumber:e.question_number,textBefore:a,textAfter:u,imageUrl:t.imageUrl,hints:t.hints,isExample:n,correctAnswer:n?e.correct_answer?.answers?.[0]:void 0})}}return{questions:r,title:n?.title||o?.title||"",imageUrl:o?n?.imageUrl:void 0,audioUrl:n?.audioUrl,exampleText:n?.exampleText,exampleHighlight:n?.exampleHighlight,instruction:n?.instruction||"LISTEN AND WRITE",showHints:n?.showHints,groupContent:o?.content||o?.groupContent,groupTitle:o?.title,groupImageUrl:o?.mainImageUrl||o?.imageUrl}}export function transformWriteCorrectVerbForm(t){const e=t[0],n=e?.content;return{questions:t.map(t=>{const e=t.content,n=e.sentence||"",o=n.match(/^(.*?)\{0\}(.*)$/),r=o?o[1].trim():n,i=o?o[2].trim():"";return{id:t.id,questionNumber:t.question_number,textBefore:r,textAfter:i,verbHint:e.verbHint}}),title:"WRITE THE CORRECT VERB FORM",instruction:n?.instruction||"Write the correct form of the verb in parentheses."}}const t=["A","B","C","D","E","F"];export function transformChooseCorrectAnswer(e){const n=e[0]?.content,o=e[0]?.questionGroup?.payload,r=e.find(t=>t.is_example),i=e.filter(t=>!t.is_example);let s;if(r){const e=r.content,n=(e.options||[]).map((e,n)=>{const o="object"==typeof e&&null!==e,i=o&&e.id?String(e.id):`${r.id}-opt-${n}`,s=o?e.text??e.content??"":String(e),a=o?e.imageUrl:void 0;return{id:i,label:t[n]||String(n+1),text:s,...a?{imageUrl:a}:{}}}),o=r.correct_answer?.answer??r.correct_answer?.optionId;let i="";if("string"==typeof o&&o){const t=n.find(t=>t.id===o);i=t?t.id:o}else"number"==typeof o&&o>=0&&o<n.length&&(i=n[o]?.id||"");s={questionNumber:r.question_number,questionText:e.question||"",options:n,correctOptionId:i||n[0]?.id||"",optionType:e.optionType||"text",imageUrl:e.imageUrl,audioUrl:e.audioUrl}}const a=i.map(e=>{const n=e.content,o=n.optionType||"text",r=(n.options||[]).map((n,o)=>{const r="object"==typeof n&&null!==n,i=r&&n.id?String(n.id):`${e.id}-opt-${o}`,s=r?n.text??n.content??"":String(n),a=r?n.imageUrl:void 0;return{id:i,label:t[o]||String(o+1),text:s,...a?{imageUrl:a}:{}}}),i=e.correct_answer?.answer??e.correct_answer?.optionId??e.correct_answer?.optionIds,s=t=>{if(null==t)return;const e=String(t),n=r.find(t=>t.id===e);if(n)return n.id;const o=e.match(/-opt-(\d+)$/);if(o){const t=parseInt(o[1],10);if(t>=0&&t<r.length)return r[t]?.id}if("number"==typeof t&&t>=0&&t<r.length)return r[t]?.id;const i=parseInt(e,10);return!isNaN(i)&&i>=0&&i<r.length&&!e.startsWith("opt-")?r[i]?.id:e};let a=[];if(Array.isArray(i))a=i.map(s).filter(t=>Boolean(t));else{const t=s(i);t&&(a=[t])}return{id:e.id,questionNumber:e.question_number,questionText:n.question||"",options:r,correctOptionId:a[0],correctOptionIds:a,imageUrl:n.imageUrl,audioUrl:n.audioUrl,optionType:o,multipleAnswers:Boolean(n.multipleAnswers||Array.isArray(i)),explanation:e.explanation}}),u=a.some(t=>!!t.audioUrl?.trim())||!!s?.audioUrl?.trim();return{questions:a,example:s,imageUrl:n?.imageUrl,groupImageUrl:o?.mainImageUrl||o?.imageUrl,groupTitle:o?.title,groupContent:o?.content,articles:o?.articles,audioUrl:u?void 0:n?.audioUrl,instruction:n?.instruction||"CHOOSE THE CORRECT ANSWER"}}export function transformChooseCorrectAdjective(e){return{questions:e.map(e=>{const n=e.content,o=n.sentence||"",r=o.match(/^(.*?)\{0\}(.*)$/),i=r?r[1]:o,s=r?r[2]:"";return{id:e.id,questionNumber:e.question_number,sentenceBefore:i,sentenceAfter:s,options:(n.options||[]).map((n,o)=>({id:`${e.id}-opt-${o}`,label:t[o]||String(o+1),text:n}))}}),instruction:"CHOOSE THE CORRECT ADJECTIVE"}}export function transformWriteShortLetter(t){const e=t.content;if(e.instructions?.mainInstruction||e.informations?.length)return{prompt:e.instructions?.mainInstruction||"",requirements:e.informations,minWords:e.minWords,maxWords:e.maxWords,guideImages:e.guideImages};return{prompt:e.contexts?.filter(t=>"text"===t.type).map(t=>t.text).join("\n")||"",minWords:e.minWords,maxWords:e.maxWords,guideImages:e.guideImages}}export function transformColorObjects(t){const e=t[0],n=e?.content,o=n?.colorNodes?.map(t=>({id:t.id,color:t.color,label:t.label}))||n?.hintItems||[],r=n?.regionNodes?.map(t=>({id:t.id,x:t.x,y:t.y,width:t.width,height:t.height,correctHintId:t.linkedColorNodeId}))||n?.regions||[],i=n?.instructions;return{instruction:(i&&i.length>0?i.join(" "):n?.instruction)||"READ AND COLOR THE OBJECTS",instructions:i,imageUrl:n?.backgroundImageUrl||n?.imageUrl||"",audioUrl:n?.audioUrl,hintItems:o,regions:r}}export function transformPictureChoose(e){const n=e[0]?.content;return{subQuestions:e.map(e=>{const n=e.content;return{id:e.id,questionNumber:e.question_number,imageUrl:n.imageUrl||"",questionText:n.questionText,options:(n.options||[]).map((n,o)=>({id:n.id||`${e.id}-opt-${o}`,label:t[o]||String(o+1),text:"string"==typeof n?n:n.text}))}}),instruction:n?.instruction||"LOOK AT THE PICTURE AND CHOOSE THE CORRECT ANSWER"}}export function transformPictureFillBlankChoose(e){const n=e[0]?.content;return{subQuestions:e.map(e=>{const n=e.content;return{id:e.id,questionNumber:e.question_number,imageUrl:n.imageUrl||"",question:n.question||"",options:(n.options||[]).map((n,o)=>({id:n.id||`${e.id}-opt-${o}`,label:t[o]||String(o+1),text:"string"==typeof n?n:n.text}))}}),instruction:n?.instruction||"LOOK AT THE PICTURE, FILL IN THE BLANK AND CHOOSE THE ANSWER"}}export function transformReadingPassage(e){if(function(t){const e=t[0];if(!e)return!1;const n=e.content;return void 0!==n?.question&&!n?.questions&&void 0!==e.questionGroup?.payload?.passage}(e)){const n=e[0],o=n.questionGroup?.payload||{},r=e.map(e=>{const n=e.content;return{id:e.id,questionNumber:e.question_number,questionText:n?.question||"",options:(n?.options||[]).map((n,o)=>({id:`${e.id}-opt-${o}`,label:t[o]||String(o+1),text:"string"==typeof n?n:String(n)}))}});return{passage:o.passage||"",passageTitle:o.passageTitle,passageImageUrl:o.passageImageUrl||o.mainImageUrl,instruction:o.instructions||"READ THE PASSAGE AND ANSWER QUESTIONS",questions:r}}const n=e[0],o=n?.content,r=o?.questions?.map((e,o)=>({id:e.id||`${n.id}-sq-${o}`,questionNumber:o+1,questionText:e.question,options:(e.options||[]).map((o,r)=>({id:`${e.id||n.id}-opt-${r}`,label:t[r]||String(r+1),text:o}))}))||[];return{passage:o?.passage||"",passageTitle:o?.passageTitle,passageImageUrl:o?.passageImageUrl||o?.mainImageUrl,instruction:o?.instructions?.mainInstruction||"READ THE PASSAGE AND ANSWER QUESTIONS",questions:r}}export function transformLabelPicture(t){const e=t[0],n=e?.content;return{imageUrl:n?.imageUrl||"",wordBank:n?.wordBank||[],labels:n?.labels?.map(t=>({id:t.id,number:t.number,isPreFilled:t.isPreFilled||!1,correctAnswer:t.correctAnswer}))||[],instruction:n?.instruction||"LABEL THE PICTURE"}}function e(t){return t&&"string"==typeof t.word&&!t.subQuestions}export function transformFillWordHint(t){const n=t[0],o=n?.content;if(t.length>1&&t.every(t=>e(t.content))){const e=n.questionGroup?.payload?.hintLetters||[];return{subQuestions:t.map(t=>{const e=t.content,n=e.word.replace(/\{\d+\}/,"_");return{id:t.id,questionNumber:t.question_number,imageUrl:e.imageUrl||"",word:n}}),hintLetters:e,instruction:o?.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}if(e(o)){const t=o,e=n.questionGroup?.payload?.hintLetters||[];return{subQuestions:function(t){const e=[],n=t.split(",").map(t=>t.trim());for(const t of n){let n;const o=/\{(\d+)\}/g;for(;null!==(n=o.exec(t));){const o=parseInt(n[1],10),r=t.replace(n[0],"_");e.push({index:o,displayWord:r})}}return e.sort((t,e)=>t.index-e.index),e}(t.word).map(e=>({id:`${n.id}-blank-${e.index}`,questionNumber:n.question_number,imageUrl:t.imageUrl||"",word:e.displayWord,blankIndex:e.index})),hintLetters:e,instruction:t.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}const r=o;return{subQuestions:r?.subQuestions?.map((t,e)=>({id:t.id,questionNumber:n.question_number+e,imageUrl:t.imageUrl||"",word:t.word||""}))||[],hintLetters:r?.hintLetters||n.questionGroup?.payload?.hintLetters||[],instruction:r?.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}export function transformGridFill(t){const e=t[0],n=e?.content;return{grid:n?.grid||[],rows:n?.rows||0,columns:n?.columns||0,instruction:n?.instruction||"FILL IN THE MISSING WORDS",disabledCells:n?.disabledCells||[]}}export function transformAnswerTheQuestion(t){const e=t[0],n=e?.questionGroup?.payload,o=e?.content;return{questions:t.map(t=>{const e=t.content,n=t.is_example||e.isExample||!1;return{id:t.id,questionNumber:t.question_number,question:(e.question||"").replace(/\{\d+\}/g,"______"),imageUrl:e.imageUrl,prefixText:e.prefixText,suffixText:e.suffixText,suggestedAnswers:e.suggestedAnswers,isExample:n,exampleAnswer:n?t.correct_answer?.answer:void 0}}),instruction:"ANSWER THE QUESTION",imageUrl:n?.mainImageUrl||n?.imageUrl||o?.imageUrl,title:o?.title,groupContent:n?.groupContent||o?.groupContent}}export function transformTrueFalse(t){const e=t[0]?.questionGroup?.payload;return{questions:t.map(t=>{const e=t.content,n=t.is_example||e.isExample||!1,o=n&&"boolean"==typeof t.correct_answer?.answer?t.correct_answer.answer:void 0;return{id:t.id,questionNumber:t.question_number,question:e.question||"",imageUrl:e.imageUrl,isExample:n,exampleCorrectAnswer:o}}),instruction:"READ AND CHOOSE TRUE OR FALSE",imageUrl:e?.mainImageUrl||e?.imageUrl,groupContent:e?.content||e?.groupContent}}export function transformWordOrdering(t){return{questions:t.map(t=>{const e=t.content,n=t.is_example||e.isExample||!1,o=Array.isArray(t.correct_answer?.answer)?t.correct_answer.answer:Array.isArray(e.answer)?e.answer:void 0;return{id:t.id,questionNumber:t.question_number,words:e.words||[],imageUrl:e.imageUrl,isExample:n,exampleAnswer:n?o:void 0}}),instruction:"ARRANGE THE LETTERS TO MAKE A WORD"}}export function transformWordFillParagraph(t){const e=t[0],n=e?.questionGroup?.payload,o=e?.content,r=o?.title||n?.title||t.find(t=>t.content?.title)?.content?.title,i=o?.wordBank||[],s=i.map(t=>"string"==typeof t?{word:t}:t),a=o?.viewMode,u=void 0!==o?.wordBank?.[0]?.options;let l;l="EMAIL"===a?"EMAIL":a||!o?.emailFrom&&!o?.emailTo?"DEFAULT"===a?"DEFAULT":"WITH_OPTIONS"===a||u?"WITH_OPTIONS":a||0!==i.length?"WITH_WORD_BANK":"DEFAULT":"EMAIL";const c=o?.emailFrom||o?.metadata?.emailFrom,m=o?.emailTo||o?.metadata?.emailTo;return{questionId:e?.id||"",paragraph:o?.paragraph||"",title:r,imageUrl:o?.imageUrl,wordBank:s,viewMode:l,instruction:"READ AND FILL IN THE BLANKS",exampleAnswer:o?.exampleAnswer,emailFrom:c,emailTo:m}}export function transformMatchByWritingAnswer(t){const e=t[0]?.questionGroup?.payload,n=t.some(t=>!!t.content?.askerName),o=t.map(t=>{const e=t.content,n=t.is_example||e.isExample||!1;return{id:t.id,questionNumber:t.question_number,question:e.question||"",imageUrl:e.imageUrl,isExample:n,exampleAnswer:n?t.correct_answer?.answer:void 0,askerName:e.askerName,answererName:e.answererName}}),r=e?.options?.map(t=>({answer:t.answer,imageUrl:t.imageUrl||"",content:t.content||""}))||[],i=n?t[0]?.content:void 0;return{questions:o,options:r,instruction:"LOOK AND WRITE THE ANSWER",viewMode:n?"CONVERSATION":"DEFAULT",groupImageUrl:e?.groupImageUrl||"",askerName:i?.askerName,answererName:i?.answererName}}export function transformWriteSentences(t){const e=t[0],n=e?.content,o=e?.questionGroup?.payload;return{questions:t.map(t=>({id:t.id,questionNumber:t.question_number})),instruction:n?.instruction||"WRITE SENTENCES ABOUT THE PICTURE",imageUrl:o?.mainImageUrl||o?.imageUrl||n?.imageUrl,title:n?.title,groupContent:o?.groupContent||n?.groupContent}}function n(t){const e=String(t||"").toLowerCase();return"letter"===e||"box"===e?"letter":"phrase"===e||"sentence"===e?"phrase":"word"}export function transformWordFillStructuredForm(t){const e=t[0],o=e?.questionGroup?.payload;return{questions:t.map(t=>{const e=t.content,o=t.correct_answer||{};let r=e?.content||"";const i=e?.blocks;!r&&i?.length&&(r=i.map(t=>(t.heading?`<h3>${t.heading}</h3>`:"")+(t.content||"")).join(""));const s=function(t){if(!Array.isArray(t)||0===t.length)return;const e=t.map(t=>{if(null==t)return null;if("object"!=typeof t||Array.isArray(t))return null;const e=t;if(Array.isArray(e.options)){const t=e.options.map(t=>String(t??"").trim()).filter(t=>t.length>0);return t.length>=2?{options:t}:null}const n=String(e.word??"").trim();return n?e.isExample?{word:n,isExample:!0}:{word:n}:null});return e.some(t=>null!=t)?e:void 0}(e?.wordBank),a=Boolean(s?.some(t=>null!=t&&"options"in t&&Array.isArray(t.options))),u=Boolean(s?.some(t=>null!=t&&"word"in t&&t.word)),l=e?.viewMode||(a?"WITH_OPTIONS":u?"WITH_WORD_BANK":void 0);return{id:t.id,questionNumber:t.question_number,title:e?.title||"",imageUrl:e?.imageUrl,content:r,answers:o?.answers||{},caseSensitive:o?.caseSensitive??e?.caseSensitive??!1,blankStyle:n(e?.blankStyle),...l?{viewMode:l}:{},...s?{wordBank:s}:{}}}),instruction:o?.instructions||"COMPLETE THE FORM BELOW",groupTitle:o?.title,groupContent:o?.content,groupImageUrl:o?.imageUrl,audioUrl:e?.audio_url||o?.audioUrl}}export function transformListenChooseObjects(t){const e=t[0],n=e?.content,o=e?.questionGroup?.payload||{};return{audioUrl:n?.audioUrl||"",backgroundImageUrl:o.backgroundImageUrl||"",objectNodes:o.objectNodes||[],correctObjectId:e?.correctAnswer?.objectId||e?.correct_answer?.objectId||"",isBackup:n?.isBackup||!1,instruction:"LISTEN AND CHOOSE THE CORRECT OBJECT"}}export function transformListenSpeakAnswer(t){return{questions:t.map(t=>{const e=t.content,n=t.questionGroup?.payload||{};return{id:t.id,questionNumber:t.question_number,audioUrl:e?.audioUrl||"",arrowNode:e?.arrowNode,backgroundImageUrl:n.backgroundImageUrl||n.imageUrl||"",isBackup:e?.isBackup||!1}}),instruction:"LISTEN AND SPEAK YOUR ANSWER"}}
|
|
1
|
+
export function groupQuestionsByPart(t,e){const n=new Map,o=new Map;for(const e of t){const t=o.get(e.part_id)||[];t.push(e),o.set(e.part_id,t)}for(const[t,r]of o.entries()){const o=[...r].sort((t,e)=>t.question_number-e.question_number),i=o[0];if(!i)continue;const s=e?.find(e=>String(e.id)===String(t)),a=void 0!==s?.id?Number(s.id):void 0,u=s?.name?.match(/\d+/),l=u?parseInt(u[0],10):i.part_no,c=s?.group,m=Boolean(s?.isGroup)&&"DOCUMENT"===c?.type,p=s?.sections??[],d=new Set(p.map(t=>t.questionType).filter(Boolean)),g=p.length>1&&d.size>1;if(m||g){const e=`${t}_part`;n.set(e,{partId:t,partNo:l,questionType:i.question_type,questions:o,name:s?.name,instructions:s?.instructions,audioUrl:s?.audioUrl,templateOrder:a,category:s?.category,points:s?.points,isGroup:!0,group:c,sections:s?.sections,startIndex:s?.startIndex,endIndex:s?.endIndex});continue}if(!s?.sections?.length){const e=`${t}_part`;n.set(e,{partId:t,partNo:l,questionType:i.question_type,questions:o,name:s?.name,instructions:s?.instructions,audioUrl:s?.audioUrl,templateOrder:a,category:s?.category,points:s?.points,isGroup:s?.isGroup,optionMode:s?.optionMode,optionCount:s?.optionCount,viewMode:s?.viewMode,defaultValue:s?.defaultValue,multipleAnswers:s?.multipleAnswers,questionConfig:s?.questionConfig,wordBankConfig:s?.wordBankConfig,group:s?.group,startIndex:s?.startIndex,endIndex:s?.endIndex});continue}for(const[e,r]of s.sections.entries()){const i=o.filter(t=>{const e=t.question_number-1;return e>=r.startIndex&&e<=r.endIndex});if(!i.length)continue;const u=`${t}_section_${e}`,c=Boolean(r.isGroup||r.group?.type);n.set(u,{partId:t,partNo:l,questionType:r.questionType||i[0].question_type,questions:i,name:s.name,instructions:r.instructions||r.name||s.instructions,audioUrl:s.audioUrl,templateOrder:a,category:s.category,points:s.points,sectionId:r.sectionId,isGroup:c,optionMode:r.optionMode,optionCount:r.optionCount,viewMode:r.viewMode,defaultValue:r.defaultValue,multipleAnswers:r.multipleAnswers,questionConfig:r.questionConfig,wordBankConfig:r.wordBankConfig,group:r.group,startIndex:r.startIndex,endIndex:r.endIndex})}}return Array.from(n.values()).sort((t,e)=>{const n=void 0===t.templateOrder||isNaN(t.templateOrder)?1/0:t.templateOrder,o=void 0===e.templateOrder||isNaN(e.templateOrder)?1/0:e.templateOrder;return n!==o?n-o:(t.questions[0]?.question_number||0)-(e.questions[0]?.question_number||0)})}export function transformFillInBlank(t){const e=t[0],n=e?.content,o=e?.questionGroup?.payload,r=[],i=t=>t.replace(/\*\*/g,"");for(const e of t){const t=e.content,n=e.is_example||!1,o=t.question||t.blanks?.[0]?.text||"";if([...o.matchAll(/\{(\d+)\}/g)].length>1){const s=o.split("\n").filter(t=>t.trim());for(const o of s){const s=o.match(/\{(\d+)\}/);if(!s)continue;const a=parseInt(s[1],10),u=o.split(/\{\d+\}/),l=i(u[0]?.trim()||""),c=i(u[1]?.trim()||"");r.push({id:`${e.id}-blank-${a}`,questionNumber:e.question_number,textBefore:l,textAfter:c,imageUrl:t.imageUrl,hints:t.hints,isExample:n,correctAnswer:n?e.correct_answer?.answers?.[a]:void 0})}}else{const s=o.match(/^(.*?)\{0\}(.*)$/),a=i(s?s[1].trim():o),u=i(s?s[2].trim():"");r.push({id:e.id,questionNumber:e.question_number,textBefore:a,textAfter:u,imageUrl:t.imageUrl,hints:t.hints,isExample:n,correctAnswer:n?e.correct_answer?.answers?.[0]:void 0})}}return{questions:r,title:n?.title||o?.title||"",imageUrl:o?n?.imageUrl:void 0,audioUrl:n?.audioUrl,exampleText:n?.exampleText,exampleHighlight:n?.exampleHighlight,instruction:n?.instruction||"LISTEN AND WRITE",showHints:n?.showHints,groupContent:o?.content||o?.groupContent,groupTitle:o?.title,groupImageUrl:o?.mainImageUrl||o?.imageUrl}}export function transformWriteCorrectVerbForm(t){const e=t[0],n=e?.content;return{questions:t.map(t=>{const e=t.content,n=e.sentence||"",o=n.match(/^(.*?)\{0\}(.*)$/),r=o?o[1].trim():n,i=o?o[2].trim():"";return{id:t.id,questionNumber:t.question_number,textBefore:r,textAfter:i,verbHint:e.verbHint}}),title:"WRITE THE CORRECT VERB FORM",instruction:n?.instruction||"Write the correct form of the verb in parentheses."}}function t(t,e){const n=[...t];let o=function(t){let e=0;for(let n=0;n<t.length;n++)e=(e<<5)-e+t.charCodeAt(n),e|=0;return Math.abs(e)}(e);for(let t=n.length-1;t>0;t--){o=1664525*o+1013904223&2147483647;const e=o%(t+1);[n[t],n[e]]=[n[e],n[t]]}return n}const e=["A","B","C","D","E","F"];export function transformChooseCorrectAnswer(n,o){const r=o?.shuffleOptions??!0,i=n[0]?.content,s=n[0]?.questionGroup?.payload,a=n.find(t=>t.is_example),u=n.filter(t=>!t.is_example);let l;if(a){const t=a.content,n=(t.options||[]).map((t,n)=>{const o="object"==typeof t&&null!==t,r=o&&t.id?String(t.id):`${a.id}-opt-${n}`,i=o?t.text??t.content??"":String(t),s=o?t.imageUrl:void 0;return{id:r,label:e[n]||String(n+1),text:i,...s?{imageUrl:s}:{}}}),o=a.correct_answer?.answer??a.correct_answer?.optionId;let r="";if("string"==typeof o&&o){const t=n.find(t=>t.id===o);r=t?t.id:o}else"number"==typeof o&&o>=0&&o<n.length&&(r=n[o]?.id||"");l={questionNumber:a.question_number,questionText:t.question||"",options:n,correctOptionId:r||n[0]?.id||"",optionType:t.optionType||"text",imageUrl:t.imageUrl,audioUrl:t.audioUrl}}const c=u.map(n=>{const o=n.content,i=o.optionType||"text",s=(o.options||[]).map((t,o)=>{const r="object"==typeof t&&null!==t,i=r&&t.id?String(t.id):`${n.id}-opt-${o}`,s=r?t.text??t.content??"":String(t),a=r?t.imageUrl:void 0;return{id:i,label:e[o]||String(o+1),text:s,...a?{imageUrl:a}:{}}}),a=n.correct_answer?.answer??n.correct_answer?.optionId??n.correct_answer?.optionIds,u=t=>{if(null==t)return;const e=String(t),n=s.find(t=>t.id===e);if(n)return n.id;const o=e.match(/-opt-(\d+)$/);if(o){const t=parseInt(o[1],10);if(t>=0&&t<s.length)return s[t]?.id}if("number"==typeof t&&t>=0&&t<s.length)return s[t]?.id;const r=parseInt(e,10);return!isNaN(r)&&r>=0&&r<s.length&&!e.startsWith("opt-")?s[r]?.id:e};let l=[];if(Array.isArray(a))l=a.map(u).filter(t=>Boolean(t));else{const t=u(a);t&&(l=[t])}const c=r?t(s,n.id).map((t,n)=>({...t,label:e[n]||String(n+1)})):s;return{id:n.id,questionNumber:n.question_number,questionText:o.question||"",options:c,correctOptionId:l[0],correctOptionIds:l,imageUrl:o.imageUrl,audioUrl:o.audioUrl,optionType:i,multipleAnswers:Boolean(o.multipleAnswers||Array.isArray(a)),explanation:n.explanation}}),m=c.some(t=>!!t.audioUrl?.trim())||!!l?.audioUrl?.trim();return{questions:c,example:l,imageUrl:i?.imageUrl,groupImageUrl:s?.mainImageUrl||s?.imageUrl,groupTitle:s?.title,groupContent:s?.content,articles:s?.articles,audioUrl:m?void 0:i?.audioUrl,instruction:i?.instruction||"CHOOSE THE CORRECT ANSWER"}}export function transformChooseCorrectAdjective(t){return{questions:t.map(t=>{const n=t.content,o=n.sentence||"",r=o.match(/^(.*?)\{0\}(.*)$/),i=r?r[1]:o,s=r?r[2]:"";return{id:t.id,questionNumber:t.question_number,sentenceBefore:i,sentenceAfter:s,options:(n.options||[]).map((n,o)=>({id:`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:n}))}}),instruction:"CHOOSE THE CORRECT ADJECTIVE"}}export function transformWriteShortLetter(t){const e=t.content;if(e.instructions?.mainInstruction||e.informations?.length)return{prompt:e.instructions?.mainInstruction||"",requirements:e.informations,minWords:e.minWords,maxWords:e.maxWords,guideImages:e.guideImages};return{prompt:e.contexts?.filter(t=>"text"===t.type).map(t=>t.text).join("\n")||"",minWords:e.minWords,maxWords:e.maxWords,guideImages:e.guideImages}}export function transformColorObjects(t){const e=t[0],n=e?.content,o=n?.colorNodes?.map(t=>({id:t.id,color:t.color,label:t.label}))||n?.hintItems||[],r=n?.regionNodes?.map(t=>({id:t.id,x:t.x,y:t.y,width:t.width,height:t.height,correctHintId:t.linkedColorNodeId}))||n?.regions||[],i=n?.instructions;return{instruction:(i&&i.length>0?i.join(" "):n?.instruction)||"READ AND COLOR THE OBJECTS",instructions:i,imageUrl:n?.backgroundImageUrl||n?.imageUrl||"",audioUrl:n?.audioUrl,hintItems:o,regions:r}}export function transformPictureChoose(t){const n=t[0]?.content;return{subQuestions:t.map(t=>{const n=t.content;return{id:t.id,questionNumber:t.question_number,imageUrl:n.imageUrl||"",questionText:n.questionText,options:(n.options||[]).map((n,o)=>({id:n.id||`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:"string"==typeof n?n:n.text}))}}),instruction:n?.instruction||"LOOK AT THE PICTURE AND CHOOSE THE CORRECT ANSWER"}}export function transformPictureFillBlankChoose(t){const n=t[0]?.content;return{subQuestions:t.map(t=>{const n=t.content;return{id:t.id,questionNumber:t.question_number,imageUrl:n.imageUrl||"",question:n.question||"",options:(n.options||[]).map((n,o)=>({id:n.id||`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:"string"==typeof n?n:n.text}))}}),instruction:n?.instruction||"LOOK AT THE PICTURE, FILL IN THE BLANK AND CHOOSE THE ANSWER"}}export function transformReadingPassage(t){if(function(t){const e=t[0];if(!e)return!1;const n=e.content;return void 0!==n?.question&&!n?.questions&&void 0!==e.questionGroup?.payload?.passage}(t)){const n=t[0],o=n.questionGroup?.payload||{},r=t.map(t=>{const n=t.content;return{id:t.id,questionNumber:t.question_number,questionText:n?.question||"",options:(n?.options||[]).map((n,o)=>({id:`${t.id}-opt-${o}`,label:e[o]||String(o+1),text:"string"==typeof n?n:String(n)}))}});return{passage:o.passage||"",passageTitle:o.passageTitle,passageImageUrl:o.passageImageUrl||o.mainImageUrl,instruction:o.instructions||"READ THE PASSAGE AND ANSWER QUESTIONS",questions:r}}const n=t[0],o=n?.content,r=o?.questions?.map((t,o)=>({id:t.id||`${n.id}-sq-${o}`,questionNumber:o+1,questionText:t.question,options:(t.options||[]).map((o,r)=>({id:`${t.id||n.id}-opt-${r}`,label:e[r]||String(r+1),text:o}))}))||[];return{passage:o?.passage||"",passageTitle:o?.passageTitle,passageImageUrl:o?.passageImageUrl||o?.mainImageUrl,instruction:o?.instructions?.mainInstruction||"READ THE PASSAGE AND ANSWER QUESTIONS",questions:r}}export function transformLabelPicture(t){const e=t[0],n=e?.content;return{imageUrl:n?.imageUrl||"",wordBank:n?.wordBank||[],labels:n?.labels?.map(t=>({id:t.id,number:t.number,isPreFilled:t.isPreFilled||!1,correctAnswer:t.correctAnswer}))||[],instruction:n?.instruction||"LABEL THE PICTURE"}}function n(t){return t&&"string"==typeof t.word&&!t.subQuestions}export function transformFillWordHint(t){const e=t[0],o=e?.content;if(t.length>1&&t.every(t=>n(t.content))){const n=e.questionGroup?.payload?.hintLetters||[];return{subQuestions:t.map(t=>{const e=t.content,n=e.word.replace(/\{\d+\}/,"_");return{id:t.id,questionNumber:t.question_number,imageUrl:e.imageUrl||"",word:n}}),hintLetters:n,instruction:o?.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}if(n(o)){const t=o,n=e.questionGroup?.payload?.hintLetters||[];return{subQuestions:function(t){const e=[],n=t.split(",").map(t=>t.trim());for(const t of n){let n;const o=/\{(\d+)\}/g;for(;null!==(n=o.exec(t));){const o=parseInt(n[1],10),r=t.replace(n[0],"_");e.push({index:o,displayWord:r})}}return e.sort((t,e)=>t.index-e.index),e}(t.word).map(n=>({id:`${e.id}-blank-${n.index}`,questionNumber:e.question_number,imageUrl:t.imageUrl||"",word:n.displayWord,blankIndex:n.index})),hintLetters:n,instruction:t.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}const r=o;return{subQuestions:r?.subQuestions?.map((t,n)=>({id:t.id,questionNumber:e.question_number+n,imageUrl:t.imageUrl||"",word:t.word||""}))||[],hintLetters:r?.hintLetters||e.questionGroup?.payload?.hintLetters||[],instruction:r?.instruction||"LOOK AT THE PICTURE AND FILL IN THE MISSING LETTER"}}export function transformGridFill(t){const e=t[0],n=e?.content;return{grid:n?.grid||[],rows:n?.rows||0,columns:n?.columns||0,instruction:n?.instruction||"FILL IN THE MISSING WORDS",disabledCells:n?.disabledCells||[]}}export function transformAnswerTheQuestion(t){const e=t[0],n=e?.questionGroup?.payload,o=e?.content;return{questions:t.map(t=>{const e=t.content,n=t.is_example||e.isExample||!1;return{id:t.id,questionNumber:t.question_number,question:(e.question||"").replace(/\{\d+\}/g,"______"),imageUrl:e.imageUrl,prefixText:e.prefixText,suffixText:e.suffixText,suggestedAnswers:e.suggestedAnswers,isExample:n,exampleAnswer:n?t.correct_answer?.answer:void 0}}),instruction:"ANSWER THE QUESTION",imageUrl:n?.mainImageUrl||n?.imageUrl||o?.imageUrl,title:o?.title,groupContent:n?.groupContent||o?.groupContent}}export function transformTrueFalse(t){const e=t[0]?.questionGroup?.payload;return{questions:t.map(t=>{const e=t.content,n=t.is_example||e.isExample||!1,o=n&&"boolean"==typeof t.correct_answer?.answer?t.correct_answer.answer:void 0;return{id:t.id,questionNumber:t.question_number,question:e.question||"",imageUrl:e.imageUrl,isExample:n,exampleCorrectAnswer:o}}),instruction:"READ AND CHOOSE TRUE OR FALSE",imageUrl:e?.mainImageUrl||e?.imageUrl,groupContent:e?.content||e?.groupContent}}export function transformWordOrdering(t){return{questions:t.map(t=>{const e=t.content,n=t.is_example||e.isExample||!1,o=Array.isArray(t.correct_answer?.answer)?t.correct_answer.answer:Array.isArray(e.answer)?e.answer:void 0;return{id:t.id,questionNumber:t.question_number,words:e.words||[],imageUrl:e.imageUrl,isExample:n,exampleAnswer:n?o:void 0}}),instruction:"ARRANGE THE LETTERS TO MAKE A WORD"}}export function transformWordFillParagraph(t){const e=t[0],n=e?.questionGroup?.payload,o=e?.content,r=o?.title||n?.title||t.find(t=>t.content?.title)?.content?.title,i=o?.wordBank||[],s=i.map(t=>"string"==typeof t?{word:t}:t),a=o?.viewMode,u=void 0!==o?.wordBank?.[0]?.options;let l;l="EMAIL"===a?"EMAIL":a||!o?.emailFrom&&!o?.emailTo?"DEFAULT"===a?"DEFAULT":"WITH_OPTIONS"===a||u?"WITH_OPTIONS":a||0!==i.length?"WITH_WORD_BANK":"DEFAULT":"EMAIL";const c=o?.emailFrom||o?.metadata?.emailFrom,m=o?.emailTo||o?.metadata?.emailTo;return{questionId:e?.id||"",paragraph:o?.paragraph||"",title:r,imageUrl:o?.imageUrl,wordBank:s,viewMode:l,instruction:"READ AND FILL IN THE BLANKS",exampleAnswer:o?.exampleAnswer,emailFrom:c,emailTo:m}}export function transformMatchByWritingAnswer(t){const e=t[0]?.questionGroup?.payload,n=t.some(t=>!!t.content?.askerName),o=t.map(t=>{const e=t.content,n=t.is_example||e.isExample||!1;return{id:t.id,questionNumber:t.question_number,question:e.question||"",imageUrl:e.imageUrl,isExample:n,exampleAnswer:n?t.correct_answer?.answer:void 0,askerName:e.askerName,answererName:e.answererName}}),r=e?.options?.map(t=>({answer:t.answer,imageUrl:t.imageUrl||"",content:t.content||""}))||[],i=n?t[0]?.content:void 0;return{questions:o,options:r,instruction:"LOOK AND WRITE THE ANSWER",viewMode:n?"CONVERSATION":"DEFAULT",groupImageUrl:e?.groupImageUrl||"",askerName:i?.askerName,answererName:i?.answererName}}export function transformWriteSentences(t){const e=t[0],n=e?.content,o=e?.questionGroup?.payload;return{questions:t.map(t=>({id:t.id,questionNumber:t.question_number})),instruction:n?.instruction||"WRITE SENTENCES ABOUT THE PICTURE",imageUrl:o?.mainImageUrl||o?.imageUrl||n?.imageUrl,title:n?.title,groupContent:o?.groupContent||n?.groupContent}}function o(t){const e=String(t||"").toLowerCase();return"letter"===e||"box"===e?"letter":"phrase"===e||"sentence"===e?"phrase":"word"}export function transformWordFillStructuredForm(t){const e=t[0],n=e?.questionGroup?.payload;return{questions:t.map(t=>{const e=t.content,n=t.correct_answer||{};let r=e?.content||"";const i=e?.blocks;!r&&i?.length&&(r=i.map(t=>(t.heading?`<h3>${t.heading}</h3>`:"")+(t.content||"")).join(""));const s=function(t){if(!Array.isArray(t)||0===t.length)return;const e=t.map(t=>{if(null==t)return null;if("object"!=typeof t||Array.isArray(t))return null;const e=t;if(Array.isArray(e.options)){const t=e.options.map(t=>String(t??"").trim()).filter(t=>t.length>0);return t.length>=2?{options:t}:null}const n=String(e.word??"").trim();return n?e.isExample?{word:n,isExample:!0}:{word:n}:null});return e.some(t=>null!=t)?e:void 0}(e?.wordBank),a=Boolean(s?.some(t=>null!=t&&"options"in t&&Array.isArray(t.options))),u=Boolean(s?.some(t=>null!=t&&"word"in t&&t.word)),l=e?.viewMode||(a?"WITH_OPTIONS":u?"WITH_WORD_BANK":void 0);return{id:t.id,questionNumber:t.question_number,title:e?.title||"",imageUrl:e?.imageUrl,content:r,answers:n?.answers||{},caseSensitive:n?.caseSensitive??e?.caseSensitive??!1,blankStyle:o(e?.blankStyle),...l?{viewMode:l}:{},...s?{wordBank:s}:{}}}),instruction:n?.instructions||"COMPLETE THE FORM BELOW",groupTitle:n?.title,groupContent:n?.content,groupImageUrl:n?.imageUrl,audioUrl:e?.audio_url||n?.audioUrl}}export function transformListenChooseObjects(t){const e=t[0],n=e?.content,o=e?.questionGroup?.payload||{};return{audioUrl:n?.audioUrl||"",backgroundImageUrl:o.backgroundImageUrl||"",objectNodes:o.objectNodes||[],correctObjectId:e?.correctAnswer?.objectId||e?.correct_answer?.objectId||"",isBackup:n?.isBackup||!1,instruction:"LISTEN AND CHOOSE THE CORRECT OBJECT"}}export function transformListenSpeakAnswer(t){return{questions:t.map(t=>{const e=t.content,n=t.questionGroup?.payload||{};return{id:t.id,questionNumber:t.question_number,audioUrl:e?.audioUrl||"",arrowNode:e?.arrowNode,backgroundImageUrl:n.backgroundImageUrl||n.imageUrl||"",isBackup:e?.isBackup||!1}}),instruction:"LISTEN AND SPEAK YOUR ANSWER"}}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
/** WFSF blank input width/shape (content.blankStyle). */
|
|
2
2
|
export type WfsfBlankStyle = 'letter' | 'word' | 'phrase';
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
/**
|
|
4
|
+
* WORD_FILL_STRUCTURED_FORM — creator / client contracts.
|
|
5
|
+
* wordBank + viewMode: plan 0024 (WITH_OPTIONS) + 0025 (WITH_WORD_BANK).
|
|
6
|
+
*/
|
|
7
|
+
export type WfsfViewMode = 'WITH_OPTIONS' | 'WITH_WORD_BANK';
|
|
8
|
+
/** Shared suggestion box (plan 0025). */
|
|
9
|
+
export type WfsfSharedWordBankEntry = {
|
|
7
10
|
word: string;
|
|
8
11
|
isExample?: boolean;
|
|
12
|
+
};
|
|
13
|
+
/** Per-blank dropdown options (plan 0024). `null` = free-type slot. */
|
|
14
|
+
export type WfsfOptionsWordBankEntry = {
|
|
15
|
+
options: string[];
|
|
9
16
|
} | null;
|
|
17
|
+
export type WfsfWordBankEntry = WfsfSharedWordBankEntry | WfsfOptionsWordBankEntry;
|
|
10
18
|
export interface WordFillStructuredFormData {
|
|
11
19
|
title?: string;
|
|
12
20
|
imageUrl?: string;
|
|
@@ -26,6 +34,8 @@ export interface WordFillStructuredFormData {
|
|
|
26
34
|
/** OPTIONS: index i ↔ {i}; WORD_BANK: shared list of { word }. */
|
|
27
35
|
wordBank?: WfsfWordBankEntry[];
|
|
28
36
|
points?: number;
|
|
37
|
+
/** Student rubric / page instruction (shown in client header). */
|
|
38
|
+
instruction?: string;
|
|
29
39
|
explanation?: string;
|
|
30
40
|
caseSensitive?: boolean;
|
|
31
41
|
groupTitle?: string;
|
|
@@ -46,17 +56,15 @@ export interface WordFillStructuredFormCreatorProps {
|
|
|
46
56
|
triggerValidation: () => Promise<boolean>;
|
|
47
57
|
getFormData: () => WordFillStructuredFormData;
|
|
48
58
|
} | null>;
|
|
49
|
-
/** Group config from exam template (e.g. [{ number: 1, questionCount: 5 }]) */
|
|
50
59
|
groups?: Array<{
|
|
51
60
|
number: number;
|
|
52
61
|
questionCount: number;
|
|
53
62
|
}>;
|
|
54
|
-
/** Zero-based index of this question within the current part */
|
|
55
63
|
questionIndexInPart?: number;
|
|
56
|
-
/** Part ID for shared group state across questions in the same group */
|
|
57
64
|
partId?: string;
|
|
58
|
-
/** Group type from exam template (e.g. "BASIC", "DOCUMENT") */
|
|
59
65
|
groupType?: string;
|
|
66
|
+
/** Template / host viewMode override (Pearson edit dialog). */
|
|
67
|
+
viewMode?: WfsfViewMode | 'DEFAULT' | 'CONVERSATION' | 'EMAIL' | null;
|
|
60
68
|
}
|
|
61
69
|
export interface WordFillStructuredFormClientProps {
|
|
62
70
|
questionData: WordFillStructuredFormData;
|
|
@@ -64,7 +72,8 @@ export interface WordFillStructuredFormClientProps {
|
|
|
64
72
|
userAnswer?: Record<string, string>;
|
|
65
73
|
onAnswerChange?: (questionNumber: string, value: string) => void;
|
|
66
74
|
autoFillCorrectAnswers?: boolean;
|
|
67
|
-
/**
|
|
75
|
+
/** Page rubric — prefer over hard-coded type label in header. */
|
|
76
|
+
instruction?: string;
|
|
68
77
|
explanation?: string;
|
|
69
78
|
/** Exercise / question number shown above instruction (e.g. Bài 1). */
|
|
70
79
|
questionNumber?: number;
|
package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as r,Fragment as t}from"react/jsx-runtime";import{useState as s,useEffect as a,useMemo as l}from"react";import{Check as n,X as i,CircleHelp as d,Lightbulb as o,ClipboardList as c,Users as m,BookOpen as g}from"lucide-react";import{usePresignedFileUrl as h}from"../../../../shared/lib/hooks";import{cn as b}from"../../../../shared/lib/utils";function p({src:r,alt:t,className:s}){const{previewUrl:a,isLoading:l}=h(r);return l?e("div",{className:"flex h-16 w-16 items-center justify-center",children:e("div",{className:"h-4 w-4 animate-spin rounded-full border-2 border-gray-200 border-t-blue-500"})}):e("img",{src:a||r,alt:t,className:b("max-h-20 w-auto object-contain rounded-md",s),onError:e=>{const r=e.target;r.onerror=null,r.src="/images/placeholder-image.svg"}})}export function ChooseTheCorrectAnswerClient({questionData:x,onSubmit:u,isReviewMode:f=!1,userAnswer:N,questionConfig:w}){const v=Boolean(x.multipleAnswers||Array.isArray(x.correctAnswer)),y=l(()=>Array.isArray(x.correctAnswer)?x.correctAnswer:-1===x.correctAnswer?[]:[x.correctAnswer],[x.correctAnswer]),j=l(()=>void 0===N?[]:Array.isArray(N)?N:-1===N?[]:[N],[N]),[C,k]=s(j),{previewUrl:A,isLoading:U}=h(x.imageUrl||"");a(()=>{k(j)},[j]);const S=C.length>0,T=f&&C.length===y.length&&C.every(e=>y.includes(e)),$=e=>0===e.length?"(Chưa trả lời)":e.map(e=>{const r=String.fromCharCode(65+e);return"image"===x.optionType?`Đáp án ${r}`:`${r}. ${x.options[e]}`}).join(", "),q=!w||0===w.length||w.includes("question"),I=!w||0===w.length||w.includes("imageUrl")||w.includes("image");console.log("questionConfig",w),console.log("showImage",I);const B=!w||0===w.length||w.includes("options"),G=x.imageUrl?.trim()?x.imageUrl:"",L=Array.isArray(x.articles)&&x.articles.length>0;return r("div",{className:"space-y-4",children:[x.isGroup&&(x.groupTitle||x.groupSubtitle||x.groupContent||x.groupImageUrl||L)&&r("div",{className:"relative overflow-hidden rounded-2xl border border-indigo-100 bg-white shadow-sm ring-1 ring-black/5 transition-all",children:[e("div",{className:"absolute inset-0 bg-gradient-to-br from-indigo-50/80 via-white to-blue-50/30 opacity-70 pointer-events-none"}),e("div",{className:"absolute left-0 top-0 bottom-0 w-1.5 bg-gradient-to-b from-indigo-500 to-blue-600 rounded-l-2xl"}),r("div",{className:"relative p-6 sm:p-7",children:[r("div",{className:"flex items-start gap-4 mb-5 border-b border-indigo-50/60 pb-4",children:[e("div",{className:"flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-indigo-100 to-blue-100 shadow-inner ring-1 ring-indigo-200/50",children:e(g,{className:"h-5 w-5 text-indigo-600"})}),r("div",{className:"flex-1 pt-1",children:[e("div",{className:"flex items-center gap-2 mb-1",children:x.groupNumber&&r("span",{className:"inline-flex items-center rounded-md bg-indigo-50 px-2 py-1 text-xs font-semibold text-indigo-700 ring-1 ring-inset ring-indigo-700/10",children:["Bài đọc ",x.groupNumber]})}),x.groupTitle&&e("h4",{className:"text-xl font-bold text-slate-800 leading-tight tracking-tight",children:x.groupTitle}),x.groupSubtitle&&e("p",{className:"mt-1 text-sm text-slate-500 leading-snug",children:x.groupSubtitle})]})]}),L&&e("div",{className:"flex flex-col gap-4",children:x.articles.map((t,s)=>r("div",{className:"group relative overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm transition-all hover:shadow-md hover:border-indigo-200",children:[r("div",{className:"flex items-center gap-2 border-b border-slate-100 bg-gradient-to-r from-indigo-50/60 to-blue-50/40 px-4 py-2.5",children:[e("div",{className:"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-indigo-500 to-blue-600 text-xs font-bold text-white shadow-sm",children:String.fromCharCode(65+s)}),e("h5",{className:"flex-1 truncate text-sm font-bold text-slate-800",children:t.name||`Bài viết ${s+1}`})]}),r("div",{className:"flex flex-col gap-3 p-4 sm:flex-row sm:items-start",children:[t.imageUrl&&e("div",{className:"flex flex-shrink-0 items-center justify-center rounded-md bg-slate-50 p-2 sm:w-40",children:e(p,{src:t.imageUrl,alt:t.name||`Article ${s+1}`,className:"max-h-40 w-auto rounded-md object-contain"})}),t.content&&e("div",{className:"prose prose-sm prose-slate max-w-none flex-1 text-[14px] leading-relaxed text-slate-700",children:t.content.split("\n").map((r,t)=>e("p",{className:"mb-2 last:mb-0",children:r},t))})]})]},s))}),!L&&r("div",{className:"space-y-6 text-slate-700",children:[x.groupContent&&e("div",{className:"prose prose-slate prose-p:leading-relaxed prose-p:mb-3 max-w-none text-[15px]",dangerouslySetInnerHTML:{__html:x.groupContent.replace(/\{(\d+)\}/g,(e,r)=>`<span style="display:inline-block;min-width:100px;padding:1px 5px;margin:0 5px;background:#eef2ff;border-bottom:2px solid #6366f1;color:#4f46e5;font-weight:700;font-size:0.85em;text-align:center;vertical-align:baseline;letter-spacing:2px">———(${Number(r)+1})———</span>`).split("\n").map(e=>`<p class="last:mb-0">${e}</p>`).join("")}}),x.groupImageUrl&&r("div",{className:"mt-5 relative overflow-hidden rounded-xl border border-slate-200/60 bg-slate-50 shadow-sm transition-all hover:shadow-md",children:[e("div",{className:"flex items-center justify-between border-b border-slate-200/60 bg-slate-100/50 px-4 py-2",children:r("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"h-2.5 w-2.5 rounded-full bg-slate-300"}),e("div",{className:"h-2.5 w-2.5 rounded-full bg-slate-300"}),e("div",{className:"h-2.5 w-2.5 rounded-full bg-slate-300"}),e("span",{className:"ml-2 text-[11px] font-semibold uppercase tracking-wider text-slate-500",children:"Tài liệu đính kèm"})]})}),e("div",{className:"flex items-center justify-center p-4 min-h-[160px]",children:e(p,{src:x.groupImageUrl,alt:x.groupTitle||"Group Image Attachment",className:"max-h-72 w-auto object-contain drop-shadow-sm rounded-lg"})})]})]})]})]}),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-blue-500 to-indigo-600 text-white shadow-sm",children:e(d,{className:"h-4 w-4"})}),e("span",{className:"text-sm font-medium text-gray-700",children:v?"Chọn các đáp án đúng":"Chọn đáp án đúng"})]}),f&&S&&r("div",{className:b("flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold",T?"bg-green-100 text-green-700":"bg-red-100 text-red-700"),children:[e(T?n:i,{className:"h-3.5 w-3.5"}),T?"Đúng":"Sai"]})]}),r("div",{className:"p-5 space-y-5",children:[(x.askerName||x.answererName)&&r("div",{className:"flex items-center gap-4 rounded-lg border border-purple-100 bg-gradient-to-r from-purple-50 to-violet-50 px-4 py-3",children:[e(m,{className:"h-4 w-4 flex-shrink-0 text-purple-500"}),r("div",{className:"flex items-center gap-4 text-sm",children:[x.askerName&&r("div",{className:"flex items-center gap-1.5",children:[e("span",{className:"font-medium text-gray-500",children:"Người hỏi:"}),e("span",{className:"font-semibold text-purple-700",children:x.askerName})]}),x.askerName&&x.answererName&&e("div",{className:"h-4 w-px bg-purple-200"}),x.answererName&&r("div",{className:"flex items-center gap-1.5",children:[e("span",{className:"font-medium text-gray-500",children:"Người trả lời:"}),e("span",{className:"font-semibold text-purple-700",children:x.answererName})]})]})]}),q&&e("div",{className:"rounded-lg bg-gradient-to-r from-blue-50 to-indigo-50 p-4 border border-blue-100",children:e("h3",{className:"text-base font-semibold text-gray-800 leading-relaxed",children:x.question||"Câu hỏi chưa được nhập"})}),I&&(A||G)&&r("div",{className:"overflow-hidden rounded-lg border border-gray-200 bg-gradient-to-br from-slate-50 to-gray-100",children:[e("div",{className:"border-b border-gray-100 px-3 py-1.5",children:r("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"h-2 w-2 rounded-full bg-red-400"}),e("div",{className:"h-2 w-2 rounded-full bg-yellow-400"}),e("div",{className:"h-2 w-2 rounded-full bg-green-400"}),e("span",{className:"ml-2 text-xs font-medium text-gray-500",children:"Hình ảnh"})]})}),e("div",{className:"flex items-center justify-center p-4",children:U?e("div",{className:"flex h-48 items-center justify-center",children:e("div",{className:"h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-blue-500"})}):e("img",{src:A||G,alt:"Question illustration",className:"max-h-56 w-auto object-contain rounded-md",onError:e=>{const r=e.target;r.onerror=null,r.src="/images/placeholder-image.svg"}})})]}),B&&r("div",{className:"space-y-2.5",children:[e("span",{className:"text-xs font-medium text-gray-500 uppercase tracking-wider",children:v?"Chọn một hoặc nhiều đáp án":"Chọn đáp án"}),x.options.map((t,s)=>{const a=C.includes(s),l=(d=s,!!f&&y.includes(d));var d;const o=String.fromCharCode(65+s);return r("button",{type:"button",onClick:()=>(e=>{if(f)return;const r=v?C.includes(e)?C.filter(r=>r!==e):[...C,e].sort((e,r)=>e-r):[e];k(r),u?.(v?r:r[0])})(s),disabled:f,className:b("group flex w-full items-center gap-3 rounded-lg border-2 p-3.5 text-left transition-all",f?l?"border-green-400 bg-green-50":a?"border-red-400 bg-red-50":"border-gray-200 bg-gray-50":a?"border-blue-500 bg-blue-50 shadow-sm ring-2 ring-blue-100":"border-gray-200 bg-white hover:border-gray-300 hover:bg-gray-50 hover:shadow-sm"),children:[e("div",{className:b("flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg text-sm font-bold transition-all",f?l?"bg-green-500 text-white":a?"bg-red-500 text-white":"bg-gray-200 text-gray-600":a?"bg-gradient-to-br from-blue-500 to-indigo-600 text-white shadow-sm":"bg-gray-100 text-gray-600 group-hover:bg-gray-200"),children:o}),"image"===x.optionType?e("div",{className:"flex-1 flex items-center justify-center py-1",children:e(p,{src:t,alt:`Đáp án ${o}`})}):e("span",{className:b("flex-1 text-sm font-medium",f&&l?"text-green-800":f&&a&&!l?"text-red-800":"text-gray-700"),children:t}),f&&(l||a)&&e("div",{className:b("flex h-6 w-6 items-center justify-center rounded-full",l?"bg-green-500":"bg-red-500"),children:e(l?n:i,{className:"h-4 w-4 text-white"})})]},s)})]}),!f&&!S&&r("div",{className:"rounded-lg border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-3 flex items-center gap-2",children:[e("div",{className:"flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full bg-amber-400 text-white",children:e("span",{className:"text-xs font-bold",children:"!"})}),e("span",{className:"text-sm text-amber-800",children:v?"Vui lòng chọn ít nhất một đáp án":"Vui lòng chọn một đáp án"})]})]})]}),f&&x.explanation&&r("div",{className:"overflow-hidden rounded-xl border border-blue-200 bg-gradient-to-br from-blue-50 to-indigo-50 shadow-sm",children:[r("div",{className:"flex items-center gap-2 border-b border-blue-100 bg-white/50 px-4 py-3",children:[e("div",{className:"flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-amber-400 to-orange-500 text-white shadow-sm",children:e(o,{className:"h-4 w-4"})}),e("h4",{className:"text-sm font-semibold text-gray-800",children:"Giải thích"})]}),e("div",{className:"p-4",children:e("p",{className:"text-sm text-gray-700 leading-relaxed",children:x.explanation})})]}),f&&r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center gap-2 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-4 py-3",children:[e("div",{className:"flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-slate-500 to-gray-600 text-white shadow-sm",children:e(c,{className:"h-4 w-4"})}),e("h4",{className:"text-sm font-semibold text-gray-800",children:"Tổng kết"})]}),r("div",{className:"p-4 space-y-3",children:[r("div",{className:"flex items-center justify-between rounded-lg bg-gray-50 p-3",children:[e("span",{className:"text-sm text-gray-600",children:"Đáp án của bạn:"}),e("span",{className:b("text-sm font-semibold",T?"text-green-600":S?"text-red-600":"text-gray-500"),children:$(C)})]}),r("div",{className:"flex items-center justify-between rounded-lg bg-green-50 p-3 border border-green-100",children:[e("span",{className:"text-sm text-gray-600",children:"Đáp án đúng:"}),e("span",{className:"text-sm font-semibold text-green-600",children:$(y)})]}),r("div",{className:b("flex items-center justify-between rounded-lg p-3 border",T?"bg-green-50 border-green-200":"bg-red-50 border-red-200"),children:[e("span",{className:"text-sm text-gray-600",children:"Kết quả:"}),e("div",{className:b("flex items-center gap-1.5 text-sm font-semibold",T?"text-green-600":"text-red-600"),children:r(t,T?{children:[e(n,{className:"h-4 w-4"}),e("span",{children:"Chính xác"})]}:{children:[e(i,{className:"h-4 w-4"}),e("span",{children:"Sai"})]})})]})]})]})]})}
|
|
1
|
+
"use client";import{jsx as e,jsxs as r,Fragment as t}from"react/jsx-runtime";import{useState as s,useEffect as a,useMemo as n}from"react";import{Check as l,X as i,CircleHelp as d,Lightbulb as o,ClipboardList as c,Users as m,BookOpen as g}from"lucide-react";import{usePresignedFileUrl as h}from"../../../../shared/lib/hooks";import{cn as b}from"../../../../shared/lib/utils";import{normalizeChooseAnswerCorrectAnswer as p}from"./normalize";function u({src:r,alt:t,className:s}){const{previewUrl:a,isLoading:n}=h(r);return n?e("div",{className:"flex h-16 w-16 items-center justify-center",children:e("div",{className:"h-4 w-4 animate-spin rounded-full border-2 border-gray-200 border-t-blue-500"})}):e("img",{src:a||r,alt:t,className:b("max-h-20 w-auto object-contain rounded-md",s),onError:e=>{const r=e.target;r.onerror=null,r.src="/images/placeholder-image.svg"}})}export function ChooseTheCorrectAnswerClient({questionData:x,onSubmit:f,isReviewMode:N=!1,userAnswer:w,questionConfig:v}){const y=Boolean(x.multipleAnswers||Array.isArray(x.correctAnswer)),j=n(()=>{const e=p(x.correctAnswer,x.options);return Array.isArray(e)?e:-1===e?[]:[e]},[x.correctAnswer,x.options]),C=n(()=>{if(null==w)return[];const e=p(w,x.options);return Array.isArray(e)?e:-1===e?[]:[e]},[w,x.options]),[k,A]=s(C),{previewUrl:U,isLoading:S}=h(x.imageUrl||"");a(()=>{A(C)},[C]);const T=k.length>0,$=N&&k.length===j.length&&k.every(e=>j.includes(e)),q=e=>0===e.length?"(Chưa trả lời)":e.map(e=>{const r=String.fromCharCode(65+e);return"image"===x.optionType?`Đáp án ${r}`:`${r}. ${x.options[e]}`}).join(", "),I=!v||0===v.length||v.includes("question"),B=!v||0===v.length||v.includes("imageUrl")||v.includes("image");console.log("questionConfig",v),console.log("showImage",B);const G=!v||0===v.length||v.includes("options"),L=x.imageUrl?.trim()?x.imageUrl:"",z=Array.isArray(x.articles)&&x.articles.length>0;return r("div",{className:"space-y-4",children:[x.isGroup&&(x.groupTitle||x.groupSubtitle||x.groupContent||x.groupImageUrl||z)&&r("div",{className:"relative overflow-hidden rounded-2xl border border-indigo-100 bg-white shadow-sm ring-1 ring-black/5 transition-all",children:[e("div",{className:"absolute inset-0 bg-gradient-to-br from-indigo-50/80 via-white to-blue-50/30 opacity-70 pointer-events-none"}),e("div",{className:"absolute left-0 top-0 bottom-0 w-1.5 bg-gradient-to-b from-indigo-500 to-blue-600 rounded-l-2xl"}),r("div",{className:"relative p-6 sm:p-7",children:[r("div",{className:"flex items-start gap-4 mb-5 border-b border-indigo-50/60 pb-4",children:[e("div",{className:"flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-indigo-100 to-blue-100 shadow-inner ring-1 ring-indigo-200/50",children:e(g,{className:"h-5 w-5 text-indigo-600"})}),r("div",{className:"flex-1 pt-1",children:[e("div",{className:"flex items-center gap-2 mb-1",children:x.groupNumber&&r("span",{className:"inline-flex items-center rounded-md bg-indigo-50 px-2 py-1 text-xs font-semibold text-indigo-700 ring-1 ring-inset ring-indigo-700/10",children:["Bài đọc ",x.groupNumber]})}),x.groupTitle&&e("h4",{className:"text-xl font-bold text-slate-800 leading-tight tracking-tight",children:x.groupTitle}),x.groupSubtitle&&e("p",{className:"mt-1 text-sm text-slate-500 leading-snug",children:x.groupSubtitle})]})]}),z&&e("div",{className:"flex flex-col gap-4",children:x.articles.map((t,s)=>r("div",{className:"group relative overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm transition-all hover:shadow-md hover:border-indigo-200",children:[r("div",{className:"flex items-center gap-2 border-b border-slate-100 bg-gradient-to-r from-indigo-50/60 to-blue-50/40 px-4 py-2.5",children:[e("div",{className:"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-indigo-500 to-blue-600 text-xs font-bold text-white shadow-sm",children:String.fromCharCode(65+s)}),e("h5",{className:"flex-1 truncate text-sm font-bold text-slate-800",children:t.name||`Bài viết ${s+1}`})]}),r("div",{className:"flex flex-col gap-3 p-4 sm:flex-row sm:items-start",children:[t.imageUrl&&e("div",{className:"flex flex-shrink-0 items-center justify-center rounded-md bg-slate-50 p-2 sm:w-40",children:e(u,{src:t.imageUrl,alt:t.name||`Article ${s+1}`,className:"max-h-40 w-auto rounded-md object-contain"})}),t.content&&e("div",{className:"prose prose-sm prose-slate max-w-none flex-1 text-[14px] leading-relaxed text-slate-700",children:t.content.split("\n").map((r,t)=>e("p",{className:"mb-2 last:mb-0",children:r},t))})]})]},s))}),!z&&r("div",{className:"space-y-6 text-slate-700",children:[x.groupContent&&e("div",{className:"prose prose-slate prose-p:leading-relaxed prose-p:mb-3 max-w-none text-[15px]",dangerouslySetInnerHTML:{__html:x.groupContent.replace(/\{(\d+)\}/g,(e,r)=>`<span style="display:inline-block;min-width:100px;padding:1px 5px;margin:0 5px;background:#eef2ff;border-bottom:2px solid #6366f1;color:#4f46e5;font-weight:700;font-size:0.85em;text-align:center;vertical-align:baseline;letter-spacing:2px">———(${Number(r)+1})———</span>`).split("\n").map(e=>`<p class="last:mb-0">${e}</p>`).join("")}}),x.groupImageUrl&&r("div",{className:"mt-5 relative overflow-hidden rounded-xl border border-slate-200/60 bg-slate-50 shadow-sm transition-all hover:shadow-md",children:[e("div",{className:"flex items-center justify-between border-b border-slate-200/60 bg-slate-100/50 px-4 py-2",children:r("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"h-2.5 w-2.5 rounded-full bg-slate-300"}),e("div",{className:"h-2.5 w-2.5 rounded-full bg-slate-300"}),e("div",{className:"h-2.5 w-2.5 rounded-full bg-slate-300"}),e("span",{className:"ml-2 text-[11px] font-semibold uppercase tracking-wider text-slate-500",children:"Tài liệu đính kèm"})]})}),e("div",{className:"flex items-center justify-center p-4 min-h-[160px]",children:e(u,{src:x.groupImageUrl,alt:x.groupTitle||"Group Image Attachment",className:"max-h-72 w-auto object-contain drop-shadow-sm rounded-lg"})})]})]})]})]}),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-blue-500 to-indigo-600 text-white shadow-sm",children:e(d,{className:"h-4 w-4"})}),e("span",{className:"text-sm font-medium text-gray-700",children:y?"Chọn các đáp án đúng":"Chọn đáp án đúng"})]}),N&&T&&r("div",{className:b("flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold",$?"bg-green-100 text-green-700":"bg-red-100 text-red-700"),children:[e($?l:i,{className:"h-3.5 w-3.5"}),$?"Đúng":"Sai"]})]}),r("div",{className:"p-5 space-y-5",children:[(x.askerName||x.answererName)&&r("div",{className:"flex items-center gap-4 rounded-lg border border-purple-100 bg-gradient-to-r from-purple-50 to-violet-50 px-4 py-3",children:[e(m,{className:"h-4 w-4 flex-shrink-0 text-purple-500"}),r("div",{className:"flex items-center gap-4 text-sm",children:[x.askerName&&r("div",{className:"flex items-center gap-1.5",children:[e("span",{className:"font-medium text-gray-500",children:"Người hỏi:"}),e("span",{className:"font-semibold text-purple-700",children:x.askerName})]}),x.askerName&&x.answererName&&e("div",{className:"h-4 w-px bg-purple-200"}),x.answererName&&r("div",{className:"flex items-center gap-1.5",children:[e("span",{className:"font-medium text-gray-500",children:"Người trả lời:"}),e("span",{className:"font-semibold text-purple-700",children:x.answererName})]})]})]}),I&&e("div",{className:"rounded-lg bg-gradient-to-r from-blue-50 to-indigo-50 p-4 border border-blue-100",children:e("h3",{className:"text-base font-semibold text-gray-800 leading-relaxed",children:x.question||"Câu hỏi chưa được nhập"})}),B&&(U||L)&&r("div",{className:"overflow-hidden rounded-lg border border-gray-200 bg-gradient-to-br from-slate-50 to-gray-100",children:[e("div",{className:"border-b border-gray-100 px-3 py-1.5",children:r("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"h-2 w-2 rounded-full bg-red-400"}),e("div",{className:"h-2 w-2 rounded-full bg-yellow-400"}),e("div",{className:"h-2 w-2 rounded-full bg-green-400"}),e("span",{className:"ml-2 text-xs font-medium text-gray-500",children:"Hình ảnh"})]})}),e("div",{className:"flex items-center justify-center p-4",children:S?e("div",{className:"flex h-48 items-center justify-center",children:e("div",{className:"h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-blue-500"})}):e("img",{src:U||L,alt:"Question illustration",className:"max-h-56 w-auto object-contain rounded-md",onError:e=>{const r=e.target;r.onerror=null,r.src="/images/placeholder-image.svg"}})})]}),G&&r("div",{className:"space-y-2.5",children:[e("span",{className:"text-xs font-medium text-gray-500 uppercase tracking-wider",children:y?"Chọn một hoặc nhiều đáp án":"Chọn đáp án"}),x.options.map((t,s)=>{const a=k.includes(s),n=(d=s,!!N&&j.includes(d));var d;const o=String.fromCharCode(65+s);return r("button",{type:"button",onClick:()=>(e=>{if(N)return;const r=y?k.includes(e)?k.filter(r=>r!==e):[...k,e].sort((e,r)=>e-r):[e];A(r),f?.(y?r:r[0])})(s),disabled:N,className:b("group flex w-full items-center gap-3 rounded-lg border-2 p-3.5 text-left transition-all",N?n?"border-green-400 bg-green-50":a?"border-red-400 bg-red-50":"border-gray-200 bg-gray-50":a?"border-blue-500 bg-blue-50 shadow-sm ring-2 ring-blue-100":"border-gray-200 bg-white hover:border-gray-300 hover:bg-gray-50 hover:shadow-sm"),children:[e("div",{className:b("flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg text-sm font-bold transition-all",N?n?"bg-green-500 text-white":a?"bg-red-500 text-white":"bg-gray-200 text-gray-600":a?"bg-gradient-to-br from-blue-500 to-indigo-600 text-white shadow-sm":"bg-gray-100 text-gray-600 group-hover:bg-gray-200"),children:o}),"image"===x.optionType?e("div",{className:"flex-1 flex items-center justify-center py-1",children:e(u,{src:t,alt:`Đáp án ${o}`})}):e("span",{className:b("flex-1 text-sm font-medium",N&&n?"text-green-800":N&&a&&!n?"text-red-800":"text-gray-700"),children:t}),N&&(n||a)&&e("div",{className:b("flex h-6 w-6 items-center justify-center rounded-full",n?"bg-green-500":"bg-red-500"),children:e(n?l:i,{className:"h-4 w-4 text-white"})})]},s)})]}),!N&&!T&&r("div",{className:"rounded-lg border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-3 flex items-center gap-2",children:[e("div",{className:"flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full bg-amber-400 text-white",children:e("span",{className:"text-xs font-bold",children:"!"})}),e("span",{className:"text-sm text-amber-800",children:y?"Vui lòng chọn ít nhất một đáp án":"Vui lòng chọn một đáp án"})]})]})]}),N&&x.explanation&&r("div",{className:"overflow-hidden rounded-xl border border-blue-200 bg-gradient-to-br from-blue-50 to-indigo-50 shadow-sm",children:[r("div",{className:"flex items-center gap-2 border-b border-blue-100 bg-white/50 px-4 py-3",children:[e("div",{className:"flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-amber-400 to-orange-500 text-white shadow-sm",children:e(o,{className:"h-4 w-4"})}),e("h4",{className:"text-sm font-semibold text-gray-800",children:"Giải thích"})]}),e("div",{className:"p-4",children:e("p",{className:"text-sm text-gray-700 leading-relaxed",children:x.explanation})})]}),N&&r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center gap-2 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-4 py-3",children:[e("div",{className:"flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-slate-500 to-gray-600 text-white shadow-sm",children:e(c,{className:"h-4 w-4"})}),e("h4",{className:"text-sm font-semibold text-gray-800",children:"Tổng kết"})]}),r("div",{className:"p-4 space-y-3",children:[r("div",{className:"flex items-center justify-between rounded-lg bg-gray-50 p-3",children:[e("span",{className:"text-sm text-gray-600",children:"Đáp án của bạn:"}),e("span",{className:b("text-sm font-semibold",$?"text-green-600":T?"text-red-600":"text-gray-500"),children:q(k)})]}),r("div",{className:"flex items-center justify-between rounded-lg bg-green-50 p-3 border border-green-100",children:[e("span",{className:"text-sm text-gray-600",children:"Đáp án đúng:"}),e("span",{className:"text-sm font-semibold text-green-600",children:q(j)})]}),r("div",{className:b("flex items-center justify-between rounded-lg p-3 border",$?"bg-green-50 border-green-200":"bg-red-50 border-red-200"),children:[e("span",{className:"text-sm text-gray-600",children:"Kết quả:"}),e("div",{className:b("flex items-center gap-1.5 text-sm font-semibold",$?"text-green-600":"text-red-600"),children:r(t,$?{children:[e(l,{className:"h-4 w-4"}),e("span",{children:"Chính xác"})]}:{children:[e(i,{className:"h-4 w-4"}),e("span",{children:"Sai"})]})})]})]})]})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const transformChooseTheCorrectAnswer=e=>{const r=e.answer;if(!r?.options||void 0===r.correctAnswer)return{apiContent:{},apiCorrectAnswer:{}};const t={question:r.question||"",optionType:r.optionType||"text",options:r.options,...r.multipleAnswers?{multipleAnswers:!0}:{}};r.imageUrl&&(t.imageUrl=r.imageUrl),r.askerName&&(t.askerName=r.askerName),r.answererName&&(t.answererName=r.answererName);const o=!!(r.groupTitle||r.groupSubtitle||r.groupContent||r.groupImageUrl||r.articles&&r.articles.length>0)?{title:r.groupTitle||"",subtitle:r.groupSubtitle||"",content:r.groupContent||"",imageUrl:r.groupImageUrl||"",...r.articles?{articles:r.articles}:{}}:void 0;return{apiContent:t,apiCorrectAnswer:{answer:r.correctAnswer,...r.multipleAnswers?{multipleAnswers:!0}:{}},isExample:r.isExample||!1,basicGroupData:o,groupNumber:r.groupNumber||1}};
|
|
1
|
+
export const transformChooseTheCorrectAnswer=e=>{const r=e.answer;if(!r?.options||void 0===r.correctAnswer)return{apiContent:{},apiCorrectAnswer:{}};const t={question:r.question||"",optionType:r.optionType||"text",options:r.options,...r.multipleAnswers?{multipleAnswers:!0}:{}};r.imageUrl&&(t.imageUrl=r.imageUrl),r.askerName&&(t.askerName=r.askerName),r.answererName&&(t.answererName=r.answererName);const o=!!(r.groupTitle||r.groupSubtitle||r.groupContent||r.groupImageUrl||r.articles&&r.articles.length>0)?{title:r.groupTitle||"",subtitle:r.groupSubtitle||"",content:r.groupContent||"",imageUrl:r.groupImageUrl||"",...r.articles?{articles:r.articles}:{}}:void 0,i=(e,r=[])=>{if("number"==typeof e)return r[e]&&"object"==typeof r[e]&&r[e].id?r[e].id:`opt-${e+1}`;if("string"==typeof e){if(e.startsWith("opt-")||isNaN(Number(e)))return e;const t=parseInt(e,10);if(!isNaN(t))return r[t]&&"object"==typeof r[t]&&r[t].id?r[t].id:`opt-${t+1}`}return String(e??"")};return{apiContent:t,apiCorrectAnswer:{answer:((e,r=[])=>Array.isArray(e)?e.map(e=>i(e,r)):i(e,r))(r.correctAnswer,r.options),...r.multipleAnswers?{multipleAnswers:!0}:{}},isExample:r.isExample||!1,basicGroupData:o,groupNumber:r.groupNumber||1}};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WfsfOptionsWordBankEntry, WfsfSharedWordBankEntry } from '../../_shared/types/word-fill-structured-form.type';
|
|
2
|
+
import type { WfsfBankMode } from './wfsf-word-bank.utils';
|
|
3
|
+
export type WfsfWordBankEditorProps = {
|
|
4
|
+
mode: WfsfBankMode;
|
|
5
|
+
onModeChange: (mode: WfsfBankMode) => void;
|
|
6
|
+
sharedBank: WfsfSharedWordBankEntry[];
|
|
7
|
+
onSharedBankChange: (next: WfsfSharedWordBankEntry[]) => void;
|
|
8
|
+
optionsBank: WfsfOptionsWordBankEntry[];
|
|
9
|
+
onOptionsBankChange: (next: WfsfOptionsWordBankEntry[]) => void;
|
|
10
|
+
blankKeys: string[];
|
|
11
|
+
answers: Record<string, string>;
|
|
12
|
+
onAnswerChange: (key: string, value: string) => void;
|
|
13
|
+
};
|
|
14
|
+
export declare function WfsfWordBankEditor({ mode, onModeChange, sharedBank, onSharedBankChange, optionsBank, onOptionsBankChange, blankKeys, answers, onAnswerChange, }: WfsfWordBankEditorProps): import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{CheckCircle2 as r,Library as n,ListChecks as a,Plus as s,Trash2 as l}from"lucide-react";import{Button as i}from"../../../../components/ui/button";import{Card as o,CardContent as d,CardHeader as c,CardTitle as h}from"../../../../components/ui/card";import{Checkbox as m}from"../../../../components/ui/checkbox";import{Input as g}from"../../../../components/ui/input";import{Label as p}from"../../../../components/ui/label";const x=[{id:"FREE_TYPE",label:"Tự gõ",hint:"Không word bank"},{id:"WITH_WORD_BANK",label:"Word Bank chung",hint:"Hộp gợi ý shared"},{id:"WITH_OPTIONS",label:"Options từng ô",hint:"Dropdown theo blank"}];export function WfsfWordBankEditor({mode:b,onModeChange:u,sharedBank:f,onSharedBankChange:N,optionsBank:y,onOptionsBankChange:w,blankKeys:v,answers:k,onAnswerChange:C}){const j=()=>{N([...f,{word:""}])};return t("div",{className:"space-y-4",children:[t(o,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-indigo-100/50",children:[e("div",{className:"h-1 bg-gradient-to-r from-indigo-400 to-purple-400"}),e(c,{className:"px-4 py-3",children:t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-6 w-6 items-center justify-center rounded-md bg-indigo-100",children:e(n,{className:"h-3.5 w-3.5 text-indigo-600"})}),t("div",{children:[e(h,{className:"text-base font-semibold text-gray-800",children:"Word Bank / gợi ý đáp án"}),e("p",{className:"mt-0.5 text-xs text-gray-500",children:"Chọn chế độ hiển thị cho học sinh khi làm bài (WFSF plan 0024/0025)"})]})]})}),e(d,{className:"space-y-3 px-4 pb-4",children:e("div",{className:"grid grid-cols-1 gap-2 sm:grid-cols-3",children:x.map(r=>{const n=b===r.id;return t("button",{type:"button",onClick:()=>u(r.id),className:"rounded-xl border-2 px-3 py-2.5 text-left transition-all "+(n?"border-indigo-400 bg-indigo-50 shadow-sm":"border-gray-200 bg-white hover:border-indigo-200"),children:[e("span",{className:"block text-sm font-semibold "+(n?"text-indigo-800":"text-gray-700"),children:r.label}),e("span",{className:"mt-0.5 block text-[11px] text-gray-500",children:r.hint})]},r.id)})})})]}),"WITH_WORD_BANK"===b&&t(o,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-purple-100/50",children:[e("div",{className:"h-1 bg-gradient-to-r from-purple-400 to-pink-400"}),e(c,{className:"px-4 py-3",children:t("div",{className:"flex items-center justify-between",children:[t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-6 w-6 items-center justify-center rounded-md bg-purple-100",children:e(n,{className:"h-3.5 w-3.5 text-purple-600"})}),t(h,{className:"text-base font-semibold text-gray-800",children:["Word Bank (",f.filter(e=>e.word.trim()).length," từ)"]})]}),t(i,{type:"button",variant:"outline",size:"sm",onClick:j,className:"gap-1.5 border-purple-200 text-purple-600 hover:bg-purple-50",children:[e(s,{className:"h-3.5 w-3.5"}),"Thêm từ"]})]})}),t(d,{className:"space-y-3 px-4 pb-4",children:[t("p",{className:"text-xs text-gray-500",children:["Danh sách gợi ý (đáp án + từ nhiễu). Không bắt buộc khớp 1:1 với số chỗ trống. Đánh dấu ",e("strong",{children:"Example"})," nếu từ là mẫu."]}),0===f.length?t("div",{className:"flex h-24 flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed border-gray-200 bg-gray-50",children:[e("p",{className:"text-sm text-gray-400",children:"Chưa có từ nào"}),t(i,{type:"button",variant:"outline",size:"sm",onClick:j,children:[e(s,{className:"mr-1 h-3.5 w-3.5"}),"Thêm từ"]})]}):e("div",{className:"grid grid-cols-1 gap-3 md:grid-cols-2",children:f.map((r,n)=>t("div",{className:"rounded-lg border p-3 "+(r.isExample?"border-amber-300 bg-amber-50/50":"border-gray-200 bg-gray-50/50"),children:[t("div",{className:"mb-2 flex items-center justify-between",children:[e("span",{className:"flex h-7 w-7 items-center justify-center rounded-lg text-xs font-bold text-white "+(r.isExample?"bg-gradient-to-br from-amber-400 to-orange-500":"bg-gradient-to-br from-purple-500 to-pink-600"),children:n+1}),t("div",{className:"flex items-center gap-2",children:[t("div",{className:"flex items-center gap-1.5",children:[e(m,{id:`wfsf-ex-${n}`,checked:!!r.isExample,onCheckedChange:e=>((e,t)=>{const r=[...f];r[e]={...r[e],isExample:t||void 0},N(r)})(n,!0===e)}),e(p,{htmlFor:`wfsf-ex-${n}`,className:"cursor-pointer text-xs text-gray-600",children:"Example"})]}),e(i,{type:"button",variant:"ghost",size:"sm",onClick:()=>(e=>{N(f.filter((t,r)=>r!==e))})(n),className:"h-7 w-7 p-0 text-gray-400 hover:bg-red-50 hover:text-red-500",children:e(l,{className:"h-3.5 w-3.5"})})]})]}),e(g,{value:r.word,onChange:e=>((e,t)=>{const r=[...f];r[e]={...r[e],word:t},N(r)})(n,e.target.value),placeholder:"Nhập từ...",className:r.isExample?"bg-amber-50":"border-gray-200"})]},n))})]})]}),"WITH_OPTIONS"===b&&t(o,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-teal-100/50",children:[e("div",{className:"h-1 bg-gradient-to-r from-teal-400 to-cyan-400"}),e(c,{className:"px-4 py-3",children:t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-6 w-6 items-center justify-center rounded-md bg-teal-100",children:e(a,{className:"h-3.5 w-3.5 text-teal-600"})}),t(h,{className:"text-base font-semibold text-gray-800",children:["Lựa chọn theo chỗ trống (",v.length,")"]})]})}),e(d,{className:"space-y-4 px-4 pb-4",children:0===v.length?t("p",{className:"rounded-lg border-2 border-dashed border-gray-200 p-6 text-center text-sm text-gray-500",children:["Chưa có chỗ trống. Thêm ","{0}",", ","{1}","… trong nội dung trước."]}):v.map((n,a)=>{const o=y[a]??null,d=null==o,c=k[n]||"";return t("div",{className:"rounded-xl border-2 p-4 "+(d?"border-dashed border-gray-200 bg-gray-50/40":"border-gray-200 bg-white"),children:[t("div",{className:"mb-3 flex flex-wrap items-center justify-between gap-2",children:[t("div",{className:"flex items-center gap-2",children:[e("span",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-teal-500 to-cyan-600 text-sm font-bold text-white",children:n}),t("span",{className:"text-sm font-semibold text-gray-700",children:["Chỗ trống ",e("code",{className:"text-teal-700",children:`{${n}}`})]}),c&&t("span",{className:"inline-flex items-center gap-1 rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-700",children:[e(r,{className:"h-3 w-3"}),c]})]}),t("label",{className:"flex items-center gap-2 text-xs text-gray-600",children:[e(m,{checked:d,onCheckedChange:e=>((e,t)=>{const r=[...y];r[e]=t?null:{options:["",""]},w(r)})(a,!0===e)}),"Free-type (không options)"]})]}),!d&&o&&t("div",{className:"space-y-2",children:[o.options.map((r,s)=>t("div",{className:"flex items-center gap-2",children:[e("button",{type:"button",title:"Chọn làm đáp án đúng",onClick:()=>r.trim()&&C(n,r.trim()),className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-xs font-bold "+(c===r.trim()&&r.trim()?"bg-green-500 text-white":"bg-gray-100 text-gray-500 hover:bg-green-100 hover:text-green-600"),children:String.fromCharCode(65+s)}),e(g,{value:r,onChange:e=>((e,t,r)=>{const n=[...y],a=n[e];if(null==a)return;const s=[...a.options];s[t]=r,n[e]={options:s},w(n)})(a,s,e.target.value),placeholder:`Lựa chọn ${String.fromCharCode(65+s)}`,className:"flex-1 border-gray-200 text-sm"}),o.options.length>2&&e(i,{type:"button",variant:"ghost",size:"sm",onClick:()=>((e,t)=>{const r=[...y],n=r[e];if(null==n||n.options.length<=2)return;const a=n.options.filter((e,r)=>r!==t);r[e]={options:a},w(r);const s=v[e],l=n.options[t];s&&k[s]===l&&C(s,"")})(a,s),className:"h-8 w-8 p-0 text-red-400 hover:bg-red-50 hover:text-red-600",children:e(l,{className:"h-3.5 w-3.5"})})]},s)),t(i,{type:"button",variant:"ghost",size:"sm",onClick:()=>(e=>{const t=[...y],r=t[e];null!=r&&(t[e]={options:[...r.options,""]},w(t))})(a),className:"mt-1 gap-1 text-xs text-teal-600 hover:bg-teal-50",children:[e(s,{className:"h-3 w-3"}),"Thêm lựa chọn"]})]})]},n)})})]})]})}
|
package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { WordFillStructuredFormClientProps } from '../../_shared/types/word-fill-structured-form.type';
|
|
3
|
-
export declare function WordFillStructuredFormClient({ questionData, isReviewMode, userAnswer, onAnswerChange, autoFillCorrectAnswers,
|
|
3
|
+
export declare function WordFillStructuredFormClient({ questionData, isReviewMode, userAnswer, onAnswerChange, autoFillCorrectAnswers, instruction, questionNumber, explanation, }: WordFillStructuredFormClientProps): React.JSX.Element;
|
package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import r,{useState as l,useEffect as n,useMemo as a,useCallback as i}from"react";import{Check as o,X as s}from"lucide-react";import{usePresignedFileUrl as d}from"../../../../shared/lib/hooks";import{cn as c}from"../../../../shared/lib/utils";export function WordFillStructuredFormClient({questionData:p,isReviewMode:m=!1,userAnswer:u,onAnswerChange:g,autoFillCorrectAnswers:b=!1,explanation:f,questionNumber:h}){const{title:x="",imageUrl:w,content:y="",answers:v={},blankStyle:k,caseSensitive:N=!1,wordBank:_}=p,A=function(e){const t=String(e||"").toLowerCase();return"letter"===t||"box"===t?"letter":"phrase"===t||"sentence"===t?"phrase":"word"}(k),C=function(e){if(!Array.isArray(e)||0===e.length)return;const t=e.map(e=>{if(null==e)return null;if("object"!=typeof e||Array.isArray(e))return null;const t=e;if(Array.isArray(t.options)){const e=t.options.map(e=>String(e??"").trim()).filter(e=>e.length>0);return e.length>=2?{options:e}:null}const r=String(t.word??"").trim();return r?t.isExample?{word:r,isExample:!0}:{word:r}:null});return t.some(e=>null!=e)?t:void 0}(_),S=a(()=>function(e){if(!e?.length)return[];const t=[];for(const r of e)if(r&&"word"in r&&"string"==typeof r.word&&r.word){const e="isExample"in r&&Boolean(r.isExample);t.push(e?{word:r.word,isExample:!0}:{word:r.word})}return t}(C),[C]),$=String(p.viewMode||""),B=S.length>0&&("WITH_WORD_BANK"===$||!C?.some(e=>null!=e&&"options"in e&&Array.isArray(e.options))),[E,W]=l(()=>u?{...u}:b?{...v}:{});n(()=>{u&&W({...u})},[u]);const{previewUrl:L,isLoading:j}=d(w||""),T=a(()=>{const e=new Set,t=/\{([\w\d]+)\}/g;let r;for(;null!==(r=t.exec(y));)e.add(r[1]);return Array.from(e).sort((e,t)=>{const r=parseInt(e),l=parseInt(t);return isNaN(r)||isNaN(l)?e.localeCompare(t):r-l})},[y]),F=T.every(e=>E[e]?.trim()),O=m&&T.every(e=>{const t=(E[e]||"").trim(),r=(v[e]||"").trim();return N?t===r:t.toLowerCase()===r.toLowerCase()}),D=String(f||p.explanation||"").trim(),H="number"==typeof h&&h>0?`Bài ${h}`:"",M=i((e,t)=>{m||(W(r=>({...r,[e]:t})),g?.(e,t))},[m,g]),z=i((r,l)=>{const n=E[r]||"",a=v[r]||"",i=N?n.trim():n.trim().toLowerCase(),d=N?a.trim():a.trim().toLowerCase(),p=m&&i===d,u=m&&!!n&&i!==d,g="letter"===A,b="phrase"===A,f=g?1:void 0,h=function(e,t,r){if(!e?.length)return null;const l=Number(t);let n;if(Number.isFinite(l)&&l>=0&&l<e.length)n=e[l];else{const l=r.indexOf(t);l>=0&&l<e.length&&(n=e[l])}return null!=n&&"options"in n&&n.options?.length?n.options:null}(C,r,T),x=Boolean(h&&h.length>=2),w=g?{display:"inline-block",width:"1.625rem",height:"1.625rem",minWidth:"1.625rem",maxWidth:"1.625rem",padding:0,margin:"0 1px",borderWidth:2,borderStyle:"solid",borderColor:m?p?"#10b981":u?"#f43f5e":"#f59e0b":"#94a3b8",borderRadius:4,textAlign:"center",fontSize:"0.8125rem",fontWeight:700,lineHeight:"1.375rem",textTransform:"uppercase",backgroundColor:m?p?"#ecfdf5":u?"#fff1f2":"#fffbeb":"#ffffff",color:m?p?"#065f46":u?"#9f1239":"#92400e":"#1e293b",verticalAlign:"middle",outline:"none",boxSizing:"border-box"}:void 0,y=m?p?"border-emerald-500 bg-emerald-50 text-emerald-800 font-bold":u?"border-rose-500 bg-rose-50 text-rose-800 font-bold":"border-amber-500 bg-amber-50 text-amber-800":"border-slate-400 text-slate-800 focus:border-teal-600";return t("span",{className:c("relative inline-flex items-center",g?"mx-px":"mx-1 align-baseline"),style:g?{display:"inline-flex",verticalAlign:"middle",whiteSpace:"nowrap",flexShrink:0}:void 0,children:[!g&&e("span",{className:"absolute -top-4 left-1 text-[10px] font-semibold text-gray-400",children:r}),x&&h?t("select",{value:n,disabled:m,onChange:e=>M(r,e.target.value),"aria-label":`Blank ${r}`,className:c("inline-block min-w-[7rem] max-w-[14rem] rounded border bg-white px-2 py-1 text-sm font-semibold outline-none transition-all align-baseline",y,!m&&"hover:border-teal-500 focus:border-teal-600 focus:ring-1 focus:ring-teal-200"),children:[e("option",{value:"",children:"—"}),h.map(t=>e("option",{value:t,children:t},t))]}):e("input",{type:"text",value:n,onChange:e=>{const t=e.target.value,l=g?t.slice(-1).replace(/\s/g,""):t;M(r,l)},disabled:m,placeholder:"",maxLength:f,inputMode:g?"text":void 0,autoComplete:"off",spellCheck:!1,"aria-label":`Blank ${r}`,style:w,className:c(!g&&"inline-block bg-slate-50/40 text-center text-sm font-semibold outline-none transition-all align-baseline hover:bg-slate-100/60 focus:bg-teal-50/60 focus:ring-0",!g&&(b?"min-w-[140px] max-w-[280px] rounded-t border-b-2 px-2 py-0.5":"min-w-[90px] max-w-[160px] rounded-t border-b-2 px-2 py-0.5"),!g&&y)}),m&&n&&(p?e(o,{className:"ml-0.5 h-3.5 w-3.5 shrink-0 text-green-600"}):e(s,{className:"ml-0.5 h-3.5 w-3.5 shrink-0 text-red-600"}))]},l)},[v,A,N,T,E,M,m,C]),I=a(()=>{if("undefined"==typeof window)return y;const t=(new DOMParser).parseFromString(y||"<p></p>","text/html"),l=/\{([\w\d]+)\}/g,n="letter"===A,a=(t,i)=>{if(t.nodeType===Node.TEXT_NODE)return((t,a)=>{if(!t)return null;const i=[];let o,s=0;for(l.lastIndex=0;null!==(o=l.exec(t));)o.index>s&&i.push({kind:"text",value:t.slice(s,o.index)}),i.push({kind:"blank",key:o[1],index:o.index}),s=o.index+o[0].length;if(s<t.length&&i.push({kind:"text",value:t.slice(s)}),!i.length)return null;if(!n){const t=i.map((e,t)=>"text"===e.kind?e.value:z(e.key,`${a}-blank-${e.index}-${t}`));return 1===t.length?t[0]:e(r.Fragment,{children:t},a)}const d=[];let c=[],p=0;const m=()=>{c.length&&(d.push(e("span",{style:{display:"inline",whiteSpace:"nowrap",verticalAlign:"baseline"},children:c},`${a}-w${p}`)),p+=1,c=[])};for(let e=0;e<i.length;e+=1){const t=i[e];if("blank"===t.kind){c.push(z(t.key,`${a}-blank-${t.index}-${e}`));continue}const r=t.value.split(/(\s+)/);for(let e=0;e<r.length;e+=1){const t=r[e];t&&(/^\s+$/.test(t)?(m(),d.push(t)):c.push(t))}}return m(),d.length?1===d.length?d[0]:e(r.Fragment,{children:d},a):null})(t.textContent||"",i);if(t.nodeType!==Node.ELEMENT_NODE)return null;const o=t,s=o.tagName.toLowerCase(),d={key:i};let c="",p={};Array.from(o.attributes).forEach(e=>{var t;if("class"!==e.name)return"style"===e.name?(t=e.value,void(p=t.split(";").map(e=>e.trim()).filter(Boolean).reduce((e,t)=>{const[r,l]=t.split(":").map(e=>e.trim());return r&&l?(e[r.replace(/-([a-z])/g,(e,t)=>t.toUpperCase())]=l,e):e},{}))):void(d[e.name]=e.value);c=e.value});const m=c.split(/\s+/).filter(Boolean);m.includes("wfsf-block")&&(p={display:"block",margin:"0 0 1.25rem 0",padding:"0.35rem 0 1rem 0",borderBottom:"1px solid #e2e8f0",...p}),m.includes("wfsf-item-no")&&(p={fontWeight:700,fontSize:"1rem",lineHeight:1.4,margin:"0 0 0.4rem 0",color:"#0f172a",...p}),"table"===s&&m.includes("dialogue")&&(p={width:"100%",borderCollapse:"collapse",tableLayout:"auto",...p}),"td"===s&&m.includes("speaker")?p={width:"1%",whiteSpace:"nowrap",verticalAlign:"top",paddingRight:"12px",paddingTop:"6px",paddingBottom:"6px",fontWeight:600,color:"#0f172a",...p}:"td"===s&&!m.includes("speaker")&&o.closest?.("table.dialogue")&&(p={verticalAlign:"top",paddingTop:"6px",paddingBottom:"6px",width:"auto",...p}),c&&(d.className=c),Object.keys(p).length>0&&(d.style=p);const u=Array.from(o.childNodes).map((e,t)=>a(e,`${i}-${t}`)).filter(e=>null!==e);return r.createElement(s,d,...u)};return Array.from(t.body.childNodes).map((e,t)=>a(e,`root-${t}`)).filter(e=>null!==e)},[A,y,z]);return e("div",{className:"space-y-4",children:t("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[(H||D||m&&F)&&e("div",{className:"border-b border-gray-100 bg-white px-5 py-4",children:t("div",{className:"flex items-start justify-between gap-3",children:[t("div",{className:"min-w-0 space-y-1.5",children:[H?e("h2",{className:"text-lg font-bold tracking-tight text-slate-900",children:H}):null,D?e("p",{className:"text-sm leading-relaxed whitespace-pre-line text-slate-700",children:D}):null]}),m&&F?t("div",{className:c("flex shrink-0 items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold",O?"bg-green-100 text-green-700":"bg-red-100 text-red-700"),children:[e(O?o:s,{className:"h-3.5 w-3.5"}),O?"Đúng":"Sai"]}):null]})}),t("div",{className:"space-y-5 p-5",children:[x?e("h3",{className:"text-center text-base font-semibold text-gray-900",children:x}):null,(L||w)&&e("div",{className:"flex justify-center",children:e("div",{className:"overflow-hidden rounded-lg border border-gray-200 bg-gray-50",children:j?e("div",{className:"flex h-48 w-48 items-center justify-center",children:e("div",{className:"h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-teal-500"})}):e("img",{src:L||w,alt:x||H||"Hình minh họa",className:"max-h-56 w-auto object-contain p-2"})})}),B?t("div",{className:"word-bank-shared space-y-2",children:[e("span",{className:"text-xs font-medium uppercase tracking-wider text-gray-500",children:"Word Bank"}),e("div",{className:"flex flex-wrap gap-2",children:S.map((t,r)=>e("span",{className:c("rounded-lg border-2 px-3 py-1.5 text-sm font-semibold",t.isExample?"border-amber-300 bg-amber-50 text-amber-800":"border-sky-200 bg-sky-50 text-sky-900"),children:t.word},`wb-${r}-${t.word}`))})]}):null,e("div",{className:c("structured-form-content space-y-2 rounded-lg border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-5 text-base leading-relaxed text-gray-800","[&_table.dialogue]:w-full [&_table.dialogue]:border-collapse [&_table.dialogue]:table-fixed","[&_table.dialogue_td.speaker]:w-[1%] [&_table.dialogue_td.speaker]:whitespace-nowrap","[&_table.dialogue_td.speaker]:align-top [&_table.dialogue_td.speaker]:pr-3","[&_table.dialogue_td.speaker]:font-semibold [&_table.dialogue_td.speaker]:text-slate-900","[&_table.dialogue_td]:align-top [&_table.dialogue_td]:py-1.5 [&_table.dialogue_td]:leading-relaxed","[&_table.dialogue_td:not(.speaker)]:w-auto","[&_table:not(.dialogue)]:w-full [&_table:not(.dialogue)]:border-collapse"),style:"letter"===A?{wordBreak:"normal",overflowWrap:"break-word",lineHeight:1.7}:void 0,children:I}),m&&!O&&t("div",{className:"rounded-lg border border-green-200 bg-green-50 p-3",children:[e("span",{className:"text-xs font-medium uppercase tracking-wider text-green-600",children:"Đáp án đúng"}),e("div",{className:"mt-2 flex flex-wrap gap-2",children:T.map(e=>t("span",{className:"rounded-lg border border-green-300 bg-green-100 px-3 py-1.5 text-sm font-semibold text-green-800",children:[`{${e}}`,": ",v[e]]},e))})]})]})]})})}
|
|
1
|
+
"use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import t,{useState as a,useEffect as l,useMemo as n,useCallback as s}from"react";import{Check as o,X as i,FileText as d,Library as m}from"lucide-react";import{usePresignedFileUrl as c}from"../../../../shared/lib/hooks";import{cn as b}from"../../../../shared/lib/utils";import{detectWfsfBankMode as p,isOptionsWordEntry as u,normalizeSharedWordBank as g}from"./wfsf-word-bank.utils";export function WordFillStructuredFormClient({questionData:x,isReviewMode:h=!1,userAnswer:f,onAnswerChange:w,autoFillCorrectAnswers:N=!1,instruction:y,questionNumber:v,explanation:k}){const{title:C="",imageUrl:S,content:E="",answers:A={},caseSensitive:T=!1,viewMode:j,wordBank:O=[],instruction:I}=x,[L,$]=a(()=>f?{...f}:N?{...A}:{}),[W,_]=a(null);l(()=>{f&&$({...f})},[f]);const B=n(()=>p(j,O),[j,O]),D=n(()=>"WITH_WORD_BANK"===B?g(O):[],[B,O]),F=n(()=>{const e=new Set;return Object.values(L).forEach(r=>{const t=String(r||"").trim().toLowerCase();t&&e.add(t)}),e},[L]),M=n(()=>{const e=new Map;return"WITH_OPTIONS"===B&&Array.isArray(O)?(O.forEach((r,t)=>{u(r)&&e.set(String(t),r.options.map(e=>String(e??"")))}),e):e},[B,O]),{previewUrl:H,isLoading:P}=c(S||""),R=n(()=>{const e=new Set,r=/\{([\w\d]+)\}/g;let t;for(;null!==(t=r.exec(E));)e.add(t[1]);return Array.from(e).sort((e,r)=>{const t=parseInt(e),a=parseInt(r);return isNaN(t)||isNaN(a)?e.localeCompare(r):t-a})},[E]),U=R.every(e=>L[e]?.trim()),q=h&&R.every(e=>{const r=(L[e]||"").trim(),t=(A[e]||"").trim();return T?r===t:r.toLowerCase()===t.toLowerCase()}),z=String(k||x.explanation||"").trim(),K=String(y||I||z||"").trim()||"Điền từ vào biểu mẫu có cấu trúc",G=z&&z!==K?z:"",X=s((e,r)=>{h||($(t=>({...t,[e]:r})),w?.(e,r))},[h,w]),J=s((e,r)=>{h||($(t=>({...t,[e]:r})),w?.(e,r),_(null))},[h,w]),Q=s((t,a)=>{const l=L[t]||"",n=A[t]||"",s=T?l.trim():l.trim().toLowerCase(),d=T?n.trim():n.trim().toLowerCase(),m=h&&s===d,c=h&&!!l&&s!==d,p=M.get(t);if("WITH_OPTIONS"===B&&p&&p.length>=2){const n=W===t;return r("span",{className:"relative mx-1 inline-flex flex-col items-center align-baseline",children:[r("button",{type:"button",onClick:()=>!h&&_(n?null:t),disabled:h,className:b("inline-flex min-w-[90px] items-center justify-center rounded border-2 border-dashed px-2 py-0.5 text-center text-sm font-semibold transition-all",h?m?"border-emerald-500 bg-emerald-50 text-emerald-800":c?"border-rose-500 bg-rose-50 text-rose-800":"border-amber-500 bg-amber-50 text-amber-800":"border-teal-400 bg-teal-50/50 text-teal-800 hover:bg-teal-50"),children:[l||`{${t}}`,h&&l&&(m?e(o,{className:"ml-0.5 h-3.5 w-3.5 text-green-600"}):e(i,{className:"ml-0.5 h-3.5 w-3.5 text-red-600"}))]}),n&&!h&&e("div",{className:"absolute left-1/2 top-full z-10 mt-1 flex -translate-x-1/2 flex-wrap gap-1 rounded-lg border border-teal-200 bg-white p-1.5 shadow-lg",children:p.map(r=>e("button",{type:"button",onClick:()=>J(t,r),className:b("rounded-md border px-2 py-1 text-xs font-medium transition-colors",l===r?"border-teal-500 bg-teal-100 text-teal-800":"border-gray-200 bg-white text-gray-700 hover:border-teal-300 hover:bg-teal-50"),children:r},r))})]},a)}return r("span",{className:"relative mx-1 inline-flex items-baseline align-baseline",children:[e("span",{className:"absolute -top-4 left-1 text-[10px] font-semibold text-gray-400",children:t}),e("input",{type:"text",value:l,onChange:e=>X(t,e.target.value),disabled:h,placeholder:"",className:b("inline-block min-w-[90px] max-w-[200px] rounded-t border-b-2 bg-slate-50/40 px-2 py-0.5 text-center text-sm font-semibold outline-none transition-all align-baseline hover:bg-slate-100/60 focus:bg-teal-50/60 focus:ring-0",h?m?"border-emerald-500 bg-emerald-50 text-emerald-800 font-bold":c?"border-rose-500 bg-rose-50 text-rose-800 font-bold":"border-amber-500 bg-amber-50 text-amber-800":"border-slate-400 text-slate-800 focus:border-teal-600")}),h&&l&&(m?e(o,{className:"ml-0.5 h-3.5 w-3.5 text-green-600"}):e(i,{className:"ml-0.5 h-3.5 w-3.5 text-red-600"}))]},a)},[A,B,T,W,L,X,J,h,M]),V=n(()=>{if("undefined"==typeof window)return E;const r=(new DOMParser).parseFromString(E||"<p></p>","text/html"),a=/\{([\w\d]+)\}/g,l=(r,n)=>{if(r.nodeType===Node.TEXT_NODE){const l=r.textContent||"",s=[];let o,i=0;for(a.lastIndex=0;null!==(o=a.exec(l));)o.index>i&&s.push(l.slice(i,o.index)),s.push(Q(o[1],`${n}-blank-${o.index}`)),i=o.index+o[0].length;return i<l.length&&s.push(l.slice(i)),0===s.length?null:1===s.length?s[0]:e(t.Fragment,{children:s},n)}if(r.nodeType!==Node.ELEMENT_NODE)return null;const s=r,o=s.tagName.toLowerCase(),i={key:n};Array.from(s.attributes).forEach(e=>{"class"!==e.name?"style"!==e.name?i[e.name]=e.value:i.style=e.value.split(";").map(e=>e.trim()).filter(Boolean).reduce((e,r)=>{const[t,a]=r.split(":").map(e=>e.trim());return t&&a?(e[t.replace(/-([a-z])/g,(e,r)=>r.toUpperCase())]=a,e):e},{}):i.className=e.value});const d=Array.from(s.childNodes).map((e,r)=>l(e,`${n}-${r}`)).filter(e=>null!==e);return t.createElement(o,i,...d)};return Array.from(r.body.childNodes).map((e,r)=>l(e,`root-${r}`)).filter(e=>null!==e)},[E,Q]);return e("div",{className:"space-y-4",children:r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center justify-between gap-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-5 py-3",children:[r("div",{className:"flex min-w-0 items-start gap-3",children:[e("div",{className:"mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-teal-500 to-cyan-600 text-white shadow-sm",children:e(d,{className:"h-4 w-4"})}),r("div",{className:"min-w-0",children:["number"==typeof v&&v>0?r("p",{className:"text-[11px] font-semibold uppercase tracking-wider text-teal-700",children:["Bài ",v]}):null,e("span",{className:"block text-sm font-medium leading-snug text-gray-800",children:K})]})]}),h&&U&&r("div",{className:b("flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold",q?"bg-green-100 text-green-700":"bg-red-100 text-red-700"),children:[e(q?o:i,{className:"h-3.5 w-3.5"}),q?"Đúng":"Sai"]})]}),r("div",{className:"space-y-5 p-5",children:[C&&e("h2",{className:"text-center text-xl font-bold text-gray-900",children:C}),(H||S)&&e("div",{className:"flex justify-center",children:e("div",{className:"overflow-hidden rounded-lg border border-gray-200 bg-gray-50",children:P?e("div",{className:"flex h-48 w-48 items-center justify-center",children:e("div",{className:"h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-teal-500"})}):e("img",{src:H||S,alt:C,className:"max-h-56 w-auto object-contain p-2"})})}),"WITH_WORD_BANK"===B&&D.length>0&&r("div",{className:"rounded-lg border border-purple-200 bg-gradient-to-r from-purple-50 to-pink-50 p-3",children:[r("div",{className:"mb-2 flex items-center gap-2",children:[e(m,{className:"h-4 w-4 text-purple-600"}),e("span",{className:"text-xs font-semibold uppercase tracking-wider text-purple-700",children:"Word Bank"})]}),e("div",{className:"flex flex-wrap gap-2",children:D.map((e,t)=>{const a=F.has(e.word.trim().toLowerCase());return r("span",{className:b("rounded-full border px-3 py-1 text-sm font-medium",e.isExample?"border-amber-300 bg-amber-100 text-amber-800":a?"border-purple-200 bg-white/60 text-purple-400 line-through":"border-purple-300 bg-white text-purple-800"),children:[e.word,e.isExample?" (ex)":""]},`${e.word}-${t}`)})})]}),e("div",{className:"structured-form-content space-y-2 rounded-lg border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-5 text-base leading-loose text-gray-800",children:V}),h&&!q&&r("div",{className:"rounded-lg border border-green-200 bg-green-50 p-3",children:[e("span",{className:"text-xs font-medium uppercase tracking-wider text-green-600",children:"Đáp án đúng"}),e("div",{className:"mt-2 flex flex-wrap gap-2",children:R.map(e=>r("span",{className:"rounded-lg border border-green-300 bg-green-100 px-3 py-1.5 text-sm font-semibold text-green-800",children:[`{${e}}`,": ",A[e]]},e))})]}),h&&G&&r("div",{className:"rounded-lg border border-blue-200 bg-gradient-to-r from-blue-50 to-indigo-50 p-3",children:[e("span",{className:"text-xs font-medium uppercase tracking-wider text-blue-600",children:"Giải thích"}),e("p",{className:"mt-1 text-sm text-blue-800",children:G})]})]})]})})}
|
package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { WordFillStructuredFormCreatorProps } from '../../_shared/types/word-fill-structured-form.type';
|
|
2
|
-
export declare function WordFillStructuredFormCreator({ initialData, onSave, onCancel, onChange, onUnsavedChangesChange: _onUnsavedChangesChange, validationRef, externalErrors, groupConfig, groupType, groups, questionIndexInPart, partId, }: WordFillStructuredFormCreatorProps): import("react").JSX.Element;
|
|
2
|
+
export declare function WordFillStructuredFormCreator({ initialData, onSave, onCancel, onChange, onUnsavedChangesChange: _onUnsavedChangesChange, validationRef, externalErrors, groupConfig, groupType, groups, questionIndexInPart, partId, viewMode: viewModeProp, }: WordFillStructuredFormCreatorProps): import("react").JSX.Element;
|
package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as n,useEffect as r,useRef as a,useMemo as i,useCallback as l}from"react";import{useEditor as s,EditorContent as c}from"@tiptap/react";import o from"@tiptap/starter-kit";import d from"@tiptap/extension-text-align";import{Table as m,TableRow as h,TableCell as g,TableHeader as u}from"@tiptap/extension-table";import{List as p,ListOrdered as x,Bold as b,Italic as f,AlignLeft as N,AlignCenter as v,AlignRight as w,TableIcon as y,Plus as C,Minus as k,Trash2 as S,BookOpen as A,Eye as I,Pencil as U,CheckCircle2 as T,PenLine as j,Info as G,MessageSquare as H,ImageIcon as B}from"lucide-react";import{Button as D}from"../../../../components/ui/button";import{Label as R}from"../../../../components/ui/label";import{Input as O}from"../../../../components/ui/input";import{Textarea as P}from"../../../../components/ui/textarea";import{Switch as F}from"../../../../components/ui/switch";import{PointsInput as L}from"../../../../components/ui/points-input";import{Card as E,CardContent as z,CardHeader as J,CardTitle as $}from"../../../../components/ui/card";import{FileUpload as q}from"../../../../components/ui/file-upload";import{ImagePreview as X}from"../../../../components/ui/image-preview";import{WordFillStructuredFormClient as M}from"./WordFillStructuredFormClient";import{useDebouncedCallback as Q,usePresignedFileUrl as V}from"../../../../shared/lib/hooks";import{BasicQuestionGroupCard as K}from"../../groups/BasicQuestionGroupCard";import{DocumentGroupCard as W}from"../../groups/DocumentGroupCard";import{useBasicQuestionGroup as _,getGroupNumberForIndex as Y}from"../../_shared/hooks/useBasicQuestionGroup";const Z=({onClick:t,active:n,disabled:r,title:a,children:i,className:l=""})=>e("button",{type:"button",onClick:t,disabled:r,title:a,className:`inline-flex h-7 min-w-7 items-center justify-center rounded px-1.5 text-sm transition-colors disabled:opacity-30\n ${n?"bg-teal-100 text-teal-700":"text-gray-500 hover:bg-gray-100 hover:text-gray-800"}\n ${l}`,children:i}),ee=()=>e("div",{className:"mx-1 h-4 w-px bg-gray-200"}),te=({editor:n})=>n?t("div",{className:"flex flex-wrap items-center gap-0.5 border-b border-gray-100 bg-gray-50/70 px-2 py-1.5 rounded-t-lg",children:[e(Z,{onClick:()=>n.chain().focus().toggleBold().run(),active:n.isActive("bold"),title:"Đậm",children:e(b,{className:"h-3.5 w-3.5"})}),e(Z,{onClick:()=>n.chain().focus().toggleItalic().run(),active:n.isActive("italic"),title:"Nghiêng",children:e(f,{className:"h-3.5 w-3.5"})}),e(ee,{}),e(Z,{onClick:()=>n.chain().focus().toggleHeading({level:2}).run(),active:n.isActive("heading",{level:2}),className:"px-2 text-xs font-bold",children:"H2"}),e(Z,{onClick:()=>n.chain().focus().toggleHeading({level:3}).run(),active:n.isActive("heading",{level:3}),className:"px-2 text-xs font-bold",children:"H3"}),e(Z,{onClick:()=>n.chain().focus().toggleHeading({level:4}).run(),active:n.isActive("heading",{level:4}),className:"px-2 text-xs font-bold",children:"H4"}),e(ee,{}),e(Z,{onClick:()=>n.chain().focus().toggleBulletList().run(),active:n.isActive("bulletList"),title:"Danh sách",children:e(p,{className:"h-3.5 w-3.5"})}),e(Z,{onClick:()=>n.chain().focus().toggleOrderedList().run(),active:n.isActive("orderedList"),title:"Danh sách có số",children:e(x,{className:"h-3.5 w-3.5"})}),e(ee,{}),e(Z,{onClick:()=>n.chain().focus().setTextAlign("left").run(),active:n.isActive({textAlign:"left"}),title:"Trái",children:e(N,{className:"h-3.5 w-3.5"})}),e(Z,{onClick:()=>n.chain().focus().setTextAlign("center").run(),active:n.isActive({textAlign:"center"}),title:"Giữa",children:e(v,{className:"h-3.5 w-3.5"})}),e(Z,{onClick:()=>n.chain().focus().setTextAlign("right").run(),active:n.isActive({textAlign:"right"}),title:"Phải",children:e(w,{className:"h-3.5 w-3.5"})}),e(ee,{}),t(Z,{onClick:()=>n.chain().focus().insertTable({rows:5,cols:2,withHeaderRow:!1}).run(),title:"Chèn bảng 2 cột × 5 hàng",className:"gap-1 px-2 text-xs",children:[e(y,{className:"h-3.5 w-3.5"}),e("span",{className:"hidden sm:inline",children:"Bảng 2 cột"})]}),t(Z,{onClick:()=>n.chain().focus().addRowAfter().run(),disabled:!n.can().addRowAfter(),title:"Thêm hàng",className:"gap-1 px-2 text-xs",children:[e(C,{className:"h-3 w-3"}),e("span",{className:"hidden sm:inline",children:"Hàng"})]}),t(Z,{onClick:()=>n.chain().focus().deleteRow().run(),disabled:!n.can().deleteRow(),title:"Xóa hàng",className:"gap-1 px-2 text-xs",children:[e(k,{className:"h-3 w-3"}),e("span",{className:"hidden sm:inline",children:"Hàng"})]}),t(Z,{onClick:()=>n.chain().focus().deleteTable().run(),disabled:!n.can().deleteTable(),title:"Xóa bảng",className:"gap-1 px-2 text-xs text-red-400 hover:text-red-600",children:[e(S,{className:"h-3 w-3"}),e("span",{className:"hidden sm:inline",children:"Bảng"})]})]}):null;export function WordFillStructuredFormCreator({initialData:p,onSave:b,onCancel:f,onChange:N,onUnsavedChangesChange:v,validationRef:w,externalErrors:y,groupConfig:C,groupType:k,groups:S,questionIndexInPart:Z=0,partId:ee=""}){const[ne,re]=n(!1),[ae,ie]=n(p?.points??1),[le,se]=n(p?.caseSensitive??!1),[ce,oe]=n(p?.explanation||""),[de,me]=n(""),{isGrouped:he,isFirstInGroup:ge,currentGroupNumber:ue,groupTitle:pe,groupSubtitle:xe,groupContent:be,imageUrl:fe,setGroupTitle:Ne,setGroupSubtitle:ve,setGroupContent:we,setImageUrl:ye}=_({partId:ee,groups:S,questionIndexInPart:Z,initialData:{title:p?.groupTitle||"",subtitle:p?.groupSubtitle||"",content:p?.groupContent||"",imageUrl:p?.groupImageUrl||""}}),Ce=(k||"BASIC").toUpperCase(),ke=!(C&&C.length>0)||C.includes("content"),Se=ue||Y(Z,S),[Ae,Ie]=n(p?.title||""),[Ue,Te]=n(p?.imageUrl||""),je=Ae,Ge=Ue,He=Ie,Be=Te,{previewUrl:De}=V(Ge),Re=de||De||"",Oe=p?.content||"<p></p>",[Pe,Fe]=n(Oe),[Le,Ee]=n(p?.answers||{}),ze=a(""),Je=a(p),$e=a(!1),qe=a(Pe),Xe=a(N);r(()=>{Xe.current=N},[N]);const Me=i(()=>[o.configure({heading:{levels:[2,3,4]}}),d.configure({types:["heading","paragraph"]}),m.configure({resizable:!0}),h,g,u],[]),Qe=i(()=>({attributes:{class:"tiptap-editor prose prose-sm max-w-none p-4 focus:outline-none min-h-[400px]"}}),[]),Ve=l(({editor:e})=>{const t=e.getHTML();t!==qe.current&&(qe.current=t,Fe(t))},[]),Ke=s({immediatelyRender:!1,extensions:Me,content:Pe,editorProps:Qe,onUpdate:Ve});r(()=>{qe.current=Pe},[Pe]),r(()=>{if(!(JSON.stringify(Je.current)!==JSON.stringify(p)))return;if(Je.current=p,!p?.content||"<p></p>"===p.content)return;$e.current=!0,Ie(p?.title||""),Te(p?.imageUrl||""),ie(p?.points??1),se(p?.caseSensitive??!1),oe(p?.explanation||""),Ee(p?.answers||{});const e=p.content;e!==qe.current&&(qe.current=e,Fe(e),Ke&&!Ke.isDestroyed&&Ke.commands.setContent(e)),setTimeout(()=>{$e.current=!1},150)},[p,Ke]);const We=Q(e=>{Xe.current?.(e)},300),_e=JSON.stringify(Le),Ye=i(()=>{const e=new Set,t=/\{([\w\d]+)\}/g;let n;for(;null!==(n=t.exec(Pe));)e.add(n[1]);return Array.from(e).sort((e,t)=>{const n=parseInt(e),r=parseInt(t);return isNaN(n)||isNaN(r)?e.localeCompare(t):n-r})},[Pe]);return r(()=>{Ee(e=>{let t=!1;const n={...e};return Object.keys(n).forEach(e=>{Ye.includes(e)||(delete n[e],t=!0)}),Ye.forEach(e=>{e in n||(n[e]="",t=!0)}),t?n:e})},[Ye]),r(()=>{const e={title:je,imageUrl:Ge,content:Pe,answers:Le,points:ae,caseSensitive:le,explanation:ce,groupTitle:pe,groupSubtitle:xe,groupContent:be,groupImageUrl:fe,groupNumber:Se};if($e.current)return void(ze.current=JSON.stringify(e));const t=JSON.stringify(e);t!==ze.current&&(ze.current=t,We(e))},[je,Ge,Pe,_e,ae,le,ce,pe,xe,be,fe,Se]),r(()=>{w&&(w.current={triggerValidation:async()=>{if(!Pe||"<p></p>"===Pe)return!1;if(0===Ye.length)return!1;for(const e of Ye)if(!Le[e]||""===Le[e].trim())return!1;return!0},getFormData:()=>({title:je,imageUrl:Ge,content:Pe,answers:Le,points:ae,caseSensitive:le,explanation:ce,groupTitle:pe,groupSubtitle:xe,groupContent:be,groupImageUrl:fe,groupNumber:Se})})},[w,je,Ge,Pe,Le,ae,le,ce,Ye,pe,xe,be,fe,Se]),t("div",ne?{className:"space-y-4",children:[e(E,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-teal-100/50",children:e(J,{className:"px-4 py-3",children:t("div",{className:"flex items-center justify-between",children:[t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-teal-500 to-cyan-600 shadow-sm",children:e(I,{className:"h-4 w-4 text-white"})}),t("div",{children:[e($,{className:"text-base font-bold text-gray-900",children:"Điền từ – Xem trước"}),e("p",{className:"text-xs text-gray-500",children:"Chế độ xem trước với đáp án đúng đã được điền sẵn"})]})]}),t(D,{variant:"outline",size:"sm",onClick:()=>re(!1),className:"gap-2 border-teal-200 text-teal-700 hover:bg-teal-50",children:[e(U,{className:"h-4 w-4"}),"Quay lại Edit"]})]})})}),e(M,{questionData:{title:je,imageUrl:Ge,content:Pe,answers:Le,points:ae,caseSensitive:le},isReviewMode:!0,userAnswer:Le})]}:{className:"space-y-4",children:[he&&"BASIC"===Ce&&e(K,{groupNumber:Se,title:pe,subtitle:xe,content:be,imageUrl:fe,onTitleChange:Ne,onSubtitleChange:ve,onContentChange:we,onImageChange:ye,groupConfig:k?C:void 0,isReadOnly:!ge,uploadIdPrefix:`word-fill-structured-${ee??"group"}`}),he&&"DOCUMENT"===Ce&&e(W,{groupNumber:Se,title:pe,subtitle:xe,content:be,imageUrl:fe,onTitleChange:Ne,onSubtitleChange:ve,onContentChange:we,onImageChange:ye,groupConfig:k?C:void 0,isReadOnly:!ge,uploadIdPrefix:`word-fill-structured-${ee??"document"}`}),t(E,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-teal-100/50",children:[e("div",{className:"h-1 bg-gradient-to-r from-teal-500 via-cyan-500 to-emerald-500"}),e(J,{className:"px-4 py-3",children:t("div",{className:"flex items-center justify-between",children:[t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gray-100",children:e(j,{className:"h-4 w-4 text-teal-600"})}),t("div",{children:[e($,{className:"text-base font-bold text-gray-900",children:"Điền từ vào biểu mẫu có cấu trúc"}),t("p",{className:"text-xs text-gray-500",children:["Nhập nội dung, đặt chỗ trống bằng ","{0}"," ","{1}","… rồi điền đáp án bên dưới"]})]})]}),t(D,{variant:"outline",size:"sm",onClick:()=>re(!0),disabled:0===Ye.length||Ye.some(e=>!Le[e]?.trim()),className:"gap-2 border-teal-200 text-teal-600 hover:bg-teal-50 hover:text-teal-700",children:[e(I,{className:"h-4 w-4"}),"Xem trước"]})]})}),t(z,{className:"space-y-4 px-4 pb-4",children:[t("div",{className:"flex flex-wrap items-center gap-3",children:[e(L,{value:ae,onChange:e=>ie(Number(e.target.value)||1)}),t("div",{role:"button",tabIndex:0,onClick:()=>se(!le),onKeyDown:e=>{" "!==e.key&&"Enter"!==e.key||se(!le)},style:{paddingBlock:"calc(var(--spacing) * 1)"},className:"inline-flex cursor-pointer items-center gap-2 rounded-md border px-3.5 text-sm font-medium transition-colors select-none "+(le?"border-teal-300 bg-teal-50 text-teal-700":"border-gray-200 bg-white text-gray-400 hover:text-gray-600"),children:[e(F,{checked:le,onCheckedChange:se,className:le?"data-[state=checked]:bg-teal-500 pointer-events-none":"pointer-events-none",tabIndex:-1}),"Phân biệt Hoa / thường"]})]}),t("div",{className:"space-y-2",children:[t(R,{htmlFor:"wfsf-title",className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(H,{className:"h-4 w-4 text-teal-500"}),"Tiêu đề",e("span",{className:"text-sm font-normal text-gray-500",children:"(tuỳ chọn)"})]}),e(O,{id:"wfsf-title",value:je,onChange:e=>He(e.target.value),placeholder:"Nhập tiêu đề câu hỏi...",className:"border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-100"})]}),t("div",{className:"space-y-2",children:[t(R,{className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(B,{className:"h-4 w-4 text-teal-500"}),"Hình ảnh",e("span",{className:"text-sm font-normal text-gray-500",children:"(tuỳ chọn)"})]}),e(q,{id:"wfsf-image",label:"",accept:"image/*",value:Ge||"",onChange:e=>Be(e),onPresignedUrlChange:me,maxSize:5,placeholder:"Upload ảnh hoặc paste URL",autoUpload:!0,prefix:"questions"}),Re&&e(X,{src:Re,alt:"Preview",className:"mt-2 h-48 w-full max-w-md rounded-lg border border-gray-200"})]}),y&&y.length>0&&t("div",{className:"flex items-start gap-3 rounded-xl border border-red-200 bg-gradient-to-r from-red-50 to-rose-50 p-4",children:[e("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-red-100",children:e("span",{className:"text-lg",children:"❌"})}),t("div",{className:"text-sm",children:[e("p",{className:"font-semibold text-red-800",children:"Lỗi:"}),e("ul",{className:"mt-1 list-inside list-disc text-red-700",children:y.map((t,n)=>e("li",{children:t},n))})]})]})]})]}),ke&&t(E,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-teal-100/50",children:[e(J,{className:"px-4 py-3",children:t("div",{className:"flex items-center justify-between",children:[t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-6 w-6 items-center justify-center rounded-md bg-teal-100",children:e(x,{className:"h-3.5 w-3.5 text-teal-600"})}),e($,{className:"text-base font-semibold text-gray-800",children:"Nội dung cấu trúc"})]}),Ye.length>0&&t("span",{className:"inline-flex items-center rounded-full border border-teal-200 bg-teal-50 px-2.5 py-0.5 text-xs font-semibold text-teal-700",children:[Ye.length," chỗ trống"]})]})}),t(z,{className:"space-y-3 px-4 pb-4",children:[t("div",{className:"overflow-hidden rounded-xl border border-gray-200 transition-all focus-within:border-teal-300 focus-within:ring-2 focus-within:ring-teal-100",children:[e(te,{editor:Ke}),e(c,{editor:Ke})]}),t("div",{className:"flex items-start gap-2 rounded-lg border border-teal-100 bg-teal-50/60 px-3 py-2.5",children:[e(G,{className:"mt-0.5 h-4 w-4 shrink-0 text-teal-500"}),t("p",{className:"text-xs text-teal-700",children:["Nhập ",e("strong",{children:"{0}"}),", ",e("strong",{children:"{1}"}),", ",e("strong",{children:"{2}"}),"… vào văn bản để tạo ô trống. Đáp án sẽ tự động xuất hiện bên dưới để bạn nhập."]})]})]})]}),Ye.length>0&&t(E,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-teal-100/50",children:[e(J,{className:"px-4 py-3",children:t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-6 w-6 items-center justify-center rounded-md bg-teal-100",children:e(T,{className:"h-3.5 w-3.5 text-teal-600"})}),t($,{className:"text-base font-semibold text-gray-800",children:["Đáp án ",t("span",{className:"text-xs font-normal text-gray-500",children:["(",Ye.length," chỗ trống)"]})]})]})}),t(z,{className:"px-4 pb-4",children:[e("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4",children:Ye.map(n=>{const r=!Le[n]||""===Le[n].trim();return t("div",{className:"rounded-xl border-2 p-3 transition-all duration-200 "+(r?"border-gray-200 bg-white":"border-teal-200 bg-gradient-to-br from-teal-50 to-cyan-50 shadow-sm shadow-teal-100"),children:[t(R,{className:"mb-1.5 flex items-center justify-between text-sm font-semibold text-gray-700",children:[t("span",{children:["Chỗ trống ",e("code",{className:"rounded bg-gray-100 px-1 text-teal-700",children:`{${n}}`})]}),r&&e("span",{className:"text-[10px] font-normal italic text-red-500",children:"*Bắt buộc"})]}),e(O,{value:Le[n]||"",onChange:e=>Ee(t=>({...t,[n]:e.target.value})),placeholder:"Đáp án đúng...",className:"border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-100 "+(r?"":"border-teal-200")}),!r&&t("span",{className:"mt-1.5 inline-flex items-center gap-1 rounded-full bg-teal-100 px-2 py-0.5 text-[10px] font-semibold text-teal-700",children:[e(T,{className:"h-3 w-3"}),"Đã nhập"]})]},n)})}),Ye.some(e=>!Le[e]?.trim())&&t("div",{className:"mt-4 flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4",children:[e("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-amber-100",children:e("span",{className:"text-lg",children:"⚠️"})}),t("div",{className:"text-sm text-amber-800",children:[e("p",{className:"font-semibold",children:"Còn chỗ trống chưa có đáp án"}),t("p",{className:"mt-0.5 text-amber-700",children:["Vui lòng điền đáp án đúng cho tất cả các ô được đánh dấu ",e("span",{className:"text-red-500 font-medium",children:"*Bắt buộc"}),"."]})]})]})]})]}),t(E,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-amber-100/50",children:[e(J,{className:"px-4 py-3",children:t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-amber-500 to-orange-500 shadow-sm",children:e(A,{className:"h-3.5 w-3.5 text-white"})}),t("div",{children:[t("div",{className:"flex items-center gap-2",children:[e($,{className:"text-base font-semibold text-gray-800",children:"Giải thích"}),e("span",{className:"inline-flex items-center rounded-full border border-amber-200 bg-amber-50 px-2 py-0.5 text-xs font-medium text-amber-600",children:"Không bắt buộc"})]}),e("p",{className:"mt-0.5 text-xs text-gray-500",children:"Giải thích cho đáp án đúng — hiển thị sau khi học sinh hoàn thành câu hỏi"})]})]})}),e(z,{className:"px-4 pb-4",children:e(P,{value:ce,onChange:e=>oe(e.target.value),placeholder:"VD: Câu trả lời đúng là... vì...",rows:3,className:"min-h-[80px] resize-none border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200"})})]})]})}
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as n,useEffect as r,useRef as a,useMemo as i,useCallback as s}from"react";import{useEditor as l,EditorContent as o}from"@tiptap/react";import c from"@tiptap/starter-kit";import d from"@tiptap/extension-text-align";import m from"@tiptap/extension-underline";import{Table as h,TableRow as g,TableCell as u,TableHeader as p}from"@tiptap/extension-table";import{List as f,ListOrdered as x,Bold as b,Italic as N,Underline as w,Strikethrough as v,AlignLeft as y,AlignCenter as C,AlignRight as k,TableIcon as I,Plus as S,Minus as T,Trash2 as O,Undo2 as A,Redo2 as B,BookOpen as H,Eye as U,Pencil as j,CheckCircle2 as W,PenLine as D,Info as P,MessageSquare as R,ImageIcon as _}from"lucide-react";import{Button as G}from"../../../../components/ui/button";import{Label as J}from"../../../../components/ui/label";import{Input as F}from"../../../../components/ui/input";import{Textarea as L}from"../../../../components/ui/textarea";import{Switch as E}from"../../../../components/ui/switch";import{PointsInput as K}from"../../../../components/ui/points-input";import{Card as M,CardContent as z,CardHeader as $,CardTitle as q}from"../../../../components/ui/card";import{FileUpload as V}from"../../../../components/ui/file-upload";import{ImagePreview as X}from"../../../../components/ui/image-preview";import{WordFillStructuredFormClient as Q}from"./WordFillStructuredFormClient";import{WfsfWordBankEditor as Y}from"./WfsfWordBankEditor";import{useDebouncedCallback as Z,usePresignedFileUrl as ee}from"../../../../shared/lib/hooks";import{BasicQuestionGroupCard as te}from"../../groups/BasicQuestionGroupCard";import{DocumentGroupCard as ne}from"../../groups/DocumentGroupCard";import{useBasicQuestionGroup as re,getGroupNumberForIndex as ae}from"../../_shared/hooks/useBasicQuestionGroup";import{bankPayloadForMode as ie,detectWfsfBankMode as se,emptySharedBank as le,normalizeOptionsWordBank as oe,normalizeSharedWordBank as ce}from"./wfsf-word-bank.utils";const de=({onClick:t,active:n,disabled:r,title:a,children:i,className:s=""})=>e("button",{type:"button",onClick:t,disabled:r,title:a,className:`inline-flex h-7 min-w-7 items-center justify-center rounded px-1.5 text-sm transition-colors disabled:opacity-30\n ${n?"bg-teal-100 text-teal-700":"text-gray-500 hover:bg-gray-100 hover:text-gray-800"}\n ${s}`,children:i}),me=()=>e("div",{className:"mx-1 h-4 w-px bg-gray-200"}),he=({editor:n})=>n?t("div",{className:"flex flex-wrap items-center gap-0.5 border-b border-gray-100 bg-gray-50/70 px-2 py-1.5 rounded-t-lg",children:[e(de,{onClick:()=>n.chain().focus().undo().run(),disabled:!n.can().chain().focus().undo().run(),title:"Hoàn tác",children:e(A,{className:"h-3.5 w-3.5"})}),e(de,{onClick:()=>n.chain().focus().redo().run(),disabled:!n.can().chain().focus().redo().run(),title:"Làm lại",children:e(B,{className:"h-3.5 w-3.5"})}),e(me,{}),e(de,{onClick:()=>n.chain().focus().toggleBold().run(),active:n.isActive("bold"),title:"Đậm",children:e(b,{className:"h-3.5 w-3.5"})}),e(de,{onClick:()=>n.chain().focus().toggleItalic().run(),active:n.isActive("italic"),title:"Nghiêng",children:e(N,{className:"h-3.5 w-3.5"})}),e(de,{onClick:()=>n.chain().focus().toggleUnderline().run(),active:n.isActive("underline"),title:"Gạch dưới",children:e(w,{className:"h-3.5 w-3.5"})}),e(de,{onClick:()=>n.chain().focus().toggleStrike().run(),active:n.isActive("strike"),title:"Gạch ngang",children:e(v,{className:"h-3.5 w-3.5"})}),e(me,{}),e(de,{onClick:()=>n.chain().focus().toggleHeading({level:2}).run(),active:n.isActive("heading",{level:2}),className:"px-2 text-xs font-bold",children:"H2"}),e(de,{onClick:()=>n.chain().focus().toggleHeading({level:3}).run(),active:n.isActive("heading",{level:3}),className:"px-2 text-xs font-bold",children:"H3"}),e(de,{onClick:()=>n.chain().focus().toggleHeading({level:4}).run(),active:n.isActive("heading",{level:4}),className:"px-2 text-xs font-bold",children:"H4"}),e(me,{}),e(de,{onClick:()=>n.chain().focus().toggleBulletList().run(),active:n.isActive("bulletList"),title:"Danh sách",children:e(f,{className:"h-3.5 w-3.5"})}),e(de,{onClick:()=>n.chain().focus().toggleOrderedList().run(),active:n.isActive("orderedList"),title:"Danh sách có số",children:e(x,{className:"h-3.5 w-3.5"})}),e(me,{}),e(de,{onClick:()=>n.chain().focus().setTextAlign("left").run(),active:n.isActive({textAlign:"left"}),title:"Trái",children:e(y,{className:"h-3.5 w-3.5"})}),e(de,{onClick:()=>n.chain().focus().setTextAlign("center").run(),active:n.isActive({textAlign:"center"}),title:"Giữa",children:e(C,{className:"h-3.5 w-3.5"})}),e(de,{onClick:()=>n.chain().focus().setTextAlign("right").run(),active:n.isActive({textAlign:"right"}),title:"Phải",children:e(k,{className:"h-3.5 w-3.5"})}),e(me,{}),t(de,{onClick:()=>n.chain().focus().insertTable({rows:5,cols:2,withHeaderRow:!1}).run(),title:"Chèn bảng 2 cột × 5 hàng",className:"gap-1 px-2 text-xs",children:[e(I,{className:"h-3.5 w-3.5"}),e("span",{className:"hidden sm:inline",children:"Bảng 2 cột"})]}),t(de,{onClick:()=>n.chain().focus().addRowAfter().run(),disabled:!n.can().addRowAfter(),title:"Thêm hàng",className:"gap-1 px-2 text-xs",children:[e(S,{className:"h-3 w-3"}),e("span",{className:"hidden sm:inline",children:"Hàng"})]}),t(de,{onClick:()=>n.chain().focus().deleteRow().run(),disabled:!n.can().deleteRow(),title:"Xóa hàng",className:"gap-1 px-2 text-xs",children:[e(T,{className:"h-3 w-3"}),e("span",{className:"hidden sm:inline",children:"Hàng"})]}),t(de,{onClick:()=>n.chain().focus().deleteTable().run(),disabled:!n.can().deleteTable(),title:"Xóa bảng",className:"gap-1 px-2 text-xs text-red-400 hover:text-red-600",children:[e(O,{className:"h-3 w-3"}),e("span",{className:"hidden sm:inline",children:"Bảng"})]})]}):null;export function WordFillStructuredFormCreator({initialData:f,onSave:b,onCancel:N,onChange:w,onUnsavedChangesChange:v,validationRef:y,externalErrors:C,groupConfig:k,groupType:I,groups:S,questionIndexInPart:T=0,partId:O="",viewMode:A}){const[B,de]=n(!1),[me,ge]=n(f?.points??1),[ue,pe]=n(f?.caseSensitive??!1),[fe,xe]=n(f?.instruction||f?.explanation||""),[be,Ne]=n(f?.explanation||""),[we,ve]=n(""),[ye,Ce]=n(f?.blankStyle),ke=se(f?.viewMode??A,f?.wordBank),[Ie,Se]=n(ke),[Te,Oe]=n(()=>"WITH_WORD_BANK"===ke?ce(f?.wordBank):[]),[Ae,Be]=n(()=>"WITH_OPTIONS"===ke?oe(f?.wordBank,Object.keys(f?.answers||{})):[]),{isGrouped:He,isFirstInGroup:Ue,currentGroupNumber:je,groupTitle:We,groupSubtitle:De,groupContent:Pe,imageUrl:Re,setGroupTitle:_e,setGroupSubtitle:Ge,setGroupContent:Je,setImageUrl:Fe}=re({partId:O,groups:S,questionIndexInPart:T,initialData:{title:f?.groupTitle||"",subtitle:f?.groupSubtitle||"",content:f?.groupContent||"",imageUrl:f?.groupImageUrl||""}}),Le=(I||"BASIC").toUpperCase(),Ee=!(k&&k.length>0)||k.includes("content"),Ke=je||ae(T,S),[Me,ze]=n(f?.title||""),[$e,qe]=n(f?.imageUrl||""),Ve=Me,Xe=$e,Qe=ze,Ye=qe,{previewUrl:Ze}=ee(Xe),et=we||Ze||"",tt=f?.content||"<p></p>",[nt,rt]=n(tt),[at,it]=n(f?.answers||{}),st=a(""),lt=a(f),ot=a(!1),ct=a(nt),dt=a(w);r(()=>{dt.current=w},[w]);const mt=i(()=>[c.configure({heading:{levels:[2,3,4]}}),m,d.configure({types:["heading","paragraph"]}),h.configure({resizable:!0}),g,u,p],[]),ht=i(()=>({attributes:{class:"tiptap-editor prose prose-sm max-w-none p-4 focus:outline-none min-h-[400px]"}}),[]),gt=s(({editor:e})=>{const t=e.getHTML();t!==ct.current&&(ct.current=t,rt(t))},[]),ut=l({immediatelyRender:!1,extensions:mt,content:nt,editorProps:ht,onUpdate:gt});r(()=>{ct.current=nt},[nt]),r(()=>{if(!(JSON.stringify(lt.current)!==JSON.stringify(f)))return;if(lt.current=f,!f?.content||"<p></p>"===f.content)return;ot.current=!0,ze(f?.title||""),qe(f?.imageUrl||""),ge(f?.points??1),pe(f?.caseSensitive??!1),xe(f?.instruction||f?.explanation||"");{const e=String(f?.instruction||f?.explanation||"").trim(),t=String(f?.explanation||"").trim();Ne(t&&t!==e?t:"")}it(f?.answers||{}),Ce(f?.blankStyle);const e=se(f?.viewMode??A,f?.wordBank);Se(e),"WITH_WORD_BANK"===e?Oe(ce(f?.wordBank)):"WITH_OPTIONS"===e?Be(oe(f?.wordBank,Object.keys(f?.answers||{}))):(Oe([]),Be([]));const t=f.content;t!==ct.current&&(ct.current=t,rt(t),ut&&!ut.isDestroyed&&ut.commands.setContent(t)),setTimeout(()=>{ot.current=!1},150)},[f,ut,A]);const pt=Z(e=>{dt.current?.(e)},300),ft=JSON.stringify(at),xt=i(()=>{const e=new Set,t=/\{([\w\d]+)\}/g;let n;for(;null!==(n=t.exec(nt));)e.add(n[1]);return Array.from(e).sort((e,t)=>{const n=parseInt(e),r=parseInt(t);return isNaN(n)||isNaN(r)?e.localeCompare(t):n-r})},[nt]);r(()=>{it(e=>{let t=!1;const n={...e};return Object.keys(n).forEach(e=>{xt.includes(e)||(delete n[e],t=!0)}),xt.forEach(e=>{e in n||(n[e]="",t=!0)}),t?n:e})},[xt]),r(()=>{"WITH_OPTIONS"===Ie&&Be(e=>{const t=oe(e,xt);return 0===e.length&&xt.length>0?xt.map(()=>null):JSON.stringify(e)===JSON.stringify(t)?e:t})},[Ie,xt]);const bt=JSON.stringify(Te),Nt=JSON.stringify(Ae),wt=s(()=>{const e=ie(Ie,Te,Ae);return{title:Ve,imageUrl:Xe,content:nt,answers:at,points:me,caseSensitive:ue,instruction:fe,explanation:be,blankStyle:ye,...e,groupTitle:We,groupSubtitle:De,groupContent:Pe,groupImageUrl:Re,groupNumber:Ke}},[Ie,Te,Ae,Ve,Xe,nt,at,me,ue,fe,be,ye,We,De,Pe,Re,Ke]),vt=s(e=>{Se(e),"WITH_WORD_BANK"===e?Oe(e=>e.length>0?e:le()):"WITH_OPTIONS"===e&&Be(e=>e.length===xt.length?e:e.length>0?oe(e,xt):xt.map(()=>({options:["",""]})))},[xt]);return r(()=>{const e=wt();if(ot.current)return void(st.current=JSON.stringify(e));const t=JSON.stringify(e);t!==st.current&&(st.current=t,pt(e))},[wt,ft,bt,Nt,Ie,ye]),r(()=>{y&&(y.current={triggerValidation:async()=>{if(!nt||"<p></p>"===nt)return!1;if(0===xt.length)return!1;for(const e of xt)if(!at[e]||""===at[e].trim())return!1;if("WITH_WORD_BANK"===Ie){if(Te.map(e=>e.word.trim()).filter(Boolean).length<1)return!1}if("WITH_OPTIONS"===Ie)for(let e=0;e<xt.length;e+=1){const t=Ae[e];if(null==t)continue;const n=t.options.map(e=>e.trim()).filter(Boolean);if(n.length<2)return!1;const r=xt[e],a=(at[r]||"").trim();if(a&&!n.includes(a))return!1}return!0},getFormData:()=>wt()})},[y,wt,nt,xt,at,Ie,Te,Ae]),t("div",B?{className:"space-y-4",children:[e(M,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-teal-100/50",children:e($,{className:"px-4 py-3",children:t("div",{className:"flex items-center justify-between",children:[t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-teal-500 to-cyan-600 shadow-sm",children:e(U,{className:"h-4 w-4 text-white"})}),t("div",{children:[e(q,{className:"text-base font-bold text-gray-900",children:"Điền từ – Xem trước"}),e("p",{className:"text-xs text-gray-500",children:"Chế độ xem trước với đáp án đúng đã được điền sẵn"})]})]}),t(G,{variant:"outline",size:"sm",onClick:()=>de(!1),className:"gap-2 border-teal-200 text-teal-700 hover:bg-teal-50",children:[e(j,{className:"h-4 w-4"}),"Quay lại Edit"]})]})})}),e(Q,{questionData:wt(),isReviewMode:!0,userAnswer:at,instruction:fe})]}:{className:"space-y-4",children:[He&&"BASIC"===Le&&e(te,{groupNumber:Ke,title:We,subtitle:De,content:Pe,imageUrl:Re,onTitleChange:_e,onSubtitleChange:Ge,onContentChange:Je,onImageChange:Fe,groupConfig:I?k:void 0,isReadOnly:!Ue,uploadIdPrefix:`word-fill-structured-${O??"group"}`}),He&&"DOCUMENT"===Le&&e(ne,{groupNumber:Ke,title:We,subtitle:De,content:Pe,imageUrl:Re,onTitleChange:_e,onSubtitleChange:Ge,onContentChange:Je,onImageChange:Fe,groupConfig:I?k:void 0,isReadOnly:!Ue,uploadIdPrefix:`word-fill-structured-${O??"document"}`}),t(M,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-teal-100/50",children:[e("div",{className:"h-1 bg-gradient-to-r from-teal-500 via-cyan-500 to-emerald-500"}),e($,{className:"px-4 py-3",children:t("div",{className:"flex items-center justify-between",children:[t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gray-100",children:e(D,{className:"h-4 w-4 text-teal-600"})}),t("div",{children:[e(q,{className:"text-base font-bold text-gray-900",children:"Điền từ vào biểu mẫu có cấu trúc"}),t("p",{className:"text-xs text-gray-500",children:["Nhập nội dung, đặt chỗ trống bằng ","{0}"," ","{1}","… rồi điền đáp án bên dưới"]})]})]}),t(G,{variant:"outline",size:"sm",onClick:()=>de(!0),disabled:0===xt.length||xt.some(e=>!at[e]?.trim()),className:"gap-2 border-teal-200 text-teal-600 hover:bg-teal-50 hover:text-teal-700",children:[e(U,{className:"h-4 w-4"}),"Xem trước"]})]})}),t(z,{className:"space-y-4 px-4 pb-4",children:[t("div",{className:"space-y-2",children:[t(J,{htmlFor:"wfsf-instruction",className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(P,{className:"h-4 w-4 text-teal-500"}),"Instruction",e("span",{className:"text-sm font-normal text-gray-500",children:"(hướng dẫn bài tập)"})]}),e(L,{id:"wfsf-instruction",value:fe,onChange:e=>xe(e.target.value),placeholder:"VD: Complete the words in the sentences. Use the words in the box.",rows:2,className:"min-h-[64px] resize-y border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-100"})]}),t("div",{className:"flex flex-wrap items-center gap-3",children:[e(K,{value:me,onChange:e=>ge(Number(e.target.value)||1)}),t("div",{role:"button",tabIndex:0,onClick:()=>pe(!ue),onKeyDown:e=>{" "!==e.key&&"Enter"!==e.key||pe(!ue)},style:{paddingBlock:"calc(var(--spacing) * 1)"},className:"inline-flex cursor-pointer items-center gap-2 rounded-md border px-3.5 text-sm font-medium transition-colors select-none "+(ue?"border-teal-300 bg-teal-50 text-teal-700":"border-gray-200 bg-white text-gray-400 hover:text-gray-600"),children:[e(E,{checked:ue,onCheckedChange:pe,className:ue?"data-[state=checked]:bg-teal-500 pointer-events-none":"pointer-events-none",tabIndex:-1}),"Phân biệt Hoa / thường"]})]}),t("div",{className:"space-y-2",children:[t(J,{htmlFor:"wfsf-title",className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(R,{className:"h-4 w-4 text-teal-500"}),"Tiêu đề",e("span",{className:"text-sm font-normal text-gray-500",children:"(tuỳ chọn)"})]}),e(F,{id:"wfsf-title",value:Ve,onChange:e=>Qe(e.target.value),placeholder:"Nhập tiêu đề câu hỏi...",className:"border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-100"})]}),t("div",{className:"space-y-2",children:[t(J,{className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(_,{className:"h-4 w-4 text-teal-500"}),"Hình ảnh",e("span",{className:"text-sm font-normal text-gray-500",children:"(tuỳ chọn)"})]}),e(V,{id:"wfsf-image",label:"",accept:"image/*",value:Xe||"",onChange:e=>Ye(e),onPresignedUrlChange:ve,maxSize:5,placeholder:"Upload ảnh hoặc paste URL",autoUpload:!0,prefix:"questions"}),et&&e(X,{src:et,alt:"Preview",className:"mt-2 h-48 w-full max-w-md rounded-lg border border-gray-200"})]}),C&&C.length>0&&t("div",{className:"flex items-start gap-3 rounded-xl border border-red-200 bg-gradient-to-r from-red-50 to-rose-50 p-4",children:[e("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-red-100",children:e("span",{className:"text-lg",children:"❌"})}),t("div",{className:"text-sm",children:[e("p",{className:"font-semibold text-red-800",children:"Lỗi:"}),e("ul",{className:"mt-1 list-inside list-disc text-red-700",children:C.map((t,n)=>e("li",{children:t},n))})]})]})]})]}),Ee&&t(M,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-teal-100/50",children:[e($,{className:"px-4 py-3",children:t("div",{className:"flex items-center justify-between",children:[t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-6 w-6 items-center justify-center rounded-md bg-teal-100",children:e(x,{className:"h-3.5 w-3.5 text-teal-600"})}),e(q,{className:"text-base font-semibold text-gray-800",children:"Nội dung cấu trúc"})]}),xt.length>0&&t("span",{className:"inline-flex items-center rounded-full border border-teal-200 bg-teal-50 px-2.5 py-0.5 text-xs font-semibold text-teal-700",children:[xt.length," chỗ trống"]})]})}),t(z,{className:"space-y-3 px-4 pb-4",children:[t("div",{className:"overflow-hidden rounded-xl border border-gray-200 transition-all focus-within:border-teal-300 focus-within:ring-2 focus-within:ring-teal-100",children:[e(he,{editor:ut}),e(o,{editor:ut})]}),t("div",{className:"flex items-start gap-2 rounded-lg border border-teal-100 bg-teal-50/60 px-3 py-2.5",children:[e(P,{className:"mt-0.5 h-4 w-4 shrink-0 text-teal-500"}),t("p",{className:"text-xs text-teal-700",children:["Nhập ",e("strong",{children:"{0}"}),", ",e("strong",{children:"{1}"}),", ",e("strong",{children:"{2}"}),"… vào văn bản để tạo ô trống. Đáp án sẽ tự động xuất hiện bên dưới để bạn nhập."]})]})]})]}),e(Y,{mode:Ie,onModeChange:vt,sharedBank:Te,onSharedBankChange:Oe,optionsBank:Ae,onOptionsBankChange:Be,blankKeys:xt,answers:at,onAnswerChange:(e,t)=>it(n=>({...n,[e]:t}))}),xt.length>0&&"WITH_OPTIONS"!==Ie&&t(M,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-teal-100/50",children:[e($,{className:"px-4 py-3",children:t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-6 w-6 items-center justify-center rounded-md bg-teal-100",children:e(W,{className:"h-3.5 w-3.5 text-teal-600"})}),t(q,{className:"text-base font-semibold text-gray-800",children:["Đáp án ",t("span",{className:"text-xs font-normal text-gray-500",children:["(",xt.length," chỗ trống)"]})]})]})}),t(z,{className:"px-4 pb-4",children:[e("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4",children:xt.map(n=>{const r=!at[n]||""===at[n].trim();return t("div",{className:"rounded-xl border-2 p-3 transition-all duration-200 "+(r?"border-gray-200 bg-white":"border-teal-200 bg-gradient-to-br from-teal-50 to-cyan-50 shadow-sm shadow-teal-100"),children:[t(J,{className:"mb-1.5 flex items-center justify-between text-sm font-semibold text-gray-700",children:[t("span",{children:["Chỗ trống ",e("code",{className:"rounded bg-gray-100 px-1 text-teal-700",children:`{${n}}`})]}),r&&e("span",{className:"text-[10px] font-normal italic text-red-500",children:"*Bắt buộc"})]}),e(F,{value:at[n]||"",onChange:e=>it(t=>({...t,[n]:e.target.value})),placeholder:"Đáp án đúng...",className:"border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-100 "+(r?"":"border-teal-200")}),!r&&t("span",{className:"mt-1.5 inline-flex items-center gap-1 rounded-full bg-teal-100 px-2 py-0.5 text-[10px] font-semibold text-teal-700",children:[e(W,{className:"h-3 w-3"}),"Đã nhập"]})]},n)})}),xt.some(e=>!at[e]?.trim())&&t("div",{className:"mt-4 flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4",children:[e("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-amber-100",children:e("span",{className:"text-lg",children:"⚠️"})}),t("div",{className:"text-sm text-amber-800",children:[e("p",{className:"font-semibold",children:"Còn chỗ trống chưa có đáp án"}),t("p",{className:"mt-0.5 text-amber-700",children:["Vui lòng điền đáp án đúng cho tất cả các ô được đánh dấu ",e("span",{className:"text-red-500 font-medium",children:"*Bắt buộc"}),"."]})]})]})]})]}),t(M,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-amber-100/50",children:[e($,{className:"px-4 py-3",children:t("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-amber-500 to-orange-500 shadow-sm",children:e(H,{className:"h-3.5 w-3.5 text-white"})}),t("div",{children:[t("div",{className:"flex items-center gap-2",children:[e(q,{className:"text-base font-semibold text-gray-800",children:"Giải thích"}),e("span",{className:"inline-flex items-center rounded-full border border-amber-200 bg-amber-50 px-2 py-0.5 text-xs font-medium text-amber-600",children:"Không bắt buộc"})]}),e("p",{className:"mt-0.5 text-xs text-gray-500",children:"Giải thích cho đáp án đúng — hiển thị sau khi học sinh hoàn thành câu hỏi"})]})]})}),e(z,{className:"px-4 pb-4",children:e(L,{value:be,onChange:e=>Ne(e.target.value),placeholder:"VD: Câu trả lời đúng là... vì...",rows:3,className:"min-h-[80px] resize-none border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200"})})]})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{WordFillStructuredFormCreator as t}from"./WordFillStructuredFormCreator";export const wordFillStructuredFormRegistration={component:t,transformInitialData:t=>{const
|
|
1
|
+
import{WordFillStructuredFormCreator as t}from"./WordFillStructuredFormCreator";import{detectWfsfBankMode as e,normalizeOptionsWordBank as n,normalizeSharedWordBank as o}from"./wfsf-word-bank.utils";export const wordFillStructuredFormRegistration={component:t,transformInitialData:t=>{const i=t?.content||{},a=t?.answer||{},r=t?.correctAnswer||a?.correctAnswer||{},s=t?.total_points?parseFloat(t.total_points):a?.points||t?.points||1,l=String(a?.instruction||t?.instruction||t?.explanation||""),p=String(a?.explanation||"");let u=i?.content||a?.content||"";const c=i?.blocks||a?.blocks;!u&&c?.length&&(u=c.map(t=>(t.heading?`<h3>${t.heading}</h3>`:"")+(t.content||"")).join(""));const g=i?.wordBank??a?.wordBank,d=e(i?.viewMode??a?.viewMode,g),w=function(t){const e=new Set,n=/\{([\w\d]+)\}/g;let o;for(;null!==(o=n.exec(t));)e.add(o[1]);return Array.from(e).sort((t,e)=>{const n=parseInt(t,10),o=parseInt(e,10);return Number.isNaN(n)||Number.isNaN(o)?t.localeCompare(e):n-o})}(String(u||""));let f=g,m="FREE_TYPE"===d?void 0:d;"WITH_WORD_BANK"===d?(f=o(g),m="WITH_WORD_BANK"):"WITH_OPTIONS"===d?(f=n(g,w),m="WITH_OPTIONS"):f=void 0;const v=t?.questionGroup?.payload;return{title:i?.title||a?.title||"",imageUrl:i?.imageUrl||a?.imageUrl||"",content:u,answers:r?.answers||a?.answers||{},caseSensitive:r?.caseSensitive??a?.caseSensitive??!1,blankStyle:i?.blankStyle??a?.blankStyle,viewMode:m,wordBank:f,instruction:l,explanation:p,points:s,groupTitle:v?.title||a?.groupTitle||"",groupSubtitle:v?.subtitle||a?.groupSubtitle||"",groupContent:v?.content||a?.groupContent||"",groupImageUrl:v?.imageUrl||a?.groupImageUrl||""}},getExtraProps:t=>({onUnsavedChangesChange:t.onUnsavedChangesChange,validationRef:t.validationRef,groupConfig:t.groupConfig,groupType:t.groupType,groups:t.groups,questionIndexInPart:t.questionIndexInPart,partId:t.partId,viewMode:t.viewMode}),wrapOnSave:(t,e)=>({type:e.questionType,content:e.state.content,points:t?.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:t,explanation:t?.explanation||""}),wrapOnChange:(t,e)=>({type:e.questionType,content:e.state.content,points:t?.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:t,explanation:t?.explanation||""})};
|
|
@@ -2,9 +2,12 @@ import type { TransformHandler } from '../../../../shared/lib/utils/question-tra
|
|
|
2
2
|
/**
|
|
3
3
|
* Transform WORD_FILL_STRUCTURED_FORM creator data → API format
|
|
4
4
|
*
|
|
5
|
-
* Creator (question.answer): {
|
|
5
|
+
* Creator (question.answer): {
|
|
6
|
+
* title, imageUrl, content, answers, caseSensitive, points, explanation,
|
|
7
|
+
* blankStyle?, viewMode?, wordBank?
|
|
8
|
+
* }
|
|
6
9
|
* API:
|
|
7
|
-
* content: { title, imageUrl, content }
|
|
10
|
+
* content: { title, imageUrl, content, blankStyle?, viewMode?, wordBank? }
|
|
8
11
|
* correctAnswer: { answers, caseSensitive }
|
|
9
12
|
*/
|
|
10
13
|
export declare const transformWordFillStructuredForm: TransformHandler;
|