Files
ibiza_sistema/views/users/index.php
Administrador Ibiza 5289fd4133 Primer version funcional
2025-12-29 23:37:11 -06:00

325 lines
14 KiB
PHP
Executable File

<div class="row mb-4">
<div class="col-12">
<h2><i class="bi bi-people"></i> Gestión de Usuarios</h2>
<p class="text-muted">Crear y administrar usuarios del sistema</p>
</div>
</div>
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0">Usuarios del Sistema</h5>
<?php if (Auth::isAdmin()): ?>
<button class="btn btn-primary btn-sm" onclick="openUserModal()">
<i class="bi bi-plus"></i> Nuevo Usuario
</button>
<?php endif; ?>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th>ID</th>
<th>Usuario</th>
<th>Email</th>
<th>Nombre</th>
<th>Rol</th>
<th>Estado</th>
<th>Último Acceso</th>
<?php if (Auth::isAdmin()): ?>
<th>Acciones</th>
<?php endif; ?>
</tr>
</thead>
<tbody id="usersTable">
<tr><td colspan="8" class="text-center">Cargando...</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<?php if (Auth::isAdmin()): ?>
<div class="modal fade" id="userModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="userModalTitle">Nuevo Usuario</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form id="userForm" novalidate>
<div class="modal-body">
<input type="hidden" id="userId" name="id">
<div class="mb-3">
<label class="form-label">Usuario</label>
<input type="text" class="form-control" name="username" required>
</div>
<div class="mb-3">
<label class="form-label">Email</label>
<input type="email" class="form-control" name="email" required>
</div>
<div class="mb-3">
<label class="form-label">Nombre</label>
<input type="text" class="form-control" name="first_name" required>
</div>
<div class="mb-3">
<label class="form-label">Apellido</label>
<input type="text" class="form-control" name="last_name" required>
</div>
<div class="mb-3">
<label class="form-label">Contraseña</label>
<input type="password" class="form-control" name="password" id="userPassword">
<small class="text-muted">Dejar vacío para no cambiar</small>
</div>
<div class="mb-3">
<label class="form-label">Rol</label>
<select class="form-select" name="role" id="userRole" required>
<option value="VIEWER">Viewer (Solo lectura)</option>
<option value="CAPTURIST">Capturista (Puede editar)</option>
<option value="ADMIN">Admin (Acceso total)</option>
<option value="LECTOR">Lector (Solo casas asignadas)</option>
</select>
</div>
<div class="mb-3" id="houseSelectionDiv" style="display:none;">
<label class="form-label">Casas Permitidas</label>
<select class="form-select" id="houseSelect" name="house_ids[]" multiple style="height: 200px;" required>
<?php
require_once __DIR__ . '/../../models/House.php';
$allHouses = House::all();
foreach ($allHouses as $house): ?>
<option value="<?= $house['id'] ?>">Casa <?= $house['number'] ?> - <?= htmlspecialchars($house['owner_name'] ?: 'Sin nombre') ?></option>
<?php endforeach; ?>
</select>
<small class="text-muted">Seleccionar una o más casas (Ctrl+Click para múltiples)</small>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-primary">Guardar</button>
</div>
</form>
</div>
</div>
</div>
<script>
let usersData = [];
function loadUsers() {
fetch('/dashboard.php?page=users_actions&action=list')
.then(r => r.json())
.then(data => {
usersData = data.users;
renderUsers();
});
}
function renderUsers() {
const tbody = document.getElementById('usersTable');
if (usersData.length === 0) {
tbody.innerHTML = '<tr><td colspan="8" class="text-center">No hay usuarios</td></tr>';
return;
}
tbody.innerHTML = usersData.map(u => {
let roleClass = u.role === 'ADMIN' ? 'danger' : (u.role === 'CAPTURIST' ? 'warning' : (u.role === 'LECTOR' ? 'secondary' : 'info'));
return `
<tr>
<td>${u.id}</td>
<td>${u.username}</td>
<td>${u.email}</td>
<td>${u.first_name} ${u.last_name}</td>
<td><span class="badge bg-${roleClass}">${u.role}</span></td>
<td>${u.is_active ? '<span class="badge bg-success">Activo</span>' : '<span class="badge bg-secondary">Inactivo</span>'}</td>
<td>${u.last_login ? new Date(u.last_login).toLocaleString() : '-'}</td>
<td>
<button class="btn btn-sm btn-primary" onclick="editUser(${u.id})">
<i class="bi bi-pencil"></i>
</button>
${u.id !== 1 ? `<button class="btn btn-sm btn-danger" onclick="deleteUser(${u.id})">
<i class="bi bi-trash"></i>
</button>` : ''}
</td>
</tr>
`;
}).join('');
}
document.getElementById('userRole').addEventListener('change', function() {
const houseDiv = document.getElementById('houseSelectionDiv');
const houseSelect = document.getElementById('houseSelect');
if (this.value === 'LECTOR') {
houseDiv.style.display = 'block';
houseSelect.required = true;
} else {
houseDiv.style.display = 'none';
houseSelect.required = false;
Array.from(houseSelect.options).forEach(opt => opt.selected = false);
}
});
function openUserModal(id = null) {
const modal = new bootstrap.Modal(document.getElementById('userModal'));
const title = document.getElementById('userModalTitle');
const passwordField = document.getElementById('userPassword');
const roleSelect = document.getElementById('userRole');
const houseDiv = document.getElementById('houseSelectionDiv');
const houseSelect = document.getElementById('houseSelect');
document.getElementById('userForm').reset();
document.getElementById('userId').value = '';
Array.from(houseSelect.options).forEach(opt => opt.selected = false);
if (id) {
const user = usersData.find(u => u.id === id);
if (user) {
title.textContent = 'Editar Usuario';
document.getElementById('userId').value = user.id;
document.querySelector('[name="username"]').value = user.username;
document.querySelector('[name="email"]').value = user.email;
document.querySelector('[name="first_name"]').value = user.first_name;
document.querySelector('[name="last_name"]').value = user.last_name;
roleSelect.value = user.role;
passwordField.placeholder = 'Dejar vacío para no cambiar';
passwordField.required = false;
if (user.role === 'LECTOR') {
houseDiv.style.display = 'block';
houseSelect.required = true;
fetch(`/dashboard.php?page=users_actions&action=get_user_houses&user_id=${id}`)
.then(r => r.json())
.then(data => {
// ...
}); }
}
} else {
title.textContent = 'Nuevo Usuario';
passwordField.placeholder = 'Contraseña requerida';
passwordField.required = true;
houseDiv.style.display = 'none';
houseSelect.required = false;
}
modal.show();
}
function editUser(id) {
openUserModal(id);
}
function deleteUser(id) {
Swal.fire({
title: '¿Eliminar usuario?',
text: 'Esta acción no se puede deshacer',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, eliminar'
}).then(result => {
if (result.isConfirmed) {
fetch(`/dashboard.php?page=users_actions&action=delete&id=${id}`, { method: 'GET' }) // Cambiado a GET
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire('Eliminado', '', 'success').then(loadUsers);
} else {
Swal.fire('Error', data.message || 'Error al eliminar', 'error'); // Mostrar mensaje de error del backend
}
});
}
});
}
document.getElementById('userForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
const data = Object.fromEntries(formData.entries());
const id = data.id;
const houseSelect = document.getElementById('houseSelect');
const selectedHouses = Array.from(houseSelect.selectedOptions).map(opt => parseInt(opt.value));
// **NUEVA VALIDACIÓN:** Si el rol es LECTOR y no hay casas seleccionadas
if (data.role === 'LECTOR' && selectedHouses.length === 0) {
Swal.fire('Error de Validación', 'Debe seleccionar al menos una casa para el rol Lector.', 'error');
return; // Detener el envío del formulario
}
// Si no hay password y es actualización, eliminar del data para no cambiarla
if (id && !data.password) {
delete data.password;
}
const apiUrl = id ? '/dashboard.php?page=users_actions&action=update' : '/dashboard.php?page=users_actions&action=create';
console.log('--- Iniciando submit de formulario de usuario ---');
console.log('Action URL:', apiUrl);
console.log('Data sent:', data);
fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
.then(r => {
console.log('Response from user save:', r);
if (!r.ok) { // Check if response is not OK (e.g., 404, 500)
return r.text().then(text => { throw new Error(text || r.statusText); });
}
return r.json();
})
.then(res => {
console.log('Result from user save:', res);
if (res.success) {
const currentUserId = id || res.user_id;
const previousRole = usersData.find(u => u.id === parseInt(id))?.role; // parseInt(id)
if (data.role === 'LECTOR' || (id && previousRole === 'LECTOR' && data.role !== 'LECTOR')) {
const housesToAssign = (data.role === 'LECTOR') ? selectedHouses : [];
console.log('Attempting to assign houses:', housesToAssign);
fetch('/dashboard.php?page=users_actions&action=assign_houses', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_id: currentUserId, house_ids: housesToAssign })
})
.then(r => {
console.log('Response from assign houses:', r);
if (!r.ok) {
return r.text().then(text => { throw new Error(text || r.statusText); });
}
return r.json();
})
.then(assignRes => {
console.log('Result from assign houses:', assignRes);
if (assignRes.success) {
Swal.fire('Guardado', res.message || 'Usuario y permisos guardados exitosamente.', 'success').then(() => {
bootstrap.Modal.getInstance(document.getElementById('userModal')).hide();
loadUsers();
});
} else {
Swal.fire('Error', assignRes.message || 'Error desconocido al asignar casas.', 'error');
}
}).catch(error => {
console.error('Error assigning houses:', error);
Swal.fire('Error', 'Error de conexión al asignar casas: ' + error.message, 'error');
});
} else {
Swal.fire('Guardado', res.message || 'Usuario guardado exitosamente.', 'success').then(() => {
bootstrap.Modal.getInstance(document.getElementById('userModal')).hide();
loadUsers();
});
}
} else {
Swal.fire('Error', res.message || 'Error desconocido al guardar usuario.', 'error');
}
})
.catch(error => {
console.error('Error saving user:', error);
Swal.fire('Error', 'Error de conexión al guardar usuario: ' + error.message, 'error');
});
});
loadUsers();
</script>
<?php endif; ?>