conn = Database::getInstance(); } public function login($username, $password) { $query = "SELECT id, username, password, full_name, role, department_id FROM " . $this->table_name . " WHERE username = :username LIMIT 0,1"; $stmt = $this->conn->prepare($query); $stmt->bindParam(':username', $username); $stmt->execute(); if ($stmt->rowCount() > 0) { $row = $stmt->fetch(); if (password_verify($password, $row['password'])) { // Set object properties $this->id = $row['id']; $this->username = $row['username']; $this->full_name = $row['full_name']; $this->role = $row['role']; $this->department_id = $row['department_id']; // Update status to online $this->updateStatus($this->id, 'online'); return true; } } return false; } public function updateStatus($user_id, $status) { $query = "UPDATE " . $this->table_name . " SET status = :status WHERE id = :id"; $stmt = $this->conn->prepare($query); $stmt->bindParam(':status', $status); $stmt->bindParam(':id', $user_id); $stmt->execute(); } public function getById($id) { $query = "SELECT * FROM " . $this->table_name . " WHERE id = :id LIMIT 1"; $stmt = $this->conn->prepare($query); $stmt->bindParam(':id', $id); $stmt->execute(); if ($stmt->rowCount() > 0) { return $stmt->fetch(); } return false; } public function getAll() { $query = "SELECT u.*, d.name as department_name FROM " . $this->table_name . " u LEFT JOIN departments d ON u.department_id = d.id ORDER BY u.created_at DESC"; $stmt = $this->conn->prepare($query); $stmt->execute(); return $stmt->fetchAll(); } public function add($username, $password, $full_name, $role, $department_id = null) { $query = "INSERT INTO " . $this->table_name . " (username, password, full_name, role, department_id, status) VALUES (:username, :password, :full_name, :role, :department_id, 'offline')"; $hashed_password = password_hash($password, PASSWORD_DEFAULT); $stmt = $this->conn->prepare($query); $stmt->bindParam(':username', $username); $stmt->bindParam(':password', $hashed_password); $stmt->bindParam(':full_name', $full_name); $stmt->bindParam(':role', $role); if ($department_id) { $stmt->bindParam(':department_id', $department_id); } else { $stmt->bindValue(':department_id', null, PDO::PARAM_NULL); } return $stmt->execute(); } public function update($id, $full_name, $role, $department_id = null) { $query = "UPDATE " . $this->table_name . " SET full_name = :full_name, role = :role, department_id = :department_id WHERE id = :id"; $stmt = $this->conn->prepare($query); $stmt->bindParam(':full_name', $full_name); $stmt->bindParam(':role', $role); $stmt->bindParam(':id', $id); if ($department_id) { $stmt->bindParam(':department_id', $department_id); } else { $stmt->bindValue(':department_id', null, PDO::PARAM_NULL); } return $stmt->execute(); } public function updatePassword($id, $password) { $query = "UPDATE " . $this->table_name . " SET password = :password WHERE id = :id"; $hashed_password = password_hash($password, PASSWORD_DEFAULT); $stmt = $this->conn->prepare($query); $stmt->bindParam(':password', $hashed_password); $stmt->bindParam(':id', $id); return $stmt->execute(); } public function delete($id) { // Since we have foreign keys, we might want to just set status or delete. // Assuming delete for now based on schema constraints (SET NULL or CASCADE might be needed) // Schema has jobs.requester_id and jobs.assigned_to referencing users(id). // Deleting a user with jobs will fail unless we handle it, or we can soft delete. // For simplicity, let's hard delete, but if it fails it throws PDOException. $query = "DELETE FROM " . $this->table_name . " WHERE id = :id"; $stmt = $this->conn->prepare($query); $stmt->bindParam(':id', $id); return $stmt->execute(); } public function getAvailableStaff() { // Find staff who are online and NOT currently handling an active job // Order by who has been idle the longest today $query = " SELECT u.id, u.full_name, MAX(j.completed_at) as last_job FROM " . $this->table_name . " u LEFT JOIN jobs j ON u.id = j.assigned_to AND j.status = 'completed' AND DATE(j.created_at) = CURDATE() WHERE u.role = 'staff' AND u.status = 'online' AND u.id NOT IN ( SELECT assigned_to FROM jobs WHERE status IN ('assigned', 'accepted', 'in_progress') AND assigned_to IS NOT NULL ) GROUP BY u.id ORDER BY last_job ASC LIMIT 1 "; $stmt = $this->conn->query($query); if ($stmt->rowCount() > 0) { return $stmt->fetch(PDO::FETCH_ASSOC); } return false; } }