frontend: fix PublicProvaUpload

Signed-off-by: Rodrigo B. de Sousa Martins <rodrigo@martinsevieira.adv.br>
This commit is contained in:
Rodrigo B. de Sousa Martins committed 2025-05-26 13:08:32 -03:00
1 parent fe54b55af0
commit 59ea762227
1 file changed
+53 -10
+53 -10
View File
@@ -3,6 +3,8 @@ import { useNavigate } from 'react-router-dom';
import { useDropzone } from 'react-dropzone'; import { useDropzone } from 'react-dropzone';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
// Página pública: NÃO requer autenticação do usuário
export function ClientProvaUpload() { export function ClientProvaUpload() {
const [file, setFile] = useState<File | null>(null); const [file, setFile] = useState<File | null>(null);
const [uploading, setUploading] = useState(false); const [uploading, setUploading] = useState(false);
@@ -43,9 +45,31 @@ export function ClientProvaUpload() {
} }
}, []); }, []);
// Validação extra do arquivo antes do upload
function validateFile(file: File | null): string | null {
if (!file) return 'Nenhum arquivo selecionado.';
const allowedTypes = [
'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'application/pdf'
];
if (!allowedTypes.includes(file.type)) {
return 'Tipo de arquivo não suportado. Use JPG, PNG, GIF, WEBP ou PDF.';
}
if (file.size > 10 * 1024 * 1024) {
return 'Arquivo excede o tamanho máximo de 10MB.';
}
return null;
}
const onDrop = useCallback(async (acceptedFiles: File[]) => { const onDrop = useCallback(async (acceptedFiles: File[]) => {
if (acceptedFiles.length > 0) { if (acceptedFiles.length > 0) {
const selectedFile = acceptedFiles[0]; const selectedFile = acceptedFiles[0];
const validationError = validateFile(selectedFile);
if (validationError) {
toast.error(validationError);
setFile(null);
setFilePreview(null);
return;
}
setFile(selectedFile); setFile(selectedFile);
// Criar preview para imagens // Criar preview para imagens
@@ -77,6 +101,12 @@ export function ClientProvaUpload() {
toast.error('Por favor, selecione um arquivo primeiro'); toast.error('Por favor, selecione um arquivo primeiro');
return; return;
} }
// Validação extra antes do envio
const validationError = validateFile(file);
if (validationError) {
toast.error(validationError);
return;
}
setUploading(true); setUploading(true);
setUploadProgress(0); setUploadProgress(0);
@@ -120,7 +150,7 @@ export function ClientProvaUpload() {
// Adicionar timestamp preciso do cliente // Adicionar timestamp preciso do cliente
formData.append('client_timestamp', new Date().toISOString()); formData.append('client_timestamp', new Date().toISOString());
// Criar simulação de progresso // Simulação de progresso
const progressInterval = setInterval(() => { const progressInterval = setInterval(() => {
setUploadProgress(prev => { setUploadProgress(prev => {
if (prev >= 95) { if (prev >= 95) {
@@ -131,10 +161,18 @@ export function ClientProvaUpload() {
}); });
}, 300); }, 300);
const response = await fetch('/api/provas/upload', { // Upload sem autenticação (página pública)
method: 'POST', let response: Response;
body: formData, try {
}); response = await fetch('/api/provas/upload', {
method: 'POST',
body: formData,
});
} catch (networkError) {
clearInterval(progressInterval);
setUploadProgress(0);
throw new Error('Erro de conexão. Verifique sua internet e tente novamente.');
}
clearInterval(progressInterval); clearInterval(progressInterval);
setUploadProgress(100); setUploadProgress(100);
@@ -155,9 +193,14 @@ export function ClientProvaUpload() {
} }
// Ler o corpo da resposta // Ler o corpo da resposta
const result = await response.json(); let result: any;
try {
if (result.id) { result = await response.json();
} catch {
throw new Error('Resposta inesperada do servidor.');
}
if (result && result.id) {
toast.success('Arquivo enviado com sucesso!'); toast.success('Arquivo enviado com sucesso!');
// Navegar para a página de status // Navegar para a página de status
navigate(`/public/provas/status/${result.id}`); navigate(`/public/provas/status/${result.id}`);
@@ -165,10 +208,10 @@ export function ClientProvaUpload() {
throw new Error('ID do documento não encontrado na resposta'); throw new Error('ID do documento não encontrado na resposta');
} }
} catch (error) { } catch (error: any) {
console.error('Erro detalhado no upload:', error); console.error('Erro detalhado no upload:', error);
setError(error.message || 'Erro ao enviar arquivo. Por favor, tente novamente.'); setError(error.message || 'Erro ao enviar arquivo. Por favor, tente novamente.');
toast.error('Falha no upload: ' + error.message); toast.error('Falha no upload: ' + (error.message || 'Erro desconhecido'));
} finally { } finally {
setUploading(false); setUploading(false);
} }