ACESSO AO APLICATIVO

Escolha como deseja entrar.

O tipo de acesso é validado pela sua conta. Nenhuma senha fica salva no código do aplicativo.

⚙ Administração de treinos e backups Abrir ferramentas
ÁREA PROFISSIONAL

Olá, Re.

Acompanhe seus alunos e veja rapidamente o que precisa de atenção.

ACOMPANHAMENTO

Alunos e treinos

Execuções confirmadas, programas publicados e informações dos alunos vinculados.

Programas e indicadores

Inventário remoto por aluno e distribuição de execução por ficha.

Resumo profissional

Visão consolidada de execuções confirmadas e programas publicados.

TREINO

Programação coletiva para todos os alunos ativos do grupo.

Programação atual

Treinos publicados para o grupo.

Alunos do grupo

Consulte os alunos ativos vinculados ao grupo.

Histórico

Programações anteriores.

PERSONALIZADO

Selecione um aluno para acessar a prescrição individualizada.

Aluno Teste
Intermediário • Ativo

PERFORMANCE

Atletas e preparação física individual.

Nenhum atleta cadastrado nesta versão de teste.

Aluno Teste

V13.1.2 · GESTÃO DE ALUNOS

Alunos

Cadastre e convide novos alunos diretamente pelo aplicativo.

Alunos vinculados

Contas vinculadas ao seu perfil profissional.

Clique em Atualizar lista.

Avaliações

Relatórios e Evolução

MÍDIA DOS EXERCÍCIOS
Vídeos e GIFs

A biblioteca continua única. A mídia fica vinculada ao exercício, sem alterar Área → Nível → Padrão.

Exercícios

Biblioteca DUO • mesma base utilizada na montagem dos treinos.

Montagem de Treinos

Biblioteca DUO

Selecione a seção do treino e clique em + EXERCÍCIO para consultar a biblioteca completa, organizada por área, nível e padrão de movimento.

Aquecimento Geral → Aquecimento Específico → Blocos principais
Os exercícios serão adicionados à seção escolhida.

Treino A

Adicione, exclua ou reorganize blocos antes de publicar. Aquecimentos permanecem separados.
GESTÃO FINANCEIRA · V12

Planos e pagamentos Pix

Cadastre planos, atribua alunos e confira os recebimentos manualmente no Mercado Pago.

Criar plano

Crie o QR Code/link no Mercado Pago com o valor correto. Nunca cole tokens, senhas ou chaves privadas aqui. Se o QR Code estiver apenas em uma imagem local, use o link de pagamento.

Vincular plano ao aluno

Planos cadastrados

Carregando...

Mensalidades e recebimentos

Marque como pago somente depois de conferir o recebimento na sua conta Mercado Pago. Esta versão não verifica pagamentos automaticamente.

Carregando...
RENILCE DIAS · TREINAMENTO FÍSICO & PERFORMANCE

Meu treinamento

Seu treino e sua evolução em um só lugar.

`); win.document.close(); } /* V10.4–10.8: ferramentas de gestão no painel, sem escrita remota. */ function dashboardFilter108(){ const q=(document.getElementById('dashboardSearch108')?.value||'').trim().toLocaleLowerCase('pt-BR'); const status=document.getElementById('dashboardStatus108')?.value||'all',now=Date.now(); document.querySelectorAll('[data-dashboard-index]').forEach(el=>{ const r=dashboardRows108[Number(el.dataset.dashboardIndex)]; if(!r)return; const latest=r.logs[0]?.completed_at; const age=latest?(now-new Date(latest).getTime())/86400000:null; const pass=status==='all'||(status==='none'&&age===null)|| (status==='recent'&&age!==null&&age<=7)|| (status==='week'&&age!==null&&age>7&&age<=14)|| (status==='late'&&age!==null&&age>14); el.hidden=!(r.name.toLocaleLowerCase('pt-BR').includes(q)&&pass); }); } function dashboardOpen108(i){ const r=dashboardRows108[i];if(!r)return; const select=document.getElementById('professionalStudent94'); const index=professionalLinks94.findIndex(x=>x.id===r.id); if(select&&index>=0){professionalOpenStudent96(index);return} professionalLoadStudents94().then(()=>{ const idx=professionalLinks94.findIndex(x=>x.id===r.id); if(idx>=0)professionalOpenStudent96(idx); else alert('Aluno não encontrado entre os vínculos ativos.'); }); } function programFilter108(q){ const term=String(q||'').trim().toLocaleLowerCase('pt-BR'); document.querySelectorAll('[data-program-index]').forEach(el=>{ const r=professionalProgramRows99[Number(el.dataset.programIndex)]; const programs=r?.state?.payload?.programs||[],workouts=r?.state?.payload?.workouts||[]; const text=[r?.name,...programs.map(x=>x.name||x.title||''),...workouts.map(x=>x.name||'')].join(' ').toLocaleLowerCase('pt-BR'); el.hidden=!text.includes(term); }); } function dashboardExport108(){ if(!dashboardRows108.length){alert('Atualize o dashboard primeiro.');return} const now=Date.now(),cut=now-28*86400000; const rows=[['Aluno','Última execução','Execuções (28 dias)','Programas publicados','Fichas não históricas','Fichas históricas']]; dashboardRows108.forEach(r=>{ const w=Array.isArray(r.payload.workouts)?r.payload.workouts:[],p=Array.isArray(r.payload.programs)?r.payload.programs:[]; const hist=w.filter(x=>String(x.status||'ATIVO').toUpperCase()==='HISTÓRICO').length; rows.push([r.name,r.logs[0]?.completed_at||'',r.logs.filter(x=>new Date(x.completed_at).getTime()>=cut).length,p.length,w.length-hist,hist]); }); const csv='\uFEFF'+rows.map(row=>row.map(professionalCSVCell10).join(';')).join('\r\n'); const blob=new Blob([csv],{type:'text/csv;charset=utf-8;'}),url=URL.createObjectURL(blob); const a=document.createElement('a');a.href=url;a.download='renilce_resumo_alunos_'+new Date().toISOString().slice(0,10)+'.csv'; document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),1000); } /* V11.1 — somente navegação visual. Mantém a cadeia de execução e Supabase. */ const studentAppTabBefore111=studentAppTab; studentAppTab=function(tab){ document.querySelectorAll('#studentNav11 [data-student-tab11]').forEach(b=>{ const active=b.dataset.studentTab11===String(tab||'inicio').toLowerCase(); b.classList.toggle('active11',active); if(active)b.setAttribute('aria-current','page');else b.removeAttribute('aria-current'); }); return studentAppTabBefore111(tab); }; const studentAppBefore111=studentApp; studentApp=function(){ const back=document.getElementById('studentReturn11'); if(back)back.style.display=authRoleV8==='student'?'none':''; return studentAppBefore111(); }; /* V11.2: página institucional do aluno. */ const studentAppTabBefore112=studentAppTab; studentAppTab=function(tab){ if(String(tab||'').toLowerCase()==='sobre'){ document.querySelectorAll('#studentNav11 [data-student-tab11]').forEach(b=>{const active=b.dataset.studentTab11==='sobre';b.classList.toggle('active11',active);if(active)b.setAttribute('aria-current','page');else b.removeAttribute('aria-current');}); const box=document.getElementById('studentAppBox');if(!box)return; box.innerHTML=`
CONHEÇA SUA TREINADORA

Renilce Dias

Treinamento Físico & Performance

Fundadora e responsável técnica do DUO Centro de Treinamento Integrado.

Movimento, força e evolução por meio de um treinamento estruturado e individualizado.
MINHA ATUAÇÃO

Treinamento com propósito

Atuo com treinamento físico e acompanhamento de pessoas com diferentes objetivos, respeitando suas necessidades e possibilidades de evolução.

DUO TREINAMENTO

Metodologia integrada

À frente do DUO, desenvolvo uma proposta que considera padrões de movimento, mobilidade, estabilidade, força e condicionamento físico.

ESTE APLICATIVO

Seu treinamento, onde você estiver

Este espaço organiza seus programas e fichas, facilita o registro das sessões e permite acompanhar sua evolução.

ACOMPANHE O DUO

DUO Centro de Treinamento Integrado

Treinamento Físico · Pilates · Fisioterapia · Liberação Miofascial · Nutrição

@duotreinamento ↗
`;return; } return studentAppTabBefore112(tab); }; /* V11.3: navegação enxuta. Recursos secundários ficam acessíveis em Perfil. */ const studentAppTabBefore113=studentAppTab; studentAppTab=function(tab){ const key=String(tab||'inicio').toLowerCase(); const selected=(key==='avaliacao'||key==='sobre')?'perfil':key; document.querySelectorAll('#studentNav11 [data-student-tab11]').forEach(b=>{ const active=b.dataset.studentTab11===selected; b.classList.toggle('active11',active); if(active)b.setAttribute('aria-current','page');else b.removeAttribute('aria-current'); }); if(key==='perfil'){ const result=studentAppTabBefore113(tab); const box=document.getElementById('studentAppBox'); if(box){ const menu=document.createElement('div');menu.className='student-secondary113 card'; menu.innerHTML='

Mais informações

Suas avaliações e informações sobre o acompanhamento.

'; box.prepend(menu); } return result; } if(key==='avaliacao')return studentAppTabBefore113(tab); if(key==='sobre'){ const result=studentAppTabBefore113(tab); const box=document.getElementById('studentAppBox'); if(box){const back=document.createElement('button');back.className='student-back113';back.textContent='← Voltar ao Perfil';back.onclick=()=>studentAppTab('perfil');box.prepend(back);} return result; } return studentAppTabBefore113(tab); }; const studentAppTabBefore114=studentAppTab; studentAppTab=function(tab){ if(String(tab||'').toLowerCase()!=='sobre')return studentAppTabBefore114(tab); document.querySelectorAll('#studentNav11 [data-student-tab11]').forEach(b=>{ const active=b.dataset.studentTab11==='perfil';b.classList.toggle('active11',active); if(active)b.setAttribute('aria-current','page');else b.removeAttribute('aria-current'); }); const box=document.getElementById('studentAppBox');if(!box)return; box.innerHTML=`

Renilce Dias

TREINAMENTO FÍSICO & PERFORMANCE

Fundadora do DUO Centro de Treinamento Integrado

SOBRE MIM

Profissional de Educação Física, fundadora do DUO Centro de Treinamento Integrado, com atuação voltada ao treinamento físico, qualidade do movimento, força, condicionamento e performance.

FORMAÇÃO

Graduação em Educação Física.

Pós-graduação em Exercício Físico para Grupos Especiais.

Pós-graduação em Lesões Musculoesqueléticas e Traumáticas — Prevenção e Reabilitação.

Cursos de Treinamento Físico Funcional, do básico ao avançado, e Preparação Física.

MINHA FORMA DE TRABALHAR

Treinamento construído a partir da avaliação, do movimento e da evolução individual, buscando desenvolver força, mobilidade, estabilidade, controle, condicionamento e performance.

`; }; /* V12 — Pix manual, authenticated Supabase only; no payment secrets in browser. */ const finEsc12=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); const finMoney12=v=>Number(v||0).toLocaleString('pt-BR',{style:'currency',currency:'BRL'}); const finUrl12=v=>{try{const u=new URL(String(v||''));return u.protocol==='https:'?u.href:''}catch(e){return ''}}; const finMsg12=t=>{let e=document.getElementById('finMsg12');if(e)e.textContent=t}; let finPlansCache12=[],finAssignCache12=[],finNamesCache121={}; async function finLoad12(){ if(authRoleV8!=='professional'||!authUserV8||!supaV8)return; finMsg12('Consultando dados financeiros...'); const [p,a,l]=await Promise.all([ supaV8.from('payment_plans').select('*').eq('professional_id',authUserV8.id).order('created_at',{ascending:false}), supaV8.from('student_plan_payments').select('*').eq('professional_id',authUserV8.id).order('created_at',{ascending:false}), supaV8.from('professional_student_links').select('student_id').eq('professional_id',authUserV8.id).eq('status','active') ]); if(p.error||a.error||l.error){finMsg12('Configure o SQL da V12 no Supabase. '+(p.error||a.error||l.error).message);return} finPlansCache12=p.data||[];finAssignCache12=a.data||[]; let ids=(l.data||[]).map(x=>x.student_id),names={}; if(ids.length){const pr=await supaV8.from('profiles').select('id,full_name').in('id',ids);if(!pr.error)(pr.data||[]).forEach(x=>names[x.id]=x.full_name)} finNamesCache121=names; const ps=document.getElementById('finPlan12'),st=document.getElementById('finStudent12'); ps.innerHTML=finPlansCache12.map(x=>``).join(''); st.innerHTML=ids.map(id=>``).join(''); document.getElementById('finPlans12').innerHTML=finPlansCache12.length?finPlansCache12.map(x=>`
${finEsc12(x.name)}
${finMoney12(x.amount)} · ${finEsc12(x.periodicity)}
${x.pix_link?'Pix cadastrado':'Sem link Pix'}
`).join(''):'Nenhum plano cadastrado.'; document.getElementById('finAssignments12').innerHTML=finAssignCache12.length?finAssignCache12.map(x=>{let plan=finPlansCache12.find(p=>p.id===x.plan_id);return `
${finEsc12(names[x.student_id]||'Aluno · '+x.student_id.slice(0,8))}
${finEsc12(plan?.name||'Plano')} · ${finMoney12(x.amount)} · vence ${finEsc12(x.due_date)}
${x.status==='paid'?(x.access_end_date?'Ativo até '+finEsc12(String(x.access_end_date).split('-').reverse().join('/')):'Pago (vigência não registrada)'):'Pendente'}
${x.status!=='paid'?``:''}
`}).join(''):'Nenhum plano atribuído.'; finMsg12('Dados atualizados.'); } async function finCreate12(){ if(authRoleV8!=='professional'||!authUserV8)return; const name=document.getElementById('finName12').value.trim(),amount=Number(document.getElementById('finPrice12').value),pix=document.getElementById('finLink12').value.trim(),qr=document.getElementById('finQr12').value.trim(); if(!name||!Number.isFinite(amount)||amount<=0){finMsg12('Informe nome e valor válido.');return} if((pix&&!finUrl12(pix))||(qr&&!finUrl12(qr))){finMsg12('Use somente endereços HTTPS válidos.');return} const {error}=await supaV8.from('payment_plans').insert({professional_id:authUserV8.id,name,amount,periodicity:document.getElementById('finPeriod12').value,pix_link:pix||null,qr_image_url:qr||null}); if(error){finMsg12(error.message);return}document.getElementById('finName12').value='';document.getElementById('finPrice12').value='';finLoad12(); } async function finAssign12(){ if(authRoleV8!=='professional'||!authUserV8)return; const student_id=document.getElementById('finStudent12').value,plan_id=document.getElementById('finPlan12').value,due_date=document.getElementById('finDue12').value,plan=finPlansCache12.find(x=>x.id===plan_id); if(!student_id||!plan||!due_date){finMsg12('Escolha aluno, plano e vencimento.');return} const {error}=await supaV8.from('student_plan_payments').insert({professional_id:authUserV8.id,student_id,plan_id,amount:plan.amount,due_date,status:'pending'}); if(error){finMsg12(error.message);const m=document.getElementById('finAssignMsg121');if(m)m.textContent='Erro: '+error.message;return} const m=document.getElementById('finAssignMsg121');if(m)m.textContent='Plano atribuído com sucesso.'; await finLoad12(); if(m)m.textContent='Plano atribuído com sucesso.'; } async function finPaid12(id){ if(!authUserV8||!supaV8)return; if(!confirm('Confirmar o recebimento deste pagamento? A vigência do novo plano começará hoje.'))return; const {data,error}=await supaV8.rpc('professional_confirm_payment',{target_payment_id:id}); if(error){finMsg12('Não foi possível confirmar o recebimento: '+error.message);return} const row=Array.isArray(data)?data[0]:data; const end=row&&row.access_end_date?String(row.access_end_date).split('-').reverse().join('/'):''; await finLoad12(); finMsg12(end?'Recebimento confirmado. Treinos liberados até '+end+'.':'Recebimento confirmado e plano ativado.'); } async function finDeleteAssignment121(id){ if(authRoleV8!=='professional'||!authUserV8||!supaV8)return; const a=finAssignCache12.find(x=>x.id===id),name=a?(finNamesCache121[a.student_id]||'este aluno'):'este aluno'; if(!confirm('Excluir a atribuição financeira de '+name+'? Esta ação não exclui o plano cadastrado.'))return; const {error}=await supaV8.from('student_plan_payments').delete().eq('id',id).eq('professional_id',authUserV8.id); if(error){finMsg12('Não foi possível excluir o vínculo: '+error.message);return} finMsg12('Vínculo financeiro excluído.'); await finLoad12();finMsg12('Vínculo financeiro excluído.'); } async function finDeletePlan121(id){ if(authRoleV8!=='professional'||!authUserV8||!supaV8)return; const p=finPlansCache12.find(x=>x.id===id);if(!p)return; const linked=finAssignCache12.some(x=>x.plan_id===id); if(linked){finMsg12('O plano "'+p.name+'" está vinculado a aluno(s). Exclua primeiro os vínculos financeiros.');alert('Este plano está vinculado a aluno(s). Exclua primeiro os vínculos financeiros.');return} if(!confirm('Excluir definitivamente o plano "'+p.name+'"?'))return; const {error}=await supaV8.from('payment_plans').delete().eq('id',id).eq('professional_id',authUserV8.id); if(error){finMsg12('Não foi possível excluir o plano: '+error.message);return} await finLoad12();finMsg12('Plano excluído.'); } async function finStudentChoosePlan123(planId){ if(authRoleV8!=='student'||!authUserV8||!supaV8)return; if(!confirm('Deseja escolher este plano? Será gerada uma cobrança pendente para pagamento via Pix.'))return; const box=document.getElementById('studentAppBox'); const {data,error}=await supaV8.rpc('student_choose_payment_plan',{target_plan_id:planId}); if(error){ alert(error.message||'Não foi possível escolher o plano.'); return; } alert('Plano escolhido. Agora realize o pagamento via Pix e aguarde a confirmação da equipe.'); await finStudentView12(); } async function finStudentView12(){ const box=document.getElementById('studentAppBox');if(!box)return; if(authRoleV8!=='student'||!authUserV8||!supaV8){box.innerHTML='
Entre com seu acesso de aluno para visualizar seus pagamentos.
';return} box.innerHTML='
Carregando planos e pagamentos...
'; const [payRes,availableRes]=await Promise.all([ supaV8.from('student_plan_payments').select('id,plan_id,amount,due_date,status,paid_at,professional_id,access_start_date,access_end_date,created_at').eq('student_id',authUserV8.id).order('created_at',{ascending:false}), supaV8.rpc('student_available_payment_plans') ]); if(payRes.error){box.textContent='Não foi possível consultar seus pagamentos: '+payRes.error.message;return} if(availableRes.error){box.textContent='Não foi possível consultar os planos disponíveis: '+availableRes.error.message;return} const payments=payRes.data||[], available=availableRes.data||[], today=new Date().toISOString().slice(0,10); const plans={};available.forEach(p=>plans[p.id]=p); const missing=[...new Set(payments.map(x=>x.plan_id).filter(id=>!plans[id]))]; if(missing.length){ const old=await supaV8.from('payment_plans').select('id,name,periodicity,pix_link,qr_image_url,amount,professional_id').in('id',missing); if(!old.error)(old.data||[]).forEach(p=>plans[p.id]=p); } const activePayment=payments.find(x=>x.status==='paid'&&x.access_start_date&&x.access_end_date&&String(x.access_start_date)<=today&&String(x.access_end_date)>=today); const activePlanId=activePayment?activePayment.plan_id:null; const pendingPlanIds=new Set(payments.filter(x=>x.status==='pending').map(x=>x.plan_id)); const planCards=available.length?available.map(p=>{ const current=String(p.id)===String(activePlanId); const pending=pendingPlanIds.has(p.id); let label=current?'PLANO ATUAL':(pending?'ALTERAÇÃO / PAGAMENTO PENDENTE':(activePlanId?'QUERO MUDAR PARA ESTE PLANO':'ESCOLHER ESTE PLANO')); let disabled=current||pending; return `
${finEsc12(String(p.periodicity||'').toUpperCase())}

${finEsc12(p.name||'Plano')}

${finMoney12(p.amount)}

${current&&activePayment&&activePayment.access_end_date?``:''}
`; }).join(''):'
Nenhum plano disponível no momento.
'; const paymentCards=payments.length?payments.map(x=>{ let p=plans[x.plan_id]||{},link=finUrl12(p.pix_link),qr=finUrl12(p.qr_image_url); const isCurrent=activePayment&&String(activePayment.id)===String(x.id); return `
${isCurrent?'PLANO ATUAL':'PAGAMENTO'}

${finEsc12(p.name||'Plano')}

${finMoney12(x.amount)}

Vencimento: ${finEsc12(String(x.due_date||'').split('-').reverse().join('/'))}

${x.status==='paid'?(x.access_end_date?(isCurrent?'Plano ativo até ':'Vigência até ')+finEsc12(String(x.access_end_date).split('-').reverse().join('/')):'Pagamento confirmado'):'Pagamento pendente'}

${x.status!=='paid'?(link?`PAGAR COM PIX ↗`:'

Aguarde a disponibilização do link Pix.

')+(qr?`
QR Code Pix do plano
`:''):'

Recebimento registrado pela equipe.

'}
`; }).join(''):'
Você ainda não possui pagamentos registrados.
'; box.innerHTML=`

Escolha seu plano

${activePlanId?'Seu plano atual continua ativo até a confirmação de um novo pagamento. Você pode solicitar a mudança abaixo.':'Selecione o plano que deseja adquirir. Após o pagamento via Pix, a equipe confirmará o recebimento e sua vigência será liberada.'}

${planCards}

MEUS PAGAMENTOS

${paymentCards}`; } const studentAppTabBefore120=studentAppTab; studentAppTab=function(tab){if(tab==='pagamentos')return finStudentView12();return studentAppTabBefore120(tab)}; /* Acrescenta acesso no perfil sem modificar o conteúdo do perfil existente. */ const studentAppTabBefore120Profile=studentAppTab; studentAppTab=function(tab){ const result=studentAppTabBefore120Profile(tab); if(tab==='perfil'){const box=document.getElementById('studentAppBox');if(box){const b=document.createElement('div');b.className='card';b.innerHTML='

Meu plano

Consulte mensalidades, vencimentos e seu link Pix.

';box.appendChild(b)}} return result; }; async function studentFinancialAccess121(){ if(authRoleV8!=='student'||!authUserV8||!supaV8)return false; const {data,error}=await supaV8.rpc('student_has_active_access',{target_student_id:authUserV8.id}); return !error && data===true; } /* V12.2 — vigência financeira controla o acesso à aba Treinos. */ const studentAppTabBefore122=studentAppTab; studentAppTab=async function(tab){ if(tab==='treinos' && authRoleV8==='student' && authUserV8 && supaV8){ const {data,error}=await supaV8.rpc('student_has_active_access',{target_student_id:authUserV8.id}); if(error){alert('Não foi possível validar a vigência do plano. Tente novamente.');return} if(!data){ const box=document.getElementById('studentAppBox'); if(box)box.innerHTML=`

Treinos bloqueados

Seu plano não possui uma vigência ativa no momento.

Consulte Meu plano e pagamentos no Perfil ou fale com a equipe para renovar.

`; return; } } return studentAppTabBefore122(tab); }; /* V12.3.2 — confirmação financeira autoritativa via Supabase RPC. Este override é carregado por último para impedir que rotinas antigas marquem apenas status=paid sem criar a vigência. */ finPaid12=async function(id){ if(!authUserV8||!supaV8)return; if(!confirm('Confirmar o recebimento deste pagamento? A vigência do novo plano começará hoje.'))return; const {data,error}=await supaV8.rpc('professional_confirm_payment',{ target_payment_id:id }); if(error){ finMsg12('Não foi possível confirmar o recebimento: '+error.message); return; } const row=Array.isArray(data)?data[0]:data; if(!row || !row.access_start_date || !row.access_end_date){ finMsg12('A confirmação não retornou a vigência. O pagamento não deve ser considerado concluído no aplicativo.'); return; } await finLoad12(); finMsg12( 'Recebimento confirmado. Novo plano ativo de '+ String(row.access_start_date).split('-').reverse().join('/')+ ' até '+ String(row.access_end_date).split('-').reverse().join('/')+ '.' ); }; /* V12.3.3 — reorganização do menu do aluno */ (function(){ const prevStudentAppTab1233=studentAppTab; studentAppTab=async function(tab){ const key=String(tab||'inicio').toLowerCase(); if(key==='perfil'){ const result=await prevStudentAppTab1233(tab); const box=document.getElementById('studentAppBox'); if(box){ /* Remove apenas atalhos institucionais/financeiros adicionados ao Perfil. Os dados e controles pessoais do aluno permanecem intactos. */ box.querySelectorAll('button').forEach(function(btn){ const t=(btn.textContent||'').toLowerCase(); if(t.includes('sobre renilce') || t.includes('meu plano') || t.includes('pagamento')){ btn.remove(); } }); box.querySelectorAll('a').forEach(function(a){ const t=(a.textContent||'').toLowerCase(); if(t.includes('sobre renilce') || t.includes('meu plano') || t.includes('pagamento')){ a.remove(); } }); } return result; } if(key==='inicio'){ const result=await prevStudentAppTab1233(tab); const box=document.getElementById('studentAppBox'); if(box && !document.getElementById('studentAboutCard1233')){ const card=document.createElement('div'); card.id='studentAboutCard1233'; card.className='card'; card.style.marginTop='16px'; card.innerHTML='

Conheça Renilce Dias

Conheça minha formação, experiência e a proposta do Treinamento Físico & Performance.

'; box.appendChild(card); } return result; } return prevStudentAppTab1233(tab); }; })(); /* V12.3.4 — entrada separada Aluno / Professor */ let authEntryRole1234=null; function showLogin1234(role){ authEntryRole1234=role==='professional'?'professional':'student'; const choices=document.getElementById('authRoleChoice1234'); const form=document.getElementById('realLogin'); const label=document.getElementById('authSelectedRole1234'); if(choices)choices.style.display='none'; if(form)form.style.display='block'; if(label)label.textContent=authEntryRole1234==='professional'?'ACESSO DO PROFESSOR':'ACESSO DO ALUNO'; authMsgV8(''); setTimeout(()=>document.getElementById('authEmail')?.focus(),0); } function backLogin1234(){ authEntryRole1234=null; const choices=document.getElementById('authRoleChoice1234'); const form=document.getElementById('realLogin'); if(form)form.style.display='none'; if(choices)choices.style.display='grid'; const pw=document.getElementById('authPassword');if(pw)pw.value=''; authMsgV8(''); } /* A escolha visual deve corresponder ao role real retornado de public.profiles. Não altera nem concede role. */ const applySessionBefore1234=applySessionV8; applySessionV8=async function(user){ if(authEntryRole1234 && supaV8 && user){ const {data:profile,error}=await supaV8.from('profiles').select('role').eq('id',user.id).maybeSingle(); if(error || !profile){ await supaV8.auth.signOut(); authMsgV8('Não foi possível validar o tipo da sua conta.'); return; } if(profile.role!==authEntryRole1234){ await supaV8.auth.signOut(); authMsgV8(authEntryRole1234==='professional' ? 'Esta conta não possui acesso de professor. Escolha ENTRAR COMO ALUNO.' : 'Esta conta é de professor. Escolha ENTRAR COMO PROFESSOR.'); return; } } return applySessionBefore1234(user); };