38815-vm/users.php
2026-02-28 22:33:39 +00:00

257 lines
9.8 KiB
PHP

<?php
session_start();
require 'db/config.php';
$db = db();
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
header('Location: index.php');
exit;
}
// Handle User Creation/Update
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_user'])) {
$id = $_POST['user_id'] ?? null;
$name = $_POST['name'];
$role = $_POST['role'];
$processes = json_encode($_POST['processes'] ?? []);
$pin = $_POST['pin'] ?? '';
if ($id) {
// Update
$sql = "UPDATE users SET name = ?, role = ?, assigned_processes = ? WHERE id = ?";
$params = [$name, $role, $processes, $id];
$db->prepare($sql)->execute($params);
if ($role === 'admin' && !empty($pin)) {
$pinHash = password_hash($pin, PASSWORD_BCRYPT);
$db->prepare("UPDATE users SET pin_hash = ? WHERE id = ?")->execute([$pinHash, $id]);
}
} else {
// Create
$pinHash = ($role === 'admin' && !empty($pin)) ? password_hash($pin, PASSWORD_BCRYPT) : null;
$db->prepare("INSERT INTO users (name, role, assigned_processes, pin_hash) VALUES (?, ?, ?, ?)")
->execute([$name, $role, $processes, $pinHash]);
}
header("Location: users.php?success=1");
exit;
}
$users = $db->query("SELECT * FROM users ORDER BY role ASC, name ASC")->fetchAll();
$processTypes = ['cutting', 'welding', 'bending', 'assembly', 'inspection'];
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>M-TRACK | User Management</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--sidebar-width: 240px;
--bg: #f8fafc;
--primary: #1e293b;
--accent: #3b82f6;
--text: #334155;
--border: #e2e8f0;
}
body {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
background-color: var(--bg);
color: var(--text);
}
.sidebar {
width: var(--sidebar-width);
position: fixed;
top: 0;
bottom: 0;
left: 0;
background-color: var(--primary);
color: white;
z-index: 1000;
padding: 1.5rem 1rem;
}
.main-content {
margin-left: var(--sidebar-width);
padding: 2.5rem;
}
.card {
background: white;
border: 1px solid var(--border);
border-radius: 4px;
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
margin-bottom: 1.5rem;
}
.badge-process {
background: #e2e8f0;
color: #475569;
font-weight: 600;
font-size: 0.75rem;
padding: 0.25rem 0.625rem;
border-radius: 4px;
margin-right: 0.25rem;
margin-bottom: 0.25rem;
display: inline-block;
}
</style>
</head>
<body>
<div class="sidebar">
<h2>M-TRACK</h2>
<nav class="nav nav-pills flex-column">
<a class="nav-link" href="dashboard.php"><i class="bi bi-grid-fill me-2"></i> Dashboard</a>
<a class="nav-link" href="jobs.php"><i class="bi bi-briefcase me-2"></i> Jobs</a>
<a class="nav-link" href="shop_floor.php"><i class="bi bi-kanban me-2"></i> Shop Floor</a>
<a class="nav-link" href="inventory.php"><i class="bi bi-boxes me-2"></i> Inventory</a>
<a class="nav-link active" href="users.php"><i class="bi bi-people me-2"></i> Users</a>
<hr class="my-4 border-secondary opacity-25">
<a class="nav-link text-danger" href="logout.php"><i class="bi bi-box-arrow-right me-2"></i> Logout</a>
</nav>
</div>
<div class="main-content">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>User Management</h1>
<button class="btn btn-primary" onclick="resetUserModal()" data-bs-toggle="modal" data-bs-target="#userModal">
<i class="bi bi-person-plus-fill me-1"></i> New User
</button>
</div>
<div class="card">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0 align-middle">
<thead class="table-light">
<tr>
<th>Name</th>
<th>Role</th>
<th>Assigned Processes</th>
<th class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($users as $user): ?>
<?php $procs = json_decode($user['assigned_processes'] ?? '[]', true); ?>
<tr>
<td><div class="fw-bold"><?= htmlspecialchars($user['name']) ?></div></td>
<td><span class="badge bg-<?= $user['role'] === 'admin' ? 'dark' : 'light text-dark border' ?> text-uppercase" style="font-size: 0.7rem;"><?= $user['role'] ?></span></td>
<td>
<?php if ($user['role'] === 'worker'): ?>
<?php foreach ($procs as $p): ?>
<span class="badge-process"><?= strtoupper($p) ?></span>
<?php endforeach; ?>
<?php if (empty($procs)): ?>
<span class="text-muted small">None assigned</span>
<?php endif; ?>
<?php else: ?>
<span class="text-muted small">—</span>
<?php endif; ?>
</td>
<td class="text-end">
<button class="btn btn-sm btn-outline-primary" onclick='editUser(<?= json_encode($user) ?>)' data-bs-toggle="modal" data-bs-target="#userModal">Edit</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- User Modal -->
<div class="modal fade" id="userModal" tabindex="-1">
<div class="modal-dialog">
<form method="POST" class="modal-content" id="userForm">
<input type="hidden" name="user_id" id="user_id">
<div class="modal-header">
<h5 class="modal-title" id="modalTitle">New User</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Full Name</label>
<input type="text" name="name" id="user_name" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">Role</label>
<select name="role" id="user_role" class="form-select" onchange="toggleRoleFields()">
<option value="worker">Worker</option>
<option value="admin">Admin</option>
</select>
</div>
<div id="worker_fields">
<label class="form-label d-block">Assigned Processes</label>
<div class="row">
<?php foreach ($processTypes as $pt): ?>
<div class="col-6 mb-2">
<div class="form-check">
<input class="form-check-input proc-checkbox" type="checkbox" name="processes[]" value="<?= $pt ?>" id="proc_<?= $pt ?>">
<label class="form-check-label text-capitalize" for="proc_<?= $pt ?>">
<?= $pt ?>
</label>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div id="admin_fields" style="display:none;">
<div class="mb-3">
<label class="form-label">PIN (4-6 digits)</label>
<input type="password" name="pin" id="user_pin" class="form-control" placeholder="Leave blank to keep current PIN if editing">
<small class="text-muted">Admins must enter this PIN to log in.</small>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="save_user" class="btn btn-primary">Save User</button>
</div>
</form>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
function toggleRoleFields() {
const role = document.getElementById('user_role').value;
document.getElementById('worker_fields').style.display = role === 'worker' ? 'block' : 'none';
document.getElementById('admin_fields').style.display = role === 'admin' ? 'block' : 'none';
}
function resetUserModal() {
document.getElementById('userForm').reset();
document.getElementById('user_id').value = '';
document.getElementById('modalTitle').innerText = 'New User';
toggleRoleFields();
}
function editUser(user) {
document.getElementById('user_id').value = user.id;
document.getElementById('user_name').value = user.name;
document.getElementById('user_role').value = user.role;
document.getElementById('modalTitle').innerText = 'Edit User: ' + user.name;
// Reset checkboxes
document.querySelectorAll('.proc-checkbox').forEach(cb => cb.checked = false);
if (user.assigned_processes) {
const procs = JSON.parse(user.assigned_processes);
procs.forEach(p => {
const cb = document.getElementById('proc_' + p);
if (cb) cb.checked = true;
});
}
toggleRoleFields();
}
</script>
</body>
</html>