PageSourceSearch

https://giaoviendoimoi.com/assets/FlyingWordsGamePage-0W_jU3LF.js

js giaoviendoimoi.com collected 2026-09-24 14:14:35 UTC 35,113 bytes, 17 lines download raw bytes

1import{r as a,j as e,R as ct}from"./vendor-react-DJzUMfd1.js";import{n as ve,a as Ce,R as Ge,p as u,m as ye,B as O,N as te,C as He,D as qe,d as Qe,e as Ke,T as w,f as Ye,U as Ve,I as fe,Y as dt,v as je,q as Je,c as ut,as as re,c4 as ue,at as Ee,K as G,o as ht,r as ft,b5 as gt,k as mt,V as pt,b as xt,ak as bt,H as yt,g as jt}from"./index-C0esqoXR.js";import{F as wt}from"./FeatureSidebar-GlvnyiAl.js";import{D as St}from"./Download-BSMddDqv.js";import{F as vt}from"./FeatureContentHeader-B6FiouTH.js";import{F as Le}from"./FeatureItemCard-B11iEbdV.js";import{u as Ct}from"./ListToolbar-qYTbGaSa.js";import{getAllLessons as At,deleteLesson as kt,getLesson as Tt,createLesson as Et,updateLesson as Lt}from"./flyingWordsService-ECtyZAS2.js";import{D as Ie}from"./demoLesson-bKz3kMLX.js";import{A as It}from"./AssignGameModal-yoaznfDx.js";import{T as Mt}from"./TeacherShareModal-D2XdNkNX.js";import{g as zt,e as Wt}from"./vendor-firebase-NOrVjYbK.js";import{u as Ft}from"./useFeatureAccess-CLO2m6i4.js";import{J as Pt}from"./jszip.min-DGzWmKqs.js";import{F as Rt}from"./FileSaver.min-d7RW4grg.js";import{S as Ut}from"./Skeleton-C-RseBC4.js";import{T as ge}from"./Tooltip-DCBvMNYw.js";import{S as Ot}from"./useShuffleQuestions-CMMUsmAD.js";import{M as Me}from"./MathEditor-xebJ_Vun.js";import{M as ze}from"./MathText-CUiST3AE.js";import"./vendor-katex-DqEyuLHo.js";import{T as Nt}from"./Toast-Cc4ZjV4U.js";import{P as Bt,u as Dt,A as $t}from"./AudioUploader-Chm1xGy2.js";import{u as _t,L as Gt}from"./useLibraryPublish-C-JOVX-R.js";import{u as We,p as Ht}from"./publicLibraryService-ZxnW36pj.js";import{F as qt}from"./teacherShareService-i2USwxcI.js";import{A as we}from"./AutoAwesome-D0bRN7MU.js";import{C as Qt}from"./Checkbox-hNFsBxwF.js";import{R as Fe}from"./RadioGroup-BAZJump4.js";import{F as q}from"./FormControlLabel-UfST9rc_.js";import{R as ee}from"./Radio-DtuO3MtI.js";import{S as xe}from"./Switch-BjW_bRl3.js";import{A as Kt,a as Yt}from"./ArrowUpward-DANMY_h1.js";import{D as Vt}from"./Delete-CqbOIsIj.js";import{F as Jt}from"./FormatSize-ByM8Do4m.js";import{A as Xt}from"./Add-X1dRrWs4.js";import"./vendor-3d-B-0V4uEN.js";import"./PinButton-DVd4Vn0o.js";import"./CardContent-HcqzoF-r.js";import"./Edit-D5TIkJzq.js";import"./PlayArrow-CWGWpNtH.js";import"./index-CPX-tAFT.js";import"./assignmentService-tzBLKRhC.js";import"./joinCodeService-Duqlw8dB.js";import"./gameTypes-f5wEe58l.js";import"./Cancel-HgNyvqSD.js";import"./HelpOutline-BjEUExVZ.js";import"./EmojiEvents-C3dbMUOl.js";import"./versusSessionService-C2bMmyTm.js";import"./htmlEmbedGameService-Plw4Vjhb.js";import"./InputAdornment-DLc3DBCX.js";import"./Link-SqD1ZXeC.js";import"./WarningAmber-CyTKnF7w.js";import"./SimpleMathKeyboard-BN4kmru0.js";import"./MusicNote-DGIOj6D7.js";import"./LinearProgress-CFq27fme.js";import"./Replay-CPM-fl2v.js";import"./Stop-CCdargpS.js";import"./Lock-fDVNKez0.js";const Zt="/export-bundles/flying-words-game/index.html",Pe="<!--GAME_DATA_PLACEHOLDER-->",es=[{url:"/sounds/slash.mp3",zipPath:"sounds/slash.mp3"},{url:"/sounds/wrong.mp3",zipPath:"sounds/wrong.mp3"},{url:"/sounds/congratulations.wav",zipPath:"sounds/congratulations.wav"},{url:"/sounds/bgm/5.mp3",zipPath:"sounds/bgm/5.mp3"}],Re=6;async function Ue(n){const h=await fetch(n);if(!h.ok)throw new Error(`Fetch failed (${h.status}): ${n}`);return h.blob()}async function Oe(n,h,x){let t=0;const f=Array.from({length:Math.min(h,n.length)},async()=>{for(;t<n.length;){const r=t++;await x(n[r],r)}});await Promise.all(f)}function Ne(n,h){const t=n.split("?")[0].split("#")[0].match(/\.([a-zA-Z0-9]+)$/);return t?t[1].toLowerCase():h}const Be=n=>typeof n=="string"&&/^https?:\/\//.test(n);async function ts(n,h){const x=await(await fetch(Zt)).text();if(!x.includes(Pe))throw new Error("Không tìm thấy placeholder dữ liệu trong bản export — vui lòng build lại vite.export.config.js");const t=new Pt,f={...n,useCamera:!1},r=[];let C=0;const L=(l,g)=>{if(!Be(l))return;const W=`assets/img-${C++}.${Ne(l,"png")}`;r.push({url:l,zipPath:W,apply:g})},b=(l,g)=>{if(!Be(l))return;const W=`assets/audio-${C++}.${Ne(l,"mp3")}`;r.push({url:l,zipPath:W,apply:g})};Array.isArray(f.questions)&&(f.questions=f.questions.map(l=>{const g={...l};return L(l.questionImage,E=>{g.questionImage=E}),b(l.questionAudio,E=>{g.questionAudio=E}),g})),await Oe(r,Re,async l=>{try{const g=await Ue(l.url);t.file(l.zipPath,g),l.apply(l.zipPath)}
1catch(g){console.warn("[exportOffline] Bỏ qua asset lỗi:",l.url,g)}finally{}}),await Oe(es,Re,async l=>{try{const g=await Ue(l.url);t.file(l.zipPath,g)}catch(g){console.warn("[exportOffline] Không tải được tài nguyên cố định:",l.url,g)}finally{}});const z=x.replace(Pe,`<script>window.__GAME__ = ${JSON.stringify(f)};<\/script>`);t.file("index.html",z);const k=await t.generateAsync({type:"blob",compression:"DEFLATE",compressionOptions:{level:6}}),R=(n.title||"tu-ngu-biet-bay").replace(/[\\/:*?"<>|]/g,"").trim()||"tu-ngu-biet-bay";Rt.saveAs(k,`tu-ngu-biet-bay-${R}.zip`)}const De={arrange:{text:"Sắp xếp câu",color:"#a78bfa",icon:"🔤"},find:{text:"Tìm từ đúng",color:"#2196f3",icon:"🎯"}};function ss({refreshKey:n,onCreateNew:h}){const x=ve(),{currentUser:t}=Ce(),{toast:f}=Ge(),[r,C]=a.useState([]),[L,b]=a.useState(!1),[z,k]=a.useState({open:!1,lessonId:null}),[R,l]=a.useState(!1),[g,E]=a.useState(null),[W,I]=a.useState(!1),[N,y]=a.useState(!1),[T,S]=a.useState(null),[U,H]=a.useState(null),{apply:v,toolbar:B}=Ct({getCount:o=>{var j;return((j=o.questions)==null?void 0:j.length)||0}}),Q=v(r),{accessInfo:A,isPinned:V,canAccessById:se,handleTogglePin:oe,pinLimitReached:p,pinLimit:D}=Ft("flyingWordsGame",r);a.useEffect(()=>{ie()},[t,n]);const ie=async()=>{if(t)try{b(!0);const o=await At(t.uid);C(o)}catch(o){console.error("Error loading lessons:",o),f.error("Không thể tải danh sách bài học")}finally{b(!1)}},ne=async o=>{try{b(!0),await kt(t.uid,o),C(r.filter(j=>j.id!==o)),f.success("Đã xóa bài học")}catch(j){console.error("Error deleting lesson:",j),f.error("Không thể xóa bài học")}finally{b(!1),k({open:!1,lessonId:null})}},ae=o=>{E(o),l(!0)},J=()=>{l(!1),E(null)},me=o=>{S({id:o.id,title:o.title,featureId:"flying-words-game",data:o}),y(!0)},le=async o=>{const j=A==null?void 0:A.level;if(!(j==="pro"||j==="premium"||j==="expired")){I(!0);return}if(!U){H(o.id);try{await ts(o)}catch(X){console.error("Error exporting offline zip:",X),f.error("Không tạo được file tải xuống, vui lòng thử lại")}finally{H(null)}}},$=async o=>{const j=await oe(o);j!=null&&j.limitReached?f.warning(`Đã đạt giới hạn ghim (${j.limit} bài học)`):f.success(V(o)?"Đã bỏ ghim":"Đã ghim")};return e.jsxs(u,{sx:{p:3},children:[e.jsx(vt,{title:e.jsx(u,{component:"span",sx:{color:"#b8860b",fontWeight:"bold"},children:"Bài học của tôi"}),subtitle:"Quản lý các bài học Từ Ngữ Biết Bay",toolbar:r.length>0?B:void 0}),e.jsxs(ye.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{duration:.3},children:[r.length>0&&e.jsxs(u,{sx:{bgcolor:A!=null&&A.isExpired?"#fff3e0":"#fffde7",border:`1px solid ${A!=null&&A.isExpired?"#ff9800":"#fdd835"}`,borderRadius:2,p:"8px 14px",mb:2,display:"flex",alignItems:"center",flexWrap:"wrap",gap:1,fontSize:"0.85rem",color:"#5d4037"},children:[e.jsx("span",{children:"Ghim bài học để ưu tiên khi hết hạn"}),e.jsxs("span",{style:{color:"#78909c"},children:["(",r.filter(o=>V(o.id)).length,"/",D," đã ghim)"]}),(A==null?void 0:A.isExpired)&&e.jsxs(u,{component:"span",sx:{ml:"auto",color:"#d32f2f",fontWeight:"bold",display:"flex",alignItems:"center",gap:.5},children:["Đã hết hạn",e.jsx(O,{size:"small",variant:"contained",color:"error",onClick:()=>I(!0),sx:{fontSize:"0.75rem",py:0,minHeight:"unset"},children:"Gia hạn"})]})]}),L&&r.length===0?e.jsx(u,{sx:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(300px, 1fr))",gap:3},children:[1,2,3].map(o=>e.jsx(Ut,{variant:"rectangular",height:200,sx:{borderRadius:2}},o))}):r.length===0?e.jsxs(e.Fragment,{children:[e.jsx(u,{sx:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(300px, 1fr))",gap:3},children:e.jsx(Le,{title:Ie.title,subtitle:e.jsxs(u,{sx:{display:"flex",gap:1,flexWrap:"wrap"},children:[e.jsx(te,{label:"Bản chạy thử",size:"small",sx:{bgcolor:"#fff8e1",color:"#a36a00",fontWeight:600}}),e.jsx(te,{label:`${Ie.questions.length} câu`,size:"small",sx:{bgcolor:"#dcfce7",color:"#166534"}})]}),description:"Trải nghiệm thử trò chơi Từ Ngữ Biết Bay",accessible:!0,primaryAction:{label:"Chơi thử",onClick:()=>x("/flying-words-game/play/__demo__"),icon:"play",color:"linear-gradient(135deg, #ffca28 0%, #f9a825 100%)"}})}),h&&e.jsx(u,{sx:{textAlign:"center",mt:2},children:e.jsx(O,{variant:"contained",onClick:h,sx:{background:"linear-gradient(135deg, #ffca28 0%, #f57f17 100%)",color:"#3e2723",textTransform:"none",fontWeight:"bold"},children:"Tạo bài học đầu tiên"})})]}):Q.length===0?e.jsx(u,{sx:{textAlign:"center",py:4,color:"#78909c"},children:"Không tìm thấy bài nào khớp"}):e.jsx(u,{sx:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(300px, 1fr))",gap:3},children:Q.map(o=>{var X;const j=se(o.id),K=De[o.mode]||De.arrange;return e.jsx(Le,{title:o.title,subtitle:e.jsxs(u,{sx:{display:"flex",gap:1,flexWrap:"wrap"},children:[e.jsx(te,{label:`${((X=o.questions)==null?void 0:X.length)||0} câu`,size:"small",variant:"outlined"}),e.jsx(te,{label:`${K.icon} ${K.text}
1`,size:"small",sx:{bgcolor:`${K.color}15`,color:K.color,fontWeight:"bold"}}),!o.scoring&&e.jsx(te,{label:"Trình chiếu",size:"small",sx:{bgcolor:"#eceff1",color:"#546e7a"}})]}),description:o.description,accessible:j,isPinned:V(o.id),onPinToggle:()=>$(o.id),pinLimitReached:p,lockedTip:"Bài học đã hết hạn sử dụng",onUpgrade:()=>I(!0),primaryAction:{label:"Chơi",onClick:()=>x(`/flying-words-game/play/${o.id}`),icon:"play",color:"linear-gradient(135deg, #ffca28 0%, #f9a825 100%)"},onEdit:()=>x(`/flying-words-game/${o.id}/edit`),onAssign:o.scoring?()=>ae(o):void 0,onShare:()=>me(o),onDelete:()=>k({open:!0,lessonId:o.id}),labels:{edit:"Sửa",assign:"Giao bài",share:"Chia sẻ",delete:"Xóa"},extraActions:(()=>{const M=A==null?void 0:A.level,Z=M==="pro"||M==="premium"||M==="expired";return e.jsx(ge,{title:Z?"Tải xuống":"Nâng cấp để tải xuống",children:e.jsx("span",{children:e.jsx(O,{size:"small",startIcon:U===o.id?e.jsx(He,{size:14,color:"inherit"}):e.jsx(St,{}),onClick:()=>j&&le(o),disabled:!j||U===o.id,sx:{color:Z?"#16a34a":"#9e9e9e",textTransform:"none",fontSize:"0.75rem","&:hover":{backgroundColor:Z?"rgba(22,163,74,0.1)":"rgba(0,0,0,0.04)"}},children:U===o.id?"Đang tải...":"Tải xuống"})})})})()},o.id)})})]}),e.jsxs(qe,{open:z.open,onClose:()=>k({open:!1,lessonId:null}),PaperProps:{sx:{borderRadius:"12px",border:"2px solid #f44336"}},children:[e.jsx(Qe,{sx:{fontWeight:"bold",color:"#f44336",background:"linear-gradient(135deg, #ffebee 0%, #ffcdd2 100%)"},children:"Xác nhận xóa"}),e.jsx(Ke,{sx:{pt:2},children:e.jsx(w,{children:"Bạn có chắc muốn xóa bài học này? Hành động này không thể hoàn tác."})}),e.jsxs(Ye,{sx:{p:2},children:[e.jsx(O,{onClick:()=>k({open:!1,lessonId:null}),variant:"outlined",sx:{borderColor:"#9e9e9e",color:"#9e9e9e"},children:"Hủy"}),e.jsx(O,{onClick:()=>ne(z.lessonId),variant:"contained",disabled:L,sx:{background:"linear-gradient(135deg, #f44336 0%, #d32f2f 100%)",color:"white",fontWeight:"bold"},children:"Xóa"})]})]}),g&&e.jsx(It,{open:R,onClose:J,game:{id:g.id,title:g.title,featureId:"flying-words-game",data:g},onSuccess:J}),T&&e.jsx(Mt,{open:N,onClose:()=>{y(!1),S(null)},game:T}),e.jsx(Ve,{feature:"flyingWordsGame",open:W,onClose:()=>I(!1)})]})}const ns="https://chatbotproxy-6evfxw332a-uc.a.run.app";function rs(n){const h=`LANGUAGE RULE (highest priority): write "sentence", "targetWords" and "hintText" in the SAME language the teacher used in their request. If the request is in English, answer entirely in English. If it is in Vietnamese, answer in Vietnamese. If the request names a target language (e.g. "sentences in French"), use that language instead. Never default to Vietnamese.
2CONTENT RULE: follow the teacher's request literally — topic, language level, grammar point, number of sentences. Do not substitute your own topic.
3OUTPUT RULE: return raw JSON array ONLY — no explanation, no markdown code fence.
4Produce 5-10 sentences unless the teacher asks for a specific number.`;return n==="find"?`You generate content for the educational game "Flying Words" (Find-the-word mode).
5Given the teacher's request, produce short, complete sentences suitable for students.
6For EACH sentence, mark the key word(s) students must catch (keyword, answer, the word class being asked about).
7${h}
8TARGET WORD RULES (critical — the game splits each sentence on spaces and students catch one card per word):
9- Every entry in "targetWords" MUST appear in "sentence" exactly, spelled identically, same capitalisation.
10- Each entry must be a SINGLE word with no spaces. To mark a phrase, list its words separately: ["is","going"].
11- Do NOT include trailing punctuation in "targetWords" (write "Hanoi", not "Hanoi.").
12Also write a short "hintText" telling students what to look for, WITHOUT revealing the answer.
13Format: [{"sentence":"...","targetWords":["word1","word2"],"hintText":"..."}]`:`You generate content for the educational game "Flying Words" (Sentence-arranging mode).
14Given the teacher's request, produce short, complete sentences suitable for students to reassemble word by word.
15For EACH sentence, write a short "hintText" giving the topic/context, WITHOUT reveal
15ing the word order.
16${h}
17Format: [{"sentence":"...","hintText":"..."}]`}function $e(n){return n.replace(/^[^\p{L}\p{N}$]+|[^\p{L}\p{N}$]+$/gu,"").toLowerCase()}function Xe(n,h){if(!(h!=null&&h.length))return[];const x=new Set;for(const t of h)for(const f of String(t).trim().split(/\s+/)){const r=$e(f);r&&x.add(r)}return n.reduce((t,f,r)=>(x.has($e(f))&&t.push(r),t),[])}function os(n){const h=n.replace(/```json/gi,"").replace(/```/g,"").trim(),x=h.match(/\[[\s\S]*\]/),t=x?x[0]:h,f=JSON.parse(t);if(!Array.isArray(f))throw new Error("AI_INVALID_FORMAT");return f.filter(r=>r&&typeof r.sentence=="string"&&r.sentence.trim()).map(r=>({sentence:r.sentence.trim(),targetWords:Array.isArray(r.targetWords)?r.targetWords:void 0,hintText:typeof r.hintText=="string"?r.hintText.trim():void 0}))}async function is(n,h){var C;const x=rs(h),t=await((C=zt().currentUser)==null?void 0:C.getIdToken());if(!t)throw new Error("AI_BUSY");const f=await fetch(ns,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({contents:[{role:"user",parts:[{text:n}]}],systemPrompt:x})});if(!f.ok)throw new Error("AI_BUSY");const r=await f.json();if(!r.text)throw new Error("AI_BUSY");try{return os(r.text)}catch{throw new Error("AI_BUSY")}}function as({open:n,mode:h,onClose:x,onImport:t}){const[f,r]=a.useState(""),[C,L]=a.useState(!1),[b,z]=a.useState(""),[k,R]=a.useState([]),[l,g]=a.useState(new Set),E=async()=>{if(f.trim())try{L(!0),z("");const y=await is(f.trim(),h);if(y.length===0){z("AI không sinh được câu nào phù hợp. Vui lòng thử lại với prompt khác.");return}R(y),g(new Set(y.map((T,S)=>S)))}catch{z("Hệ thống AI đang bận do nhiều người dùng, bạn vui lòng đợi chút hoặc tự nhập câu nhé 🙏")}finally{L(!1)}},W=y=>{g(T=>{const S=new Set(T);return S.has(y)?S.delete(y):S.add(y),S})},I=()=>{const y=k.filter((T,S)=>l.has(S));t(y),N()},N=()=>{r(""),R([]),g(new Set),z(""),x()};return e.jsxs(qe,{open:n,onClose:N,maxWidth:"sm",fullWidth:!0,children:[e.jsxs(Qe,{sx:{display:"flex",alignItems:"center",justifyContent:"space-between"},children:[e.jsxs(u,{sx:{display:"flex",alignItems:"center",gap:1},children:[e.jsx(we,{sx:{color:"#a78bfa"}}),e.jsx(w,{variant:"h6",children:"Gợi ý câu bằng AI"})]}),e.jsx(fe,{size:"small",onClick:N,children:e.jsx(dt,{})})]}),e.jsxs(Ke,{dividers:!0,children:[e.jsxs(w,{variant:"body2",color:"text.secondary",sx:{mb:2},children:["Nhập chủ đề/yêu cầu, AI sẽ sinh ra danh sách câu phù hợp",h==="find"?" và tự đánh dấu từ đúng":"","."," ","Viết yêu 
17cầu bằng ngôn ngữ nào thì câu sinh ra bằng ngôn ngữ đó (gõ tiếng Anh → câu tiếng Anh)."]}),e.jsx(je,{fullWidth:!0,multiline:!0,rows:2,placeholder:'Ví dụ: "câu về thủ đô các nước" hoặc "10 sentences using present simple, mark the verbs"',value:f,onChange:y=>r(y.target.value),sx:{mb:2}}),e.jsx(O,{variant:"contained",onClick:E,disabled:C||!f.trim(),startIcon:C?e.jsx(He,{size:18,color:"inherit"}):e.jsx(we,{}),sx:{background:"linear-gradient(135deg, #a78bfa, #7c3aed)"},children:C?"Đang sinh câu...":"Sinh câu"}),b&&e.jsx(Je,{severity:"warning",sx:{mt:2},children:b}),k.length>0&&e.jsxs(u,{sx:{mt:2},children:[e.jsxs(w,{variant:"subtitle2",sx:{mb:1},children:["Kết quả (",l.size,"/",k.length," đã chọn)"]}),e.jsx(u,{sx:{maxHeight:300,overflowY:"auto",border:"1px solid #e0e0e0",borderRadius:1},children:k.map((y,T)=>e.jsxs(u,{sx:{display:"flex",alignItems:"flex-start",p:1,borderBottom:T<k.length-1?"1px solid #f0f0f0":"none"},children:[e.jsx(Qt,{checked:l.has(T),onChange:()=>W(T),size:"small"}),e.jsxs(u,{sx:{flex:1,pt:.5},children:[e.jsx(w,{variant:"body2",children:y.sentence}),h==="find"&&(()=>{const S=y.sentence.trim().split(/\s+/).filter(Boolean),U=Xe(S,y.targetWords);return U.length>0?e.jsxs(w,{variant:"caption",color:"success.main",children:["Từ đúng: ",U.map(H=>S[H]).join(", ")]}):e.jsx(w,{variant:"caption",color:"warning.main",children:"Chưa xác định được từ đúng — cần tự chọn sau khi nhập"})})()]})]},T))})]})]}),e.jsxs(Ye,{sx:{px:3,py:2},children:[e.jsx(O,{onClick:N,children:"Hủy"}),e.jsxs(O,{variant:"contained",onClick:I,disabled:l.size===0,sx:{background:"linear-gradient(135deg, #a78bfa, #7c3aed)"},children:["Nhập ",l.size>0?`${l.size} câu`:""]})]})]})}const Y=100;function Se(n){return n.trim().split(/\s+/).filter(Boolean)}function ls(n){return!!n&&n.includes("$")}function be(n=""){return{sentence:n,words:Se(n),targetIndices:[],questionImage:"",questionImageSize:"m",fs:2,hintText:"",questionAudio:""}}const _e=["#fff3e0","#e3f2fd","#e8f5e9","#fce4ec","#f3e5f5","#fffde7","#e0f7fa","#f1f8e9"];function he({title:n,children:h}){return e.jsxs(ft,{elevation:0,sx:{p:2.5,mb:2.5,borderRadius:"12px",border:"1px solid #e0e0e0"},children:[e.jsx(w,{sx:{fontWeight:700,fontSize:"0.95rem",color:"#7c3aed",mb:2,textTransform:"uppercase",letterSpacing:"0.04em"},children:n}),h]})}function cs(n){return e.jsx(Bt,{children:e.jsx(ds,{...n})})}function ds({lessonId:n,onSaved:h,onCancel:x}){const{t}=ut("flyingWords"),{flushAll:f}=Dt(),{currentUser:r}=Ce(),C=ve(),{toasts:L,toast:b,removeToast:z}=Ge(),[k,R]=a.useState(""),[l,g]=a.useState("arrange"),[E,W]=a.useState(!1),[I,N]=a.useState(!0),[y,T]=a.useState(!0),[S,U]=a.useState(!1),[H,v]=a.useState("medium"),[B,Q]=a.useState(30),[A,V]=a.useState(4),[se,oe]=a.useState("#ffd700"),[p,D]=a.useState([]),[ie,ne]=a.useState(!1),[ae,J]=a.useState(""),[me,le]=a.useState(!1),[$,o]=a.useState([]),[j,K]=a.useState(new Map),X=a.useRef(0),{libraryPublish:M,setLibraryPublish:Z,uploadLimitReached:Ze}=_t(),[ce,de]=a.useState(null);a.useEffect(()=>{n&&n!=="new"?et():D([be()])},[n]),a.useEffect(()=>{if($.length!==p.length)if(p.length>$.length){const s=[],i=new Map(j);for(let c=$.length;c<p.length;c++){const m=X.current++;s.push(m),i.set(m,_e[Math.floor(Math.random()*_e.length)])}o([...$,...s]),K(i)}else o($.slice(0,p.length))},[p.length,$,j]);const et=async()=>{try{const s=await Tt(r.uid,n);R(s.title),g(s.mode||"arrange"),W(s.useCamera||!1),N(s.scoring??!0),T(s.bgMusicOn??!0),U(s.shuffleQuestions||!1),v(s.wordSpeed||"medium"),Q(s.timeLimit||30),V(s.globalAfs??4),oe(s.bgColor||"#ffd700"),D(s.questions||[]),de(s.publicLibraryId||null),Z({publish:!!s.publicLibraryId,level:s.libraryLevel||"",subject:s.librarySubject||"",grade:s.libraryGrade||""})}catch(s){J(t("messages.loadError")),console.error(s)}},tt=()=>{if(p.length>=Y){b.error(t("messages.maxQuestionsError",{max:Y}));return}D(s=>[...s,be()])},st=s=>{if(p.length===1){b.error(t("messages.minOneQuestionError"));return}D(p.filter((i,c)=>c!==s)),o($.filter((i,c)=>c!==s))},Ae=(s,i)=>{const c=s+i;
17if(c<0||c>=p.length)return;const m=[...p];[m[s],m[c]]=[m[c],m[s]],D(m);const d=[...$];[d[s],d[c]]=[d[c],d[s]],o(d)},pe=(s,i,c)=>{const m=[...p];m[s]={...m[s],[i]:c},D(m)},nt=(s,i)=>{const c=Se(i),m=[...p];m[s]={...m[s],sentence:i,words:c,targetIndices:(m[s].targetIndices||[]).filter(d=>d<c.length)},D(m)},rt=(s,i)=>{const c=[...p],m=c[s].targetIndices||[];c[s]={...c[s],targetIndices:m.includes(i)?m.filter(d=>d!==i):[...m,i]},D(c)},ot=s=>{const i=Y-p.length,c=s.slice(0,i).map(d=>{var P;const _=Se(d.sentence),F=l==="find"?Xe(_,d.targetWords):[];return{...be(d.sentence),targetIndices:F,hintText:((P=d.hintText)==null?void 0:P.trim())||""}});D(d=>{var F;return[...d.length===1&&!((F=d[0].sentence)!=null&&F.trim())?[]:d,...c]});const m=l==="find"?c.filter(d=>d.targetIndices.length===0).length:0;m>0?b.warning(t("messages.aiImportWarning",{total:c.length,unmatched:m})):b.success(t("messages.aiImportSuccess",{total:c.length}))},it=async()=>{var s;if(!B||Number(B)<7){b.error(t("messages.timeLimitError"));return}if(p.length===0){b.error(t("messages.minOneQuestionError"));return}for(let i=0;i<p.length;i++){const c=p[i];if(!((s=c.sentence)!=null&&s.trim())){b.error(t("messages.emptySentenceError",{num:i+1}));return}if(!c.words||c.words.length<2){b.error(t("messages.minWordsError",{num:i+1}));return}if(l==="find"&&(!c.targetIndices||c.targetIndices.length===0)){b.error(t("messages.targetWordRequiredError",{num:i+1}));return}}if(M.publish&&(!M.level||!M.subject||!M.grade)){b.error(t("messages.libraryFieldsRequired"));return}try{ne(!0),J("");let i=p;try{const P=await f();P.size>0&&(i=p.map((ke,lt)=>{const Te=P.get(`q-${lt}`);return Te?{...ke,questionAudio:Te}:ke}))}catch{J(t("messages.audioUploadError")),ne(!1);return}const c=k.trim()||gt(),m={title:c,mode:l,useCamera:E,scoring:I,bgMusicOn:y,shuffleQuestions:S,wordSpeed:H,timeLimit:B,globalAfs:A,bgColor:se,questions:i};let d=n;n==="new"?d=(await Et(r.uid,m)).id||"new":await Lt(r.uid,n,m);const _=qt["flying-words-game"],F=Wt(mt,..._.collectionPath(r.uid),d);if(!M.publish&&ce)try{await We(ce,F),de(null)}catch(P){console.error("Error unpublishing:",P)}if(M.publish&&d&&d!=="new")try{ce&&(await We(ce,F),de(null));const P=await Ht(r.uid,r.displayName||"",{id:d,featureId:"flying-words-game",data:m,title:c},{level:M.level,subject:M.subject,grade:M.grade},F);de(P)}catch(P){P.message!=="SNAPSHOT_TOO_LARGE"&&console.error("Error publishing to library:",P)}h?h():C("/flying-words-game")}catch(i){i.code==="LIMIT_REACHED"?(window.dispatchEvent(new CustomEvent("showUpgradeModal",{detail:{feature:"flyingWordsGame"}})),x?x():C("/flying-words-game")):b.error(i.message||t("messages.genericError"))}finally{ne(!1)}},at=()=>{x?x():C("/flying-words-game")};return e.jsxs(u,{sx:{p:3},children:[e.jsx(w,{variant:"h5",sx:{mb:3,fontWeight:"bold",color:"#a78bfa"},children:t(n==="new"?"form.newTitle":"form.editTitle")}),ae&&e.jsx(Je,{severity:"error",sx:{mb:2},children:ae}),e.jsx(he,{title:t("form.generalInfo"),children:e.jsxs(u,{sx:{display:"flex",gap:2,flexWrap:"wrap"},children:[e.jsx(je,{sx:{flex:"1 1 320px"},label:t("form.lessonTitle"),value:k,onChange:s=>R(s.target.value)}),e.jsx(je,{sx:{width:220},type:"number",label:t("form.timeLimitPerQuestion"),value:B,onChange:s=>{const i=s.target.value;Q(i===""?"":Number(i))},inputProps:{min:7}})]})}),e.jsxs(he,{title:t("form.gameplay"),children:[e.jsxs(u,{sx:{display:"flex",gap:4,flexWrap:"wrap",mb:2},children:[e.jsxs(re,{component:"fieldset",children:[e.jsx(ue,{component:"legend",sx:{fontWeight:"bold",color:"#333",mb:.5,fontSize:"0.9rem"},children:t("form.gameMode")}),e.jsxs(Fe,{row:!0,value:l,onChange:s=>g(s.target.value),children:[e.jsx(q,{value:"arrange",control:e.jsx(ee,{sx:{color:"#a78bfa","&.Mui-checked":{color:"#a78bfa"}}}),label:t("form.modeArrange")}),e.jsx(q,{value:"find",control:e.jsx(ee,{sx:{color:"#a78bfa","&.Mui-checked":{color:"#a78bfa"}}}),label:t("form.modeFind")})]})]}),e.jsxs(re,{component:"fieldset",children:[e.jsx(ue,{component:"legend",sx:{fontWeight:"bold",color:"#333",mb:.5,fontSize:"0.9rem"},children:t("form.wordSpeed")}),e.jsxs(Fe,{row:!0,value:H,onChange:s=>v(s.target.value),children:[e.jsx(q,{value:"veryslow",control:e.jsx(ee,{sx:{color:"#2196f3","&.Mui-checked":{color:"#2196f3"}}}),label:t("form.speedVerySlow")}),e.jsx(q,{value:"slow",control:e.jsx(ee,{sx:{color:"#4caf50","&.Mui-checked":{color:"#4caf50"}}}),label:t("form.speedSlow")}),e.jsx(q,{value:"medium",control:e.jsx(ee,{sx:{color:"#ff9800","&.Mui-checked":{color:"#ff9800"}}}),label:t("form.speedMedium")}),e.jsx(q,{value:"fast",control:e.jsx(ee,{sx:{color:"#f44336","&.Mu
17i-checked":{color:"#f44336"}}}),label:t("form.speedFast")})]})]})]}),e.jsxs(u,{sx:{display:"flex",gap:4,flexWrap:"wrap",mb:2},children:[e.jsxs(re,{sx:{minWidth:180},children:[e.jsx(ue,{sx:{fontWeight:"bold",color:"#333",mb:.5,fontSize:"0.9rem"},children:t("form.defaultCardFontSize")}),e.jsxs(Ee,{size:"small",value:A,onChange:s=>V(Number(s.target.value)),children:[e.jsx(G,{value:1,children:t("form.fontSizes.1")}),e.jsx(G,{value:2,children:t("form.fontSizes.2")}),e.jsx(G,{value:3,children:t("form.fontSizes.3")}),e.jsx(G,{value:4,children:t("form.fontSizes.4")}),e.jsx(G,{value:5,children:t("form.fontSizes.5")})]})]}),e.jsxs(re,{children:[e.jsx(ue,{sx:{fontWeight:"bold",color:"#333",mb:.5,fontSize:"0.9rem"},children:t("form.bgColor")}),e.jsxs(u,{sx:{display:"flex",alignItems:"center",gap:1},children:[e.jsx("input",{type:"color",value:se,onChange:s=>oe(s.target.value),style:{width:40,height:40,border:"none",borderRadius:8,cursor:"pointer",padding:0}}),e.jsx(w,{variant:"caption",color:"textSecondary",children:se})]})]})]}),e.jsxs(u,{sx:{display:"flex",flexDirection:"column",gap:.5},children:[e.jsxs(u,{sx:{display:"flex",gap:4,flexWrap:"wrap"},children:[e.jsx(q,{control:e.jsx(xe,{checked:E,onChange:s=>W(s.target.checked),sx:{"& .MuiSwitch-switchBase.Mui-checked":{color:"#a78bfa"},"& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track":{backgroundColor:"#a78bfa"}}}),label:e.jsx(w,{sx:{fontWeight:"bold",color:"#333",fontSize:"0.9rem"},children:t("form.cameraGesture")})}),e.jsx(q,{control:e.jsx(xe,{checked:I,onChange:s=>N(s.target.checked),sx:{"& .MuiSwitch-switchBase.Mui-checked":{color:"#43e97b"},"& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track":{backgroundColor:"#43e97b"}}}),label:e.jsx(w,{sx:{fontWeight:"bold",color:"#333",fontSize:"0.9rem"},children:t("form.scoring")})})]}),e.jsx(Ot,{checked:S,onChange:U}),e.jsx(q,{control:e.jsx(xe,{checked:y,onChange:s=>T(s.target.checked),sx:{"& .MuiSwitch-switchBase.Mui-checked":{color:"#ff9800"},"& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track":{backgroundColor:"#ff9800"}}}),label:e.jsx(w,{sx:{fontWeight:"bold",color:"#333",fontSize:"0.9rem"},children:t("form.bgMusic")})})]})]}),e.jsxs(he,{title:t("form.questionsList",{current:p.length,max:Y}),children:[e.jsxs(u,{sx:{display:"flex",flexDirection:"column",gap:2},children:[p.map((s,i)=>{var c,m;return e.jsxs(u,{sx:{border:"1.5px solid #e0e0e0",borderRadius:"12px",overflow:"hidden",background:j.get($[i])||"#fff",boxShadow:"0 1px 4px rgba(0,0,0,0.06)"},children:[e.jsxs(u,{sx:{display:"flex",justifyContent:"space-between",alignItems:"center",background:"rgba(0,0,0,0.04)",padding:"8px 14px",borderBottom:"1px solid rgba(0,0,0,0.06)"},children:[e.jsx(w,{sx:{fontWeight:700,fontSize:"0.85rem",color:"#555"},children:t("form.questionNum",{num:i+1})}),e.jsxs(u,{sx:{display:"flex",alignItems:"center"},children:[e.jsx(ge,{title:t("form.moveUp"),children:e.jsx("span",{children:e.jsx(fe,{size:"small",onClick:()=>Ae(i,-1),disabled:i===0,children:e.jsx(Kt,{fontSize:"small"})})})}),e.jsx(ge,{title:t("form.moveDown"),children:e.jsx("span",{children:e.jsx(fe,{size:"small",onClick:()=>Ae(i,1),disabled:i===p.length-1,children:e.jsx(Yt,{fontSize:"small"})})})}),e.jsx(ge,{title:t("form.deleteQuestion"),children:e.jsx(fe,{size:"small",onClick:()=>st(i),children:e.jsx(Vt,{fontSize:"small"})})})]})]}),e.jsxs(u,{sx:{p:"14px",display:"flex",flexDirection:"column",gap:1.25},children:[e.jsxs(u,{sx:{display:"flex",justifyContent:"space-between",alignItems:"center"},children:[e.jsx(w,{sx:{fontSize:"0.75rem",fontWeight:700,textTransform:"uppercase",letterSpacing:"0.06em",color:"#888"},children:t("form.completeSentenceAnswer")}),e.jsxs(u,{sx:{display:"flex",alignItems:"center",gap:1},children:[e.jsx($t,{value:s.questionAudio||"",onChange:d=>pe(i,"questionAudio",d),compact:!0,deferUpload:!0,slotId:`q-${i}`}),e.jsx(Jt,{fontSize:"small",color:"action"}),e.jsx(w,{variant:"caption",color:"text.secondary",children:t("form.hintFontSize")}),e.jsx(re,{size:"small",sx:{minWidth:90},children:e.jsxs(Ee,{value:s.fs||2,onChange:d=>pe(i,"fs",d.target.value),variant:"standard",children:[e.jsx(G,{value:1,children:t("form.fontSizes.1")}),e.jsx(G,{value:2,children:t("form.fontSizes.2")}),e.jsx(G,{value:3,children:t("form.fontSizes.3")}),e.jsx(G,{value:4,children:t("form.fontSizes.4")}),e.jsx(G,{value:5,children:t("form.fontSizes.5")})]})})]})]}),e.jsx(Me,{value:s.sentence,onChange:d=>nt(i,d),placeholder:t("form.sentencePlaceholder"),rows:2,size:"small",variant:"outlined"}),ls(s.sentence)&&e.jsx(w,{variant:"caption",sx:{color:"#7c3aed",display:"block",mt:-.5},children:e.jsxs(ht,{i18nKey:"form.mathFormulaHint",ns:"flyingWords",children:["Công thức Toán: mỗi công thức phải nằm gọn trong ",e.jsx("b",{children:"một từ"})," (câu được tách theo khoảng trắng) — viết ",e.jsx("code",{children:"$x^2$ $+$ $y^2$"})," (3 thẻ), không viết"," ",e.jsx("code",{children:"$x^2 + y^2$"})," (sẽ bị xé thành ",e.jsx("code",{children:"$x^2"}),", ",e.jsx("code",{children:"+"}),", ",e.jsx("code",{children:"y^2$"})," và hiện sai)."]})}),e.jsxs(u,{sx:{mt:.5}
17,children:[e.jsx(w,{variant:"caption",sx:{display:"block",color:"#666",mb:.5},children:t("form.hintLabel")}),e.jsx(Me,{value:s.hintText||"",onChange:d=>pe(i,"hintText",d),placeholder:t(l==="arrange"?"form.hintPlaceholderArrange":"form.hintPlaceholderFind"),rows:1,size:"small",variant:"outlined"})]}),l==="find"&&((c=s.words)==null?void 0:c.length)>0&&e.jsxs(u,{children:[e.jsx(w,{variant:"caption",sx:{display:"block",mb:.75,color:"#666"},children:t("form.findInstruction")}),e.jsx(u,{sx:{display:"flex",flexWrap:"wrap",gap:1},children:s.words.map((d,_)=>{const F=(s.targetIndices||[]).includes(_);return e.jsx(te,{label:e.jsx(ze,{content:d}),onClick:()=>rt(i,_),sx:{bgcolor:F?"#4caf50":"rgba(255,255,255,0.7)",color:F?"white":void 0,fontWeight:F?"bold":void 0,cursor:"pointer"},variant:F?"filled":"outlined"},_)})})]}),l==="arrange"&&((m=s.words)==null?void 0:m.length)>0&&e.jsxs(u,{children:[e.jsx(w,{variant:"caption",color:"text.secondary",sx:{display:"block",mb:.5},children:t("form.arrangeInstruction",{count:s.words.length})}),e.jsx(u,{sx:{display:"flex",flexWrap:"wrap",gap:.5,alignItems:"center"},children:s.words.map((d,_)=>e.jsxs(ct.Fragment,{children:[e.jsx(u,{sx:{px:1,py:.25,borderRadius:"999px",background:"rgba(124,58,237,0.1)",border:"1px solid rgba(124,58,237,0.3)",fontSize:"0.85rem"},children:e.jsx(ze,{content:d})}),_<s.words.length-1&&e.jsx(w,{variant:"caption",sx:{color:"#aaa"},children:"→"})]},_))})]})]})]},i)}),p.length>=Y&&e.jsx(w,{sx:{fontSize:"0.85rem",color:"#d32f2f"},children:t("form.maxQuestionsReached")})]}),e.jsxs(u,{sx:{display:"flex",gap:1,mt:2.5,flexWrap:"wrap"},children:[e.jsx(O,{onClick:()=>le(!0),disabled:p.length>=Y,variant:"contained",startIcon:e.jsx(we,{}),sx:{background:"linear-gradient(135deg, #a78bfa, #7c3aed)",fontWeight:"bold"},children:t("form.aiSuggest")}),e.jsx(O,{onClick:tt,disabled:p.length>=Y,variant:"outlined",startIcon:e.jsx(Xt,{}),sx:{borderColor:"#a78bfa",color:"#a78bfa",fontWeight:"bold"},children:t("form.addManualQuestion")})]})]}),e.jsx(he,{title:t("form.communityLibrary"),children:e.jsx(Gt,{value:M,onChange:Z,uploadLimitReached:Ze})}),e.jsxs(u,{sx:{display:"flex",gap:2,justifyContent:"flex-end"},children:[e.jsx(O,{variant:"outlined",onClick:at,children:t("form.cancel")}),e.jsx(O,{variant:"contained",onClick:it,disabled:ie,sx:{background:"linear-gradient(135deg, #a78bfa, #7c3aed)"},children:t(ie?"form.saving":"form.saveLesson")})]}),e.jsx(as,{open:me,mode:l,onClose:()=>le(!1),onImport:ot}),e.jsx(Nt,{toasts:L,removeToast:z})]})}function xn(){const n=ve(),h=pt(),{currentUser:x}=Ce(),{subscription:t}=xt(),[f,r]=a.useState("my-lessons"),[C,L]=a.useState(null),[b,z]=a.useState(0),[k,R]=a.useState(!1),[l,g]=a.useState(!1),[E,W]=a.useState("flyingWordsGame"),[I,N]=a.useState({allowed:!1,remaining:0,limit:5,currentCount:0});a.useEffect(()=>{const B=h.pathname.match(/\/flying-words-game\/(.+)\/edit/);B&&(L(B[1]),r("create"))},[h.pathname]),a.useEffect(()=>{const v=bt(t,"flyingWordsGame");N({allowed:v.canUse,remaining:v.remaining,limit:v.limit||5,currentCount:v.currentCount||0,unlimited:v.remaining===-1,level:v.level})},[t]),a.useEffect(()=>{const v=B=>{var Q;((Q=B.detail)==null?void 0:Q.feature)==="flyingWordsGame"&&g(!0)};return window.addEventListener("showUpgradeModal",v),()=>window.removeEventListener("showUpgradeModal",v)},[]);const y=()=>{z(v=>v+1),r("my-lessons"),L(null),n("/flying-words-game",{replace:!0})},T=()=>{r("my-lessons"),L(null),n("/flying-words-game",{replace:!0})},S=()=>{I.allowed?(L("new"),r("create"),n("/flying-words-game/new/edit",{replace:!0})):g(!0)},U=[{id:"my-lessons",icon:"📚",label:"Bài học của tôi",view:"my-lessons"},{id:"create",icon:"➕",label:"Tạo bài mới",view:"create"}],H=v=>{v.view==="create"?S():r(v.view)};return e.jsxs("div",{className:"flying-words-game-page",children:[e.jsx(yt,{}),e.jsxs("div",{className:"fw-container",children:[e.jsx(wt,{bugReportUrl:"https://docs.google.com/document/d/18pZYh3r19ndHbBSDMtZ5qa7ldQYGykc95pr0P2VCpu4/edit?tab=t.0",className:"fw-sidebar",title:"Từ Ngữ Biết Bay",subscriptionStatus:{mode:I.level,currentCount:I.currentCount,limit:I.limit},rawSub:t,featureKey:"flyingWordsGame",navItems:U,activeView:f,onNavClick:H,onUpgradeClick:()=>{W("flyingWordsGame"),g(!0)},upgradeLabel:"Nâng cấp",onHelpClick:()=>R(!0),helpLabel:"Hướng dẫn"}),e.jsxs("div",{className:"fw-content",children:[f==="my-lessons"&&e.jsx(ye.div,{initial:{opacity:0,x:20}
17,animate:{opacity:1,x:0},exit:{opacity:0,x:-20},transition:{duration:.3},children:e.jsx(ss,{refreshKey:b,onCreateNew:S},b)},"my-lessons"),f==="create"&&e.jsx(ye.div,{initial:{opacity:0,x:20},animate:{opacity:1,x:0},exit:{opacity:0,x:-20},transition:{duration:.3},children:e.jsx(cs,{lessonId:C||"new",onSaved:y,onCancel:T})},"create")]})]}),e.jsx(jt,{isOpen:k,onClose:()=>R(!1),videoId:"Wcz1AKUiE3A",title:"Hướng dẫn Từ Ngữ Biết Bay",description:"Hướng dẫn tạo và chơi trò chơi Từ Ngữ Biết Bay"}),e.jsx(Ve,{feature:E,open:l,onClose:()=>{g(!1),W("flyingWordsGame")}})]})}export{xn as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.