fix(pre-matricula, types, db): fix pre-enrollment field editor and add max_score db column
Build and Deploy (Gitea) / build-and-deploy (push) Successful in 2m5s Details

This commit is contained in:
Sidney 2026-05-29 20:15:59 -03:00
parent 4f5c2e6c7f
commit b34b5bf523
4 changed files with 52 additions and 20 deletions

View File

@ -94,10 +94,14 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
};
const addField = async () => {
if (!newField.label.trim()) return;
let label = newField.label.trim();
if (newField.tipo === 'banner' && !label) {
label = 'Folder Promocional';
}
if (!label) return;
const campo = {
id: crypto.randomUUID(),
label: newField.label,
label: label,
tipo: newField.tipo,
placeholder: newField.placeholder,
obrigatorio: newField.obrigatorio,
@ -126,12 +130,17 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
};
const updateField = async (campo: PreMatriculaCampo) => {
let label = campo.label.trim();
if (campo.tipo === 'banner' && !label) {
label = 'Folder Promocional';
}
const updatedCampo = { ...campo, label };
try {
await fetch(`/api/prematricula/campos/${campo.id}`, {
method: 'PUT', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(campo)
body: JSON.stringify(updatedCampo)
});
setCampos(prev => prev.map(c => c.id === campo.id ? campo : c));
setCampos(prev => prev.map(c => c.id === campo.id ? updatedCampo : c));
setEditingCampo(null);
} catch (e) { console.error(e); }
};
@ -468,22 +477,22 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
<div className="col-span-2">
<label className="block text-[10px] font-bold text-slate-500 uppercase mb-1">Folder / Panfleto de Promoção (Banner)</label>
{newField.placeholder ? (
<div className="relative group border border-slate-200 rounded-xl overflow-hidden shadow-sm">
<img src={newField.placeholder} alt="Banner" className="w-full h-24 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">
<div className="relative group border border-slate-200 rounded-xl overflow-hidden shadow-sm flex justify-center items-center bg-slate-50">
<img src={newField.placeholder} alt="Banner" className="w-full max-h-[350px] object-contain rounded-xl" />
<div className="absolute inset-0 bg-slate-900/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center rounded-xl">
<button
type="button"
onClick={() => setNewField(prev => ({ ...prev, placeholder: '' }))}
className="px-3 py-1 bg-red-600 hover:bg-red-700 text-white text-[10px] font-bold rounded-lg transition-all"
className="px-3 py-1 bg-red-600 hover:bg-red-700 text-white text-[10px] font-bold rounded-lg transition-all shadow-md"
>
Remover Folder
</button>
</div>
</div>
) : (
<label className="flex flex-col items-center justify-center w-full h-24 border-2 border-slate-200 border-dashed rounded-xl cursor-pointer bg-white hover:bg-slate-50 border-slate-300 transition-all">
<label className="flex flex-col items-center justify-center w-full h-32 border-2 border-slate-200 border-dashed rounded-xl cursor-pointer bg-white hover:bg-slate-50 border-slate-300 transition-all">
<div className="flex flex-col items-center justify-center pt-3 pb-3">
<Upload className="w-6 h-6 text-slate-400 mb-1" />
<Upload className="w-6 h-6 text-slate-400 mb-1 animate-bounce" />
<p className="text-[10px] text-slate-500 font-bold">Upload do Folder/Flyer</p>
<p className="text-[8px] text-slate-400 mt-0.5">PNG, JPG ou WEBP até 10MB</p>
</div>
@ -648,22 +657,22 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
<div>
<label className="block text-[10px] font-bold text-slate-500 uppercase mb-1">Folder / Panfleto de Promoção (Banner)</label>
{editingCampo.placeholder ? (
<div className="relative group border border-slate-200 rounded-xl overflow-hidden shadow-sm">
<img src={editingCampo.placeholder} alt="Banner" className="w-full h-24 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">
<div className="relative group border border-slate-200 rounded-xl overflow-hidden shadow-sm flex justify-center items-center bg-slate-50">
<img src={editingCampo.placeholder} alt="Banner" className="w-full max-h-[350px] object-contain rounded-xl" />
<div className="absolute inset-0 bg-slate-900/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center rounded-xl">
<button
type="button"
onClick={() => setEditingCampo(prev => prev ? { ...prev, placeholder: '' } : null)}
className="px-3 py-1 bg-red-600 hover:bg-red-700 text-white text-[10px] font-bold rounded-lg transition-all"
className="px-3 py-1 bg-red-600 hover:bg-red-700 text-white text-[10px] font-bold rounded-lg transition-all shadow-md"
>
Remover Folder
</button>
</div>
</div>
) : (
<label className="flex flex-col items-center justify-center w-full h-24 border-2 border-slate-200 border-dashed rounded-xl cursor-pointer bg-slate-50 hover:bg-slate-100 border-slate-300 transition-all">
<label className="flex flex-col items-center justify-center w-full h-32 border-2 border-slate-200 border-dashed rounded-xl cursor-pointer bg-slate-50 hover:bg-slate-100 border-slate-300 transition-all">
<div className="flex flex-col items-center justify-center pt-3 pb-3">
<Upload className="w-6 h-6 text-slate-400 mb-1" />
<Upload className="w-6 h-6 text-slate-400 mb-1 animate-bounce" />
<p className="text-[10px] text-slate-500 font-bold">Upload do Folder/Flyer</p>
</div>
<input

View File

@ -68,7 +68,7 @@ const Sidebar: React.FC<SidebarProps> = ({ currentView, setView, user, logo, onL
{/* Mobile Toggle */}
<div className="md:hidden fixed top-0 left-0 right-0 bg-white border-b border-slate-200 p-4 flex justify-between items-center z-40">
<h1 className="text-xl font-bold text-indigo-600 flex items-center gap-2">
{logo ? <img src={logo} alt="Logo" className="h-8 w-8 rounded-full object-cover" /> : <BookOpen size={24} />}
{logo ? <img src={logo} alt="Logo" className="h-10 w-10 object-contain flex-shrink-0" /> : <BookOpen size={24} />}
<span>EduManager</span>
</h1>
<button onClick={toggleMobile} className="p-2 text-slate-600">
@ -93,11 +93,11 @@ const Sidebar: React.FC<SidebarProps> = ({ currentView, setView, user, logo, onL
<div className={`p-6 border-b border-slate-200 flex items-center ${isCollapsed ? 'justify-center' : 'justify-between'}`}>
{(!isCollapsed || isMobileOpen) && (
<h1 className="text-xl font-bold text-indigo-600 flex items-center gap-2 overflow-hidden whitespace-nowrap">
{logo ? <img src={logo} alt="Logo" className="h-8 w-8 rounded-full object-cover flex-shrink-0" /> : <BookOpen size={24} className="flex-shrink-0" />}
{logo ? <img src={logo} alt="Logo" className="h-10 w-10 object-contain flex-shrink-0" /> : <BookOpen size={24} className="flex-shrink-0" />}
<span>EduManager</span>
</h1>
)}
{isCollapsed && !isMobileOpen && (logo ? <img src={logo} alt="Logo" className="h-8 w-8 rounded-full object-cover" /> : <BookOpen size={24} className="text-indigo-600" />)}
{isCollapsed && !isMobileOpen && (logo ? <img src={logo} alt="Logo" className="h-10 w-10 object-contain flex-shrink-0" /> : <BookOpen size={24} className="text-indigo-600" />)}
<button
onClick={() => setIsCollapsed(!isCollapsed)}

View File

@ -0,0 +1,23 @@
const { Pool } = require('pg');
const pool = new Pool({
host: '150.230.87.131',
port: 5432,
database: 'edumanager',
user: 'edumanager',
password: 'EduManager2026!Seguro',
ssl: false
});
async function runAlter() {
try {
console.log("Adicionando a coluna 'max_score' na tabela 'provas'...");
await pool.query("ALTER TABLE provas ADD COLUMN IF NOT EXISTS max_score NUMERIC DEFAULT 10.0");
console.log("Coluna 'max_score' adicionada com sucesso!");
} catch(e) {
console.error("Erro ao alterar tabela:", e.message);
} finally {
await pool.end();
}
}
runAlter();

View File

@ -261,7 +261,7 @@ export interface Exam {
export interface PreMatriculaCampo {
id: string;
label: string;
tipo: 'text' | 'email' | 'phone' | 'cpf' | 'date' | 'select' | 'textarea' | 'number';
tipo: 'text' | 'email' | 'phone' | 'cpf' | 'date' | 'select' | 'textarea' | 'number' | 'file' | 'banner';
placeholder?: string;
obrigatorio: boolean;
opcoes?: string[];