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'); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Elenco Reparti / Departments
+
+
+
+
+
+
+
+
+ | ID |
+ Color |
+ Name |
+ Code |
+ Description |
+ Order |
+ Status |
+ Created |
+ Actions |
+
+
+
+
+
+
+
+
+ | = $id ?> |
+
+
+
+ = htmlspecialchars($color) ?>
+ |
+
+
+ = htmlspecialchars($name) ?>
+ |
+
+
+
+ = htmlspecialchars($code) ?>
+
+ -
+
+ |
+
+
+ = $description !== '' ? htmlspecialchars($description) : '-' ?>
+ |
+
+ = $sortOrder ?> |
+
+
+
+ = htmlspecialchars($statusLabel) ?>
+
+ |
+
+ = $createdAt ?> |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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
+
+