feat(pre-matricula): add upload progress indicators for folder flyers and adjust backend compression to 1200px
Build and Deploy (Gitea) / build-and-deploy (push) Successful in 2m8s
Details
Build and Deploy (Gitea) / build-and-deploy (push) Successful in 2m8s
Details
This commit is contained in:
parent
ec903c4c9c
commit
14e12d2096
|
|
@ -54,6 +54,8 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
|
|||
const [showNewField, setShowNewField] = useState(false);
|
||||
const [newField, setNewField] = useState({ label: '', tipo: 'text', placeholder: '', obrigatorio: false, opcoes: '' });
|
||||
const [uploadProgress, setUploadProgress] = useState<number | null>(null);
|
||||
const [newBannerProgress, setNewBannerProgress] = useState<number | null>(null);
|
||||
const [editBannerProgress, setEditBannerProgress] = useState<number | null>(null);
|
||||
|
||||
const [showMassModal, setShowMassModal] = useState(false);
|
||||
const [targetType, setTargetType] = useState('todos');
|
||||
|
|
@ -672,6 +674,20 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : newBannerProgress !== null ? (
|
||||
<div className="border border-slate-200 rounded-xl p-5 bg-slate-50 flex flex-col items-center justify-center space-y-3 shadow-inner h-32">
|
||||
<RefreshCw size={20} className="animate-spin text-indigo-600" />
|
||||
<div className="text-center">
|
||||
<p className="text-[10px] font-bold text-slate-700">Enviando e compactando folder...</p>
|
||||
<p className="text-[9px] text-slate-400 font-bold mt-0.5">{newBannerProgress}% concluído</p>
|
||||
</div>
|
||||
<div className="w-full bg-slate-200 rounded-full h-1.5 overflow-hidden shadow-inner">
|
||||
<div
|
||||
className="bg-indigo-600 h-full rounded-full transition-all duration-300 ease-out"
|
||||
style={{ width: `${newBannerProgress}%` }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<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">
|
||||
|
|
@ -688,13 +704,38 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
|
|||
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 result = await res.json();
|
||||
setNewField(prev => ({ ...prev, placeholder: result.url }));
|
||||
|
||||
setNewBannerProgress(0);
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.upload.addEventListener('progress', (event) => {
|
||||
if (event.lengthComputable) {
|
||||
const percent = Math.round((event.loaded / event.total) * 100);
|
||||
setNewBannerProgress(percent);
|
||||
}
|
||||
} catch (err) { console.error(err); }
|
||||
});
|
||||
|
||||
xhr.addEventListener('load', () => {
|
||||
setNewBannerProgress(null);
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
try {
|
||||
const result = JSON.parse(xhr.responseText);
|
||||
setNewField(prev => ({ ...prev, placeholder: result.url }));
|
||||
} catch (err) {
|
||||
showAlert('Erro', 'Falha ao processar resposta do servidor.', 'error');
|
||||
}
|
||||
} else {
|
||||
showAlert('Erro', 'Falha ao carregar folder.', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener('error', () => {
|
||||
setNewBannerProgress(null);
|
||||
showAlert('Erro', 'Erro de conexão ao enviar folder.', 'error');
|
||||
});
|
||||
|
||||
xhr.open('POST', '/api/prematricula/upload');
|
||||
xhr.send(formData);
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
|
|
@ -852,6 +893,20 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : editBannerProgress !== null ? (
|
||||
<div className="border border-slate-200 rounded-xl p-5 bg-slate-50 flex flex-col items-center justify-center space-y-3 shadow-inner h-32">
|
||||
<RefreshCw size={20} className="animate-spin text-indigo-600" />
|
||||
<div className="text-center">
|
||||
<p className="text-[10px] font-bold text-slate-700">Enviando e compactando folder...</p>
|
||||
<p className="text-[9px] text-slate-400 font-bold mt-0.5">{editBannerProgress}% concluído</p>
|
||||
</div>
|
||||
<div className="w-full bg-slate-200 rounded-full h-1.5 overflow-hidden shadow-inner">
|
||||
<div
|
||||
className="bg-indigo-600 h-full rounded-full transition-all duration-300 ease-out"
|
||||
style={{ width: `${editBannerProgress}%` }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<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">
|
||||
|
|
@ -867,13 +922,38 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
|
|||
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 result = await res.json();
|
||||
setEditingCampo(prev => prev ? { ...prev, placeholder: result.url } : null);
|
||||
|
||||
setEditBannerProgress(0);
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.upload.addEventListener('progress', (event) => {
|
||||
if (event.lengthComputable) {
|
||||
const percent = Math.round((event.loaded / event.total) * 100);
|
||||
setEditBannerProgress(percent);
|
||||
}
|
||||
} catch (err) { console.error(err); }
|
||||
});
|
||||
|
||||
xhr.addEventListener('load', () => {
|
||||
setEditBannerProgress(null);
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
try {
|
||||
const result = JSON.parse(xhr.responseText);
|
||||
setEditingCampo(prev => prev ? { ...prev, placeholder: result.url } : null);
|
||||
} catch (err) {
|
||||
showAlert('Erro', 'Falha ao processar resposta do servidor.', 'error');
|
||||
}
|
||||
} else {
|
||||
showAlert('Erro', 'Falha ao carregar folder.', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener('error', () => {
|
||||
setEditBannerProgress(null);
|
||||
showAlert('Erro', 'Erro de conexão ao enviar folder.', 'error');
|
||||
});
|
||||
|
||||
xhr.open('POST', '/api/prematricula/upload');
|
||||
xhr.send(formData);
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
|
|
|
|||
|
|
@ -4265,7 +4265,7 @@ async function startServer() {
|
|||
if (contentType.startsWith('image/')) {
|
||||
try {
|
||||
fileBuffer = await sharp(req.file.buffer)
|
||||
.resize(600, 600, { fit: 'inside', withoutEnlargement: true })
|
||||
.resize(1200, 1200, { fit: 'inside', withoutEnlargement: true })
|
||||
.jpeg({ quality: 75, progressive: true })
|
||||
.toBuffer();
|
||||
contentType = 'image/jpeg';
|
||||
|
|
|
|||
Loading…
Reference in New Issue