feat(pre-matricula): add metadata preview image upload and deletion UI
Build and Deploy (Gitea) / build-and-deploy (push) Successful in 2m3s Details

This commit is contained in:
Sidney 2026-07-18 20:59:07 -03:00
parent a47f23d95a
commit e5e3c6d89e
1 changed files with 58 additions and 1 deletions

View File

@ -4,7 +4,7 @@ import {
Plus, Trash2, Save, Eye, EyeOff, Download, GripVertical, Link2, Plus, Trash2, Save, Eye, EyeOff, Download, GripVertical, Link2,
ClipboardPen, Copy, Check, ChevronDown, ChevronRight, Users, RefreshCw, ClipboardPen, Copy, Check, ChevronDown, ChevronRight, Users, RefreshCw,
FileText, X, Settings2, ArrowLeft, ExternalLink, AlertCircle, UserCheck, Edit, Upload, FileText, X, Settings2, ArrowLeft, ExternalLink, AlertCircle, UserCheck, Edit, Upload,
MessageSquare, Paperclip, Smile MessageSquare, Paperclip, Smile, Image
} from 'lucide-react'; } from 'lucide-react';
import { useDialog } from '../DialogContext'; import { useDialog } from '../DialogContext';
@ -502,6 +502,63 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
<textarea className="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:outline-none text-sm font-medium resize-none" rows={2} <textarea className="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:outline-none text-sm font-medium resize-none" rows={2}
value={config?.mensagemSucesso || ''} onChange={e => setConfig(prev => prev ? { ...prev, mensagemSucesso: e.target.value } : prev)} /> value={config?.mensagemSucesso || ''} onChange={e => setConfig(prev => prev ? { ...prev, mensagemSucesso: e.target.value } : prev)} />
</div> </div>
<div>
<label className="block text-[10px] font-bold text-slate-500 uppercase mb-1">Imagem de Pré-Visualização (WhatsApp/Social)</label>
<div className="space-y-3">
{config?.logoUrl ? (
<div className="relative group border border-slate-200 rounded-xl overflow-hidden bg-slate-50 p-2 flex items-center justify-between shadow-sm">
<div className="flex items-center gap-3">
<img src={config.logoUrl} alt="Preview" className="w-12 h-12 object-contain rounded-lg border border-slate-200 bg-white" />
<span className="text-[10px] text-slate-400 font-mono truncate max-w-[140px]" title={config.logoUrl}>
{config.logoUrl.split('/').pop()}
</span>
</div>
<button
type="button"
onClick={() => setConfig(prev => prev ? { ...prev, logoUrl: '' } : prev)}
className="p-2 bg-red-50 hover:bg-red-100 text-red-600 rounded-lg transition-colors"
title="Remover Imagem"
>
<Trash2 size={16} />
</button>
</div>
) : (
<div className="flex items-center justify-center border-2 border-dashed border-slate-200 hover:border-indigo-400 rounded-xl p-5 bg-slate-50 hover:bg-indigo-50/20 transition-all cursor-pointer relative">
<input
type="file"
accept="image/*"
className="absolute inset-0 opacity-0 cursor-pointer"
onChange={async (e) => {
const file = e.target.files?.[0];
if (!file) return;
const formData = new FormData();
formData.append('file', file);
try {
const res = await fetch('/api/prematricula/upload', {
method: 'POST',
body: formData
});
if (res.ok) {
const resData = await res.json();
setConfig(prev => prev ? { ...prev, logoUrl: resData.url } : prev);
showAlert('Sucesso', 'Imagem de visualização carregada!', 'success');
} else {
showAlert('Erro', 'Falha ao carregar imagem.', 'error');
}
} catch (err) {
showAlert('Erro', 'Erro de conexão ao enviar imagem.', 'error');
}
}}
/>
<div className="text-center space-y-1">
<Image size={24} className="mx-auto text-slate-400 animate-pulse" />
<p className="text-xs font-bold text-slate-600">Fazer Upload da Imagem</p>
<p className="text-[9px] text-slate-400">JPG, PNG ou WebP até 5MB</p>
</div>
</div>
)}
</div>
</div>
<button onClick={saveConfig} disabled={isSaving} <button onClick={saveConfig} disabled={isSaving}
className="w-full py-3 bg-indigo-600 text-white rounded-xl font-bold text-sm hover:bg-indigo-700 transition-all active:scale-95 flex items-center justify-center gap-2 disabled:opacity-50" className="w-full py-3 bg-indigo-600 text-white rounded-xl font-bold text-sm hover:bg-indigo-700 transition-all active:scale-95 flex items-center justify-center gap-2 disabled:opacity-50"
> >