console.log('Carregando script militantes.js...'); // Constantes para responsabilidades const Militante = { RESPONSAVEL_FINANCAS: 256, RESPONSAVEL_IMPRENSA: 512, QUADRO_ORIENTADOR: 64, SECRETARIO: 1, TESOUREIRO: 2, IMPRENSA: 4, MNS: 8, MPS: 16, JUVENTUDE: 32, ASPIRANTE: 128 }; // Função para obter o token CSRF da meta tag function getCsrfToken() { const token = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); if (!token) { console.error('CSRF token não encontrado!'); return ''; } return token; } // Variáveis globais para controle dos filtros e paginação let filtroAtual = 'todos'; let filtroResponsabilidade = null; let filtroCelula = null; let currentPage = 1; let rowsPerPage = 20; let totalRows = 0; let buscarTexto = ''; // Mapa de responsabilidades para valores numéricos const RESPONSABILIDADES_MAP = { 'secretario': 1, 'tesoureiro': 2, 'imprensa': 4, 'mns': 8, 'mps': 16, 'juventude': 32, 'quadro-orientador': 64, 'aspirante': 128, 'responsavel-financas': 256, 'responsavel-imprensa': 512 }; // Mapa reverso para converter valores em nomes const RESPONSABILIDADES_REVERSE_MAP = { 1: 'Secretário', 2: 'Tesoureiro', 4: 'Imprensa', 8: 'MNS', 16: 'MPS', 32: 'Juventude', 64: 'Quadro-Orientador', 128: 'Aspirante', 256: 'Responsável de Finanças', 512: 'Responsável de Imprensa' }; // Função para validar data no formato DD/MM/YYYY function validarData(data) { if (!data) return true; // Campo vazio é válido console.log('Validando data:', data); // Verifica o formato if (!/^\d{2}\/\d{2}\/\d{4}$/.test(data)) { console.warn('Data com formato inválido (deve ser DD/MM/YYYY):', data); return false; } // Extrai dia, mês e ano const [dia, mes, ano] = data.split('/').map(Number); // Verifica se os valores são números válidos if (isNaN(dia) || isNaN(mes) || isNaN(ano)) { console.warn('Data contém valores não numéricos:', { dia, mes, ano }); return false; } // Verifica se os valores estão dentro dos limites if (mes < 1 || mes > 12) { console.warn('Mês inválido (deve estar entre 1 e 12):', mes); return false; } if (dia < 1 || dia > 31) { console.warn('Dia inválido (deve estar entre 1 e 31):', dia); return false; } if (ano < 1900 || ano > 2100) { console.warn('Ano fora do intervalo permitido (1900-2100):', ano); return false; } // Verifica meses com 30 dias if ([4, 6, 9, 11].includes(mes) && dia > 30) { console.warn(`Dia inválido para o mês ${mes} (máximo 30):`, dia); return false; } // Verifica fevereiro e ano bissexto if (mes === 2) { const bissexto = (ano % 4 === 0 && ano % 100 !== 0) || (ano % 400 === 0); const maxDias = bissexto ? 29 : 28; if (dia > maxDias) { console.warn(`Dia inválido para fevereiro ${bissexto ? '(bissexto)' : ''} (máximo ${maxDias}):`, dia); return false; } } // Verifica se a data não é futura const hoje = new Date(); const dataInformada = new Date(ano, mes - 1, dia); if (dataInformada > hoje) { console.warn('Data futura não permitida:', data); return false; } console.log('Data válida:', data); return true; } // Função para formatar data do formato ISO (YYYY-MM-DD) para DD/MM/YYYY function formatarData(data) { if (!data) { console.log('Data vazia, retornando string vazia'); return ''; } console.log('Formatando data:', data); // Se já estiver no formato DD/MM/YYYY, valida e retorna if (/^\d{2}\/\d{2}\/\d{4}$/.test(data)) { if (validarData(data)) { console.log('Data já está no formato correto e é válida:', data); return data; } else { console.warn('Data já está no formato DD/MM/YYYY mas é inválida:', data); return ''; } } try { // Tenta converter do formato ISO if (/^\d{4}-\d{2}-\d{2}$/.test(data)) { const [ano, mes, dia] = data.split('-'); const dataFormatada = `${dia}/${mes}/${ano}`; // Valida a data antes de retornar if (validarData(dataFormatada)) { console.log('Data ISO convertida com sucesso:', data, '->', dataFormatada); return dataFormatada; } else { console.warn('Data ISO inválida após formatação:', data, '->', dataFormatada); return ''; } } console.warn('Formato de data não reconhecido (deve ser YYYY-MM-DD ou DD/MM/YYYY):', data); return ''; } catch (error) { console.error('Erro ao formatar data:', error, 'Data:', data); return ''; } } // Função para converter data de DD/MM/YYYY para YYYY-MM-DD function converterDataParaISO(data) { if (!data) { console.log('Data vazia, retornando string vazia'); return ''; } console.log('Convertendo data para ISO:', data); // Se já estiver no formato ISO, valida e retorna if (/^\d{4}-\d{2}-\d{2}$/.test(data)) { const [ano, mes, dia] = data.split('-').map(Number); if (!isNaN(ano) && !isNaN(mes) && !isNaN(dia)) { console.log('Data já está no formato ISO:', data); return data; } else { console.warn('Data no formato ISO mas com valores inválidos:', data); return ''; } } try { // Verifica se está no formato DD/MM/YYYY if (/^\d{2}\/\d{2}\/\d{4}$/.test(data)) { // Valida a data antes de converter if (!validarData(data)) { console.warn('Data inválida antes da conversão para ISO:', data); return ''; } const [dia, mes, ano] = data.split('/'); const dataISO = `${ano}-${mes}-${dia}`; console.log('Data convertida para ISO com sucesso:', data, '->', dataISO); return dataISO; } console.warn('Formato de data não reconhecido (deve ser DD/MM/YYYY):', data); return ''; } catch (error) { console.error('Erro ao converter data para ISO:', error, 'Data:', data); return ''; } } // Função para calcular o total de páginas function calculateTotalPages() { const allRows = document.querySelectorAll('#militantesTable tbody tr'); const visibleRows = Array.from(allRows).filter(row => !row.hasAttribute('data-filtered-out') ); totalRows = visibleRows.length; return Math.ceil(totalRows / rowsPerPage); } // Função para atualizar o texto de contagem function updateCountText() { const allRows = document.querySelectorAll('#militantesTable tbody tr'); const visibleRows = Array.from(allRows).filter(row => !row.hasAttribute('data-filtered-out') ); totalRows = visibleRows.length; const startIndex = (currentPage - 1) * rowsPerPage + 1; const endIndex = Math.min(currentPage * rowsPerPage, totalRows); // Atualizar texto de contagem document.getElementById('countMilitantes').textContent = `${startIndex}-${endIndex} de ${totalRows}`; } // Função para atualizar a paginação function updatePagination() { const totalPages = calculateTotalPages(); const paginationUl = document.querySelector('.pagination'); const prevPage = document.getElementById('prevPage'); const nextPage = document.getElementById('nextPage'); // Limpar páginas existentes (exceto prev e next) const pageItems = paginationUl.querySelectorAll('li:not(#prevPage):not(#nextPage)'); pageItems.forEach(item => item.remove()); // Adicionar novas páginas for (let i = 1; i <= totalPages; i++) { const li = document.createElement('li'); li.className = `page-item${i === currentPage ? ' active' : ''}`; li.innerHTML = `${i}`; li.addEventListener('click', (e) => { e.preventDefault(); currentPage = i; updateVisibleRows(); updatePagination(); }); paginationUl.insertBefore(li, nextPage); } // Atualizar estado dos botões prev/next prevPage.classList.toggle('disabled', currentPage === 1); nextPage.classList.toggle('disabled', currentPage === totalPages || totalPages === 0); // Adicionar eventos aos botões prev/next prevPage.onclick = (e) => { e.preventDefault(); if (currentPage > 1) { currentPage--; updateVisibleRows(); updatePagination(); } }; nextPage.onclick = (e) => { e.preventDefault(); if (currentPage < totalPages) { currentPage++; updateVisibleRows(); updatePagination(); } }; // Atualizar texto de contagem updateCountText(); } // Função para atualizar as linhas visíveis function updateVisibleRows() { const allRows = document.querySelectorAll('#militantesTable tbody tr'); const visibleRows = Array.from(allRows).filter(row => !row.hasAttribute('data-filtered-out') ); const startIndex = (currentPage - 1) * rowsPerPage; const endIndex = startIndex + rowsPerPage; visibleRows.forEach((row, index) => { if (index >= startIndex && index < endIndex) { row.style.display = ''; } else { row.style.display = 'none'; } }); updateCountText(); } // Função para atualizar a contagem de militantes visíveis function atualizarContagem() { const allRows = document.querySelectorAll('#militantesTable tbody tr'); const visibleRows = Array.from(allRows).filter(row => !row.hasAttribute('data-filtered-out')); // Atualizar o contador document.getElementById('countMilitantes').textContent = visibleRows.length; // Resetar paginação currentPage = 1; updateVisibleRows(); updatePagination(); } // Função para filtrar militantes function filtrarMilitantes() { console.log('Filtrando militantes...'); console.log('Filtro atual:', filtroAtual); console.log('Texto busca:', buscarTexto); console.log('Filtro responsabilidade:', filtroResponsabilidade); console.log('Filtro célula:', filtroCelula); const allRows = document.querySelectorAll('#militantesTable tbody tr'); allRows.forEach(row => { const nome = row.querySelector('[data-nome]')?.getAttribute('data-nome')?.toLowerCase() || ''; const cpf = row.querySelector('[data-cpf]')?.getAttribute('data-cpf')?.toLowerCase() || ''; const email = row.querySelector('[data-email]')?.getAttribute('data-email')?.toLowerCase() || ''; const telefone = row.querySelector('[data-telefone]')?.getAttribute('data-telefone')?.toLowerCase() || ''; // Filtro de texto const matchesSearch = buscarTexto === '' || nome.includes(buscarTexto) || cpf.includes(buscarTexto) || email.includes(buscarTexto) || telefone.includes(buscarTexto); // Filtro de responsabilidades let matchesResponsabilidade = true; if (filtroResponsabilidade) { const valorResponsabilidade = RESPONSABILIDADES_MAP[filtroResponsabilidade]; console.log('Valor da responsabilidade:', valorResponsabilidade); if (valorResponsabilidade !== undefined) { const responsabilidades = parseInt(row.getAttribute('data-responsabilidades') || '0'); console.log('Responsabilidades do militante:', responsabilidades); matchesResponsabilidade = (responsabilidades & valorResponsabilidade) !== 0; console.log('Matches responsabilidade:', matchesResponsabilidade); } } // Filtro de célula let matchesCelula = true; if (filtroCelula) { const celulaId = row.getAttribute('data-celula-id'); console.log('Célula do militante:', celulaId, 'Filtro:', filtroCelula); matchesCelula = celulaId === filtroCelula; console.log('Matches célula:', matchesCelula); } // Aplicar filtros if (matchesSearch && matchesResponsabilidade && matchesCelula) { row.removeAttribute('data-filtered-out'); row.style.display = ''; } else { row.setAttribute('data-filtered-out', ''); row.style.display = 'none'; } }); // Atualizar contagem e paginação atualizarContagem(); } // Listener para o campo de busca com debounce let timeoutId; document.getElementById('searchInput').addEventListener('input', function(e) { clearTimeout(timeoutId); timeoutId = setTimeout(() => { buscarTexto = this.value.toLowerCase(); filtrarMilitantes(); }, 300); }); // Função para configurar um campo de data function configurarCampoData(campo) { if (!campo) return; // Remover campo de texto anterior se existir const campoTextoExistente = campo.previousElementSibling; if (campoTextoExistente && campoTextoExistente.classList.contains('campo-data-texto')) { campoTextoExistente.remove(); } // Configurar o campo de data campo.type = 'date'; // Se já tiver valor, garantir que está no formato ISO if (campo.value) { campo.value = converterDataParaISO(campo.value); } // Quando o valor mudar, garantir formato ISO campo.addEventListener('change', function() { if (this.value) { this.value = converterDataParaISO(this.value); } }); } // Função para carregar dados do militante async function carregarDadosMilitante(militanteId) { try { console.log('Carregando dados do militante:', militanteId); const response = await fetch(`/militantes/dados/${militanteId}`, { method: 'GET', headers: { 'X-Requested-With': 'XMLHttpRequest' } }); if (!response.ok) { throw new Error(`Erro ao carregar dados do militante: ${response.status} ${response.statusText}`); } const data = await response.json(); console.log('Dados recebidos do servidor:', data); if (data.status === 'error') { throw new Error(data.message || 'Erro ao carregar dados do militante'); } // Preencher campos do formulário com os dados do banco document.getElementById('edit_militante_id').value = militanteId; document.getElementById('edit_nome').value = data.nome || ''; document.getElementById('edit_cpf').value = data.cpf || ''; document.getElementById('edit_titulo_eleitoral').value = data.titulo_eleitoral || ''; // Função auxiliar para tratar campo de data function tratarCampoData(campo, valor, nomeCampo) { if (!campo) { console.warn(`Campo ${nomeCampo} não encontrado no DOM`); return; } // Limpar campo e remover validações campo.value = ''; campo.classList.remove('is-invalid'); const feedback = campo.nextElementSibling; if (feedback && feedback.classList.contains('invalid-feedback')) { feedback.remove(); } if (!valor) { console.log(`${nomeCampo} não informada`); return; } try { console.log(`Formatando ${nomeCampo}:`, valor); const dataFormatada = formatarData(valor); if (validarData(dataFormatada)) { campo.value = dataFormatada; console.log(`${nomeCampo} formatada com sucesso:`, dataFormatada); } else { console.warn(`${nomeCampo} inválida após formatação:`, valor); campo.classList.add('is-invalid'); const div = document.createElement('div'); div.className = 'invalid-feedback'; div.textContent = 'Data inválida'; campo.parentNode.insertBefore(div, campo.nextSibling); } } catch (error) { console.error(`Erro ao formatar ${nomeCampo}:`, error); campo.classList.add('is-invalid'); const div = document.createElement('div'); div.className = 'invalid-feedback'; div.textContent = 'Erro ao formatar data'; campo.parentNode.insertBefore(div, campo.nextSibling); } } // Tratar campos de data tratarCampoData( document.getElementById('edit_data_nascimento'), data.data_nascimento, 'Data de Nascimento' ); tratarCampoData( document.getElementById('edit_data_entrada_oci'), data.data_entrada_oci, 'Data de Entrada na OCI' ); tratarCampoData( document.getElementById('edit_data_efetivacao_oci'), data.data_efetivacao_oci, 'Data de Efetivação na OCI' ); // Preencher outros campos document.getElementById('edit_email').value = data.emails?.[0] || ''; document.getElementById('edit_telefone1').value = data.telefone1 || ''; // Setar célula const selectCelula = document.getElementById('edit_celula'); if (selectCelula) { selectCelula.value = data.celula_id || ''; console.log('Célula definida:', data.celula_id); } else { console.warn('Seletor de célula não encontrado'); } // Setar responsabilidades const responsabilidadesValue = data.responsabilidades_valor || 0; document.getElementById('responsabilidades_values').value = responsabilidadesValue; console.log('Responsabilidades definidas:', responsabilidadesValue); // Atualizar badges de responsabilidades const badges = document.querySelectorAll('.badge-clickable'); badges.forEach(badge => { const valor = parseInt(badge.getAttribute('data-valor')); if (responsabilidadesValue & valor) { badge.classList.add('active'); const originalClass = badge.getAttribute('data-original-class'); if (originalClass) { badge.className = `badge badge-clickable active ${originalClass}`; } console.log('Badge ativada:', badge.getAttribute('title')); } else { badge.classList.remove('active'); const originalClass = badge.getAttribute('data-original-class'); if (originalClass) { badge.className = `badge badge-clickable ${originalClass}`; } } }); // Setar campos de sindicato ['sindicato', 'cargo_sindical', 'central_sindical'].forEach(campo => { const elemento = document.getElementById(campo); if (elemento) { elemento.value = data[campo] || ''; console.log(`Campo ${campo} definido:`, data[campo]); } }); // Setar checkbox de dirigente sindical const checkDirigente = document.getElementById('dirigente_sindical'); if (checkDirigente) { checkDirigente.checked = data.dirigente_sindical || false; console.log('Dirigente sindical:', data.dirigente_sindical); } // Atualizar título do modal const modalTitle = document.querySelector('#modalEditarMilitante .modal-title'); if (modalTitle) { modalTitle.innerHTML = `Editar ${data.nome}`; console.log('Título do modal atualizado'); } console.log('Dados carregados com sucesso'); } catch (error) { console.error('Erro ao carregar dados:', error); mostrarAlerta('danger', `Erro ao carregar dados do militante: ${error.message}`); } } // Função para mostrar alertas function mostrarAlerta(tipo, mensagem) { // Remover alertas existentes document.querySelectorAll('.alert').forEach(alert => alert.remove()); const alertDiv = document.createElement('div'); alertDiv.className = `alert alert-${tipo} alert-dismissible fade show`; alertDiv.role = 'alert'; alertDiv.style.marginBottom = '1rem'; alertDiv.innerHTML = ` ${mensagem} `; const container = document.querySelector('.container-fluid'); if (container) { container.insertBefore(alertDiv, container.firstChild); // Remover o alerta após 5 segundos setTimeout(() => { if (alertDiv && alertDiv.parentNode) { alertDiv.remove(); } }, 5000); } } // Configurar o token CSRF para todas as requisições AJAX $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", getCsrfToken()); } } }); // Configurar eventos quando o DOM estiver carregado document.addEventListener('DOMContentLoaded', function() { console.log('DOM carregado, configurando eventos...'); // Configurar seletor de linhas por página const rowsPerPageSelect = document.getElementById('rowsPerPage'); if (rowsPerPageSelect) { rowsPerPageSelect.addEventListener('change', function() { rowsPerPage = parseInt(this.value); currentPage = 1; updateVisibleRows(); updatePagination(); }); } // Configurar filtros document.querySelectorAll('.dropdown-item[data-filter]').forEach(item => { item.addEventListener('click', function(e) { e.preventDefault(); const filter = this.getAttribute('data-filter'); const dropdownButton = document.querySelector('.dropdown-toggle'); console.log('Filtro selecionado:', filter); if (filter === 'todos') { filtroResponsabilidade = null; filtroCelula = null; } else if (filter === 'celula') { filtroResponsabilidade = null; filtroCelula = this.getAttribute('data-celula'); console.log('Filtro por célula:', filtroCelula); } else { filtroResponsabilidade = filter; filtroCelula = null; console.log('Filtro por responsabilidade:', filtroResponsabilidade); } // Atualizar filtro atual filtroAtual = filter; // Atualizar texto do botão dropdownButton.innerHTML = `${this.textContent}`; // Aplicar filtros filtrarMilitantes(); }); }); console.log('Configurando modal de edição...'); // Configurar máscara para campos de data $('.date-mask').mask('00/00/0000', { placeholder: 'DD/MM/AAAA', clearIfNotMatch: true, translation: { 'placeholder': "DD/MM/AAAA" } }); // Validar campos de data quando perderem o foco $('.date-mask').on('blur', function() { const valor = $(this).val(); if (valor) { if (!validarData(valor)) { $(this).addClass('is-invalid'); if (!$(this).next('.invalid-feedback').length) { $(this).after('
Data inválida
'); } } else { $(this).removeClass('is-invalid'); $(this).next('.invalid-feedback').remove(); } } else { // Se o campo estiver vazio, remover validação $(this).removeClass('is-invalid'); $(this).next('.invalid-feedback').remove(); } }); // Impedir entrada de caracteres inválidos nos campos de data $('.date-mask').on('keypress', function(e) { const char = String.fromCharCode(e.which); if (!/[\d\/]/.test(char)) { e.preventDefault(); return false; } const valor = $(this).val(); if (valor.length === 10 && char !== '\b') { e.preventDefault(); return false; } }); // Limpar campos de data quando o valor for inválido $('.date-mask').on('input', function() { const valor = $(this).val(); if (valor && valor.length === 10 && !validarData(valor)) { $(this).val(''); $(this).addClass('is-invalid'); if (!$(this).next('.invalid-feedback').length) { $(this).after('
Data inválida
'); } } }); // Configurar campos de data em todos os modais const modalNovoMilitante = document.getElementById('modalNovoMilitante'); const modalEditarMilitante = document.getElementById('modalEditarMilitante'); // Configurar modal de edição if (modalEditarMilitante) { modalEditarMilitante.addEventListener('show.bs.modal', async function(event) { console.log('Modal de edição aberto'); const button = event.relatedTarget; if (!button) { console.error('Botão não encontrado'); mostrarAlerta('danger', 'Erro ao abrir modal: botão não encontrado'); return; } const militanteId = button.getAttribute('data-militante-id'); const militanteNome = button.getAttribute('data-militante-nome'); console.log('Dados do botão:', { militanteId, militanteNome }); if (!militanteId) { console.error('ID do militante não encontrado no botão'); mostrarAlerta('danger', 'Erro ao abrir modal: ID do militante não encontrado'); return; } // Atualizar título do modal const modalTitle = this.querySelector('.modal-title'); if (modalTitle) { modalTitle.innerHTML = `Editar ${militanteNome}`; } try { // Carregar dados do militante await carregarDadosMilitante(militanteId); } catch (error) { console.error('Erro ao carregar dados:', error); mostrarAlerta('danger', 'Erro ao carregar dados do militante'); } }); // Limpar dados quando o modal for fechado modalEditarMilitante.addEventListener('hidden.bs.modal', function() { // Limpar formulário const form = this.querySelector('form'); if (form) { form.reset(); } // Limpar campos hidden document.getElementById('edit_militante_id').value = ''; document.getElementById('responsabilidades_values').value = '0'; // Resetar badges this.querySelectorAll('.badge-clickable').forEach(badge => { badge.classList.remove('active'); const originalClass = badge.getAttribute('data-original-class'); if (originalClass) { badge.className = `badge badge-clickable ${originalClass}`; } }); // Limpar feedback de validação this.querySelectorAll('.is-invalid').forEach(campo => { campo.classList.remove('is-invalid'); }); this.querySelectorAll('.invalid-feedback').forEach(feedback => { feedback.remove(); }); }); } else { console.error('Modal de edição não encontrado!'); } // Ajustar o formulário de novo militante const formNovoMilitante = document.getElementById('formNovoMilitante'); if (formNovoMilitante) { formNovoMilitante.addEventListener('submit', function(e) { e.preventDefault(); // Validar todas as datas antes do envio const camposData = this.querySelectorAll('.date-mask'); let datasValidas = true; camposData.forEach(campo => { const valor = campo.value; if (valor && !validarData(valor)) { datasValidas = false; $(campo).addClass('is-invalid'); if (!$(campo).next('.invalid-feedback').length) { $(campo).after('
Data inválida
'); } } }); if (!datasValidas) { return; // Não envia o formulário se houver datas inválidas } // Converter datas para formato ISO antes do envio camposData.forEach(campo => { if (campo.value) { campo.value = converterDataParaISO(campo.value); } }); const formData = new FormData(this); fetch(this.action, { method: 'POST', headers: { 'X-Requested-With': 'XMLHttpRequest', 'X-CSRF-Token': getCsrfToken() }, body: formData }) .then(response => response.json()) .then(data => { if (data.status === 'success') { // Fechar o modal const modal = bootstrap.Modal.getInstance(modalNovoMilitante); modal.hide(); // Limpar o formulário formNovoMilitante.reset(); // Adicionar o novo militante à tabela const tbody = document.querySelector('#militantesTable tbody'); const tr = document.createElement('tr'); tr.setAttribute('data-militante', data.militante.id); tr.setAttribute('data-filiado', data.militante.filiado ? 'sim' : 'nao'); tr.innerHTML = ` ${data.militante.nome} ${data.militante.cpf} ${data.militante.emails && data.militante.emails.length > 0 ? data.militante.emails[0].endereco_email : ''} ${data.militante.telefone1} ${data.militante.filiado ? 'Sim' : 'Não'}
`; // Inserir no início da tabela tbody.insertBefore(tr, tbody.firstChild); // Atualizar contador const countElement = document.getElementById('countMilitantes'); countElement.textContent = parseInt(countElement.textContent) + 1; // Mostrar mensagem de sucesso const alertDiv = document.createElement('div'); alertDiv.className = 'alert alert-success alert-dismissible fade show'; alertDiv.innerHTML = ` ${data.message} `; document.querySelector('.container').insertBefore(alertDiv, document.querySelector('.container').firstChild); } else { // Mostrar erro const alertDiv = document.createElement('div'); alertDiv.className = 'alert alert-danger alert-dismissible fade show'; alertDiv.innerHTML = ` ${data.message} `; document.querySelector('.modal-body').insertBefore(alertDiv, formNovoMilitante); } }) .catch(error => { console.error('Erro:', error); // Mostrar erro genérico const alertDiv = document.createElement('div'); alertDiv.className = 'alert alert-danger alert-dismissible fade show'; alertDiv.innerHTML = ` Erro ao cadastrar militante. Tente novamente. `; document.querySelector('.modal-body').insertBefore(alertDiv, formNovoMilitante); }); }); } // Máscara para CPF const cpfInputs = document.querySelectorAll('input[name="cpf"]'); cpfInputs.forEach(input => { input.addEventListener('input', function(e) { let value = e.target.value.replace(/\D/g, ''); if (value.length <= 11) { value = value.replace(/(\d{3})(\d)/, '$1.$2'); value = value.replace(/(\d{3})(\d)/, '$1.$2'); value = value.replace(/(\d{3})(\d{1,2})$/, '$1-$2'); e.target.value = value; } }); }); // Máscara para telefone const telefoneInputs = document.querySelectorAll('input[name="telefone1"], input[name="telefone2"]'); telefoneInputs.forEach(input => { input.addEventListener('input', function(e) { let value = e.target.value.replace(/\D/g, ''); if (value.length <= 11) { value = value.replace(/(\d{2})(\d)/, '($1) $2'); value = value.replace(/(\d{4,5})(\d{4})$/, '$1-$2'); e.target.value = value; } }); }); // Configuração do modal de exclusão const deleteModal = document.getElementById('deleteModal'); if (deleteModal) { deleteModal.addEventListener('show.bs.modal', function(event) { const button = event.relatedTarget; const militanteId = button.getAttribute('data-militante-id'); const militanteNome = button.getAttribute('data-militante-nome'); document.getElementById('militanteNome').textContent = militanteNome; document.getElementById('deleteForm').action = `/militantes/excluir/${militanteId}`; }); } // Ordenação const headers = document.querySelectorAll('#militantesTable th[data-sort]'); headers.forEach(header => { header.addEventListener('click', function() { const column = this.getAttribute('data-sort'); const tbody = document.querySelector('#militantesTable tbody'); const rows = Array.from(tbody.querySelectorAll('tr')); const isAsc = !this.classList.contains('sort-asc'); // Remover classes de ordenação de todos os headers headers.forEach(h => { h.classList.remove('sort-asc', 'sort-desc'); h.querySelector('i').className = 'fas fa-sort'; }); // Adicionar classe de ordenação ao header clicado this.classList.add(isAsc ? 'sort-asc' : 'sort-desc'); this.querySelector('i').className = `fas fa-sort-${isAsc ? 'up' : 'down'}`; // Ordenar linhas rows.sort((a, b) => { const aVal = a.querySelector(`td[data-${column}]`).getAttribute(`data-${column}`); const bVal = b.querySelector(`td[data-${column}]`).getAttribute(`data-${column}`); return isAsc ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal); }); // Reposicionar linhas rows.forEach(row => tbody.appendChild(row)); }); }); // Exportar para CSV const btnExportar = document.getElementById('btnExportar'); if (btnExportar) { btnExportar.addEventListener('click', function() { const rows = document.querySelectorAll('#militantesTable tbody tr:not([style*="display: none"])'); const headers = ['Nome', 'CPF', 'Email', 'Telefone', 'Filiado']; let csv = headers.join(',') + '\n'; rows.forEach(row => { const cols = row.querySelectorAll('td'); const values = [ cols[0].textContent, cols[1].textContent, cols[2].textContent, cols[3].textContent, cols[4].textContent.trim() ].map(val => `"${val}"`); csv += values.join(',') + '\n'; }); const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.setAttribute('download', 'militantes.csv'); document.body.appendChild(link); link.click(); document.body.removeChild(link); }); } // Configurar máscaras de input // CEP const cepInputs = document.querySelectorAll('input[name="cep"]'); cepInputs.forEach(input => { input.addEventListener('input', function(e) { let value = e.target.value.replace(/\D/g, ''); if (value.length <= 8) { value = value.replace(/(\d{5})(\d)/, '$1-$2'); e.target.value = value; } }); // Buscar endereço pelo CEP input.addEventListener('blur', function(e) { const cep = e.target.value.replace(/\D/g, ''); if (cep.length === 8) { fetch(`https://viacep.com.br/ws/${cep}/json/`) .then(response => response.json()) .then(data => { if (!data.erro) { const form = input.closest('form'); form.querySelector('input[name="logradouro"]').value = data.logradouro; form.querySelector('input[name="bairro"]').value = data.bairro; form.querySelector('input[name="cidade"]').value = data.localidade; form.querySelector('select[name="estado"]').value = data.uf; } }); } }); }); // Título Eleitoral const tituloInputs = document.querySelectorAll('input[name="titulo_eleitoral"]'); tituloInputs.forEach(input => { input.addEventListener('input', function(e) { let value = e.target.value.replace(/\D/g, ''); if (value.length <= 12) { value = value.replace(/(\d{4})(\d)/, '$1 $2'); value = value.replace(/(\d{4})(\d)/, '$1 $2'); e.target.value = value; } }); }); // Inicializar tooltips do Bootstrap const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl, { placement: 'top', trigger: 'hover' }); }); // Inicializar paginação updateVisibleRows(); updatePagination(); }); // Função para atualizar o valor total das responsabilidades function atualizarValorResponsabilidades() { const badges = document.querySelectorAll('.badge-clickable.active'); let valorTotal = 0; badges.forEach(badge => { const valor = parseInt(badge.getAttribute('data-value')); if (!isNaN(valor)) { valorTotal |= valor; } }); const input = document.getElementById('responsabilidades_values'); if (input) { input.value = valorTotal; } return valorTotal; } // Função para salvar as alterações do militante async function salvarAlteracoesMilitante(militanteId) { try { const form = document.getElementById('formEditarMilitante'); const formData = new FormData(form); // Garantir que as datas estão no formato correto (YYYY-MM-DD) const dataNascimento = formData.get('data_nascimento'); const dataEntradaOci = formData.get('data_entrada_oci'); const dataEfetivacaoOci = formData.get('data_efetivacao_oci'); if (dataNascimento) formData.set('data_nascimento', converterDataParaISO(dataNascimento)); if (dataEntradaOci) formData.set('data_entrada_oci', converterDataParaISO(dataEntradaOci)); if (dataEfetivacaoOci) formData.set('data_efetivacao_oci', converterDataParaISO(dataEfetivacaoOci)); // Adicionar responsabilidades let responsabilidadesValor = 0; form.querySelectorAll('input[name="responsabilidades"]:checked').forEach(checkbox => { responsabilidadesValor |= parseInt(checkbox.value); }); formData.append('responsabilidades_valor', responsabilidadesValor); const response = await fetch(`/militantes/editar/${militanteId}`, { method: 'POST', body: formData, headers: { 'X-CSRFToken': getCsrfToken(), 'X-Requested-With': 'XMLHttpRequest' } }); const data = await response.json(); console.log('Resposta completa do servidor:', data); if (data.status === 'success') { mostrarAlerta('success', data.message); // Atualizar a linha na tabela console.log('Dados detalhados para atualizarLinhaMilitante:', JSON.stringify(data, null, 2)); atualizarLinhaMilitante(militanteId, data); console.log('Linha da tabela atualizada'); // Fechar o modal const modal = bootstrap.Modal.getInstance(document.getElementById('modalEditarMilitante')); if (modal) { modal.hide(); } } else { mostrarAlerta('danger', data.message || 'Erro ao salvar alterações'); } } catch (error) { console.error('Erro ao salvar alterações:', error); mostrarAlerta('danger', 'Erro ao salvar alterações. Por favor, tente novamente.'); } } // Função para atualizar linha do militante na tabela function atualizarLinhaMilitante(militanteId, dados) { console.log('Atualizando linha do militante:', militanteId, dados); const row = document.querySelector(`tr[data-militante="${militanteId}"]`); if (row) { // Atualizar dados básicos e seus atributos data-* const tdNome = row.querySelector('[data-nome]'); if (tdNome) { console.log('Atualizando nome:', dados.data.nome); tdNome.textContent = dados.data.nome; tdNome.setAttribute('data-nome', dados.data.nome); } const tdCpf = row.querySelector('[data-cpf]'); if (tdCpf) { console.log('Atualizando CPF:', dados.data.cpf); tdCpf.textContent = dados.data.cpf; tdCpf.setAttribute('data-cpf', dados.data.cpf); } const tdEmail = row.querySelector('[data-email]'); if (tdEmail) { const email = dados.data.emails && dados.data.emails.length > 0 ? dados.data.emails[0] : ''; console.log('Atualizando email:', email); tdEmail.textContent = email; tdEmail.setAttribute('data-email', email); } const tdTelefone = row.querySelector('[data-telefone]'); if (tdTelefone) { const telefone = dados.data.telefone1 || ''; console.log('Atualizando telefone:', telefone); tdTelefone.textContent = telefone; tdTelefone.setAttribute('data-telefone', telefone); } // Atualizar atributos para filtros console.log('Atualizando célula ID:', dados.data.celula_id); row.setAttribute('data-celula-id', dados.data.celula_id || ''); console.log('Atualizando responsabilidades:', dados.data.responsabilidades_valor); row.setAttribute('data-responsabilidades', dados.data.responsabilidades_valor || '0'); // Atualizar badges de responsabilidades const tdResponsabilidades = row.querySelector('td:nth-child(5)'); if (tdResponsabilidades) { console.log('Atualizando badges de responsabilidades'); tdResponsabilidades.innerHTML = gerarBadgesResponsabilidades(dados.data.responsabilidades_valor); } // Remover qualquer estado de filtro da linha row.removeAttribute('data-filtered-out'); row.style.display = ''; // Verificar se a linha deve estar visível com os filtros atuais const nome = row.querySelector('[data-nome]')?.getAttribute('data-nome')?.toLowerCase() || ''; const cpf = row.querySelector('[data-cpf]')?.getAttribute('data-cpf')?.toLowerCase() || ''; const email = row.querySelector('[data-email]')?.getAttribute('data-email')?.toLowerCase() || ''; const telefone = row.querySelector('[data-telefone]')?.getAttribute('data-telefone')?.toLowerCase() || ''; // Filtro de texto const matchesSearch = buscarTexto === '' || nome.includes(buscarTexto) || cpf.includes(buscarTexto) || email.includes(buscarTexto) || telefone.includes(buscarTexto); // Filtro de responsabilidades let matchesResponsabilidade = true; if (filtroResponsabilidade) { const valorResponsabilidade = RESPONSABILIDADES_MAP[filtroResponsabilidade]; if (valorResponsabilidade !== undefined) { const responsabilidades = parseInt(row.getAttribute('data-responsabilidades') || '0'); matchesResponsabilidade = (responsabilidades & valorResponsabilidade) !== 0; } } // Filtro de célula let matchesCelula = true; if (filtroCelula) { const celulaId = row.getAttribute('data-celula-id'); matchesCelula = celulaId === filtroCelula; } // Aplicar filtros mantendo a linha visível se corresponder aos critérios if (matchesSearch && matchesResponsabilidade && matchesCelula) { row.removeAttribute('data-filtered-out'); row.style.display = ''; } else { row.setAttribute('data-filtered-out', ''); row.style.display = 'none'; } // Atualizar a paginação sem recarregar a página updateVisibleRows(); updatePagination(); } } // Função para gerar HTML das badges de responsabilidades function gerarBadgesResponsabilidades(valor) { const badges = []; if (valor & RESPONSABILIDADES_MAP['responsavel-financas']) badges.push('RFI'); if (valor & RESPONSABILIDADES_MAP['responsavel-imprensa']) badges.push('RIM'); if (valor & RESPONSABILIDADES_MAP['quadro-orientador']) badges.push('QOR'); if (valor & RESPONSABILIDADES_MAP['secretario']) badges.push('SEC'); if (valor & RESPONSABILIDADES_MAP['tesoureiro']) badges.push('TES'); if (valor & RESPONSABILIDADES_MAP['imprensa']) badges.push('IMP'); if (valor & RESPONSABILIDADES_MAP['mns']) badges.push('MNS'); if (valor & RESPONSABILIDADES_MAP['mps']) badges.push('MPS'); if (valor & RESPONSABILIDADES_MAP['juventude']) badges.push('JUV'); if (valor & RESPONSABILIDADES_MAP['aspirante']) badges.push('ASP'); return badges.join(' '); } // Handler para o formulário de edição document.getElementById('formEditarMilitante').addEventListener('submit', async function(e) { e.preventDefault(); console.log('Iniciando envio do formulário de edição...'); // Função auxiliar para validar e converter data function validarEConverterData(campo, nomeCampo) { const valor = campo.value; console.log(`Validando ${nomeCampo}:`, valor); if (!valor) { console.log(`${nomeCampo} não informada`); return true; } if (!validarData(valor)) { console.warn(`${nomeCampo} inválida:`, valor); campo.classList.add('is-invalid'); if (!campo.nextElementSibling?.classList.contains('invalid-feedback')) { const div = document.createElement('div'); div.className = 'invalid-feedback'; div.textContent = 'Data inválida'; campo.parentNode.insertBefore(div, campo.nextSibling); } return false; } const dataISO = converterDataParaISO(valor); if (!dataISO) { console.warn(`Erro ao converter ${nomeCampo} para ISO:`, valor); campo.classList.add('is-invalid'); if (!campo.nextElementSibling?.classList.contains('invalid-feedback')) { const div = document.createElement('div'); div.className = 'invalid-feedback'; div.textContent = 'Erro ao converter data'; campo.parentNode.insertBefore(div, campo.nextSibling); } return false; } console.log(`${nomeCampo} validada e convertida:`, valor, '->', dataISO); return true; } // Validar todas as datas const camposData = { 'Data de Nascimento': document.getElementById('edit_data_nascimento'), 'Data de Entrada na OCI': document.getElementById('edit_data_entrada_oci'), 'Data de Efetivação na OCI': document.getElementById('edit_data_efetivacao_oci') }; let datasValidas = true; for (const [nome, campo] of Object.entries(camposData)) { if (campo && !validarEConverterData(campo, nome)) { datasValidas = false; } } if (!datasValidas) { console.warn('Formulário contém datas inválidas'); mostrarAlerta('danger', 'Por favor, corrija as datas inválidas antes de salvar.'); return; } // Validar sequência lógica das datas const dataNascimento = camposData['Data de Nascimento']?.value; const dataEntrada = camposData['Data de Entrada na OCI']?.value; const dataEfetivacao = camposData['Data de Efetivação na OCI']?.value; if (dataNascimento && dataEntrada) { const nascimento = new Date(converterDataParaISO(dataNascimento)); const entrada = new Date(converterDataParaISO(dataEntrada)); if (entrada < nascimento) { console.warn('Data de entrada anterior à data de nascimento'); mostrarAlerta('danger', 'A data de entrada na OCI não pode ser anterior à data de nascimento.'); return; } } if (dataEntrada && dataEfetivacao) { const entrada = new Date(converterDataParaISO(dataEntrada)); const efetivacao = new Date(converterDataParaISO(dataEfetivacao)); if (efetivacao < entrada) { console.warn('Data de efetivação anterior à data de entrada'); mostrarAlerta('danger', 'A data de efetivação não pode ser anterior à data de entrada na OCI.'); return; } } const militanteId = document.getElementById('edit_militante_id').value; console.log('ID do militante:', militanteId); const formData = new FormData(this); try { // Converter datas para formato ISO for (const [nome, campo] of Object.entries(camposData)) { if (campo?.value) { const dataISO = converterDataParaISO(campo.value); formData.set(campo.name, dataISO); console.log(`${nome} convertida para envio:`, campo.value, '->', dataISO); } } console.log('Enviando dados para o servidor...'); const response = await fetch(`/militantes/editar/${militanteId}`, { method: 'POST', headers: { 'X-Requested-With': 'XMLHttpRequest', 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') }, body: formData }); if (!response.ok) { throw new Error(`Erro ${response.status}: ${response.statusText}`); } const data = await response.json(); console.log('Resposta do servidor:', data); if (data.status === 'success') { // Atualizar linha na tabela console.log('Dados detalhados para atualizarLinhaMilitante:', JSON.stringify(data, null, 2)); atualizarLinhaMilitante(militanteId, data); console.log('Linha da tabela atualizada'); // Mostrar mensagem de sucesso mostrarAlerta('success', data.message); // Fechar modal const modal = bootstrap.Modal.getInstance(document.getElementById('modalEditarMilitante')); if (modal) { modal.hide(); console.log('Modal fechado'); } } else { console.warn('Erro retornado pelo servidor:', data.message); mostrarAlerta('danger', data.message || 'Erro ao salvar alterações'); } } catch (error) { console.error('Erro ao salvar alterações:', error); mostrarAlerta('danger', `Erro ao salvar alterações: ${error.message}`); } }); // Handler para clique nas badges de responsabilidade document.querySelectorAll('.badge-clickable').forEach(badge => { badge.addEventListener('click', function() { const valor = parseInt(this.getAttribute('data-valor')); const responsabilidadesInput = document.getElementById('responsabilidades_values'); let valorAtual = parseInt(responsabilidadesInput.value) || 0; if (this.classList.contains('active')) { // Remover responsabilidade valorAtual &= ~valor; // usando operador bitwise NOT e AND this.classList.remove('active'); const originalClass = this.getAttribute('data-original-class'); if (originalClass) { this.className = `badge badge-clickable ${originalClass}`; } } else { // Adicionar responsabilidade valorAtual |= valor; // usando operador bitwise OR this.classList.add('active'); const originalClass = this.getAttribute('data-original-class'); if (originalClass) { this.className = `badge badge-clickable active ${originalClass}`; } } responsabilidadesInput.value = valorAtual; }); });