2025-04-03 15:05:48 -03:00
|
|
|
console.log('Carregando script militantes.js...');
|
|
|
|
|
|
2025-04-09 09:59:12 -03:00
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-04 13:31:52 -03:00
|
|
|
// Variáveis globais para controle dos filtros e paginação
|
2025-04-04 09:49:06 -03:00
|
|
|
let filtroAtual = 'todos';
|
|
|
|
|
let filtroResponsabilidade = null;
|
|
|
|
|
let filtroCelula = null;
|
2025-04-04 13:31:52 -03:00
|
|
|
let currentPage = 1;
|
|
|
|
|
let rowsPerPage = 20;
|
|
|
|
|
let totalRows = 0;
|
2025-04-09 09:20:07 -03:00
|
|
|
let buscarTexto = '';
|
2025-04-04 13:31:52 -03:00
|
|
|
|
2025-04-04 20:37:22 -03:00
|
|
|
// Mapa de responsabilidades para valores numéricos
|
|
|
|
|
const RESPONSABILIDADES_MAP = {
|
2025-04-09 09:20:07 -03:00
|
|
|
'secretario': 1,
|
|
|
|
|
'tesoureiro': 2,
|
|
|
|
|
'imprensa': 4,
|
|
|
|
|
'mns': 8,
|
|
|
|
|
'mps': 16,
|
|
|
|
|
'juventude': 32,
|
|
|
|
|
'quadro-orientador': 64,
|
|
|
|
|
'aspirante': 128,
|
|
|
|
|
'responsavel-financas': 256,
|
|
|
|
|
'responsavel-imprensa': 512
|
2025-04-04 20:37:22 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Mapa reverso para converter valores em nomes
|
|
|
|
|
const RESPONSABILIDADES_REVERSE_MAP = {
|
2025-04-09 09:59:12 -03:00
|
|
|
1: 'Secretário',
|
2025-04-04 20:37:22 -03:00
|
|
|
2: 'Tesoureiro',
|
|
|
|
|
4: 'Imprensa',
|
|
|
|
|
8: 'MNS',
|
|
|
|
|
16: 'MPS',
|
|
|
|
|
32: 'Juventude',
|
|
|
|
|
64: 'Quadro-Orientador',
|
|
|
|
|
128: 'Aspirante',
|
2025-04-09 09:59:12 -03:00
|
|
|
256: 'Responsável de Finanças',
|
|
|
|
|
512: 'Responsável de Imprensa'
|
2025-04-04 20:37:22 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Função para validar data no formato DD/MM/YYYY
|
|
|
|
|
function validarData(data) {
|
|
|
|
|
if (!data) return true; // Campo vazio é válido
|
|
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
console.log('Validando data:', data);
|
|
|
|
|
|
2025-04-04 20:37:22 -03:00
|
|
|
// Verifica o formato
|
2025-04-09 09:20:07 -03:00
|
|
|
if (!/^\d{2}\/\d{2}\/\d{4}$/.test(data)) {
|
|
|
|
|
console.warn('Data com formato inválido (deve ser DD/MM/YYYY):', data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2025-04-04 20:37:22 -03:00
|
|
|
|
|
|
|
|
// Extrai dia, mês e ano
|
|
|
|
|
const [dia, mes, ano] = data.split('/').map(Number);
|
|
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// 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;
|
|
|
|
|
}
|
2025-04-04 20:37:22 -03:00
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
console.log('Data válida:', data);
|
|
|
|
|
return true;
|
2025-04-04 20:37:22 -03:00
|
|
|
}
|
|
|
|
|
|
2025-04-04 15:54:26 -03:00
|
|
|
// Função para formatar data do formato ISO (YYYY-MM-DD) para DD/MM/YYYY
|
|
|
|
|
function formatarData(data) {
|
2025-04-09 09:20:07 -03:00
|
|
|
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 '';
|
|
|
|
|
}
|
2025-04-04 15:54:26 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Função para converter data de DD/MM/YYYY para YYYY-MM-DD
|
|
|
|
|
function converterDataParaISO(data) {
|
2025-04-09 09:20:07 -03:00
|
|
|
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 '';
|
|
|
|
|
}
|
2025-04-04 15:54:26 -03:00
|
|
|
}
|
|
|
|
|
|
2025-04-04 13:31:52 -03:00
|
|
|
// 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 = `<a class="page-link" href="#">${i}</a>`;
|
|
|
|
|
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();
|
|
|
|
|
}
|
2025-04-04 09:49:06 -03:00
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// 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();
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-04 09:49:06 -03:00
|
|
|
// Função para filtrar militantes
|
|
|
|
|
function filtrarMilitantes() {
|
2025-04-09 09:20:07 -03:00
|
|
|
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() || '';
|
|
|
|
|
|
2025-04-04 09:49:06 -03:00
|
|
|
// Filtro de texto
|
2025-04-09 09:20:07 -03:00
|
|
|
const matchesSearch = buscarTexto === '' ||
|
|
|
|
|
nome.includes(buscarTexto) ||
|
|
|
|
|
cpf.includes(buscarTexto) ||
|
|
|
|
|
email.includes(buscarTexto) ||
|
|
|
|
|
telefone.includes(buscarTexto);
|
|
|
|
|
|
2025-04-04 09:49:06 -03:00
|
|
|
// Filtro de responsabilidades
|
2025-04-09 09:20:07 -03:00
|
|
|
let matchesResponsabilidade = true;
|
2025-04-04 09:49:06 -03:00
|
|
|
if (filtroResponsabilidade) {
|
2025-04-09 09:20:07 -03:00
|
|
|
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);
|
2025-04-04 09:49:06 -03:00
|
|
|
}
|
|
|
|
|
}
|
2025-04-09 09:20:07 -03:00
|
|
|
|
2025-04-04 09:49:06 -03:00
|
|
|
// Filtro de célula
|
2025-04-09 09:20:07 -03:00
|
|
|
let matchesCelula = true;
|
2025-04-04 09:49:06 -03:00
|
|
|
if (filtroCelula) {
|
2025-04-09 09:20:07 -03:00
|
|
|
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);
|
2025-04-04 09:49:06 -03:00
|
|
|
}
|
2025-04-09 09:20:07 -03:00
|
|
|
|
|
|
|
|
// Aplicar filtros
|
|
|
|
|
if (matchesSearch && matchesResponsabilidade && matchesCelula) {
|
2025-04-04 13:31:52 -03:00
|
|
|
row.removeAttribute('data-filtered-out');
|
2025-04-04 20:37:22 -03:00
|
|
|
row.style.display = '';
|
2025-04-04 13:31:52 -03:00
|
|
|
} else {
|
|
|
|
|
row.setAttribute('data-filtered-out', '');
|
|
|
|
|
row.style.display = 'none';
|
|
|
|
|
}
|
2025-04-04 09:49:06 -03:00
|
|
|
});
|
2025-04-09 09:20:07 -03:00
|
|
|
|
|
|
|
|
// Atualizar contagem e paginação
|
|
|
|
|
atualizarContagem();
|
2025-04-03 15:05:48 -03:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// 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);
|
|
|
|
|
});
|
|
|
|
|
|
2025-04-04 16:01:41 -03:00
|
|
|
// Função para configurar um campo de data
|
|
|
|
|
function configurarCampoData(campo) {
|
|
|
|
|
if (!campo) return;
|
|
|
|
|
|
2025-04-04 20:37:22 -03:00
|
|
|
// 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
|
2025-04-04 16:01:41 -03:00
|
|
|
campo.type = 'date';
|
|
|
|
|
|
2025-04-04 20:37:22 -03:00
|
|
|
// Se já tiver valor, garantir que está no formato ISO
|
2025-04-04 16:01:41 -03:00
|
|
|
if (campo.value) {
|
2025-04-04 20:37:22 -03:00
|
|
|
campo.value = converterDataParaISO(campo.value);
|
2025-04-04 16:01:41 -03:00
|
|
|
}
|
|
|
|
|
|
2025-04-04 20:37:22 -03:00
|
|
|
// Quando o valor mudar, garantir formato ISO
|
2025-04-04 16:01:41 -03:00
|
|
|
campo.addEventListener('change', function() {
|
2025-04-04 20:37:22 -03:00
|
|
|
if (this.value) {
|
|
|
|
|
this.value = converterDataParaISO(this.value);
|
|
|
|
|
}
|
2025-04-04 16:01:41 -03:00
|
|
|
});
|
2025-04-04 20:37:22 -03:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// Função para carregar dados do militante
|
2025-04-09 09:59:12 -03:00
|
|
|
async function carregarDadosMilitante(militanteId) {
|
|
|
|
|
try {
|
|
|
|
|
console.log('Carregando dados do militante:', militanteId);
|
2025-04-09 09:20:07 -03:00
|
|
|
|
|
|
|
|
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}`);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 09:59:12 -03:00
|
|
|
const data = await response.json();
|
2025-04-09 09:20:07 -03:00
|
|
|
console.log('Dados recebidos do servidor:', data);
|
2025-04-09 09:59:12 -03:00
|
|
|
|
|
|
|
|
if (data.status === 'error') {
|
2025-04-09 09:20:07 -03:00
|
|
|
throw new Error(data.message || 'Erro ao carregar dados do militante');
|
2025-04-09 09:59:12 -03:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// 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 || '';
|
2025-04-09 09:59:12 -03:00
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// 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);
|
2025-04-04 20:37:22 -03:00
|
|
|
} else {
|
2025-04-09 09:20:07 -03:00
|
|
|
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);
|
2025-04-04 20:37:22 -03:00
|
|
|
}
|
2025-04-09 09:20:07 -03:00
|
|
|
} 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);
|
2025-04-09 09:59:12 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// Tratar campos de data
|
|
|
|
|
tratarCampoData(
|
|
|
|
|
document.getElementById('edit_data_nascimento'),
|
|
|
|
|
data.data_nascimento,
|
|
|
|
|
'Data de Nascimento'
|
|
|
|
|
);
|
2025-04-09 09:59:12 -03:00
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
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'
|
|
|
|
|
);
|
2025-04-09 09:59:12 -03:00
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// 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');
|
2025-04-09 09:59:12 -03:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// 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 {
|
2025-04-04 20:37:22 -03:00
|
|
|
badge.classList.remove('active');
|
2025-04-09 09:59:12 -03:00
|
|
|
const originalClass = badge.getAttribute('data-original-class');
|
|
|
|
|
if (originalClass) {
|
|
|
|
|
badge.className = `badge badge-clickable ${originalClass}`;
|
|
|
|
|
}
|
2025-04-09 09:20:07 -03:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 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 = `<i class="fas fa-user-edit me-2"></i>Editar ${data.nome}`;
|
|
|
|
|
console.log('Título do modal atualizado');
|
2025-04-09 09:59:12 -03:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
console.log('Dados carregados com sucesso');
|
|
|
|
|
|
2025-04-09 09:59:12 -03:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Erro ao carregar dados:', error);
|
2025-04-09 09:20:07 -03:00
|
|
|
mostrarAlerta('danger', `Erro ao carregar dados do militante: ${error.message}`);
|
2025-04-09 09:59:12 -03:00
|
|
|
}
|
2025-04-04 20:37:22 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Função para mostrar alertas
|
2025-04-09 09:20:07 -03:00
|
|
|
function mostrarAlerta(tipo, mensagem) {
|
|
|
|
|
// Remover alertas existentes
|
|
|
|
|
document.querySelectorAll('.alert').forEach(alert => alert.remove());
|
|
|
|
|
|
2025-04-09 09:59:12 -03:00
|
|
|
const alertDiv = document.createElement('div');
|
|
|
|
|
alertDiv.className = `alert alert-${tipo} alert-dismissible fade show`;
|
|
|
|
|
alertDiv.role = 'alert';
|
2025-04-09 09:20:07 -03:00
|
|
|
alertDiv.style.marginBottom = '1rem';
|
2025-04-09 09:59:12 -03:00
|
|
|
alertDiv.innerHTML = `
|
|
|
|
|
${mensagem}
|
2025-04-09 09:20:07 -03:00
|
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Fechar"></button>
|
2025-04-04 20:37:22 -03:00
|
|
|
`;
|
2025-04-09 09:59:12 -03:00
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
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);
|
|
|
|
|
}
|
2025-04-04 16:01:41 -03:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 09:59:12 -03:00
|
|
|
// 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());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-04-04 09:49:06 -03:00
|
|
|
// Configurar eventos quando o DOM estiver carregado
|
2025-04-03 15:05:48 -03:00
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
2025-04-04 11:37:48 -03:00
|
|
|
console.log('DOM carregado, configurando eventos...');
|
|
|
|
|
|
2025-04-04 13:31:52 -03:00
|
|
|
// 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();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-04 09:49:06 -03:00
|
|
|
// Configurar filtros
|
|
|
|
|
document.querySelectorAll('.dropdown-item[data-filter]').forEach(item => {
|
|
|
|
|
item.addEventListener('click', function(e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
|
|
const filter = this.getAttribute('data-filter');
|
2025-04-09 09:20:07 -03:00
|
|
|
const dropdownButton = document.querySelector('.dropdown-toggle');
|
|
|
|
|
|
|
|
|
|
console.log('Filtro selecionado:', filter);
|
2025-04-04 09:49:06 -03:00
|
|
|
|
|
|
|
|
if (filter === 'todos') {
|
|
|
|
|
filtroResponsabilidade = null;
|
|
|
|
|
filtroCelula = null;
|
|
|
|
|
} else if (filter === 'celula') {
|
|
|
|
|
filtroResponsabilidade = null;
|
2025-04-09 09:20:07 -03:00
|
|
|
filtroCelula = this.getAttribute('data-celula');
|
|
|
|
|
console.log('Filtro por célula:', filtroCelula);
|
|
|
|
|
} else {
|
|
|
|
|
filtroResponsabilidade = filter;
|
|
|
|
|
filtroCelula = null;
|
|
|
|
|
console.log('Filtro por responsabilidade:', filtroResponsabilidade);
|
2025-04-04 09:49:06 -03:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// Atualizar filtro atual
|
|
|
|
|
filtroAtual = filter;
|
2025-04-04 09:49:06 -03:00
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// Atualizar texto do botão
|
|
|
|
|
dropdownButton.innerHTML = `<i class="fas fa-filter me-2"></i>${this.textContent}`;
|
|
|
|
|
|
|
|
|
|
// Aplicar filtros
|
|
|
|
|
filtrarMilitantes();
|
2025-04-04 09:49:06 -03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2025-04-04 11:37:48 -03:00
|
|
|
console.log('Configurando modal de edição...');
|
2025-04-03 15:05:48 -03:00
|
|
|
|
2025-04-04 20:37:22 -03:00
|
|
|
// Configurar máscara para campos de data
|
|
|
|
|
$('.date-mask').mask('00/00/0000', {
|
|
|
|
|
placeholder: 'DD/MM/AAAA',
|
2025-04-09 09:20:07 -03:00
|
|
|
clearIfNotMatch: true,
|
|
|
|
|
translation: {
|
|
|
|
|
'placeholder': "DD/MM/AAAA"
|
|
|
|
|
}
|
2025-04-04 20:37:22 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Validar campos de data quando perderem o foco
|
|
|
|
|
$('.date-mask').on('blur', function() {
|
|
|
|
|
const valor = $(this).val();
|
2025-04-09 09:20:07 -03:00
|
|
|
if (valor) {
|
|
|
|
|
if (!validarData(valor)) {
|
|
|
|
|
$(this).addClass('is-invalid');
|
|
|
|
|
if (!$(this).next('.invalid-feedback').length) {
|
|
|
|
|
$(this).after('<div class="invalid-feedback">Data inválida</div>');
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$(this).removeClass('is-invalid');
|
|
|
|
|
$(this).next('.invalid-feedback').remove();
|
2025-04-04 20:37:22 -03:00
|
|
|
}
|
|
|
|
|
} else {
|
2025-04-09 09:20:07 -03:00
|
|
|
// Se o campo estiver vazio, remover validação
|
2025-04-04 20:37:22 -03:00
|
|
|
$(this).removeClass('is-invalid');
|
|
|
|
|
$(this).next('.invalid-feedback').remove();
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-04-09 09:20:07 -03:00
|
|
|
|
|
|
|
|
// 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('<div class="invalid-feedback">Data inválida</div>');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-04-04 20:37:22 -03:00
|
|
|
|
2025-04-04 16:03:36 -03:00
|
|
|
// Configurar campos de data em todos os modais
|
|
|
|
|
const modalNovoMilitante = document.getElementById('modalNovoMilitante');
|
2025-04-03 15:05:48 -03:00
|
|
|
const modalEditarMilitante = document.getElementById('modalEditarMilitante');
|
2025-04-04 16:03:36 -03:00
|
|
|
|
|
|
|
|
// Configurar modal de edição
|
2025-04-03 15:05:48 -03:00
|
|
|
if (modalEditarMilitante) {
|
2025-04-09 09:59:12 -03:00
|
|
|
modalEditarMilitante.addEventListener('show.bs.modal', async function(event) {
|
|
|
|
|
console.log('Modal de edição aberto');
|
2025-04-04 12:15:19 -03:00
|
|
|
const button = event.relatedTarget;
|
2025-04-09 09:59:12 -03:00
|
|
|
|
|
|
|
|
if (!button) {
|
|
|
|
|
console.error('Botão não encontrado');
|
2025-04-09 09:20:07 -03:00
|
|
|
mostrarAlerta('danger', 'Erro ao abrir modal: botão não encontrado');
|
2025-04-09 09:59:12 -03:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-03 15:05:48 -03:00
|
|
|
const militanteId = button.getAttribute('data-militante-id');
|
2025-04-04 11:37:48 -03:00
|
|
|
const militanteNome = button.getAttribute('data-militante-nome');
|
2025-04-04 12:15:19 -03:00
|
|
|
|
2025-04-09 09:59:12 -03:00
|
|
|
console.log('Dados do botão:', { militanteId, militanteNome });
|
2025-04-03 15:05:48 -03:00
|
|
|
|
2025-04-09 09:59:12 -03:00
|
|
|
if (!militanteId) {
|
|
|
|
|
console.error('ID do militante não encontrado no botão');
|
2025-04-09 09:20:07 -03:00
|
|
|
mostrarAlerta('danger', 'Erro ao abrir modal: ID do militante não encontrado');
|
2025-04-09 09:59:12 -03:00
|
|
|
return;
|
2025-04-04 11:37:48 -03:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 09:59:12 -03:00
|
|
|
// Atualizar título do modal
|
|
|
|
|
const modalTitle = this.querySelector('.modal-title');
|
|
|
|
|
if (modalTitle) {
|
2025-04-09 09:20:07 -03:00
|
|
|
modalTitle.innerHTML = `<i class="fas fa-user-edit me-2"></i>Editar ${militanteNome}`;
|
2025-04-09 09:59:12 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Carregar dados do militante
|
2025-04-09 09:20:07 -03:00
|
|
|
await carregarDadosMilitante(militanteId);
|
2025-04-09 09:59:12 -03:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Erro ao carregar dados:', error);
|
2025-04-09 09:20:07 -03:00
|
|
|
mostrarAlerta('danger', 'Erro ao carregar dados do militante');
|
2025-04-09 09:59:12 -03:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// 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}`;
|
2025-04-09 09:59:12 -03:00
|
|
|
}
|
|
|
|
|
});
|
2025-04-09 09:20:07 -03:00
|
|
|
|
|
|
|
|
// Limpar feedback de validação
|
|
|
|
|
this.querySelectorAll('.is-invalid').forEach(campo => {
|
|
|
|
|
campo.classList.remove('is-invalid');
|
|
|
|
|
});
|
|
|
|
|
this.querySelectorAll('.invalid-feedback').forEach(feedback => {
|
|
|
|
|
feedback.remove();
|
2025-04-03 15:05:48 -03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
console.error('Modal de edição não encontrado!');
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-04 20:37:22 -03:00
|
|
|
// Ajustar o formulário de novo militante
|
2025-04-03 15:05:48 -03:00
|
|
|
const formNovoMilitante = document.getElementById('formNovoMilitante');
|
|
|
|
|
if (formNovoMilitante) {
|
|
|
|
|
formNovoMilitante.addEventListener('submit', function(e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
2025-04-04 20:37:22 -03:00
|
|
|
// 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('<div class="invalid-feedback">Data inválida</div>');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-04-04 16:01:41 -03:00
|
|
|
|
2025-04-03 15:05:48 -03:00
|
|
|
const formData = new FormData(this);
|
|
|
|
|
|
|
|
|
|
fetch(this.action, {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
2025-04-09 09:59:12 -03:00
|
|
|
'X-Requested-With': 'XMLHttpRequest',
|
|
|
|
|
'X-CSRF-Token': getCsrfToken()
|
|
|
|
|
},
|
|
|
|
|
body: formData
|
2025-04-03 15:05:48 -03:00
|
|
|
})
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
.then(data => {
|
|
|
|
|
if (data.status === 'success') {
|
|
|
|
|
// Fechar o modal
|
2025-04-04 16:03:36 -03:00
|
|
|
const modal = bootstrap.Modal.getInstance(modalNovoMilitante);
|
2025-04-03 15:05:48 -03:00
|
|
|
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 = `
|
|
|
|
|
<td data-nome="${data.militante.nome}">${data.militante.nome}</td>
|
|
|
|
|
<td data-cpf="${data.militante.cpf}">${data.militante.cpf}</td>
|
2025-04-09 09:59:12 -03:00
|
|
|
<td data-email="${data.militante.emails && data.militante.emails.length > 0 ? data.militante.emails[0].endereco_email : ''}">${data.militante.emails && data.militante.emails.length > 0 ? data.militante.emails[0].endereco_email : ''}</td>
|
|
|
|
|
<td data-telefone="${data.militante.telefone1}">${data.militante.telefone1}</td>
|
2025-04-03 15:05:48 -03:00
|
|
|
<td data-filiado="${data.militante.filiado}">
|
|
|
|
|
<span class="badge ${data.militante.filiado ? 'bg-success' : 'bg-secondary'}">
|
|
|
|
|
${data.militante.filiado ? 'Sim' : 'Não'}
|
|
|
|
|
</span>
|
|
|
|
|
</td>
|
|
|
|
|
<td class="text-end">
|
|
|
|
|
<div class="btn-group">
|
|
|
|
|
<button type="button"
|
|
|
|
|
class="btn btn-sm btn-outline-primary"
|
|
|
|
|
data-bs-toggle="modal"
|
|
|
|
|
data-bs-target="#modalEditarMilitante"
|
|
|
|
|
data-militante-id="${data.militante.id}"
|
|
|
|
|
data-militante-nome="${data.militante.nome}"
|
|
|
|
|
data-militante-cpf="${data.militante.cpf}"
|
2025-04-09 09:59:12 -03:00
|
|
|
data-militante-email="${data.militante.emails && data.militante.emails.length > 0 ? data.militante.emails[0].endereco_email : ''}"
|
|
|
|
|
data-militante-telefone="${data.militante.telefone1}"
|
2025-04-03 15:05:48 -03:00
|
|
|
data-militante-endereco="${data.militante.endereco}"
|
|
|
|
|
data-militante-filiado="${data.militante.filiado}"
|
|
|
|
|
title="Editar">
|
|
|
|
|
<i class="fas fa-edit"></i>
|
|
|
|
|
</button>
|
|
|
|
|
<button type="button"
|
|
|
|
|
class="btn btn-sm btn-outline-danger"
|
|
|
|
|
data-bs-toggle="modal"
|
|
|
|
|
data-bs-target="#deleteModal"
|
|
|
|
|
data-militante-id="${data.militante.id}"
|
|
|
|
|
data-militante-nome="${data.militante.nome}"
|
|
|
|
|
title="Excluir">
|
|
|
|
|
<i class="fas fa-trash"></i>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
// 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}
|
|
|
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
|
|
|
`;
|
|
|
|
|
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}
|
|
|
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
|
|
|
`;
|
|
|
|
|
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.
|
|
|
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
|
|
|
`;
|
|
|
|
|
document.querySelector('.modal-body').insertBefore(alertDiv, formNovoMilitante);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Máscara para CPF
|
2025-04-04 11:37:48 -03:00
|
|
|
const cpfInputs = document.querySelectorAll('input[name="cpf"]');
|
|
|
|
|
cpfInputs.forEach(input => {
|
|
|
|
|
input.addEventListener('input', function(e) {
|
2025-04-03 15:05:48 -03:00
|
|
|
let value = e.target.value.replace(/\D/g, '');
|
|
|
|
|
if (value.length <= 11) {
|
2025-04-04 11:37:48 -03:00
|
|
|
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');
|
2025-04-03 15:05:48 -03:00
|
|
|
e.target.value = value;
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-04-04 11:37:48 -03:00
|
|
|
});
|
2025-04-03 15:05:48 -03:00
|
|
|
|
|
|
|
|
// Máscara para telefone
|
2025-04-04 11:37:48 -03:00
|
|
|
const telefoneInputs = document.querySelectorAll('input[name="telefone1"], input[name="telefone2"]');
|
|
|
|
|
telefoneInputs.forEach(input => {
|
|
|
|
|
input.addEventListener('input', function(e) {
|
2025-04-03 15:05:48 -03:00
|
|
|
let value = e.target.value.replace(/\D/g, '');
|
|
|
|
|
if (value.length <= 11) {
|
2025-04-04 11:37:48 -03:00
|
|
|
value = value.replace(/(\d{2})(\d)/, '($1) $2');
|
|
|
|
|
value = value.replace(/(\d{4,5})(\d{4})$/, '$1-$2');
|
2025-04-03 15:05:48 -03:00
|
|
|
e.target.value = value;
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-04-04 11:37:48 -03:00
|
|
|
});
|
2025-04-03 15:05:48 -03:00
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-04-04 11:37:48 -03:00
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
2025-04-04 13:31:52 -03:00
|
|
|
|
2025-04-04 20:37:22 -03:00
|
|
|
// 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'
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2025-04-04 13:31:52 -03:00
|
|
|
// Inicializar paginação
|
|
|
|
|
updateVisibleRows();
|
|
|
|
|
updatePagination();
|
2025-04-04 11:37:48 -03:00
|
|
|
});
|
|
|
|
|
|
2025-04-09 09:59:12 -03:00
|
|
|
// Função para atualizar o valor total das responsabilidades
|
|
|
|
|
function atualizarValorResponsabilidades() {
|
|
|
|
|
const badges = document.querySelectorAll('.badge-clickable.active');
|
|
|
|
|
let valorTotal = 0;
|
2025-04-04 11:37:48 -03:00
|
|
|
|
2025-04-04 20:37:22 -03:00
|
|
|
badges.forEach(badge => {
|
2025-04-09 09:59:12 -03:00
|
|
|
const valor = parseInt(badge.getAttribute('data-value'));
|
|
|
|
|
if (!isNaN(valor)) {
|
|
|
|
|
valorTotal |= valor;
|
2025-04-04 20:37:22 -03:00
|
|
|
}
|
|
|
|
|
});
|
2025-04-04 11:37:48 -03:00
|
|
|
|
2025-04-09 09:59:12 -03:00
|
|
|
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);
|
|
|
|
|
|
2025-04-09 09:20:07 -03:00
|
|
|
// 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));
|
|
|
|
|
|
2025-04-09 09:59:12 -03:00
|
|
|
// 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: {
|
2025-04-09 09:20:07 -03:00
|
|
|
'X-CSRFToken': getCsrfToken(),
|
|
|
|
|
'X-Requested-With': 'XMLHttpRequest'
|
2025-04-04 20:37:22 -03:00
|
|
|
}
|
|
|
|
|
});
|
2025-04-09 09:59:12 -03:00
|
|
|
|
|
|
|
|
const data = await response.json();
|
2025-04-09 09:20:07 -03:00
|
|
|
console.log('Resposta completa do servidor:', data);
|
2025-04-09 09:59:12 -03:00
|
|
|
|
|
|
|
|
if (data.status === 'success') {
|
2025-04-09 09:20:07 -03:00
|
|
|
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();
|
|
|
|
|
}
|
2025-04-09 09:59:12 -03:00
|
|
|
} else {
|
2025-04-09 09:20:07 -03:00
|
|
|
mostrarAlerta('danger', data.message || 'Erro ao salvar alterações');
|
2025-04-09 09:59:12 -03:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Erro ao salvar alterações:', error);
|
2025-04-09 09:20:07 -03:00
|
|
|
mostrarAlerta('danger', 'Erro ao salvar alterações. Por favor, tente novamente.');
|
2025-04-09 09:59:12 -03:00
|
|
|
}
|
2025-04-09 09:20:07 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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('<span class="badge bg-primary" title="Responsável de Finanças">RFI</span>');
|
|
|
|
|
if (valor & RESPONSABILIDADES_MAP['responsavel-imprensa']) badges.push('<span class="badge bg-info" title="Responsável de Imprensa">RIM</span>');
|
|
|
|
|
if (valor & RESPONSABILIDADES_MAP['quadro-orientador']) badges.push('<span class="badge bg-success" title="Quadro-Orientador">QOR</span>');
|
|
|
|
|
if (valor & RESPONSABILIDADES_MAP['secretario']) badges.push('<span class="badge bg-secondary" title="Secretário">SEC</span>');
|
|
|
|
|
if (valor & RESPONSABILIDADES_MAP['tesoureiro']) badges.push('<span class="badge bg-warning" title="Tesoureiro">TES</span>');
|
|
|
|
|
if (valor & RESPONSABILIDADES_MAP['imprensa']) badges.push('<span class="badge bg-danger" title="Imprensa">IMP</span>');
|
|
|
|
|
if (valor & RESPONSABILIDADES_MAP['mns']) badges.push('<span class="badge bg-purple" title="MNS">MNS</span>');
|
|
|
|
|
if (valor & RESPONSABILIDADES_MAP['mps']) badges.push('<span class="badge bg-teal" title="MPS">MPS</span>');
|
|
|
|
|
if (valor & RESPONSABILIDADES_MAP['juventude']) badges.push('<span class="badge bg-orange" title="Juventude">JUV</span>');
|
|
|
|
|
if (valor & RESPONSABILIDADES_MAP['aspirante']) badges.push('<span class="badge bg-dark" title="Aspirante">ASP</span>');
|
|
|
|
|
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;
|
|
|
|
|
});
|
|
|
|
|
});
|