diff --git a/public/userarea/departments.php b/public/userarea/departments.php new file mode 100644 index 0000000..e2d725e --- /dev/null +++ b/public/userarea/departments.php @@ -0,0 +1,799 @@ +getConnection(); + +/* ========================================== + AJAX HANDLERS + ========================================== */ +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['ajax'] == '1') { + header('Content-Type: application/json'); + + $action = $_POST['action'] ?? ''; + + try { + if ($action === 'add') { + $name = trim($_POST['name'] ?? ''); + $code = trim($_POST['code'] ?? ''); + $description = trim($_POST['description'] ?? ''); + $color = trim($_POST['color'] ?? '#6c757d'); + $sort_order = isset($_POST['sort_order']) && $_POST['sort_order'] !== '' ? (int)$_POST['sort_order'] : 999; + $is_active = isset($_POST['is_active']) ? (int)$_POST['is_active'] : 1; + + if ($name === '') { + echo json_encode([ + 'success' => false, + 'message' => 'Department name is required.' + ]); + exit; + } + + if ($code === '') { + $code = strtoupper(str_replace(' ', '_', $name)); + $code = preg_replace('/[^A-Z0-9_]/', '', $code); + } else { + $code = strtoupper($code); + $code = preg_replace('/[^A-Z0-9_]/', '', $code); + } + + if (!preg_match('/^#[0-9A-Fa-f]{6}$/', $color)) { + $color = '#6c757d'; + } + + $is_active = $is_active === 1 ? 1 : 0; + + $check = $pdo->prepare(" + SELECT COUNT(*) + FROM departments + WHERE name = :name OR code = :code + "); + $check->execute([ + 'name' => $name, + 'code' => $code + ]); + + if ((int)$check->fetchColumn() > 0) { + echo json_encode([ + 'success' => false, + 'message' => 'A department with the same name or code already exists.' + ]); + exit; + } + + $sql = "INSERT INTO departments + (name, code, description, color, sort_order, is_active, created_at, updated_at) + VALUES + (:name, :code, :description, :color, :sort_order, :is_active, NOW(), NOW())"; + + $stmt = $pdo->prepare($sql); + $stmt->execute([ + 'name' => $name, + 'code' => $code !== '' ? $code : null, + 'description' => $description !== '' ? $description : null, + 'color' => $color, + 'sort_order' => $sort_order, + 'is_active' => $is_active + ]); + + echo json_encode(['success' => true]); + exit; + } + + if ($action === 'edit') { + $id = (int)($_POST['id'] ?? 0); + $name = trim($_POST['name'] ?? ''); + $code = trim($_POST['code'] ?? ''); + $description = trim($_POST['description'] ?? ''); + $color = trim($_POST['color'] ?? '#6c757d'); + $sort_order = isset($_POST['sort_order']) && $_POST['sort_order'] !== '' ? (int)$_POST['sort_order'] : 999; + $is_active = isset($_POST['is_active']) ? (int)$_POST['is_active'] : 1; + + if ($id <= 0) { + echo json_encode([ + 'success' => false, + 'message' => 'Invalid department ID.' + ]); + exit; + } + + if ($name === '') { + echo json_encode([ + 'success' => false, + 'message' => 'Department name is required.' + ]); + exit; + } + + if ($code === '') { + $code = strtoupper(str_replace(' ', '_', $name)); + $code = preg_replace('/[^A-Z0-9_]/', '', $code); + } else { + $code = strtoupper($code); + $code = preg_replace('/[^A-Z0-9_]/', '', $code); + } + + if (!preg_match('/^#[0-9A-Fa-f]{6}$/', $color)) { + $color = '#6c757d'; + } + + $is_active = $is_active === 1 ? 1 : 0; + + $check = $pdo->prepare(" + SELECT COUNT(*) + FROM departments + WHERE (name = :name OR code = :code) + AND id <> :id + "); + $check->execute([ + 'name' => $name, + 'code' => $code, + 'id' => $id + ]); + + if ((int)$check->fetchColumn() > 0) { + echo json_encode([ + 'success' => false, + 'message' => 'Another department with the same name or code already exists.' + ]); + exit; + } + + $sql = "UPDATE departments + SET name = :name, + code = :code, + description = :description, + color = :color, + sort_order = :sort_order, + is_active = :is_active, + updated_at = NOW() + WHERE id = :id"; + + $stmt = $pdo->prepare($sql); + $stmt->execute([ + 'name' => $name, + 'code' => $code !== '' ? $code : null, + 'description' => $description !== '' ? $description : null, + 'color' => $color, + 'sort_order' => $sort_order, + 'is_active' => $is_active, + '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 department ID.' + ]); + exit; + } + + /* + * Future-proof check: + * If later you add employees.department_id, this prevents deleting + * a department already used by employees. + */ + $columnCheck = $pdo->prepare(" + SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'employees' + AND COLUMN_NAME = 'department_id' + "); + $columnCheck->execute(); + $hasDepartmentId = (int)$columnCheck->fetchColumn() > 0; + + if ($hasDepartmentId) { + $usageCheck = $pdo->prepare(" + SELECT COUNT(*) + FROM employees + WHERE department_id = :id + "); + $usageCheck->execute(['id' => $id]); + + if ((int)$usageCheck->fetchColumn() > 0) { + echo json_encode([ + 'success' => false, + 'message' => 'This department is linked to one or more employees and cannot be deleted.' + ]); + exit; + } + } + + $stmt = $pdo->prepare("DELETE FROM departments 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 + ========================================== */ + +$sql = " + SELECT * + FROM departments + ORDER BY sort_order ASC, name ASC +"; +$stmtDepartments = $pdo->query($sql); +$departments = $stmtDepartments->fetchAll(PDO::FETCH_ASSOC); +?> + + + + + + + + + + Gestione Departments - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?> + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+
Gestione Departments
+ +
+ +
+
+
Elenco Reparti / Departments
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDColorNameCodeDescriptionOrderStatusCreatedActions
+ + + + + + + + + - + + + + + + + + + + + +
+
+ +
+
+
+
+ + +
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/userarea/production_dashboard.php b/public/userarea/production_dashboard.php index 9d764b9..ceb6511 100644 --- a/public/userarea/production_dashboard.php +++ b/public/userarea/production_dashboard.php @@ -255,6 +255,15 @@ background: linear-gradient(135deg, #a5b4fc, #c7d2fe); } + .btn-departments { + background: linear-gradient(135deg, #bfdbfe, #dbeafe); + color: #1f2d3d; + } + + .btn-departments:hover { + background: linear-gradient(135deg, #93c5fd, #bfdbfe); + } + .btn-setup { background: linear-gradient(135deg, #e5e7eb, #f3f4f6); } @@ -297,8 +306,8 @@
getConnection(); - include(__DIR__ . '/scadenzario/include/my_deadlines_widget.php'); + $pdo = DBHandlerSelect::getInstance()->getConnection(); + include(__DIR__ . '/scadenzario/include/my_deadlines_widget.php'); ?>

Dashboard Produzione

@@ -505,6 +514,11 @@
Employees
+ + + + + + + +
+
@@ -1116,9 +1184,9 @@ function getContrastTextColor($hexColor) locale: 'it', allowInput: false, onChange: function() { - if (table) table.draw(); - filterCards(); - if (typeof updateFilterBadge === 'function') updateFilterBadge(); + if (typeof applyFiltersRefresh === 'function') { + applyFiltersRefresh(); + } } }; var fpDue = flatpickr('#filterDueRange', fpOpts); @@ -1313,10 +1381,22 @@ function getContrastTextColor($hexColor) } $('#filterStatus, #filterDepartment, #filterEmployee, #filterSubject').on('change', function() { + applyFiltersRefresh(); + }); + + function applyFiltersRefresh() { if (table) table.draw(); filterCards(); updateFilterBadge(); - }); + updateQuickFilterButtons(); + } + + function updateQuickFilterButtons() { + var statusVal = $('#filterStatus').val(); + + $('#btnQuickApproaching').toggleClass('active', statusVal === 'in-scadenza'); + $('#btnQuickOverdue').toggleClass('active', statusVal === 'scaduta'); + } function resetFilters() { $('#filterStatus').val('non-completata'); @@ -1325,12 +1405,22 @@ function getContrastTextColor($hexColor) $('#filterSubject').val(''); fpDue.clear(); fpCheck.clear(); - if (table) table.draw(); - filterCards(); - updateFilterBadge(); + + applyFiltersRefresh(); } + $('#btnResetFilters, #btnResetFiltersModal').on('click', resetFilters); + $('#btnQuickApproaching').on('click', function() { + $('#filterStatus').val('in-scadenza'); + applyFiltersRefresh(); + }); + + $('#btnQuickOverdue').on('click', function() { + $('#filterStatus').val('scaduta'); + applyFiltersRefresh(); + }); + // Apply URL filters (e.g. from dashboard widgets) (function() { var qs = new URLSearchParams(window.location.search); @@ -1339,9 +1429,7 @@ function getContrastTextColor($hexColor) })(); // Apply default filter on load - if (table) table.draw(); - filterCards(); - updateFilterBadge(); + applyFiltersRefresh(); // --- Modal --- var modal = new bootstrap.Modal(document.getElementById('deadlineModal'));