style(prematricula): proportional banner flyer preview, larger public logo and documentation
Build and Deploy (Gitea) / build-and-deploy (push) Successful in 2m4s Details

This commit is contained in:
Sidney 2026-05-28 20:18:39 -03:00
parent 640604a5df
commit 95f469099c
4 changed files with 13 additions and 3 deletions

View File

@ -79,3 +79,5 @@
46. **Geração de Contratos Automáticos (Fase SQL-First)**: A geração de contratos no cadastro de alunos deve sincronizar diretamente no banco de dados com `POST /api/contratos` e manter fallbacks no `updateData`. Além disso, para evitar contratos duplicados acidentais, o checkbox `generateContract` deve ser desmarcado por padrão ao editar um aluno, mas marcado por padrão ao cadastrar um novo aluno. O checkbox de "Gerar Taxa" foi removido. 46. **Geração de Contratos Automáticos (Fase SQL-First)**: A geração de contratos no cadastro de alunos deve sincronizar diretamente no banco de dados com `POST /api/contratos` e manter fallbacks no `updateData`. Além disso, para evitar contratos duplicados acidentais, o checkbox `generateContract` deve ser desmarcado por padrão ao editar um aluno, mas marcado por padrão ao cadastrar um novo aluno. O checkbox de "Gerar Taxa" foi removido.
47. **Ficha de Frequência Geral (Roster de Turma) em PDF**: O botão de exportação de PDF na lista de alunos da turma no módulo Registro de Frequência do Manager deve exportar um relatório de frequência geral de todos os alunos ativos da turma, com a contagem total acumulada de presenças (P), faltas (F), justificadas (J) e porcentagem de frequência (%) de forma a bater perfeitamente com os dados exibidos na tela, evitando PDFs vazios ou em branco para datas sem aulas. 47. **Ficha de Frequência Geral (Roster de Turma) em PDF**: O botão de exportação de PDF na lista de alunos da turma no módulo Registro de Frequência do Manager deve exportar um relatório de frequência geral de todos os alunos ativos da turma, com a contagem total acumulada de presenças (P), faltas (F), justificadas (J) e porcentagem de frequência (%) de forma a bater perfeitamente com os dados exibidos na tela, evitando PDFs vazios ou em branco para datas sem aulas.
48. **Pré-Matrícula - Folder Promocional, Rascunho e Duplicatas**: O painel de administração permite que o administrador faça o upload de um folder/banner de promoção (flyer) que é salvo diretamente no bucket `prematriculas` do MinIO. Na página pública de pré-matrícula, se configurado, esse banner é renderizado de forma responsiva acima do formulário. Se o formulário estiver em modo rascunho (`draft`), a página pública oculta todas as turmas e exibe uma mensagem polida informando que todas as vagas estão lotadas e novas vagas abrirão em breve. Inscrições duplicadas são bloqueadas via validação por e-mail e telefone higienizado no backend.

View File

@ -68,3 +68,11 @@ Nesta sessão de trabalho, realizamos o "core" da transição do sistema EduMana
- **Sincronização Direta de Contratos (Manager)**: O fluxo de salvamento de matrículas foi aprimorado para disparar uma chamada de `POST /api/contratos` em tempo real ao salvar o aluno, escrevendo a emissão do contrato diretamente no PostgreSQL na VPS. - **Sincronização Direta de Contratos (Manager)**: O fluxo de salvamento de matrículas foi aprimorado para disparar uma chamada de `POST /api/contratos` em tempo real ao salvar o aluno, escrevendo a emissão do contrato diretamente no PostgreSQL na VPS.
- **Refinamento do Modal de Alunos (Manager)**: O checkbox "Gerar Taxa" foi inteiramente removido do modal de matrícula. O checkbox "Gerar Contrato Automático" agora vem selecionado (`true`) por padrão em novos cadastros e desmarcado (`false`) ao editar matrículas para prevenir duplicações acidentais. - **Refinamento do Modal de Alunos (Manager)**: O checkbox "Gerar Taxa" foi inteiramente removido do modal de matrícula. O checkbox "Gerar Contrato Automático" agora vem selecionado (`true`) por padrão em novos cadastros e desmarcado (`false`) ao editar matrículas para prevenir duplicações acidentais.
- **Relatório de Frequência Geral em PDF (Manager)**: Refatoração do exportador de PDF no módulo Registro de Frequência para gerar uma Ficha de Frequência Geral (Roster de todos os alunos ativos da turma, com contagem acumulada de presenças, faltas, justificativas e porcentagem de frequência de cada um) de modo a corresponder perfeitamente ao que o administrador visualiza na modal, eliminando downloads vazios. - **Relatório de Frequência Geral em PDF (Manager)**: Refatoração do exportador de PDF no módulo Registro de Frequência para gerar uma Ficha de Frequência Geral (Roster de todos os alunos ativos da turma, com contagem acumulada de presenças, faltas, justificativas e porcentagem de frequência de cada um) de modo a corresponder perfeitamente ao que o administrador visualiza na modal, eliminando downloads vazios.
### Fase 9: Endurecimento da Pré-Matrícula, Upload de Panfleto Promocional e Proteção contra Duplicatas
- **Upload de Folder Promocional (MinIO)**: Adição da coluna `banner_url` na tabela SQL `prematricula_config`. Criada a área de upload no painel do administrador para subir folders promocionais diretamente para a pasta `prematriculas` no MinIO Storage local, com pré-visualização em tempo real e remoção inteligente.
- **Renderização Pública Premium**: O folder promocional carregado pelo administrador é renderizado em destaque no topo do formulário público com cantos arredondados, limite de tamanho responsivo e sombras sutis.
- **Prevenção de Duplicatas e Spam**: Bloqueio de envios duplicados no backend comparando e-mail e telefone limpos de caracteres não-numéricos (para total equivalência).
- **Tratamento de Estado Rascunho (`draft`)**: Se a configuração estiver em rascunho, exibe automaticamente uma página informativa de "Vagas Lotadas - Novas vagas em breve" para proteger a integridade operacional antes do lançamento oficial.
- **Gestão de Campos Personalizados com Arquivos**: Implementação de tipo `file` para campos customizados no formulário do aluno, com upload assíncrono transparente via `FormData` e exibição em formato de hiperlink nos detalhes da inscrição para o administrador.

View File

@ -392,7 +392,7 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
<label className="block text-[10px] font-bold text-slate-500 uppercase mb-1">Folder / Panfleto de Promoção (Banner)</label> <label className="block text-[10px] font-bold text-slate-500 uppercase mb-1">Folder / Panfleto de Promoção (Banner)</label>
{config?.bannerUrl ? ( {config?.bannerUrl ? (
<div className="relative group border border-slate-200 rounded-xl overflow-hidden shadow-sm mb-3"> <div className="relative group border border-slate-200 rounded-xl overflow-hidden shadow-sm mb-3">
<img src={config.bannerUrl} alt="Banner" className="w-full h-32 object-cover" /> <img src={config.bannerUrl} alt="Banner" className="w-full h-auto max-h-96 object-contain bg-slate-50" />
<div className="absolute inset-0 bg-slate-900/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-2"> <div className="absolute inset-0 bg-slate-900/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-2">
<button <button
type="button" type="button"

View File

@ -79,7 +79,7 @@ function getPreMatriculaHTML(slug) {
body{font-family:'Inter',sans-serif;background:#f8fafc;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px} body{font-family:'Inter',sans-serif;background:#f8fafc;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px}
.container{max-width:640px;width:100%;background:#fff;border-radius:24px;box-shadow:0 25px 50px -12px rgba(0,0,0,.1);overflow:hidden} .container{max-width:640px;width:100%;background:#fff;border-radius:24px;box-shadow:0 25px 50px -12px rgba(0,0,0,.1);overflow:hidden}
.header{padding:40px 32px 24px;text-align:center} .header{padding:40px 32px 24px;text-align:center}
.header img{max-height:110px;margin:0 auto 24px;display:block} .header img{max-height:180px;max-width:280px;width:auto;height:auto;margin:0 auto 24px;display:block;object-fit:contain}
.header h1{font-size:28px;font-weight:900;color:#0f172a;margin-bottom:8px} .header h1{font-size:28px;font-weight:900;color:#0f172a;margin-bottom:8px}
.header p{font-size:14px;color:#64748b;line-height:1.6} .header p{font-size:14px;color:#64748b;line-height:1.6}
.form{padding:0 32px 32px} .form{padding:0 32px 32px}
@ -172,7 +172,7 @@ async function init(){
let html='<div class="top-bar"></div><div class="header">'; let html='<div class="top-bar"></div><div class="header">';
if(data.escola.logo)html+='<img src="'+data.escola.logo+'" alt="Logo">'; if(data.escola.logo)html+='<img src="'+data.escola.logo+'" alt="Logo">';
html+='<h1>'+c.titulo+'</h1><p>'+c.descricao+'</p></div>'; html+='<h1>'+c.titulo+'</h1><p>'+c.descricao+'</p></div>';
if(c.bannerUrl)html+='<div style="padding:0 32px 24px;text-align:center"><img src="'+c.bannerUrl+'" alt="Banner" style="width:100%;max-height:350px;object-fit:cover;border-radius:16px;box-shadow:0 4px 12px rgba(0,0,0,.05)"></div>'; if(c.bannerUrl)html+='<div style="padding:0 32px 24px;text-align:center"><img src="'+c.bannerUrl+'" alt="Banner" style="width:100%;height:auto;border-radius:16px;box-shadow:0 4px 12px rgba(0,0,0,.05);display:block;margin:0 auto"></div>';
html+='<form class="form" id="preForm" onsubmit="return submitForm(event)">'; html+='<form class="form" id="preForm" onsubmit="return submitForm(event)">';
// Render fields dynamically in their exact database order // Render fields dynamically in their exact database order