Files
controles/templates/home.html

643 lines
26 KiB
HTML

{% extends "base.html" %}
{% block title %}Início{% endblock %}
{% block content %}
<div class="row g-4">
<div class="col-12">
<div class="welcome-header">
<h2 class="mb-2">Olá, {{ nome_usuario }}!</h2>
<h4 class="text-muted">
{{ data_atual }}
</h4>
</div>
</div>
<!-- Cards de Estatísticas -->
<div class="col-md-6 col-lg-3">
<div class="stats-card blue">
<div class="title">Total de Militantes</div>
<div class="value">{{ total_militantes }}</div>
<a href="{{ url_for('listar_militantes') }}" class="link">
Ver detalhes <i class="fas fa-arrow-right"></i>
</a>
<div class="icon">
<i class="fas fa-users"></i>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="stats-card green">
<div class="title">Total de Cotas</div>
<div class="value">R$ {{ total_cotas }}</div>
<a href="{{ url_for('listar_cotas') }}" class="link">
Ver detalhes <i class="fas fa-arrow-right"></i>
</a>
<div class="icon">
<i class="fas fa-dollar-sign"></i>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="stats-card cyan">
<div class="title">Materiais Vendidos</div>
<div class="value">{{ total_materiais }}</div>
<a href="{{ url_for('listar_materiais') }}" class="link">
Ver detalhes <i class="fas fa-arrow-right"></i>
</a>
<div class="icon">
<i class="fas fa-book"></i>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="stats-card yellow">
<div class="title">Assinaturas Ativas</div>
<div class="value">{{ total_assinaturas }}</div>
<a href="{{ url_for('listar_assinaturas') }}" class="link">
Ver detalhes <i class="fas fa-arrow-right"></i>
</a>
<div class="icon">
<i class="fas fa-newspaper"></i>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<!-- Últimos Militantes -->
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-user-plus"></i>Últimos Militantes Cadastrados
</h5>
</div>
<div class="card-body p-0">
{% if ultimos_militantes %}
<div class="list-group list-group-flush">
{% for militante in ultimos_militantes %}
<div class="list-group-item" style="cursor: pointer"
data-bs-toggle="modal"
data-bs-target="#militanteModal"
data-militante-id="{{ militante.id }}"
data-militante-nome="{{ militante.nome }}"
data-militante-cpf="{{ militante.cpf }}"
data-militante-email="{{ militante.email }}"
data-militante-telefone="{{ militante.telefone }}"
data-militante-endereco="{{ militante.endereco }}"
data-militante-filiado="{{ militante.filiado }}">
<div class="militante-info">
<h6 class="mb-1">{{ militante.nome }}</h6>
<small>{{ militante.email }}</small>
</div>
<i class="fas fa-chevron-right text-muted"></i>
</div>
{% endfor %}
</div>
{% else %}
<p class="text-muted m-3">Nenhum militante cadastrado recentemente.</p>
{% endif %}
</div>
</div>
</div>
<!-- Últimos Pagamentos -->
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-money-bill-wave"></i>Últimos Pagamentos
</h5>
</div>
<div class="card-body p-0">
{% if ultimos_pagamentos %}
<div class="list-group list-group-flush">
{% for pagamento in ultimos_pagamentos %}
<div class="list-group-item" style="cursor: pointer" onclick="carregarDadosPagamento({{ pagamento.id }})">
<div class="militante-info">
<h6 class="mb-1">{{ pagamento.militante.nome }}</h6>
<small>{{ pagamento.data_pagamento.strftime('%d/%m/%Y') }}</small>
</div>
<div class="d-flex align-items-center gap-2">
<span class="badge bg-success">R$ {{ "%.2f"|format(pagamento.valor) }}</span>
<div class="dropdown">
<button class="btn btn-link text-secondary p-0" type="button" data-bs-toggle="dropdown">
<i class="fas fa-ellipsis-v"></i>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="#" onclick="event.stopPropagation(); carregarDadosPagamento({{ pagamento.id }})">
<i class="fas fa-edit me-2"></i>Editar
</a>
</li>
<li>
<a class="dropdown-item text-danger" href="#" onclick="event.stopPropagation(); confirmarExclusao({{ pagamento.id }}, 'pagamentos')">
<i class="fas fa-trash me-2"></i>Excluir
</a>
</li>
</ul>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<p class="text-muted m-3">Nenhum pagamento registrado recentemente.</p>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Modal de Detalhes do Militante -->
<div class="modal fade" id="militanteModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fas fa-user me-2"></i>Detalhes do Militante
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fechar"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="fw-bold">Nome:</label>
<p id="militanteNome" class="mb-2"></p>
</div>
<div class="mb-3">
<label class="fw-bold">CPF:</label>
<p id="militanteCPF" class="mb-2"></p>
</div>
<div class="mb-3">
<label class="fw-bold">Email:</label>
<p id="militanteEmail" class="mb-2"></p>
</div>
<div class="mb-3">
<label class="fw-bold">Telefone:</label>
<p id="militanteTelefone" class="mb-2"></p>
</div>
<div class="mb-3">
<label class="fw-bold">Endereço:</label>
<p id="militanteEndereco" class="mb-2"></p>
</div>
<div class="mb-3">
<label class="fw-bold">Status:</label>
<p id="militanteFiliado" class="mb-2"></p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalEditarMilitante" style="background-color: var(--bs-primary) !important; border-color: var(--bs-primary) !important;">
<i class="fas fa-edit me-2"></i>Editar
</button>
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
<i class="fas fa-trash me-2"></i>Excluir
</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
</div>
</div>
</div>
</div>
<!-- Modal de Edição -->
<div class="modal fade" id="modalEditarMilitante" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fas fa-user-edit me-2"></i>Editar Militante
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="formEditarMilitante" method="post">
<div class="row">
<div class="col-md-6 mb-3">
<label for="editNome" class="form-label">Nome:</label>
<input type="text" class="form-control" id="editNome" name="nome" required>
</div>
<div class="col-md-6 mb-3">
<label for="editCpf" class="form-label">CPF:</label>
<input type="text" class="form-control" id="editCpf" name="cpf" required>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="editEmail" class="form-label">Email:</label>
<input type="email" class="form-control" id="editEmail" name="email" required>
</div>
<div class="col-md-6 mb-3">
<label for="editTelefone" class="form-label">Telefone:</label>
<input type="text" class="form-control" id="editTelefone" name="telefone">
</div>
</div>
<div class="mb-3">
<label for="editEndereco" class="form-label">Endereço:</label>
<input type="text" class="form-control" id="editEndereco" name="endereco">
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="editFiliado" name="filiado">
<label class="form-check-label" for="editFiliado">Filiado</label>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" form="formEditarMilitante" class="btn btn-success">
<i class="fas fa-save me-2"></i>Salvar
</button>
</div>
</div>
</div>
</div>
<!-- Modal de Edição de Pagamento -->
<div class="modal fade" id="modalEditarPagamento" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fas fa-money-bill-wave me-2"></i>Editar Pagamento
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="formEditarPagamento" method="post">
<input type="hidden" id="editPagamentoId" name="id">
<div class="mb-3">
<label for="editValor" class="form-label">Valor</label>
<div class="input-group">
<span class="input-group-text">R$</span>
<input type="number" step="0.01" class="form-control" id="editValor" name="valor" required>
</div>
</div>
<div class="mb-3">
<label for="editDataPagamento" class="form-label">Data do Pagamento</label>
<input type="date" class="form-control" id="editDataPagamento" name="data_pagamento" required>
</div>
<div class="mb-3">
<label for="editTipoPagamento" class="form-label">Tipo de Pagamento</label>
<select class="form-select" id="editTipoPagamento" name="tipo_pagamento" required>
{% for tipo in tipos_pagamento %}
<option value="{{ tipo.id }}">{{ tipo.nome }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label for="editObservacao" class="form-label">Observação</label>
<textarea class="form-control" id="editObservacao" name="observacao" rows="3"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
<i class="fas fa-times me-2"></i>Cancelar
</button>
<button type="submit" form="formEditarPagamento" class="btn btn-primary">
<i class="fas fa-save me-2"></i>Salvar Alterações
</button>
</div>
</div>
</div>
</div>
<!-- Modal de Confirmação de Exclusão -->
<div class="modal fade" id="deleteModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fas fa-exclamation-triangle me-2"></i>Confirmar Exclusão
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Tem certeza que deseja excluir este item?</p>
<p class="text-danger"><small>Esta ação não pode ser desfeita.</small></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
<i class="fas fa-times me-2"></i>Cancelar
</button>
<button type="button" class="btn btn-danger" id="btnConfirmarExclusao">
<i class="fas fa-trash me-2"></i>Excluir
</button>
</div>
</div>
</div>
</div>
<style>
.welcome-header {
background: linear-gradient(to right, var(--background-color), rgba(232, 0, 12, 0.05));
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 2rem;
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
}
.welcome-header h2 {
font-size: 2rem;
margin-bottom: 0.5rem;
color: var(--primary-color);
}
.welcome-header h4 {
font-size: 1.2rem;
color: var(--secondary-color);
opacity: 0.8;
margin: 0;
}
.valor-container {
flex: 1;
min-width: 0; /* Permite que o texto quebre corretamente */
}
.valor-cota {
font-size: calc(1.2rem + 0.8vw);
line-height: 1.2;
word-break: break-word;
margin-right: 0.5rem;
}
.icon-container {
font-size: 1.5rem;
opacity: 0.8;
margin-left: 8px;
margin-top: 4px;
}
/* Estilo para o backdrop com blur em todos os modais */
.modal-backdrop.show {
backdrop-filter: blur(8px);
background-color: rgba(0, 0, 0, 0.7);
}
/* Estilo para o botão de fechar dos modais */
.btn-close {
background-color: transparent;
padding: 0.5rem;
opacity: 0.8;
transition: opacity 0.2s;
filter: invert(1) grayscale(100%) brightness(200%);
}
.btn-close:hover {
opacity: 1;
background-color: transparent;
}
/* Estilo para modais */
.modal-content {
border: none;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
.modal-header {
background: linear-gradient(to right, var(--bs-gray-dark), var(--bs-gray));
color: white;
border-radius: 12px 12px 0 0;
border-bottom: none;
padding: 1rem;
}
.modal-body {
padding: 1.5rem;
}
.modal-footer {
border-top: 1px solid #eee;
padding: 1rem;
}
/* Garantir que o botão de editar fique azul */
.btn-primary {
background-color: var(--bs-primary) !important;
border-color: var(--bs-primary) !important;
}
.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active {
background-color: var(--bs-primary-dark) !important;
border-color: var(--bs-primary-dark) !important;
}
</style>
{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Modal de Detalhes
const militanteModal = document.getElementById('militanteModal');
militanteModal.addEventListener('show.bs.modal', function(event) {
const button = event.relatedTarget;
const militanteId = button.getAttribute('data-militante-id');
// Preencher os dados do militante
document.getElementById('militanteNome').textContent = button.getAttribute('data-militante-nome');
document.getElementById('militanteCPF').textContent = button.getAttribute('data-militante-cpf');
document.getElementById('militanteEmail').textContent = button.getAttribute('data-militante-email');
document.getElementById('militanteTelefone').textContent = button.getAttribute('data-militante-telefone');
document.getElementById('militanteEndereco').textContent = button.getAttribute('data-militante-endereco');
document.getElementById('militanteFiliado').textContent = button.getAttribute('data-militante-filiado') === 'True' ? 'Filiado' : 'Não Filiado';
// Configurar dados para o modal de edição
const btnEditar = this.querySelector('.btn-primary');
btnEditar.addEventListener('click', function() {
const modalEditar = document.getElementById('modalEditarMilitante');
// Preencher o formulário de edição
document.getElementById('editNome').value = button.getAttribute('data-militante-nome');
document.getElementById('editCpf').value = button.getAttribute('data-militante-cpf');
document.getElementById('editEmail').value = button.getAttribute('data-militante-email');
document.getElementById('editTelefone').value = button.getAttribute('data-militante-telefone');
document.getElementById('editEndereco').value = button.getAttribute('data-militante-endereco');
document.getElementById('editFiliado').checked = button.getAttribute('data-militante-filiado') === 'True';
// Configurar action do formulário
document.getElementById('formEditarMilitante').action = `/militantes/editar/${militanteId}`;
});
// Configurar dados para o modal de exclusão
const btnExcluir = this.querySelector('.btn-danger');
btnExcluir.addEventListener('click', function() {
const deleteModal = document.getElementById('deleteModal');
const btnConfirmarExclusao = deleteModal.querySelector('#btnConfirmarExclusao');
// Atualizar texto do modal
deleteModal.querySelector('.modal-body p').textContent = `Tem certeza que deseja excluir o militante ${button.getAttribute('data-militante-nome')}?`;
// Configurar ação de exclusão
btnConfirmarExclusao.onclick = function() {
fetch(`/militantes/excluir/${militanteId}`, {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
// Fechar os modais
bootstrap.Modal.getInstance(deleteModal).hide();
bootstrap.Modal.getInstance(militanteModal).hide();
// Atualizar a página
location.reload();
} else {
alert(data.message || 'Erro ao excluir militante');
}
})
.catch(error => {
console.error('Erro:', error);
alert('Erro ao excluir militante');
});
};
});
});
// Limpar event listeners quando o modal for fechado
militanteModal.addEventListener('hidden.bs.modal', function () {
const btnEditar = this.querySelector('.btn-primary');
const btnExcluir = this.querySelector('.btn-danger');
btnEditar.replaceWith(btnEditar.cloneNode(true));
btnExcluir.replaceWith(btnExcluir.cloneNode(true));
});
// Envio do formulário de edição via AJAX
const formEditarMilitante = document.getElementById('formEditarMilitante');
formEditarMilitante.addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch(this.action, {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
// Fechar os modais
bootstrap.Modal.getInstance(document.getElementById('modalEditarMilitante')).hide();
bootstrap.Modal.getInstance(document.getElementById('militanteModal')).hide();
// Atualizar a página
location.reload();
} 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, formEditarMilitante);
}
})
.catch(error => {
console.error('Erro:', error);
const alertDiv = document.createElement('div');
alertDiv.className = 'alert alert-danger alert-dismissible fade show';
alertDiv.innerHTML = `
Erro ao atualizar militante. Tente novamente.
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.querySelector('.modal-body').insertBefore(alertDiv, formEditarMilitante);
});
});
// Função para carregar dados do pagamento no modal
function carregarDadosPagamento(id) {
fetch(`/api/pagamentos/${id}`)
.then(response => response.json())
.then(data => {
document.getElementById('editPagamentoId').value = data.id;
document.getElementById('editValor').value = data.valor;
document.getElementById('editDataPagamento').value = data.data_pagamento;
document.getElementById('editTipoPagamento').value = data.tipo_pagamento_id;
document.getElementById('editObservacao').value = data.observacao || '';
// Abre o modal
new bootstrap.Modal(document.getElementById('modalEditarPagamento')).show();
})
.catch(error => {
console.error('Erro ao carregar dados:', error);
alert('Erro ao carregar dados do pagamento');
});
}
// Função para salvar alterações do pagamento
document.getElementById('formEditarPagamento').addEventListener('submit', function(e) {
e.preventDefault();
const id = document.getElementById('editPagamentoId').value;
const formData = new FormData(this);
fetch(`/api/pagamentos/${id}`, {
method: 'PUT',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Fecha o modal
bootstrap.Modal.getInstance(document.getElementById('modalEditarPagamento')).hide();
// Recarrega a página
location.reload();
} else {
alert('Erro ao salvar alterações: ' + data.message);
}
})
.catch(error => {
console.error('Erro ao salvar:', error);
alert('Erro ao salvar alterações');
});
});
// Configuração do modal de exclusão
let itemParaExcluir = null;
let tipoItem = null;
function confirmarExclusao(id, tipo) {
itemParaExcluir = id;
tipoItem = tipo;
new bootstrap.Modal(document.getElementById('deleteModal')).show();
}
document.getElementById('btnConfirmarExclusao').addEventListener('click', function() {
if (!itemParaExcluir || !tipoItem) return;
fetch(`/api/${tipoItem}/${itemParaExcluir}`, {
method: 'DELETE'
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Erro ao excluir: ' + data.message);
}
})
.catch(error => {
console.error('Erro ao excluir:', error);
alert('Erro ao excluir item');
});
});
});
</script>
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='js/militantes.js') }}"></script>
{% endblock %}
{% endblock %}