2025-12-11 10:45:24 +01:00

752 lines
33 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
include('include/headscript.php');
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
/* ==========================================
AJAX HANDLERS (ADD / EDIT / DELETE)
========================================== */
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['ajax'] == '1') {
header('Content-Type: application/json');
$action = $_POST['action'] ?? '';
try {
if ($action === 'add') {
$employee_code = trim($_POST['employee_code'] ?? '');
$first_name = trim($_POST['first_name'] ?? '');
$last_name = trim($_POST['last_name'] ?? '');
$department = trim($_POST['department'] ?? '');
$position = trim($_POST['position'] ?? '');
$hire_date = trim($_POST['hire_date'] ?? '');
$status = trim($_POST['status'] ?? 'active');
$auth_user_id = $_POST['auth_user_id'] !== '' ? (int)$_POST['auth_user_id'] : null;
if ($first_name === '' || $last_name === '') {
echo json_encode([
'success' => false,
'message' => 'First name and Last name are required.'
]);
exit;
}
if (!in_array($status, ['active', 'inactive', 'suspended'], true)) {
$status = 'active';
}
$sql = "INSERT INTO employees
(auth_user_id, employee_code, first_name, last_name, department, position, hire_date, status, created_at, updated_at)
VALUES
(:auth_user_id, :employee_code, :first_name, :last_name, :department, :position, :hire_date, :status, NOW(), NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'auth_user_id' => $auth_user_id,
'employee_code' => $employee_code !== '' ? $employee_code : null,
'first_name' => $first_name,
'last_name' => $last_name,
'department' => $department !== '' ? $department : null,
'position' => $position !== '' ? $position : null,
'hire_date' => $hire_date !== '' ? $hire_date : null,
'status' => $status
]);
echo json_encode(['success' => true]);
exit;
}
if ($action === 'edit') {
$id = (int)($_POST['id'] ?? 0);
$employee_code = trim($_POST['employee_code'] ?? '');
$first_name = trim($_POST['first_name'] ?? '');
$last_name = trim($_POST['last_name'] ?? '');
$department = trim($_POST['department'] ?? '');
$position = trim($_POST['position'] ?? '');
$hire_date = trim($_POST['hire_date'] ?? '');
$status = trim($_POST['status'] ?? 'active');
$auth_user_id = $_POST['auth_user_id'] !== '' ? (int)$_POST['auth_user_id'] : null;
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid employee ID.']);
exit;
}
if ($first_name === '' || $last_name === '') {
echo json_encode([
'success' => false,
'message' => 'First name and Last name are required.'
]);
exit;
}
if (!in_array($status, ['active', 'inactive', 'suspended'], true)) {
$status = 'active';
}
$sql = "UPDATE employees
SET auth_user_id = :auth_user_id,
employee_code = :employee_code,
first_name = :first_name,
last_name = :last_name,
department = :department,
position = :position,
hire_date = :hire_date,
status = :status,
updated_at = NOW()
WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'auth_user_id' => $auth_user_id,
'employee_code' => $employee_code !== '' ? $employee_code : null,
'first_name' => $first_name,
'last_name' => $last_name,
'department' => $department !== '' ? $department : null,
'position' => $position !== '' ? $position : null,
'hire_date' => $hire_date !== '' ? $hire_date : null,
'status' => $status,
'id' => $id
]);
echo json_encode(['success' => true]);
exit;
}
if ($action === 'delete') {
$id = (int)($_POST['id'] ?? 0);
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid employee ID.']);
exit;
}
$stmt = $pdo->prepare("DELETE FROM employees WHERE id = :id");
$stmt->execute(['id' => $id]);
echo json_encode(['success' => true]);
exit;
}
echo json_encode(['success' => false, 'message' => 'Unknown action.']);
exit;
} catch (Exception $e) {
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
exit;
}
}
/* ==========================================
PAGE DATA (LIST + USERS LIST)
========================================== */
// Employees list
$sql = "
SELECT e.*,
au.email AS user_email,
CONCAT(COALESCE(au.first_name, ''), ' ', COALESCE(au.last_name, '')) AS user_fullname
FROM employees e
LEFT JOIN auth_users au ON e.auth_user_id = au.id
ORDER BY e.id DESC
";
$stmtEmployees = $pdo->query($sql);
$employees = $stmtEmployees->fetchAll(PDO::FETCH_ASSOC);
// Users list for select
$sqlUsers = "
SELECT id,
CONCAT(
COALESCE(first_name, ''),
' ',
COALESCE(last_name, ''),
' (',
email,
')'
) AS label
FROM auth_users
ORDER BY first_name, last_name, email
";
$stmtUsers = $pdo->query($sqlUsers);
$users = $stmtUsers->fetchAll(PDO::FETCH_ASSOC);
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
<?php include('cssinclude.php'); ?>
<title>Gestione Dipendenti - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
<!-- jQuery e Bootstrap -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- DataTables -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css">
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
<!-- Select2 -->
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.full.min.js"></script>
<style>
body {
font-size: 1.05rem;
background: #f8fafc;
}
.card {
border-radius: 16px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.back-dashboard {
background-color: #cfe3ff !important;
color: #1f2d3d !important;
border: 1px solid #bcd4f4 !important;
border-radius: 10px;
font-weight: 600;
font-size: 1rem;
padding: 10px 18px;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease-in-out;
}
.back-dashboard:hover {
background-color: #b9d3ff !important;
transform: translateY(-2px);
}
.btn-add {
background-color: #0d6efd;
color: #fff;
border-radius: 8px;
padding: 10px 20px;
font-weight: 500;
transition: all 0.2s ease-in-out;
}
.btn-add:hover {
background-color: #0b5ed7;
transform: scale(1.02);
}
.table thead {
background-color: #cfe3ff;
color: #1f2d3d;
}
.modal-content {
border-radius: 16px;
}
#tabellaDipendenti thead th {
text-align: center;
vertical-align: middle;
}
.badge-status {
padding: 0.25rem 0.6rem;
border-radius: 999px;
font-size: 0.8rem;
font-weight: 600;
}
.badge-status.active {
background-color: #d1fae5;
color: #065f46;
}
.badge-status.inactive {
background-color: #e5e7eb;
color: #374151;
}
.badge-status.suspended {
background-color: #fee2e2;
color: #b91c1c;
}
</style>
</head>
<body>
<div class="wrapper toggled">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<div class="card p-3">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Gestione Dipendenti</h5>
<button type="button" class="btn back-dashboard" onclick="location.href='production_dashboard.php'">
↩️ Torna alla Dashboard
</button>
</div>
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="fw-semibold mb-0">Elenco Completo</h6>
<button class="btn btn-add" data-bs-toggle="modal" data-bs-target="#addEmployeeModal">
Aggiungi Dipendente
</button>
</div>
<!-- TABELLA -->
<div class="table-responsive">
<table id="tabellaDipendenti" class="table table-striped align-middle text-center" style="width:100%;">
<thead>
<tr>
<th>ID</th>
<th>Code</th>
<th>Name</th>
<th>Department</th>
<th>Position</th>
<th>Hire Date</th>
<th>Status</th>
<th>Linked User</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($employees)): ?>
<tr>
<td colspan="9" class="text-muted">No employees found</td>
</tr>
<?php else: ?>
<?php foreach ($employees as $row): ?>
<?php
$fullName = trim(($row['first_name'] ?? '') . ' ' . ($row['last_name'] ?? ''));
$hireDate = $row['hire_date'] && $row['hire_date'] !== '0000-00-00'
? date('d/m/Y', strtotime($row['hire_date']))
: '-';
$status = $row['status'] ?? 'active';
$statusClass = $status;
$statusLabel = ucfirst($status);
$linkedUser = '-';
if (!empty($row['user_email'])) {
$labelName = trim($row['user_fullname']);
if ($labelName !== '') {
$linkedUser = htmlspecialchars($labelName . ' (' . $row['user_email'] . ')');
} else {
$linkedUser = htmlspecialchars($row['user_email']);
}
}
?>
<tr>
<td><?= (int)$row['id'] ?></td>
<td><?= htmlspecialchars($row['employee_code'] ?? '') ?></td>
<td><?= htmlspecialchars($fullName) ?></td>
<td><?= htmlspecialchars($row['department'] ?? '') ?></td>
<td><?= htmlspecialchars($row['position'] ?? '') ?></td>
<td><?= $hireDate ?></td>
<td>
<span class="badge-status <?= $statusClass ?>">
<?= htmlspecialchars($statusLabel) ?>
</span>
</td>
<td><?= $linkedUser ?></td>
<td>
<button
class="btn btn-sm btn-outline-secondary edit-employee"
data-id="<?= (int)$row['id'] ?>"
data-code="<?= htmlspecialchars($row['employee_code'] ?? '', ENT_QUOTES) ?>"
data-first_name="<?= htmlspecialchars($row['first_name'] ?? '', ENT_QUOTES) ?>"
data-last_name="<?= htmlspecialchars($row['last_name'] ?? '', ENT_QUOTES) ?>"
data-department="<?= htmlspecialchars($row['department'] ?? '', ENT_QUOTES) ?>"
data-position="<?= htmlspecialchars($row['position'] ?? '', ENT_QUOTES) ?>"
data-hire_date="<?= htmlspecialchars($row['hire_date'] ?? '', ENT_QUOTES) ?>"
data-status="<?= htmlspecialchars($status, ENT_QUOTES) ?>"
data-auth_user_id="<?= $row['auth_user_id'] !== null ? (int)$row['auth_user_id'] : '' ?>">
✏️ Modifica
</button>
<button
class="btn btn-sm btn-outline-danger delete-employee"
data-id="<?= (int)$row['id'] ?>"
data-name="<?= htmlspecialchars($fullName, ENT_QUOTES) ?>">
🗑️ Cancella
</button>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<!-- MODALE AGGIUNTA DIPENDENTE -->
<div class="modal fade" id="addEmployeeModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header" style="background-color:#cfe3ff;">
<h5 class="modal-title">Aggiungi Nuovo Dipendente</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="addEmployeeForm">
<div class="mb-3">
<label class="form-label fw-semibold">Employee Code</label>
<input type="text" class="form-control" id="addEmployeeCode" name="employee_code" placeholder="Optional">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">First Name</label>
<input type="text" class="form-control" id="addFirstName" name="first_name" required>
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Last Name</label>
<input type="text" class="form-control" id="addLastName" name="last_name" required>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Department</label>
<input type="text" class="form-control" id="addDepartment" name="department" placeholder="e.g. Production">
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Position</label>
<input type="text" class="form-control" id="addPosition" name="position" placeholder="e.g. Line Operator">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Hire Date</label>
<input type="date" class="form-control" id="addHireDate" name="hire_date">
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Status</label>
<select class="form-select" id="addStatus" name="status">
<option value="active" selected>Active</option>
<option value="inactive">Inactive</option>
<option value="suspended">Suspended</option>
</select>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Linked User (auth_users)</label>
<select class="form-select" id="addAuthUserId" name="auth_user_id" style="width:100%;">
<option value="">-- None --</option>
<?php foreach ($users as $u): ?>
<option value="<?= (int)$u['id'] ?>">
<?= htmlspecialchars($u['label']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="text-center">
<button type="submit" class="btn btn-add">💾 Save</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- MODALE EDIT DIPENDENTE -->
<div class="modal fade" id="editEmployeeModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header" style="background-color:#cfe3ff;">
<h5 class="modal-title">Modifica Dipendente</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="editEmployeeForm">
<input type="hidden" id="editEmployeeId">
<div class="mb-3">
<label class="form-label fw-semibold">Employee Code</label>
<input type="text" class="form-control" id="editEmployeeCode" name="employee_code" placeholder="Optional">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">First Name</label>
<input type="text" class="form-control" id="editFirstName" name="first_name" required>
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Last Name</label>
<input type="text" class="form-control" id="editLastName" name="last_name" required>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Department</label>
<input type="text" class="form-control" id="editDepartment" name="department">
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Position</label>
<input type="text" class="form-control" id="editPosition" name="position">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Hire Date</label>
<input type="date" class="form-control" id="editHireDate" name="hire_date">
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Status</label>
<select class="form-select" id="editStatus" name="status">
<option value="active">Active</option>
<option value="inactive">Inactive</option>
<option value="suspended">Suspended</option>
</select>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Linked User (auth_users)</label>
<select class="form-select" id="editAuthUserId" name="auth_user_id" style="width:100%;">
<option value="">-- None --</option>
<?php foreach ($users as $u): ?>
<option value="<?= (int)$u['id'] ?>">
<?= htmlspecialchars($u['label']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="text-center">
<button type="submit" class="btn btn-add">💾 Save Changes</button>
</div>
</form>
</div>
</div>
</div>
</div>
<?php include('jsinclude.php'); ?>
<script>
$(document).ready(function() {
// DataTable
$('#tabellaDipendenti').DataTable({
order: [
[0, 'desc']
],
pageLength: 25,
language: {
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json'
}
});
// Select2 on user selects
$('#addAuthUserId, #editAuthUserId').select2({
theme: 'bootstrap-5',
width: '100%'
});
/* -------- ADD EMPLOYEE -------- */
$("#addEmployeeForm").on("submit", function(e) {
e.preventDefault();
const payload = new URLSearchParams();
payload.append('ajax', '1');
payload.append('action', 'add');
payload.append('employee_code', $("#addEmployeeCode").val().trim());
payload.append('first_name', $("#addFirstName").val().trim());
payload.append('last_name', $("#addLastName").val().trim());
payload.append('department', $("#addDepartment").val().trim());
payload.append('position', $("#addPosition").val().trim());
payload.append('hire_date', $("#addHireDate").val());
payload.append('status', $("#addStatus").val());
payload.append('auth_user_id', $("#addAuthUserId").val() || '');
fetch("", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: payload.toString()
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: "success",
title: "Saved!",
confirmButtonColor: "#3085d6"
})
.then(() => location.reload());
} else {
Swal.fire({
icon: "error",
title: "Error",
text: data.message || "Unable to save employee."
});
}
})
.catch(err => {
Swal.fire({
icon: "error",
title: "Error",
text: "Communication error."
});
console.error(err);
});
});
/* -------- OPEN EDIT MODAL -------- */
$(document).on("click", ".edit-employee", function() {
const btn = $(this);
$("#editEmployeeId").val(btn.data("id"));
$("#editEmployeeCode").val(btn.data("code"));
$("#editFirstName").val(btn.data("first_name"));
$("#editLastName").val(btn.data("last_name"));
$("#editDepartment").val(btn.data("department"));
$("#editPosition").val(btn.data("position"));
$("#editHireDate").val(btn.data("hire_date"));
$("#editStatus").val(btn.data("status"));
const authUserId = btn.data("auth_user_id");
$("#editAuthUserId").val(authUserId ? String(authUserId) : '').trigger('change');
$("#editEmployeeModal").modal("show");
});
/* -------- SAVE EDIT -------- */
$("#editEmployeeForm").on("submit", function(e) {
e.preventDefault();
const payload = new URLSearchParams();
payload.append('ajax', '1');
payload.append('action', 'edit');
payload.append('id', $("#editEmployeeId").val());
payload.append('employee_code', $("#editEmployeeCode").val().trim());
payload.append('first_name', $("#editFirstName").val().trim());
payload.append('last_name', $("#editLastName").val().trim());
payload.append('department', $("#editDepartment").val().trim());
payload.append('position', $("#editPosition").val().trim());
payload.append('hire_date', $("#editHireDate").val());
payload.append('status', $("#editStatus").val());
payload.append('auth_user_id', $("#editAuthUserId").val() || '');
fetch("", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: payload.toString()
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: "success",
title: "Updated!",
confirmButtonColor: "#3085d6"
})
.then(() => location.reload());
} else {
Swal.fire({
icon: "error",
title: "Error",
text: data.message || "Unable to update employee."
});
}
})
.catch(err => {
Swal.fire({
icon: "error",
title: "Error",
text: "Communication error."
});
console.error(err);
});
});
/* -------- DELETE EMPLOYEE -------- */
$(document).on("click", ".delete-employee", function() {
const id = $(this).data("id");
const name = $(this).data("name");
Swal.fire({
title: "Confermi la cancellazione?",
text: name ? ("Dipendente: " + name) : "This employee will be deleted.",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#d33",
cancelButtonColor: "#6c757d",
confirmButtonText: "Sì, cancella",
cancelButtonText: "Annulla"
}).then((result) => {
if (!result.isConfirmed) return;
const payload = new URLSearchParams();
payload.append('ajax', '1');
payload.append('action', 'delete');
payload.append('id', id);
fetch("", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: payload.toString()
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: "success",
title: "Deleted!",
confirmButtonColor: "#3085d6"
})
.then(() => location.reload());
} else {
Swal.fire({
icon: "error",
title: "Error",
text: data.message || "Unable to delete employee."
});
}
})
.catch(err => {
Swal.fire({
icon: "error",
title: "Error",
text: "Communication error."
});
console.error(err);
});
});
});
});
</script>
</body>
</html>