<?php
// Start session
session_start();
// Include database configuration
require_once 'database/db_config.php';
require_once 'includes/functions.php';
// Check if user is logged in and is admin
if (!isset($_SESSION['user_id']) || !isset($_SESSION['role']) || ($_SESSION['role'] !== 'admin' && $_SESSION['role'] !== 'director')) {
header('Location: login.php');
exit;
}
// Initialize variables
$action = isset($_GET['action']) ? $_GET['action'] : 'list';
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
$msg = isset($_GET['msg']) ? $_GET['msg'] : '';
$error = '';
// Handle form submissions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
if (isset($_POST['add_instructor']) || isset($_POST['update_instructor'])) {
// Sanitize and validate inputs
$first_name = trim($_POST['first_name']);
$last_name = trim($_POST['last_name']);
$email = trim($_POST['email']);
$designation = trim($_POST['designation']);
$bio = trim($_POST['bio']);
$expertise = trim($_POST['expertise']);
$status = $_POST['status'];
$password = isset($_POST['password']) ? trim($_POST['password']) : '';
// Prepare social links as JSON
$social_links = [
'facebook' => trim($_POST['facebook'] ?? ''),
'twitter' => trim($_POST['twitter'] ?? ''),
'linkedin' => trim($_POST['linkedin'] ?? ''),
'instagram' => trim($_POST['instagram'] ?? ''),
'youtube' => trim($_POST['youtube'] ?? '')
];
$social_links_json = json_encode($social_links);
// Handle profile image upload
$profile_image = '';
if (isset($_FILES['profile_image']) && $_FILES['profile_image']['error'] === UPLOAD_ERR_OK) {
$upload_dir = '../assets/images/instructors/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
$file_tmp = $_FILES['profile_image']['tmp_name'];
$file_name = $_FILES['profile_image']['name'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
$allowed_extensions = ['jpg', 'jpeg', 'png', 'webp'];
if (in_array($file_ext, $allowed_extensions)) {
// Generate unique filename
$new_file_name = uniqid('instructor_') . '.' . $file_ext;
$destination = $upload_dir . $new_file_name;
if (move_uploaded_file($file_tmp, $destination)) {
$profile_image = 'assets/images/instructors/' . $new_file_name;
} else {
throw new Exception("Failed to upload image.");
}
} else {
throw new Exception("Invalid file type. Only JPG, JPEG, PNG, and WEBP are allowed.");
}
}
if (isset($_POST['add_instructor'])) {
// Check if email already exists
$check_email = $conn->prepare("SELECT id FROM users WHERE email = ?");
$check_email->bind_param("s", $email);
$check_email->execute();
$result = $check_email->get_result();
if ($result->num_rows > 0) {
throw new Exception("Email already exists. Please use a different email.");
}
// Validate password for new instructors
if (empty($password)) {
throw new Exception("Password is required for new instructors.");
}
// Hash password
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
// Insert into users table
$stmt = $conn->prepare("INSERT INTO users (first_name, last_name, email, password, role, status, profile_image, bio, designation, expertise, social_links) VALUES (?, ?, ?, ?, 'instructor', ?, ?, ?, ?, ?, ?)");
$stmt->bind_param("ssssssssss", $first_name, $last_name, $email, $hashed_password, $status, $profile_image, $bio, $designation, $expertise, $social_links_json);
if ($stmt->execute()) {
header("Location: instructors.php?msg=Instructor added successfully");
exit;
} else {
throw new Exception("Failed to add instructor: " . $conn->error);
}
} elseif (isset($_POST['update_instructor'])) {
// Check if email already exists for a different user
$check_email = $conn->prepare("SELECT id FROM users WHERE email = ? AND id != ?");
$check_email->bind_param("si", $email, $id);
$check_email->execute();
$result = $check_email->get_result();
if ($result->num_rows > 0) {
throw new Exception("Email already exists. Please use a different email.");
}
// Get current instructor data for the image
$current_data = $conn->prepare("SELECT profile_image FROM users WHERE id = ?");
$current_data->bind_param("i", $id);
$current_data->execute();
$current_result = $current_data->get_result();
$current = $current_result->fetch_assoc();
// If no new image uploaded, use existing one
if (empty($profile_image) && isset($current['profile_image'])) {
$profile_image = $current['profile_image'];
}
// Update user in database
if (!empty($password)) {
// Update with new password
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
$stmt = $conn->prepare("UPDATE users SET first_name = ?, last_name = ?, email = ?, password = ?, status = ?, profile_image = ?, bio = ?, designation = ?, expertise = ?, social_links = ? WHERE id = ?");
$stmt->bind_param("ssssssssssi", $first_name, $last_name, $email, $hashed_password, $status, $profile_image, $bio, $designation, $expertise, $social_links_json, $id);
} else {
// Update without changing password
$stmt = $conn->prepare("UPDATE users SET first_name = ?, last_name = ?, email = ?, status = ?, profile_image = ?, bio = ?, designation = ?, expertise = ?, social_links = ? WHERE id = ?");
$stmt->bind_param("sssssssssi", $first_name, $last_name, $email, $status, $profile_image, $bio, $designation, $expertise, $social_links_json, $id);
}
if ($stmt->execute()) {
header("Location: instructors.php?msg=Instructor updated successfully");
exit;
} else {
throw new Exception("Failed to update instructor: " . $conn->error);
}
}
} elseif (isset($_POST['delete_instructor'])) {
$instructor_id = (int)$_POST['instructor_id'];
// Check if instructor is assigned to any courses
$check_courses = $conn->prepare("SELECT COUNT(*) as course_count FROM courses WHERE instructor_id = ?");
$check_courses->bind_param("i", $instructor_id);
$check_courses->execute();
$course_result = $check_courses->get_result()->fetch_assoc();
if ($course_result['course_count'] > 0) {
throw new Exception("This instructor is assigned to {$course_result['course_count']} courses. Please reassign the courses before deleting this instructor.");
}
// Delete instructor
$stmt = $conn->prepare("DELETE FROM users WHERE id = ? AND role = 'instructor'");
$stmt->bind_param("i", $instructor_id);
if ($stmt->execute()) {
header("Location: instructors.php?msg=Instructor deleted successfully");
exit;
} else {
throw new Exception("Failed to delete instructor: " . $conn->error);
}
}
} catch (Exception $e) {
$error = $e->getMessage();
}
}
// Get instructor data for edit
if ($action === 'edit' && $id > 0) {
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ? AND role = 'instructor'");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 0) {
header("Location: instructors.php?error=Instructor not found");
exit;
}
$instructor = $result->fetch_assoc();
$social_links = json_decode($instructor['social_links'] ?? '{}', true);
}
// Include header
include 'includes/header.php';
?>
<!-- Breadcrumb -->
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="index.php">Dashboard</a></li>
<li class="breadcrumb-item active">Instructors</li>
<?php if ($action === 'add'): ?>
<li class="breadcrumb-item active">Add New Instructor</li>
<?php elseif ($action === 'edit'): ?>
<li class="breadcrumb-item active">Edit Instructor</li>
<?php endif; ?>
</ol>
</nav>
<!-- Page Title and Action Buttons -->
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">
<?php
if ($action === 'add') echo 'Add New Instructor';
elseif ($action === 'edit') echo 'Edit Instructor';
else echo 'Instructor Management';
?>
</h1>
<?php if ($action === 'list'): ?>
<a href="?action=add" class="btn btn-primary">
<i class="fas fa-plus me-1"></i> Add New Instructor
</a>
<?php endif; ?>
</div>
<!-- Alerts for success and error messages -->
<?php if ($msg): ?>
<div class="alert alert-success alert-dismissible fade show mb-4" role="alert">
<?php echo $msg; ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<?php if ($error): ?>
<div class="alert alert-danger alert-dismissible fade show mb-4" role="alert">
<?php echo $error; ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<!-- Main Content -->
<?php if ($action === 'list'): ?>
<!-- Instructor List View -->
<div class="card mb-4 shadow-sm">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Instructors</h5>
<form class="d-flex" method="get">
<input type="hidden" name="action" value="list">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search instructors..." name="search"
value="<?php echo isset($_GET['search']) ? htmlspecialchars($_GET['search']) : ''; ?>">
<button class="btn btn-outline-primary" type="submit">
<i class="fas fa-search"></i>
</button>
</div>
</form>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead>
<tr>
<th width="60">ID</th>
<th width="80">Image</th>
<th>Name</th>
<th>Email</th>
<th>Designation</th>
<th>Courses</th>
<th>Status</th>
<th width="150">Actions</th>
</tr>
</thead>
<tbody>
<?php
// Build the query with search functionality
$search_condition = "WHERE role = 'instructor'";
if (isset($_GET['search']) && !empty($_GET['search'])) {
$search = $conn->real_escape_string($_GET['search']);
$search_condition .= " AND (first_name LIKE '%$search%' OR last_name LIKE '%$search%' OR email LIKE '%$search%' OR designation LIKE '%$search%')";
}
$sql = "SELECT u.*,
(SELECT COUNT(*) FROM courses WHERE instructor_id = u.id) as course_count
FROM users u
$search_condition
ORDER BY u.first_name, u.last_name";
$result = $conn->query($sql);
if ($result && $result->num_rows > 0) {
while ($instructor = $result->fetch_assoc()) {
$status_badge = '';
switch ($instructor['status']) {
case 'active':
$status_badge = '<span class="badge bg-success">Active</span>';
break;
case 'inactive':
$status_badge = '<span class="badge bg-warning text-dark">Inactive</span>';
break;
default:
$status_badge = '<span class="badge bg-secondary">' . ucfirst($instructor['status']) . '</span>';
}
$profile_image = !empty($instructor['profile_image']) ? '../' . $instructor['profile_image'] : '../assets/images/avatar-placeholder.jpg';
?>
<tr>
<td><?php echo $instructor['id']; ?></td>
<td>
<img src="<?php echo $profile_image; ?>" class="rounded-circle instructor-thumbnail" alt="<?php echo htmlspecialchars($instructor['first_name'] . ' ' . $instructor['last_name']); ?>">
</td>
<td>
<div class="d-flex flex-column">
<strong><?php echo htmlspecialchars($instructor['first_name'] . ' ' . $instructor['last_name']); ?></strong>
</div>
</td>
<td><?php echo htmlspecialchars($instructor['email']); ?></td>
<td><?php echo htmlspecialchars($instructor['designation'] ?? 'Instructor'); ?></td>
<td>
<span class="badge bg-info"><?php echo $instructor['course_count']; ?> courses</span>
</td>
<td><?php echo $status_badge; ?></td>
<td>
<div class="btn-group btn-group-sm">
<a href="?action=edit&id=<?php echo $instructor['id']; ?>" class="btn btn-primary" title="Edit">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-danger delete-instructor-btn"
data-id="<?php echo $instructor['id']; ?>"
data-name="<?php echo htmlspecialchars($instructor['first_name'] . ' ' . $instructor['last_name']); ?>"
title="Delete">
<i class="fas fa-trash"></i>
</button>
</div>
</td>
</tr>
<?php
}
} else {
?>
<tr>
<td colspan="8" class="text-center py-4">
<div class="d-flex flex-column align-items-center">
<i class="fas fa-user-slash fa-3x text-muted mb-3"></i>
<h5 class="mb-2">No Instructors Found</h5>
<p class="text-muted">No instructors match your search criteria or no instructors have been added yet.</p>
<a href="?action=add" class="btn btn-primary btn-sm mt-2">
<i class="fas fa-plus me-1"></i> Add New Instructor
</a>
</div>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div class="modal fade" id="deleteInstructorModal" tabindex="-1" aria-labelledby="deleteInstructorModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteInstructorModalLabel">Confirm Deletion</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Are you sure you want to delete instructor <strong id="instructorName"></strong>?</p>
<p class="text-danger">This action cannot be undone.</p>
</div>
<div class="modal-footer">
<form method="post">
<input type="hidden" name="instructor_id" id="instructorIdToDelete">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="delete_instructor" class="btn btn-danger">Delete</button>
</form>
</div>
</div>
</div>
</div>
<?php else: ?>
<!-- Instructor Add/Edit Form -->
<div class="card shadow-sm mb-4">
<div class="card-header">
<h5 class="mb-0"><?php echo ($action === 'add') ? 'Add New Instructor' : 'Edit Instructor'; ?></h5>
</div>
<div class="card-body">
<form method="post" enctype="multipart/form-data">
<div class="row mb-4">
<div class="col-md-3">
<div class="form-group">
<label class="form-label">Profile Image:</label>
<div class="profile-image-wrapper">
<div class="profile-image">
<?php
$current_image = '../assets/images/avatar-placeholder.jpg';
if ($action === 'edit' && !empty($instructor['profile_image'])) {
$current_image = '../' . $instructor['profile_image'];
}
?>
<img src="<?php echo $current_image; ?>" id="profileImagePreview" class="img-thumbnail">
</div>
<div class="mt-2">
<input type="file" class="form-control" name="profile_image" id="profileImageInput" accept="image/*">
<small class="form-text text-muted">Recommended size: 400x400px</small>
</div>
</div>
</div>
</div>
<div class="col-md-9">
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label class="form-label">First Name:</label>
<input type="text" class="form-control" name="first_name" required
value="<?php echo ($action === 'edit') ? htmlspecialchars($instructor['first_name']) : ''; ?>">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="form-label">Last Name:</label>
<input type="text" class="form-control" name="last_name" required
value="<?php echo ($action === 'edit') ? htmlspecialchars($instructor['last_name']) : ''; ?>">
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label class="form-label">Email:</label>
<input type="email" class="form-control" name="email" required
value="<?php echo ($action === 'edit') ? htmlspecialchars($instructor['email']) : ''; ?>">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="form-label">Password:</label>
<input type="password" class="form-control" name="password"
<?php echo ($action === 'add') ? 'required' : ''; ?>>
<?php if ($action === 'edit'): ?>
<small class="form-text text-muted">Leave blank to keep current password</small>
<?php endif; ?>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-group">
<label class="form-label">Designation:</label>
<input type="text" class="form-control" name="designation" placeholder="e.g., Web Development Instructor"
value="<?php echo ($action === 'edit') ? htmlspecialchars($instructor['designation'] ?? '') : ''; ?>">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="form-label">Status:</label>
<select class="form-select" name="status" required>
<option value="active" <?php echo ($action === 'edit' && $instructor['status'] === 'active') ? 'selected' : ''; ?>>Active</option>
<option value="inactive" <?php echo ($action === 'edit' && $instructor['status'] === 'inactive') ? 'selected' : ''; ?>>Inactive</option>
</select>
</div>
</div>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-12">
<div class="form-group">
<label class="form-label">Expertise:</label>
<input type="text" class="form-control" name="expertise" placeholder="e.g., HTML, CSS, JavaScript, React"
value="<?php echo ($action === 'edit') ? htmlspecialchars($instructor['expertise'] ?? '') : ''; ?>">
<small class="form-text text-muted">Comma separated list of skills and expertise</small>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-12">
<div class="form-group">
<label class="form-label">Bio:</label>
<textarea class="form-control" name="bio" rows="5" placeholder="Instructor biography and professional experience"><?php echo ($action === 'edit') ? htmlspecialchars($instructor['bio'] ?? '') : ''; ?></textarea>
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-12">
<h5 class="mb-3">Social Media Links</h5>
</div>
<div class="col-md-6">
<div class="form-group mb-3">
<label class="form-label">
<i class="fab fa-facebook text-primary me-2"></i> Facebook:
</label>
<input type="url" class="form-control" name="facebook" placeholder="https://facebook.com/username"
value="<?php echo ($action === 'edit') ? htmlspecialchars($social_links['facebook'] ?? '') : ''; ?>">
</div>
</div>
<div class="col-md-6">
<div class="form-group mb-3">
<label class="form-label">
<i class="fab fa-twitter text-info me-2"></i> Twitter:
</label>
<input type="url" class="form-control" name="twitter" placeholder="https://twitter.com/username"
value="<?php echo ($action === 'edit') ? htmlspecialchars($social_links['twitter'] ?? '') : ''; ?>">
</div>
</div>
<div class="col-md-6">
<div class="form-group mb-3">
<label class="form-label">
<i class="fab fa-linkedin text-primary me-2"></i> LinkedIn:
</label>
<input type="url" class="form-control" name="linkedin" placeholder="https://linkedin.com/in/username"
value="<?php echo ($action === 'edit') ? htmlspecialchars($social_links['linkedin'] ?? '') : ''; ?>">
</div>
</div>
<div class="col-md-6">
<div class="form-group mb-3">
<label class="form-label">
<i class="fab fa-instagram text-danger me-2"></i> Instagram:
</label>
<input type="url" class="form-control" name="instagram" placeholder="https://instagram.com/username"
value="<?php echo ($action === 'edit') ? htmlspecialchars($social_links['instagram'] ?? '') : ''; ?>">
</div>
</div>
<div class="col-md-6">
<div class="form-group mb-3">
<label class="form-label">
<i class="fab fa-youtube text-danger me-2"></i> YouTube:
</label>
<input type="url" class="form-control" name="youtube" placeholder="https://youtube.com/c/channelname"
value="<?php echo ($action === 'edit') ? htmlspecialchars($social_links['youtube'] ?? '') : ''; ?>">
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-group mt-4">
<a href="instructors.php" class="btn btn-secondary">Cancel</a>
<?php if ($action === 'add'): ?>
<button type="submit" name="add_instructor" class="btn btn-primary">Add Instructor</button>
<?php else: ?>
<button type="submit" name="update_instructor" class="btn btn-primary">Update Instructor</button>
<?php endif; ?>
</div>
</div>
</div>
</form>
</div>
</div>
<?php endif; ?>
<style>
.instructor-thumbnail {
width: 50px;
height: 50px;
object-fit: cover;
}
.profile-image-wrapper {
text-align: center;
}
.profile-image img {
width: 150px;
height: 150px;
object-fit: cover;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Handle Delete Confirmation
const deleteButtons = document.querySelectorAll('.delete-instructor-btn');
const instructorNameElement = document.getElementById('instructorName');
const instructorIdInput = document.getElementById('instructorIdToDelete');
const deleteModal = new bootstrap.Modal(document.getElementById('deleteInstructorModal'));
deleteButtons.forEach(button => {
button.addEventListener('click', function() {
const instructorId = this.getAttribute('data-id');
const instructorName = this.getAttribute('data-name');
instructorNameElement.textContent = instructorName;
instructorIdInput.value = instructorId;
deleteModal.show();
});
});
// Image Preview
const imageInput = document.getElementById('profileImageInput');
const imagePreview = document.getElementById('profileImagePreview');
if (imageInput) {
imageInput.addEventListener('change', function() {
if (this.files && this.files[0]) {
const reader = new FileReader();
reader.onload = function(e) {
imagePreview.src = e.target.result;
}
reader.readAsDataURL(this.files[0]);
}
});
}
});
</script>
<?php
// Include footer
include 'includes/footer.php';
?>