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 [showNewField, setShowNewField] = useState(false);
|
||||||
const [newField, setNewField] = useState({ label: '', tipo: 'text', placeholder: '', obrigatorio: false, opcoes: '' });
|
const [newField, setNewField] = useState({ label: '', tipo: 'text', placeholder: '', obrigatorio: false, opcoes: '' });
|
||||||
const [uploadProgress, setUploadProgress] = useState<number | null>(null);
|
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 [showMassModal, setShowMassModal] = useState(false);
|
||||||
const [targetType, setTargetType] = useState('todos');
|
const [targetType, setTargetType] = useState('todos');
|
||||||
|
|
@ -672,6 +674,20 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<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">
|
<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;
|
if (!file) return;
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
try {
|
|
||||||
const res = await fetch('/api/prematricula/upload', { method: 'POST', body: formData });
|
setNewBannerProgress(0);
|
||||||
if (res.ok) {
|
const xhr = new XMLHttpRequest();
|
||||||
const result = await res.json();
|
|
||||||
setNewField(prev => ({ ...prev, placeholder: result.url }));
|
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>
|
</label>
|
||||||
|
|
@ -852,6 +893,20 @@ const PreMatricula: React.FC<Props> = ({ data, onConvert }) => {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<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">
|
<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;
|
if (!file) return;
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
try {
|
|
||||||
const res = await fetch('/api/prematricula/upload', { method: 'POST', body: formData });
|
setEditBannerProgress(0);
|
||||||
if (res.ok) {
|
const xhr = new XMLHttpRequest();
|
||||||
const result = await res.json();
|
|
||||||
setEditingCampo(prev => prev ? { ...prev, placeholder: result.url } : null);
|
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>
|
</label>
|
||||||
|
|
|
||||||
|
|
@ -4265,7 +4265,7 @@ async function startServer() {
|
||||||
if (contentType.startsWith('image/')) {
|
if (contentType.startsWith('image/')) {
|
||||||
try {
|
try {
|
||||||
fileBuffer = await sharp(req.file.buffer)
|
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 })
|
.jpeg({ quality: 75, progressive: true })
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
contentType = 'image/jpeg';
|
contentType = 'image/jpeg';
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue