diff --git a/app.py b/app.py
index d97f0e3..24ea324 100644
--- a/app.py
+++ b/app.py
@@ -297,7 +297,8 @@ def home():
total_assinaturas=total_assinaturas,
ultimos_militantes=ultimos_militantes,
ultimos_pagamentos=ultimos_pagamentos,
- tipos_pagamento=tipos_pagamento)
+ tipos_pagamento=tipos_pagamento,
+ Militante=Militante)
except Exception as e:
print(f"Erro na página inicial: {e}")
import traceback
@@ -311,7 +312,8 @@ def home():
total_materiais=0,
total_assinaturas=0,
ultimos_militantes=[],
- ultimos_pagamentos=[])
+ ultimos_pagamentos=[],
+ Militante=Militante)
finally:
db.close()
@@ -1057,12 +1059,24 @@ def editar_militante(militante_id):
if responsabilidades_json:
responsabilidades_lista = json.loads(responsabilidades_json)
valor_responsabilidades = 0
- if 'Finanças' in responsabilidades_lista:
+ if 'Responsável de Finanças' in responsabilidades_lista:
valor_responsabilidades |= Militante.RESPONSAVEL_FINANCAS
- if 'Imprensa' in responsabilidades_lista:
+ if 'Responsável de Imprensa' in responsabilidades_lista:
valor_responsabilidades |= Militante.RESPONSAVEL_IMPRENSA
if 'Quadro-Orientador' in responsabilidades_lista:
valor_responsabilidades |= Militante.QUADRO_ORIENTADOR
+ if 'Secretário' in responsabilidades_lista:
+ valor_responsabilidades |= Militante.SECRETARIO
+ if 'MPS' in responsabilidades_lista:
+ valor_responsabilidades |= Militante.MPS
+ if 'Tesoureiro' in responsabilidades_lista:
+ valor_responsabilidades |= Militante.TESOUREIRO
+ if 'MNS' in responsabilidades_lista:
+ valor_responsabilidades |= Militante.MNS
+ if 'Juventude' in responsabilidades_lista:
+ valor_responsabilidades |= Militante.JUVENTUDE
+ if 'Aspirante' in responsabilidades_lista:
+ valor_responsabilidades |= Militante.ASPIRANTE
militante.responsabilidades = valor_responsabilidades
else:
militante.responsabilidades = 0
@@ -1080,6 +1094,34 @@ def editar_militante(militante_id):
db.commit()
print("Alterações salvas com sucesso")
+ # Converter responsabilidades para lista de strings
+ responsabilidades = []
+ if militante.responsabilidades & Militante.RESPONSAVEL_FINANCAS:
+ responsabilidades.append('Responsável de Finanças')
+ if militante.responsabilidades & Militante.RESPONSAVEL_IMPRENSA:
+ responsabilidades.append('Responsável de Imprensa')
+ if militante.responsabilidades & Militante.QUADRO_ORIENTADOR:
+ responsabilidades.append('Quadro-Orientador')
+ if militante.responsabilidades & Militante.SECRETARIO:
+ responsabilidades.append('Secretário')
+ if militante.responsabilidades & Militante.MPS:
+ responsabilidades.append('MPS')
+ if militante.responsabilidades & Militante.TESOUREIRO:
+ responsabilidades.append('Tesoureiro')
+ if militante.responsabilidades & Militante.MNS:
+ responsabilidades.append('MNS')
+ if militante.responsabilidades & Militante.JUVENTUDE:
+ responsabilidades.append('Juventude')
+ if militante.responsabilidades & Militante.ASPIRANTE:
+ responsabilidades.append('Aspirante')
+
+ return jsonify({
+ 'status': 'success',
+ 'message': f'Militante {militante.nome} atualizado com sucesso!',
+ 'responsabilidades': responsabilidades,
+ 'responsabilidades_bits': militante.responsabilidades
+ })
+
return jsonify({
'status': 'success',
'message': f'Militante {militante.nome} atualizado com sucesso!'
@@ -1586,11 +1628,23 @@ def buscar_dados_militante(militante_id):
# Converter responsabilidades para lista de strings
responsabilidades = []
if militante.responsabilidades & Militante.RESPONSAVEL_FINANCAS:
- responsabilidades.append('Finanças')
+ responsabilidades.append('Responsável de Finanças')
if militante.responsabilidades & Militante.RESPONSAVEL_IMPRENSA:
- responsabilidades.append('Imprensa')
+ responsabilidades.append('Responsável de Imprensa')
if militante.responsabilidades & Militante.QUADRO_ORIENTADOR:
responsabilidades.append('Quadro-Orientador')
+ if militante.responsabilidades & Militante.SECRETARIO:
+ responsabilidades.append('Secretário')
+ if militante.responsabilidades & Militante.MPS:
+ responsabilidades.append('MPS')
+ if militante.responsabilidades & Militante.TESOUREIRO:
+ responsabilidades.append('Tesoureiro')
+ if militante.responsabilidades & Militante.MNS:
+ responsabilidades.append('MNS')
+ if militante.responsabilidades & Militante.JUVENTUDE:
+ responsabilidades.append('Juventude')
+ if militante.responsabilidades & Militante.ASPIRANTE:
+ responsabilidades.append('Aspirante')
return jsonify({
'nome': militante.nome,
@@ -1610,7 +1664,7 @@ def buscar_dados_militante(militante_id):
'rua': militante.endereco.rua if militante.endereco else None,
'numero': militante.endereco.numero if militante.endereco else None,
'complemento': militante.endereco.complemento if militante.endereco else None
- } if militante.endereco else None,
+ },
'profissao': militante.profissao,
'regime_trabalho': militante.regime_trabalho,
'empresa': militante.empresa,
@@ -1621,8 +1675,9 @@ def buscar_dados_militante(militante_id):
'cargo_sindical': militante.cargo_sindical,
'central_sindical': militante.central_sindical,
'dirigente_sindical': militante.dirigente_sindical,
- 'estado': militante.estado.name if militante.estado else None,
+ 'estado': militante.estado.value if militante.estado else None,
'celula_id': militante.celula_id,
+ 'responsabilidades': responsabilidades,
'responsabilidades': responsabilidades
})
except Exception as e:
diff --git a/static/js/militantes.js b/static/js/militantes.js
index 4994c04..e45117d 100644
--- a/static/js/militantes.js
+++ b/static/js/militantes.js
@@ -8,6 +8,54 @@ let currentPage = 1;
let rowsPerPage = 20;
let totalRows = 0;
+// 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 de Financas': 256,
+ 'Responsavel de Imprensa': 512
+};
+
+// Mapa reverso para converter valores em nomes
+const RESPONSABILIDADES_REVERSE_MAP = {
+ 1: 'Secretario',
+ 2: 'Tesoureiro',
+ 4: 'Imprensa',
+ 8: 'MNS',
+ 16: 'MPS',
+ 32: 'Juventude',
+ 64: 'Quadro-Orientador',
+ 128: 'Aspirante',
+ 256: 'Responsavel de Financas',
+ 512: 'Responsavel de Imprensa'
+};
+
+// Função para validar data no formato DD/MM/YYYY
+function validarData(data) {
+ if (!data) return true; // Campo vazio é válido
+
+ // Verifica o formato
+ if (!/^\d{2}\/\d{2}\/\d{4}$/.test(data)) return false;
+
+ // Extrai dia, mês e ano
+ const [dia, mes, ano] = data.split('/').map(Number);
+
+ // Cria um objeto Date
+ const dataObj = new Date(ano, mes - 1, dia);
+
+ // Verifica se a data é válida
+ return dataObj.getDate() === dia &&
+ dataObj.getMonth() === mes - 1 &&
+ dataObj.getFullYear() === ano &&
+ ano >= 1900 && ano <= 2100;
+}
+
// Função para formatar data do formato ISO (YYYY-MM-DD) para DD/MM/YYYY
function formatarData(data) {
if (!data) return '';
@@ -18,7 +66,7 @@ function formatarData(data) {
// Função para converter data de DD/MM/YYYY para YYYY-MM-DD
function converterDataParaISO(data) {
if (!data) return '';
- if (data.includes('-')) return data; // Já está no formato ISO
+ if (data.includes('-')) return data;
const [dia, mes, ano] = data.split('/');
return `${ano}-${mes}-${dia}`;
}
@@ -138,8 +186,21 @@ function filtrarMilitantes() {
// Filtro de responsabilidades
if (filtroResponsabilidade) {
const badges = row.querySelectorAll('.badge');
+ const responsabilidadeMap = {
+ 'responsavel-financas': 'RFI',
+ 'responsavel-imprensa': 'RIM',
+ 'quadro-orientador': 'QOR',
+ 'secretario': 'SEC',
+ 'tesoureiro': 'TES',
+ 'imprensa': 'IMP',
+ 'mns': 'MNS',
+ 'mps': 'MPS',
+ 'juventude': 'JUV',
+ 'aspirante': 'ASP'
+ };
+ const responsabilidadeTexto = responsabilidadeMap[filtroResponsabilidade];
const hasResponsabilidade = Array.from(badges).some(badge =>
- badge.textContent.toLowerCase() === filtroResponsabilidade.toLowerCase()
+ badge.textContent.trim() === responsabilidadeTexto
);
if (!hasResponsabilidade) {
shouldShow = false;
@@ -157,6 +218,7 @@ function filtrarMilitantes() {
// Marcar linha como filtrada ou não
if (shouldShow) {
row.removeAttribute('data-filtered-out');
+ row.style.display = '';
} else {
row.setAttribute('data-filtered-out', '');
row.style.display = 'none';
@@ -173,35 +235,208 @@ function filtrarMilitantes() {
function configurarCampoData(campo) {
if (!campo) return;
- // Criar um campo de texto para exibição
- const campoTexto = document.createElement('input');
- campoTexto.type = 'text';
- campoTexto.className = campo.className;
- campoTexto.placeholder = 'dd/mm/aaaa';
- campoTexto.readOnly = true; // Evita edição manual
-
- // Esconder o campo original mas manter ao lado
+ // 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';
- campo.style.position = 'absolute';
- campo.style.left = '-9999px';
- // Inserir o campo de texto antes do campo de data
- campo.parentNode.insertBefore(campoTexto, campo);
-
- // Se já tiver valor, formatar
+ // Se já tiver valor, garantir que está no formato ISO
if (campo.value) {
- campoTexto.value = formatarData(campo.value);
+ campo.value = converterDataParaISO(campo.value);
}
- // Quando o campo original mudar, atualizar o texto
+ // Quando o valor mudar, garantir formato ISO
campo.addEventListener('change', function() {
- campoTexto.value = this.value ? formatarData(this.value) : '';
+ if (this.value) {
+ this.value = converterDataParaISO(this.value);
+ }
});
+}
+
+// Função para carregar os dados do militante no modal de edição
+function carregarDadosMilitante(id) {
+ console.log('Carregando dados do militante:', id);
- // Quando clicar no campo de texto, abrir o calendário
- campoTexto.addEventListener('click', function() {
- campo.showPicker();
- });
+ fetch(`/militantes/dados/${id}`)
+ .then(response => {
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ return response.text().then(text => {
+ try {
+ return JSON.parse(text);
+ } catch (e) {
+ console.error('Erro ao fazer parse do JSON:', e);
+ console.log('Texto recebido:', text);
+ throw e;
+ }
+ });
+ })
+ .then(data => {
+ console.log('Dados recebidos:', data);
+
+ // Mapear campos básicos
+ const camposTexto = {
+ 'edit_militante_id': data.id,
+ 'edit_nome': data.nome || '',
+ 'edit_cpf': data.cpf || '',
+ 'edit_titulo_eleitoral': data.titulo_eleitoral || '',
+ 'edit_email': data.email || '',
+ 'edit_telefone1': data.telefone1 || '',
+ 'edit_telefone2': data.telefone2 || '',
+ 'edit_sindicato': data.sindicato || '',
+ 'edit_cargo_sindical': data.cargo_sindical || '',
+ 'edit_central_sindical': data.central_sindical || ''
+ };
+
+ // Preencher campos de texto simples
+ Object.entries(camposTexto).forEach(([id, valor]) => {
+ const campo = document.getElementById(id);
+ if (campo) {
+ campo.value = valor;
+ } else {
+ console.warn(`Campo não encontrado: ${id}`);
+ }
+ });
+
+ // Tratar campos de seleção
+ const selects = {
+ 'edit_estado_militante': data.estado || 'ATIVO',
+ 'edit_celula': data.celula_id || ''
+ };
+
+ Object.entries(selects).forEach(([id, valor]) => {
+ const campo = document.getElementById(id);
+ if (campo) {
+ campo.value = valor;
+ } else {
+ console.warn(`Campo select não encontrado: ${id}`);
+ }
+ });
+
+ // Tratar campos de checkbox
+ const checkboxes = {
+ 'edit_dirigente_sindical': data.dirigente_sindical || false
+ };
+
+ Object.entries(checkboxes).forEach(([id, valor]) => {
+ const campo = document.getElementById(id);
+ if (campo) {
+ campo.checked = !!valor;
+ } else {
+ console.warn(`Campo checkbox não encontrado: ${id}`);
+ }
+ });
+
+ // Tratar campos de data
+ const camposData = {
+ 'edit_data_nascimento': data.data_nascimento,
+ 'edit_data_entrada': data.data_entrada_oci,
+ 'edit_data_efetivacao': data.data_efetivacao_oci
+ };
+
+ Object.entries(camposData).forEach(([id, valor]) => {
+ const campo = document.getElementById(id);
+ if (campo) {
+ // Se o valor existe e está em formato ISO, converter para DD/MM/AAAA
+ if (valor && typeof valor === 'string' && valor.includes('-')) {
+ campo.value = formatarData(valor);
+ } else {
+ campo.value = valor || '';
+ }
+ } else {
+ console.warn(`Campo data não encontrado: ${id}`);
+ }
+ });
+
+ // Converter responsabilidades
+ const responsabilidadesBits = data.responsabilidades_bits || data.responsabilidades || 0;
+ console.log('Responsabilidades bits:', responsabilidadesBits);
+
+ // Resetar todas as badges para o estado inicial
+ const badges = document.querySelectorAll('#modalEditarMilitante .badge-clickable');
+ badges.forEach(badge => {
+ // Remover todas as classes exceto 'badge' e 'badge-clickable'
+ const classesToKeep = ['badge', 'badge-clickable'];
+ badge.classList.forEach(cls => {
+ if (!classesToKeep.includes(cls)) {
+ badge.classList.remove(cls);
+ }
+ });
+
+ // Adicionar a classe bg-light como estado inicial
+ badge.classList.add('bg-light');
+ badge.classList.remove('active');
+ });
+
+ // Ativar as badges correspondentes às responsabilidades
+ badges.forEach(badge => {
+ const value = parseInt(badge.getAttribute('data-value'));
+ if ((responsabilidadesBits & value) === value) {
+ badge.classList.remove('bg-light');
+ badge.classList.add('active');
+
+ // Adicionar a classe original
+ const originalClass = badge.getAttribute('data-original-class');
+ if (originalClass) {
+ originalClass.split(' ').forEach(cls => {
+ badge.classList.add(cls);
+ });
+ }
+ }
+ });
+
+ // Atualizar o valor total das responsabilidades
+ const responsabilidadesInput = document.getElementById('responsabilidades_values');
+ if (responsabilidadesInput) {
+ responsabilidadesInput.value = responsabilidadesBits;
+ }
+
+ // Reinicializar os badges clicáveis
+ initBadgeClickable();
+ })
+ .catch(error => {
+ console.error('Erro ao carregar dados do militante:', error);
+ // Mostrar alerta de erro
+ mostrarAlerta('Erro ao carregar dados do militante: ' + error.message, 'danger');
+ });
+}
+
+// Função para mostrar alertas
+function mostrarAlerta(mensagem, tipo = 'success') {
+ console.log('Mostrando alerta:', mensagem, tipo);
+
+ // Criar div de alerta se não existir
+ let alertPlaceholder = document.getElementById('alertPlaceholder');
+ if (!alertPlaceholder) {
+ alertPlaceholder = document.createElement('div');
+ alertPlaceholder.id = 'alertPlaceholder';
+ alertPlaceholder.style.position = 'fixed';
+ alertPlaceholder.style.top = '20px';
+ alertPlaceholder.style.right = '20px';
+ alertPlaceholder.style.zIndex = '9999';
+ document.body.appendChild(alertPlaceholder);
+ }
+
+ // Criar wrapper para o alerta
+ const wrapper = document.createElement('div');
+ wrapper.innerHTML = `
+
+ ${mensagem}
+
+
+ `;
+ alertPlaceholder.appendChild(wrapper);
+
+ // Remover o alerta após 5 segundos
+ setTimeout(() => {
+ wrapper.firstElementChild.classList.remove('show');
+ setTimeout(() => wrapper.remove(), 150);
+ }, 5000);
}
// Configurar eventos quando o DOM estiver carregado
@@ -242,10 +477,10 @@ document.addEventListener('DOMContentLoaded', function() {
filtroAtual = 'todos';
filtroResponsabilidade = null;
filtroCelula = null;
- } else if (['financas', 'imprensa', 'quadro-orientador'].includes(filter)) {
+ } else if (['responsavel-financas', 'responsavel-imprensa', 'quadro-orientador'].includes(filter)) {
filtroAtual = 'todos';
- filtroResponsabilidade = filter === 'financas' ? 'Finanças' :
- filter === 'imprensa' ? 'Imprensa' :
+ filtroResponsabilidade = filter === 'responsavel-financas' ? 'Responsável de Finanças' :
+ filter === 'responsavel-imprensa' ? 'Responsável de Imprensa' :
'Quadro-Orientador';
filtroCelula = null;
} else if (filter === 'celula') {
@@ -265,44 +500,32 @@ document.addEventListener('DOMContentLoaded', function() {
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
+ });
+
+ // Validar campos de data quando perderem o foco
+ $('.date-mask').on('blur', function() {
+ const valor = $(this).val();
+ if (valor && !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();
+ }
+ });
+
// Configurar campos de data em todos os modais
const modalNovoMilitante = document.getElementById('modalNovoMilitante');
const modalEditarMilitante = document.getElementById('modalEditarMilitante');
- // Configurar campos quando o modal novo for aberto
- if (modalNovoMilitante) {
- modalNovoMilitante.addEventListener('show.bs.modal', function() {
- // Configurar campos de data do modal novo
- const camposData = this.querySelectorAll('input[type="date"]');
- camposData.forEach(configurarCampoData);
- });
-
- // Limpar formulário e alertas quando o modal for fechado
- modalNovoMilitante.addEventListener('hidden.bs.modal', function () {
- formNovoMilitante.reset();
- const alerts = this.querySelectorAll('.alert');
- alerts.forEach(alert => alert.remove());
- });
- }
-
- // Configurar campos quando o modal editar for aberto
- if (modalEditarMilitante) {
- modalEditarMilitante.addEventListener('show.bs.modal', function() {
- // Configurar campos de data do modal editar
- const camposData = this.querySelectorAll('input[type="date"]');
- camposData.forEach(configurarCampoData);
- });
- }
-
// Configurar modal de edição
if (modalEditarMilitante) {
- console.log('Modal encontrado, configurando eventos...');
-
- // Criar instância do modal Bootstrap
- const modalInstance = new bootstrap.Modal(modalEditarMilitante);
- console.log('Instância do modal criada:', modalInstance);
-
- // Configurar eventos quando o modal é mostrado
modalEditarMilitante.addEventListener('show.bs.modal', function(event) {
console.log('Modal sendo aberto...');
@@ -327,201 +550,126 @@ document.addEventListener('DOMContentLoaded', function() {
}
// Buscar dados do militante
- fetch(`/militantes/dados/${militanteId}`, {
- headers: {
- 'X-Requested-With': 'XMLHttpRequest'
- }
- })
- .then(response => {
- if (!response.ok) {
- return response.json().then(data => {
- throw new Error(data.message || `HTTP error! status: ${response.status}`);
- });
- }
- return response.json();
- })
- .then(dados => {
- console.log('Dados do militante recebidos:', dados);
-
- if (!dados) {
- throw new Error('Dados do militante não encontrados');
- }
-
- try {
- // Preencher os campos do formulário
- const campos = {
- 'edit_nome': dados.nome,
- 'edit_cpf': dados.cpf,
- 'edit_titulo_eleitoral': dados.titulo_eleitoral,
- 'edit_data_nascimento': dados.data_nascimento,
- 'edit_data_entrada': dados.data_entrada_oci,
- 'edit_data_efetivacao': dados.data_efetivacao_oci,
- 'edit_telefone1': dados.telefone1,
- 'edit_telefone2': dados.telefone2,
- 'edit_email': dados.email,
- 'edit_cep': dados.endereco?.cep,
- 'edit_estado': dados.endereco?.estado,
- 'edit_cidade': dados.endereco?.cidade,
- 'edit_bairro': dados.endereco?.bairro,
- 'edit_rua': dados.endereco?.rua,
- 'edit_numero': dados.endereco?.numero,
- 'edit_complemento': dados.endereco?.complemento,
- 'edit_profissao': dados.profissao,
- 'edit_regime_trabalho': dados.regime_trabalho,
- 'edit_empresa': dados.empresa,
- 'edit_contratante': dados.contratante,
- 'edit_instituicao_ensino': dados.instituicao_ensino,
- 'edit_tipo_instituicao': dados.tipo_instituicao,
- 'edit_sindicato': dados.sindicato,
- 'edit_cargo_sindical': dados.cargo_sindical,
- 'edit_central_sindical': dados.central_sindical,
- 'edit_estado_militante': dados.estado,
- 'edit_celula': dados.celula_id
- };
-
- // Preencher cada campo se ele existir
- Object.entries(campos).forEach(([id, valor]) => {
- const campo = document.getElementById(id);
- if (campo) {
- if (campo.type === 'date') {
- // Para campos de data, atualizar também o campo de texto
- campo.value = valor || '';
- const campoTexto = campo.previousElementSibling;
- if (campoTexto && campoTexto.type === 'text') {
- campoTexto.value = valor ? formatarData(valor) : '';
- }
- } else {
- campo.value = valor || '';
- }
- }
- });
-
- // Checkbox de dirigente sindical
- const checkDirigente = document.getElementById('edit_dirigente_sindical');
- if (checkDirigente) {
- checkDirigente.checked = dados.dirigente_sindical;
- }
-
- // Checkboxes de responsabilidades
- const responsabilidadesMap = {
- 'Finanças': 'edit_resp_1',
- 'Imprensa': 'edit_resp_2',
- 'Quadro-Orientador': 'edit_resp_4'
- };
-
- console.log('Responsabilidades recebidas:', dados.responsabilidades);
-
- // Resetar todos os checkboxes primeiro
- Object.values(responsabilidadesMap).forEach(id => {
- const checkbox = document.getElementById(id);
- if (checkbox) {
- checkbox.checked = false;
- }
- });
-
- // Marcar os checkboxes baseado nas responsabilidades recebidas
- if (Array.isArray(dados.responsabilidades)) {
- dados.responsabilidades.forEach(resp => {
- const checkboxId = responsabilidadesMap[resp];
- if (checkboxId) {
- const checkbox = document.getElementById(checkboxId);
- if (checkbox) {
- checkbox.checked = true;
- console.log(`Marcando checkbox ${checkboxId} para responsabilidade ${resp}`);
- }
- }
- });
- }
-
- console.log('Formulário preenchido com sucesso');
- } catch (error) {
- console.error('Erro ao preencher formulário:', error);
- mostrarAlerta('Erro ao carregar dados do militante', 'danger');
- }
- })
- .catch(error => {
- console.error('Erro ao buscar dados:', error);
- mostrarAlerta('Erro ao carregar dados do militante', 'danger');
- });
+ carregarDadosMilitante(militanteId);
});
- // Envio do formulário de edição via AJAX
+ // Configurar formulário de edição
const formEditarMilitante = document.getElementById('formEditarMilitante');
if (formEditarMilitante) {
formEditarMilitante.addEventListener('submit', function(e) {
e.preventDefault();
- console.log('Enviando formulário de edição...');
+ console.log('Formulário submetido');
- // Os campos de data já estarão no formato ISO, não precisa converter
+ // Validar todas as datas antes do envio
+ const camposData = this.querySelectorAll('.date-mask');
+ let datasValidas = true;
- // Coletar responsabilidades selecionadas
- const responsabilidades = [];
- if (document.getElementById('edit_resp_1').checked) responsabilidades.push('Finanças');
- if (document.getElementById('edit_resp_2').checked) responsabilidades.push('Imprensa');
- if (document.getElementById('edit_resp_4').checked) responsabilidades.push('Quadro-Orientador');
+ 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
');
+ }
+ } else {
+ $(campo).removeClass('is-invalid');
+ $(campo).next('.invalid-feedback').remove();
+ }
+ });
+ if (!datasValidas) {
+ mostrarAlerta('Existem datas inválidas no formulário', 'danger');
+ return;
+ }
+
+ // Converter datas para formato ISO
+ camposData.forEach(campo => {
+ if (campo.value) {
+ campo.value = converterDataParaISO(campo.value);
+ console.log(`Data convertida para ISO: ${campo.name} = ${campo.value}`);
+ }
+ });
+
+ // Criar FormData com todos os campos
const formData = new FormData(this);
- formData.set('responsabilidades', JSON.stringify(responsabilidades));
- console.log('Responsabilidades enviadas:', responsabilidades);
-
- // Obter o CSRF token
- const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
-
- // Obter o ID do militante do campo hidden
- const militanteId = document.getElementById('edit_militante_id').value;
-
- if (!militanteId) {
- console.error('ID do militante não encontrado!');
- mostrarAlerta('Erro: ID do militante não encontrado', 'danger');
+ // Verificar se o input de responsabilidades existe
+ const responsabilidadesInput = document.getElementById('responsabilidades_values');
+ if (!responsabilidadesInput) {
+ mostrarAlerta('Erro: Campo de responsabilidades não encontrado', 'danger');
return;
}
- // Garantir que o campo de endereço está correto
- const logradouro = formData.get('logradouro');
- if (logradouro) {
- formData.set('rua', logradouro);
- formData.delete('logradouro');
+ // Converter responsabilidades para array antes de enviar
+ const responsabilidadesBits = parseInt(responsabilidadesInput.value) || 0;
+ const responsabilidades = [];
+
+ // Converter bits para nomes de responsabilidades
+ for (const [valor, nome] of Object.entries(RESPONSABILIDADES_REVERSE_MAP)) {
+ if ((responsabilidadesBits & parseInt(valor)) === parseInt(valor)) {
+ responsabilidades.push(nome);
+ }
}
+ // Substituir o valor numérico pelo array de responsabilidades
+ formData.set('responsabilidades', JSON.stringify(responsabilidades));
+
+ // Log dos dados sendo enviados
+ console.log('Dados do formulário:');
+ for (let [key, value] of formData.entries()) {
+ console.log(`${key}: ${value}`);
+ }
+
+ // Obter o ID do militante
+ const militanteId = document.getElementById('edit_militante_id').value;
+ if (!militanteId) {
+ mostrarAlerta('Erro: ID do militante não encontrado', 'danger');
+ return;
+ }
+
+ // Enviar dados para o servidor
fetch(`/militantes/editar/${militanteId}`, {
method: 'POST',
- body: formData,
- headers: {
- 'X-Requested-With': 'XMLHttpRequest',
- 'X-CSRFToken': csrfToken
- },
- credentials: 'same-origin'
+ body: formData
})
.then(response => {
- console.log('Resposta recebida:', response);
if (!response.ok) {
- return response.json().then(data => {
- throw new Error(data.message || `HTTP error! status: ${response.status}`);
+ return response.text().then(text => {
+ try {
+ const jsonResponse = JSON.parse(text);
+ return jsonResponse;
+ } catch (e) {
+ console.error('Erro ao fazer parse do JSON:', e);
+ console.log('Texto recebido:', text);
+ throw new Error('Erro ao processar resposta do servidor');
+ }
});
}
return response.json();
})
.then(data => {
- console.log('Resposta processada:', data);
- if (data.status === 'success') {
+ console.log('Resposta do servidor:', data);
+ if (data.success) {
+ mostrarAlerta('Militante atualizado com sucesso!', 'success');
+
// Fechar o modal
- bootstrap.Modal.getInstance(modalEditarMilitante).hide();
+ const modal = bootstrap.Modal.getInstance(document.getElementById('modalEditarMilitante'));
+ if (modal) {
+ modal.hide();
+ } else {
+ console.warn('Modal não encontrado');
+ }
- // Mostrar mensagem de sucesso
- mostrarAlerta(data.message, 'success');
-
- // Recarregar a página após um breve delay
- setTimeout(() => {
- location.reload();
- }, 1500);
+ // Recarregar a página após 1 segundo
+ setTimeout(() => window.location.reload(), 1000);
} else {
- throw new Error(data.message || 'Erro ao salvar dados');
+ throw new Error(data.message || 'Erro ao atualizar militante');
}
})
.catch(error => {
- console.error('Erro ao enviar formulário:', error);
- mostrarAlerta(`Erro ao salvar dados: ${error.message}`, 'danger');
+ console.error('Erro:', error);
+ mostrarAlerta(error.message || 'Erro ao atualizar militante', 'danger');
});
});
}
@@ -535,13 +683,37 @@ document.addEventListener('DOMContentLoaded', function() {
console.error('Modal de edição não encontrado!');
}
- // Envio do formulário via AJAX
+ // Ajustar o formulário de novo militante
const formNovoMilitante = document.getElementById('formNovoMilitante');
if (formNovoMilitante) {
formNovoMilitante.addEventListener('submit', function(e) {
e.preventDefault();
- // Os campos de data já estarão no formato ISO, não precisa converter
+ // 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);
@@ -792,30 +964,82 @@ document.addEventListener('DOMContentLoaded', function() {
});
});
+ // 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 badges clicáveis
+ initBadgeClickable();
+
// Inicializar paginação
updateVisibleRows();
updatePagination();
});
-// Função para mostrar alertas
-function mostrarAlerta(mensagem, tipo) {
- // Criar o elemento de alerta
- const alertDiv = document.createElement('div');
- alertDiv.className = `alert alert-${tipo} alert-dismissible fade show position-fixed top-0 start-50 translate-middle-x mt-3`;
- alertDiv.style.zIndex = '9999';
- alertDiv.innerHTML = `
- ${mensagem}
-
- `;
+// Função para inicializar as badges clicáveis
+function initBadgeClickable() {
+ const badges = document.querySelectorAll('.badge-clickable');
+ const selectedValues = [];
- // Adicionar o alerta ao corpo do documento
- document.body.appendChild(alertDiv);
+ // Inicializar o array com os valores das badges que já estão ativas
+ badges.forEach(badge => {
+ if (badge.classList.contains('active')) {
+ const value = parseInt(badge.getAttribute('data-value'));
+ if (!selectedValues.includes(value)) {
+ selectedValues.push(value);
+ }
+ }
+ });
- // Configurar o Bootstrap alert
- const bsAlert = new bootstrap.Alert(alertDiv);
+ // Atualizar o input hidden com o valor total inicial
+ const totalValue = selectedValues.reduce((a, b) => a + b, 0);
+ document.getElementById('responsabilidades_values').value = totalValue;
- // Remover o alerta após 3 segundos
- setTimeout(() => {
- bsAlert.close();
- }, 3000);
-}
\ No newline at end of file
+ // Adicionar evento de clique para cada badge
+ badges.forEach(badge => {
+ badge.addEventListener('click', function() {
+ const value = parseInt(this.getAttribute('data-value'));
+ const originalClass = this.getAttribute('data-original-class');
+
+ // Toggle do estado ativo
+ if (this.classList.contains('active')) {
+ // Desativar badge
+ this.classList.remove('active');
+ originalClass.split(' ').forEach(cls => {
+ this.classList.remove(cls);
+ });
+ this.classList.add('bg-light');
+
+ // Remover valor do array
+ const index = selectedValues.indexOf(value);
+ if (index > -1) {
+ selectedValues.splice(index, 1);
+ }
+ } else {
+ // Ativar badge
+ this.classList.add('active');
+ this.classList.remove('bg-light');
+ originalClass.split(' ').forEach(cls => {
+ this.classList.add(cls);
+ });
+
+ // Adicionar valor ao array
+ if (!selectedValues.includes(value)) {
+ selectedValues.push(value);
+ }
+ }
+
+ // Atualizar o input hidden com o novo valor total
+ const newTotal = selectedValues.reduce((a, b) => a + b, 0);
+ document.getElementById('responsabilidades_values').value = newTotal;
+
+ console.log('Valores selecionados:', selectedValues);
+ console.log('Valor total:', newTotal);
+ });
+ });
+}
\ No newline at end of file
diff --git a/templates/listar_militantes.html b/templates/listar_militantes.html
index 144c353..8e33eef 100644
--- a/templates/listar_militantes.html
+++ b/templates/listar_militantes.html
@@ -1,5 +1,10 @@
{% extends "base.html" %}
+{% block head %}
+
+
+{% endblock %}
+
{% block title %}Militantes{% endblock %}
{% block content %}
@@ -39,9 +44,16 @@
Todos
- Finanças
- Imprensa
+ Responsável de Finanças
+ Responsável de Imprensa
Quadro-Orientador
+ Secretário
+ Tesoureiro
+ Imprensa
+ MNS
+ MPS
+ Juventude
+ Aspirante
{% for celula in celulas %}
@@ -78,13 +90,34 @@
{{ militante.celula.nome }}
{% if militante.responsabilidades|bitwise_and(Militante.RESPONSAVEL_FINANCAS) %}
- Finanças
+ RFI
{% endif %}
{% if militante.responsabilidades|bitwise_and(Militante.RESPONSAVEL_IMPRENSA) %}
- Imprensa
+ RIM
{% endif %}
{% if militante.responsabilidades|bitwise_and(Militante.QUADRO_ORIENTADOR) %}
- Quadro-Orientador
+ QOR
+ {% endif %}
+ {% if militante.responsabilidades|bitwise_and(Militante.SECRETARIO) %}
+ SEC
+ {% endif %}
+ {% if militante.responsabilidades|bitwise_and(Militante.TESOUREIRO) %}
+ TES
+ {% endif %}
+ {% if militante.responsabilidades|bitwise_and(Militante.IMPRENSA) %}
+ IMP
+ {% endif %}
+ {% if militante.responsabilidades|bitwise_and(Militante.MNS) %}
+ MNS
+ {% endif %}
+ {% if militante.responsabilidades|bitwise_and(Militante.MPS) %}
+ MPS
+ {% endif %}
+ {% if militante.responsabilidades|bitwise_and(Militante.JUVENTUDE) %}
+ JUV
+ {% endif %}
+ {% if militante.responsabilidades|bitwise_and(Militante.ASPIRANTE) %}
+ ASP
{% endif %}
@@ -162,11 +195,70 @@
{% endblock %}
{% block scripts %}
-
+
+
+
+
+
+
+
+
{% endblock %}
{% block extra_css %}
{% endblock %}
\ No newline at end of file
diff --git a/templates/modals/militante_editar.html b/templates/modals/militante_editar.html
index efbca5a..aa67a46 100644
--- a/templates/modals/militante_editar.html
+++ b/templates/modals/militante_editar.html
@@ -58,20 +58,20 @@
Data de Nascimento
-
+
@@ -232,26 +232,31 @@
-
-
Responsabilidades
-
-
-
-
-
-
- Quadro-Orientador
-
+
+
+
Responsabilidades
+
+
+
+ Secretário
+
+ Responsável de Imprensa
+
+ Imprensa
+
+ MPS
+
+ Quadro-Orientador
+
+ Responsável de Finanças
+
+ Tesoureiro
+
+ MNS
+
+ Juventude
+
+ Aspirante
@@ -267,4 +272,52 @@
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/templates/modals/militante_novo.html b/templates/modals/militante_novo.html
index 91be6e7..d5af0c5 100644
--- a/templates/modals/militante_novo.html
+++ b/templates/modals/militante_novo.html
@@ -57,20 +57,20 @@
Data de Nascimento
-
+
@@ -230,18 +230,32 @@
-
-
Responsabilidades
-
- {% for valor, nome in Militante.get_responsabilidades_list() %}
-
-
-
- {{ nome }}
-
+
+
+
Responsabilidades
+
+
+
+ Secretário
+
+ Responsável de Imprensa
+
+ Imprensa
+
+ MPS
+
+ Quadro-Orientador
+
+ Responsável de Finanças
+
+ Tesoureiro
+
+ MNS
+
+ Juventude
+
+ Aspirante
- {% endfor %}
@@ -256,4 +270,34 @@
-
\ No newline at end of file
+
+
+
\ No newline at end of file