# Melhorias em Filtros Financeiros e Cadastro - Changelog **Data de Implementação:** 19 de janeiro de 2026 **Branch:** dev ## 📋 Visão Geral Implementação de filtros avançados de data na página de Extrato Financeiro e validação obrigatória de foto de perfil no cadastro de profissionais, visando melhorar o controle financeiro e a qualidade dos dados cadastrais. ## 🚀 Funcionalidades Implementadas ### 1. Sistema de Filtros Avançados de Data - Extrato Financeiro **Objetivo:** Fornecer controle granular sobre visualização de transações financeiras **Implementações:** - ✅ Filtro de data de início para definir período inicial - ✅ Filtro de data final para definir período final - ✅ Opção para incluir/excluir finais de semana - ✅ Painel expansível/recolhível para organização da interface - ✅ Botão de limpeza rápida de filtros - ✅ Integração com filtros existentes (FOT, Evento, Serviço, etc.) **Funcionalidades:** - ✅ Painel de filtros com indicador visual (▶/▼) - ✅ Layout responsivo com grid para desktop - ✅ Cálculo automático de intervalos de datas - ✅ Exclusão automática de sábados e domingos quando desabilitado - ✅ Mensagem visual quando filtros estão ativos - ✅ Preservação de filtros de coluna existentes **Arquivos Modificados:** - `frontend/pages/Finance.tsx` ### 2. Validação Obrigatória de Foto de Perfil **Objetivo:** Garantir que todos os profissionais tenham foto de perfil cadastrada **Implementações:** **No Formulário (ProfessionalForm):** - ✅ Validação no `handleSubmit` antes do envio - ✅ Label atualizado com asterisco (*) indicando obrigatoriedade - ✅ Mensagem de erro clara: "A foto de perfil é obrigatória!" - ✅ Bloqueio do envio se foto não estiver presente **No Registro (ProfessionalRegister):** - ✅ Validação adicional antes do upload - ✅ Tratamento de erro específico para foto ausente - ✅ Upload obrigatório (não mais opcional) - ✅ Mensagem de erro: "A foto de perfil é obrigatória." **Arquivos Modificados:** - `frontend/components/ProfessionalForm.tsx` - `frontend/pages/ProfessionalRegister.tsx` ## 🔧 Detalhes Técnicos ### 1. Filtros Avançados de Data **Novos Estados Implementados:** ```typescript const [dateFilters, setDateFilters] = useState({ startDate: "", endDate: "", includeWeekends: true, }); const [showDateFilters, setShowDateFilters] = useState(false); ``` **Algoritmo de Filtragem:** ```typescript // Advanced date filters if (dateFilters.startDate || dateFilters.endDate || !dateFilters.includeWeekends) { result = result.filter(t => { // Parse date from dataRaw (YYYY-MM-DD) or data (DD/MM/YYYY) let dateToCheck: Date; if (t.dataRaw) { dateToCheck = new Date(t.dataRaw); } else { const parts = t.data.split('/'); if (parts.length === 3) { dateToCheck = new Date( parseInt(parts[2]), parseInt(parts[1]) - 1, parseInt(parts[0]) ); } else { return true; // Keep if can't parse } } // Check date range if (dateFilters.startDate) { const startDate = new Date(dateFilters.startDate); if (dateToCheck < startDate) return false; } if (dateFilters.endDate) { const endDate = new Date(dateFilters.endDate); endDate.setHours(23, 59, 59, 999); if (dateToCheck > endDate) return false; } // Check weekends if (!dateFilters.includeWeekends) { const dayOfWeek = dateToCheck.getDay(); if (dayOfWeek === 0 || dayOfWeek === 6) return false; } return true; }); } ``` **Lógica de Exclusão de Finais de Semana:** - `dayOfWeek === 0` → Domingo - `dayOfWeek === 6` → Sábado - Exclusão automática quando checkbox desmarcado **Interface de Usuário:** ```tsx
``` ### 2. Validação de Foto Obrigatória **Fluxo de Validação:** 1. **Formulário (ProfessionalForm.tsx):** ```typescript const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); // Validação de foto de perfil if (!formData.avatar) { alert("A foto de perfil é obrigatória!"); return; } // ... restante das validações }; ``` 2. **Upload (ProfessionalRegister.tsx):** ```typescript // Upload de Avatar (obrigatório) if (!professionalData.avatar) { throw new Error("A foto de perfil é obrigatória."); } try { console.log("Iniciando upload do avatar..."); const uploadRes = await getUploadURL( professionalData.avatar.name, professionalData.avatar.type ); if (uploadRes.error || !uploadRes.data) { throw new Error(uploadRes.error || "Erro ao obter URL de upload"); } await uploadFileToSignedUrl( uploadRes.data.upload_url, professionalData.avatar ); avatarUrl = uploadRes.data.public_url; console.log("Upload concluído. URL:", avatarUrl); } catch (err) { console.error("Erro no upload do avatar:", err); throw new Error( "Falha ao enviar foto de perfil: " + (err instanceof Error ? err.message : "Erro desconhecido") ); } ``` **Indicadores Visuais:** - Label com asterisco vermelho: "Foto de Perfil *" - Preview circular da foto com borda destacada (#B9CF33) - Botão de remoção (X) quando foto está carregada - Placeholder visual quando não há foto