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
Build and Deploy (Gitea) / build-and-deploy (push) Successful in 2m5s
Details
This commit is contained in:
parent
4f5c2e6c7f
commit
b34b5bf523
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
@ -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[];
|
||||
|
|
|
|||
Loading…
Reference in New Issue