function TrainingSignal() { const [missing,setMissing]=React.useState(false); const src=window.TRAINING_STUDIO_CONFIG?.backgroundGif; return
; } function TrainingStudio({user, available, onStart, running, summary, onBack}) { const [activity,setActivity]=React.useState('zeroError'); const [path,setPath]=React.useState([]); const [basket,setBasket]=React.useState([]); const [notice,setNotice]=React.useState(''); const [fusion,setFusion]=React.useState(null); const [count,setCount]=React.useState(1); const [catalog,setCatalog]=React.useState({f:[],m:[],d:[]}); const [loading,setLoading]=React.useState(false); const [error,setError]=React.useState(''); const [refresh,setRefresh]=React.useState(0); React.useEffect(()=>{ let masters=JSON.stringify(window.MasterSpecialties?.selected(user?.id)||[]); const update=event=>{if(String(event.detail?.userId)===String(user?.id)){ const next=JSON.stringify(window.MasterSpecialties?.selected(user?.id)||[]); if(next!==masters){masters=next;setRefresh(value=>value+1);setBasket([]);} }}; window.addEventListener('tb:student-personalization-updated',update); return ()=>window.removeEventListener('tb:student-personalization-updated',update); },[user?.id]); const availableRef=React.useRef(available); availableRef.current=available; const vm=window.MyProgressEngine.getMyProgressViewModel(user?.id || ''); const groups=vm.structureGroups; const roots=[ {...groups.completeIdea,id:'completeIdea',label:'Estructuras',items:[groups.important,...groups.completeIdea.items]}, {...groups.extraInformation,id:'extraInformation',label:'Extra information'}, {id:'fusion',label:'Fusion',items:window.SpecialTechniques.list().map(item=>({...item,topicIds:item.practiceTopicIds,percentLabel:window.MyProgressEngine.formatPercent(item.practiceTopicIds.reduce((sum,id)=>sum+window.MyProgressEngine.getTopicProgress(user?.id||'',id).percent,0)/item.practiceTopicIds.length)}))} ]; const current=path.reduce((parent,node)=>(parent?.items || roots).find(item=>item.id===node.id),null); const leaf=current && !current.items?.length ? current : null; const base=fusion?.base || leaf; const primary=base?.topicIds || []; const extra=fusion?.selected || []; const activities=[{id:'zeroError',label:'ZERO ERROR',note:'3 preguntas · cero errores'}, {id:'reaction',label:'REACTION',note:'Reacción y precisión'}, {id:'mirror',label:'Mirror Reflection',note:'Respuestas completas'}, {id:'alien',label:'Alien Contact',note:'Construye con figuras'}]; const labels={f:'Fácil',m:'Medio',d:'Difícil'}; React.useEffect(()=>{ let live=true; setError('');setCatalog({f:[],m:[],d:[]}); if(!base){setLoading(false);return;} setLoading(true); Promise.all(['f','m','d'].map(diff=>window.TrainingStudioCatalog.groups({activity,primary,extra,diff,userId:user?.id,available:(...args)=>availableRef.current(...args)}))) .then(results=>{if(!live)return;setCatalog({f:results[0].rows,m:results[1].rows,d:results[2].rows});if(results.some(r=>r.errors.length))setError('No se pudo cargar parte del material. Puedes reintentar.');}) .catch(()=>{if(live)setError('No se pudo cargar el material. Reintenta.');}) .finally(()=>{if(live)setLoading(false);}); return ()=>{live=false;}; },[activity,base?.id,extra.join('|'),user?.id,refresh]); const rows=Object.values(catalog).flat(); const related=window.TrainingStudioCatalog.related(rows,[...primary,...extra]); const choosingFusion=Boolean(fusion?.target && extra.length
No hay sets disponibles. El tema principal debe estar desbloqueado en Paso a paso.
}No hay ejercicios que compartan esta combinación de temas.
}>} {loading &&Buscando ejercicios…
}{error&&