Nov 19th,2025 V.3
This commit is contained in:
parent
bc846e76cd
commit
ef6e573967
427
dashboard.php
427
dashboard.php
@ -8,70 +8,82 @@ if (!is_logged_in()) {
|
||||
}
|
||||
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Fetch data for analytics
|
||||
$pdo = db();
|
||||
|
||||
// Candidate stats
|
||||
$stmt = $pdo->query('SELECT status, COUNT(*) as count FROM candidates GROUP BY status');
|
||||
$candidate_stats = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$total_candidates = array_sum(array_column($candidate_stats, 'count'));
|
||||
|
||||
// Task stats
|
||||
$stmt = $pdo->query('SELECT status, COUNT(*) as count FROM tasks GROUP BY status');
|
||||
$task_stats = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$total_tasks = array_sum(array_column($task_stats, 'count'));
|
||||
$completed_tasks = 0;
|
||||
foreach ($task_stats as $stat) {
|
||||
if ($stat['status'] === 'Completed') {
|
||||
$completed_tasks = $stat['count'];
|
||||
break;
|
||||
}
|
||||
// Function to check for permissions
|
||||
function hasPermission($permission) {
|
||||
// In a real app, you'd check this against the user's role
|
||||
return true;
|
||||
}
|
||||
|
||||
// Candidates per day
|
||||
$stmt = $pdo->query("SELECT DATE(created_at) as date, COUNT(*) as count FROM candidates GROUP BY DATE(created_at) ORDER BY DATE(created_at) DESC LIMIT 7");
|
||||
$candidates_per_day = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Tasks created per day
|
||||
$stmt = $pdo->query("SELECT DATE(created_at) as date, COUNT(*) as count FROM tasks GROUP BY DATE(created_at) ORDER BY DATE(created_at) DESC LIMIT 7");
|
||||
$tasks_created_per_day = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Tasks completed per day
|
||||
$stmt = $pdo->query("SELECT DATE(updated_at) as date, COUNT(*) as count FROM tasks WHERE status = 'Done' GROUP BY DATE(updated_at) ORDER BY DATE(updated_at) DESC LIMIT 7");
|
||||
$tasks_completed_per_day = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
|
||||
// Fetch candidates for table
|
||||
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
// Pagination for Candidates
|
||||
$candidate_page = isset($_GET['candidate_page']) ? (int)$_GET['candidate_page'] : 1;
|
||||
$limit = 5;
|
||||
$offset = ($page - 1) * $limit;
|
||||
$candidate_offset = ($candidate_page - 1) * $limit;
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM candidates LIMIT :limit OFFSET :offset");
|
||||
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':offset', $candidate_offset, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$candidates = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$stmt = $pdo->query("SELECT COUNT(*) FROM candidates");
|
||||
$total_candidates_records = $stmt->fetchColumn();
|
||||
$total_candidate_pages = ceil($total_candidates_records / $limit);
|
||||
|
||||
// Fetch tasks for table
|
||||
// Pagination for Tasks
|
||||
$task_page = isset($_GET['task_page']) ? (int)$_GET['task_page'] : 1;
|
||||
$task_offset = ($task_page - 1) * $limit;
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM tasks LIMIT :limit OFFSET :offset");
|
||||
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
|
||||
$stmt->bindParam(':offset', $task_offset, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$tasks = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$stmt = $pdo->query("SELECT COUNT(*) FROM tasks");
|
||||
$total_tasks_records = $stmt->fetchColumn();
|
||||
$total_task_pages = ceil($total_tasks_records / $limit);
|
||||
|
||||
// Handle form submissions for adding candidates and tasks
|
||||
$message = '';
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_POST['add_candidate'])) {
|
||||
$name = $_POST['name'];
|
||||
$email = $_POST['email'];
|
||||
$status = $_POST['status'];
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO candidates (name, email, status) VALUES (:name, :email, :status)");
|
||||
$stmt->execute(['name' => $name, 'email' => $email, 'status' => $status]);
|
||||
$message = 'Candidate added successfully!';
|
||||
}
|
||||
|
||||
if (isset($_POST['add_task'])) {
|
||||
$title = $_POST['title'];
|
||||
$status = $_POST['status'];
|
||||
$assigned_to = $_POST['assigned_to'];
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO tasks (title, status, assigned_to) VALUES (:title, :status, :assigned_to)");
|
||||
$stmt->execute(['title' => $title, 'status' => $status, 'assigned_to' => $assigned_to]);
|
||||
$message = 'Task added successfully!';
|
||||
}
|
||||
// Redirect to the same page to avoid form resubmission
|
||||
header("Location: dashboard.php?tab=" . (isset($_POST['add_candidate']) ? 'candidates' : 'tasks'));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Fetch data for overview
|
||||
$total_candidates = $pdo->query("SELECT COUNT(*) FROM candidates")->fetchColumn();
|
||||
$total_tasks = $pdo->query("SELECT COUNT(*) FROM tasks")->fetchColumn();
|
||||
$completed_tasks = $pdo->query("SELECT COUNT(*) FROM tasks WHERE status = 'Completed'")->fetchColumn();
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Analytics Dashboard</title>
|
||||
<title>Dashboard</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
</head>
|
||||
@ -95,10 +107,14 @@ $total_task_pages = ceil($total_tasks_records / $limit);
|
||||
</header>
|
||||
|
||||
<main class="container-fluid mt-4">
|
||||
<h2 class="mb-4">Analytics Dashboard</h2>
|
||||
<h2 class="mb-4">Dashboard</h2>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-success"><?php echo $message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Nav tabs -->
|
||||
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
||||
<ul class="nav nav-tabs" id="dashboardTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="overview-tab" data-bs-toggle="tab" data-bs-target="#overview" type="button" role="tab" aria-controls="overview" aria-selected="true">Overview</button>
|
||||
</li>
|
||||
@ -115,27 +131,23 @@ $total_task_pages = ceil($total_tasks_records / $limit);
|
||||
</ul>
|
||||
|
||||
<!-- Tab content -->
|
||||
<div class="tab-content" id="myTabContent">
|
||||
<div class="tab-content" id="dashboardTabContent">
|
||||
<!-- Overview Tab -->
|
||||
<div class="tab-pane fade show active" id="overview" role="tabpanel" aria-labelledby="overview-tab">
|
||||
<!-- Key Metrics -->
|
||||
<div class="row mb-4 mt-4">
|
||||
<?php if (hasPermission('view_candidates')) { ?>
|
||||
<div class="col-md-4">
|
||||
<div class="card text-center shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Total Candidates</h5>
|
||||
<p class="card-text fs-4" id="total-candidates"><?php echo $total_candidates; ?></p>
|
||||
<p class="card-text fs-4"><?php echo $total_candidates; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php if (hasPermission('view_tasks')) { ?>
|
||||
<div class="col-md-4">
|
||||
<div class="card text-center shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Total Tasks</h5>
|
||||
<p class="card-text fs-4" id="total-tasks"><?php echo $total_tasks; ?></p>
|
||||
<p class="card-text fs-4"><?php echo $total_tasks; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -143,183 +155,196 @@ $total_task_pages = ceil($total_tasks_records / $limit);
|
||||
<div class="card text-center shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Completed Tasks</h5>
|
||||
<p class="card-text fs-4" id="completed-tasks"><?php echo $completed_tasks; ?></p>
|
||||
<p class="card-text fs-4"><?php echo $completed_tasks; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<!-- Summaries -->
|
||||
<div class="row">
|
||||
<?php if (hasPermission('view_candidates')) { ?>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Candidates by Status</h5>
|
||||
<p class="card-text">
|
||||
<?php foreach ($candidate_stats as $stat): ?>
|
||||
<span class="badge bg-light text-dark me-2"><?php echo htmlspecialchars($stat['status']); ?>: <?php echo $stat['count']; ?></span>
|
||||
<?php endforeach; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php if (hasPermission('view_tasks')) { ?>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Tasks by Status</h5>
|
||||
<p class="card-text">
|
||||
<?php foreach ($task_stats as $stat): ?>
|
||||
<span class="badge bg-light text-dark me-2"><?php echo htmlspecialchars($stat['status']); ?>: <?php echo $stat['count']; ?></span>
|
||||
<?php endforeach; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php if (hasPermission('view_candidates')) { ?>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Recent Candidate Activity</h5>
|
||||
<p class="card-text">
|
||||
<?php foreach ($candidates_per_day as $day): ?>
|
||||
<span class="badge bg-light text-dark me-2"><?php echo date("M j", strtotime($day['date'])); ?>: <?php echo $day['count']; ?></span>
|
||||
<?php endforeach; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php if (hasPermission('view_tasks')) { ?>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Recent Task Activity</h5>
|
||||
<p class="card-text">
|
||||
<strong>Created:</strong>
|
||||
<?php foreach ($tasks_created_per_day as $day): ?>
|
||||
<span class="badge bg-light text-dark me-2"><?php echo date("M j", strtotime($day['date'])); ?>: <?php echo $day['count']; ?></span>
|
||||
<?php endforeach; ?>
|
||||
</p>
|
||||
<p class="card-text">
|
||||
<strong>Completed:</strong>
|
||||
<?php foreach ($tasks_completed_per_day as $day): ?>
|
||||
<span class="badge bg-light text-dark me-2"><?php echo date("M j", strtotime($day['date'])); ?>: <?php echo $day['count']; ?></span>
|
||||
<?php endforeach; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Candidates Tab -->
|
||||
<?php if (hasPermission('view_candidates')) { ?>
|
||||
<div class="tab-pane fade" id="candidates" role="tabpanel" aria-labelledby="candidates-tab">
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5 class="card-title">Recent Candidates</h5>
|
||||
<a href="edit_candidate.php" class="btn btn-primary">Add Candidate</a>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($candidates as $candidate) { ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($candidate['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($candidate['email']); ?></td>
|
||||
<td><span class="badge bg-secondary"><?php echo htmlspecialchars($candidate['status']); ?></span></td>
|
||||
<td>
|
||||
<a href="edit_candidate.php?id=<?php echo $candidate['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<a href="delete_candidate.php?id=<?php echo $candidate['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure?')">Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="pagination">
|
||||
<?php for ($i = 1; $i <= $total_candidate_pages; $i++) { ?>
|
||||
<li class="page-item <?php if ($i == $page) echo 'active'; ?>"><a class="page-link" href="?page=<?php echo $i; ?>"><?php echo $i; ?></a></li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="card shadow-sm mt-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5 class="card-title">Candidates</h5>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addCandidateModal">Add Candidate</button>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($candidates as $candidate) { ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($candidate['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($candidate['email']); ?></td>
|
||||
<td><span class="badge bg-secondary"><?php echo htmlspecialchars($candidate['status']); ?></span></td>
|
||||
<td>
|
||||
<a href="edit_candidate.php?id=<?php echo $candidate['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<a href="delete_candidate.php?id=<?php echo $candidate['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure?')">Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="pagination">
|
||||
<?php for ($i = 1; $i <= $total_candidate_pages; $i++) { ?>
|
||||
<li class="page-item <?php if ($i == $candidate_page) echo 'active'; ?>"><a class="page-link" href="?candidate_page=<?php echo $i; ?>&tab=candidates"><?php echo $i; ?></a></li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<!-- Tasks Tab -->
|
||||
<?php if (hasPermission('view_tasks')) { ?>
|
||||
<div class="tab-pane fade" id="tasks" role="tabpanel" aria-labelledby="tasks-tab">
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5 class="card-title">Recent Tasks</h5>
|
||||
<a href="edit_task.php" class="btn btn-primary">Add Task</a>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Status</th>
|
||||
<th>Assigned To</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($tasks as $task) { ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($task['title']); ?></td>
|
||||
<td><span class="badge bg-info"><?php echo htmlspecialchars($task['status']); ?></span></td>
|
||||
<td><?php echo htmlspecialchars($task['assigned_to'] ?? 'N/A'); ?></td>
|
||||
<td>
|
||||
<a href="edit_task.php?id=<?php echo $task['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<a href="delete_task.php?id=<?php echo $task['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure?')">Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="pagination">
|
||||
<?php for ($i = 1; $i <= $total_task_pages; $i++) { ?>
|
||||
<li class="page-item <?php if ($i == $page) echo 'active'; ?>"><a class="page-link" href="?page=<?php echo $i; ?>"><?php echo $i; ?></a></li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="card shadow-sm mt-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5 class="card-title">Tasks</h5>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addTaskModal">Add Task</button>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Status</th>
|
||||
<th>Assigned To</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($tasks as $task) { ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($task['title']); ?></td>
|
||||
<td><span class="badge bg-info"><?php echo htmlspecialchars($task['status']); ?></span></td>
|
||||
<td><?php echo htmlspecialchars($task['assigned_to'] ?? 'N/A'); ?></td>
|
||||
<td>
|
||||
<a href="edit_task.php?id=<?php echo $task['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<a href="delete_task.php?id=<?php echo $task['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure?')">Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="pagination">
|
||||
<?php for ($i = 1; $i <= $total_task_pages; $i++) { ?>
|
||||
<li class="page-item <?php if ($i == $task_page) echo 'active'; ?>"><a class="page-link" href="?task_page=<?php echo $i; ?>&tab=tasks"><?php echo $i; ?></a></li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Add Candidate Modal -->
|
||||
<div class="modal fade" id="addCandidateModal" tabindex="-1" aria-labelledby="addCandidateModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addCandidateModalLabel">Add New Candidate</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="POST" action="dashboard.php">
|
||||
<input type="hidden" name="add_candidate" value="1">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Name</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="status" class="form-label">Status</label>
|
||||
<select class="form-select" id="status" name="status">
|
||||
<option>Applied</option>
|
||||
<option>Interviewing</option>
|
||||
<option>Offered</option>
|
||||
<option>Hired</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Save Candidate</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Task Modal -->
|
||||
<div class="modal fade" id="addTaskModal" tabindex="-1" aria-labelledby="addTaskModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addTaskModalLabel">Add New Task</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="POST" action="dashboard.php">
|
||||
<input type="hidden" name="add_task" value="1">
|
||||
<div class="mb-3">
|
||||
<label for="title" class="form-label">Title</label>
|
||||
<input type="text" class="form-control" id="title" name="title" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="status" class="form-label">Status</label>
|
||||
<select class="form-select" id="status" name="status">
|
||||
<option>Pending</option>
|
||||
<option>In Progress</option>
|
||||
<option>Completed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="assigned_to" class="form-label">Assigned To</label>
|
||||
<input type="text" class="form-control" id="assigned_to" name="assigned_to">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Save Task</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Tab persistence
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const tab = urlParams.get('tab');
|
||||
if (tab) {
|
||||
const tabEl = document.querySelector('#' + tab + '-tab');
|
||||
if(tabEl) {
|
||||
const tab = new bootstrap.Tab(tabEl);
|
||||
tab.show();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset URL after modal close
|
||||
const modals = document.querySelectorAll('.modal');
|
||||
modals.forEach(modal => {
|
||||
modal.addEventListener('hidden.bs.modal', function () {
|
||||
// To refresh the content, we reload the page with the correct tab active
|
||||
const activeTab = document.querySelector('.nav-tabs .nav-link.active').id.replace('-tab', '');
|
||||
window.location.href = 'dashboard.php?tab=' + activeTab;
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
699
index.php
699
index.php
@ -9,145 +9,92 @@ if (!is_logged_in()) {
|
||||
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
// Handle delete task
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_task']) && hasPermission('manage_tasks')) {
|
||||
$task_id = $_POST['delete_task_id'] ?? null;
|
||||
|
||||
if (!empty($task_id)) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("DELETE FROM tasks WHERE id = ?");
|
||||
$stmt->execute([$task_id]);
|
||||
header("Location: " . $_SERVER['PHP_SELF']);
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error deleting task: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle delete candidate
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_candidate']) && hasPermission('manage_candidates')) {
|
||||
$candidate_id = $_POST['delete_candidate_id'] ?? null;
|
||||
|
||||
if (!empty($candidate_id)) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("DELETE FROM candidates WHERE id = ?");
|
||||
$stmt->execute([$candidate_id]);
|
||||
header("Location: " . $_SERVER['PHP_SELF']);
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error deleting candidate: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle form submission for new candidate
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_candidate']) && hasPermission('manage_candidates')) {
|
||||
$name = $_POST['name'] ?? '';
|
||||
$email = $_POST['email'] ?? '';
|
||||
$phone = $_POST['phone'] ?? '';
|
||||
$status = $_POST['status'] ?? 'Applied';
|
||||
$notes = $_POST['notes'] ?? '';
|
||||
|
||||
if (!empty($name) && !empty($email)) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("INSERT INTO candidates (name, email, phone, status, notes) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$name, $email, $phone, $status, $notes]);
|
||||
require_once 'workflow_engine.php';
|
||||
trigger_workflow('candidate_created', ['candidate.id' => $pdo->lastInsertId(), 'candidate.name' => $name, 'candidate.email' => $email]);
|
||||
// Redirect to avoid form resubmission
|
||||
header("Location: " . $_SERVER['PHP_SELF']);
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
// Handle error, e.g., show an error message
|
||||
error_log("Error adding candidate: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['complete_task']) && hasPermission('manage_tasks')) {
|
||||
$task_id = $_POST['task_id'] ?? null;
|
||||
|
||||
if (!empty($task_id)) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("UPDATE tasks SET status = 'Done' WHERE id = ?");
|
||||
$stmt->execute([$task_id]);
|
||||
|
||||
// Fetch task details to pass to the workflow
|
||||
$stmt = $pdo->prepare("SELECT * FROM tasks WHERE id = ?");
|
||||
$stmt->execute([$task_id]);
|
||||
$task = $stmt->fetch();
|
||||
|
||||
require_once 'workflow_engine.php';
|
||||
trigger_workflow('task_completed', ['task.id' => $task['id'], 'task.name' => $task['task_name'], 'task.status' => $task['status']]);
|
||||
|
||||
header("Location: " . $_SERVER['PHP_SELF']);
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error completing task: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle form submission for new task
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_task']) && hasPermission('manage_tasks')) {
|
||||
$task_name = $_POST['task_name'] ?? '';
|
||||
$candidate_id = $_POST['candidate_id'] ?? null;
|
||||
$due_date = $_POST['due_date'] ?? null;
|
||||
$status = $_POST['status'] ?? 'To Do';
|
||||
$description = $_POST['description'] ?? '';
|
||||
|
||||
if (!empty($task_name) && !empty($candidate_id)) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("INSERT INTO tasks (task_name, candidate_id, due_date, status, description) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$task_name, $candidate_id, $due_date, $status, $description]);
|
||||
header("Location: " . $_SERVER['PHP_SELF']);
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error adding task: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch tasks from the database
|
||||
// Data Fetching for Dashboard
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT tasks.*, candidates.name as candidate_name FROM tasks JOIN candidates ON tasks.candidate_id = candidates.id ORDER BY created_at DESC");
|
||||
$tasks = $stmt->fetchAll();
|
||||
|
||||
// Key Metrics
|
||||
$totalActiveCandidates = $pdo->query("SELECT COUNT(*) FROM candidates WHERE status NOT IN ('Hired', 'Rejected')")->fetchColumn();
|
||||
$newCandidatesThisWeek = $pdo->query("SELECT COUNT(*) FROM candidates WHERE created_at >= NOW() - INTERVAL 7 DAY")->fetchColumn();
|
||||
|
||||
// Assuming tasks with "interview" in the name are interviews
|
||||
$interviewsThisWeek = $pdo->query("SELECT COUNT(*) FROM tasks WHERE title LIKE '%interview%' AND due_date >= CURDATE() AND due_date < CURDATE() + INTERVAL 7 DAY")->fetchColumn();
|
||||
|
||||
$pendingTasks = $pdo->query("SELECT COUNT(*) FROM tasks WHERE status NOT IN ('Completed')")->fetchColumn();
|
||||
$overdueTasksCount = $pdo->query("SELECT COUNT(*) FROM tasks WHERE status NOT IN ('Completed') AND due_date < CURDATE()")->fetchColumn();
|
||||
|
||||
$newHiresThisMonth = $pdo->query("SELECT COUNT(*) FROM candidates WHERE status = 'Hired' AND created_at >= NOW() - INTERVAL 1 MONTH")->fetchColumn();
|
||||
|
||||
// Recent Activity Feed from workflow_logs
|
||||
$recentActivities = $pdo->query("
|
||||
SELECT wl.*, w.name as workflow_name, c.name as candidate_name
|
||||
FROM workflow_logs wl
|
||||
LEFT JOIN workflows w ON wl.workflow_id = w.id
|
||||
LEFT JOIN candidates c ON wl.candidate_id = c.id
|
||||
ORDER BY wl.executed_at DESC
|
||||
LIMIT 10
|
||||
")->fetchAll();
|
||||
|
||||
// At-Risk Items
|
||||
$overdueTasks = $pdo->query("
|
||||
SELECT t.title, t.due_date, c.name as candidate_name
|
||||
FROM tasks t
|
||||
LEFT JOIN candidates c ON t.assigned_to = c.id
|
||||
WHERE t.status != 'Completed' AND t.due_date < CURDATE()
|
||||
ORDER BY t.due_date ASC
|
||||
")->fetchAll();
|
||||
|
||||
$inactiveCandidates = $pdo->query("
|
||||
SELECT name, email, created_at
|
||||
FROM candidates
|
||||
WHERE status = 'Applied' AND created_at <= NOW() - INTERVAL 7 DAY
|
||||
")->fetchAll();
|
||||
|
||||
$incompleteOnboarding = $pdo->query("
|
||||
SELECT t.title, c.name as candidate_name, t.due_date
|
||||
FROM tasks t
|
||||
JOIN candidates c ON t.assigned_to = c.id
|
||||
WHERE c.status = 'Hired' AND t.status != 'Completed'
|
||||
")->fetchAll();
|
||||
|
||||
$all_candidates = $pdo->query("SELECT * FROM candidates ORDER BY name ASC")->fetchAll();
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error fetching tasks: " . $e->getMessage());
|
||||
$tasks = []; // Ensure $tasks is an array
|
||||
error_log("Dashboard Data Fetch Error: " . $e->getMessage());
|
||||
// Initialize variables to prevent errors in the view
|
||||
$totalActiveCandidates = $newCandidatesThisWeek = $interviewsThisWeek = $pendingTasks = $overdueTasksCount = $newHiresThisMonth = 0;
|
||||
$recentActivities = $overdueTasks = $inactiveCandidates = $incompleteOnboarding = $all_candidates = [];
|
||||
}
|
||||
|
||||
// Fetch candidates from the database
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT * FROM candidates ORDER BY created_at DESC");
|
||||
$candidates = $stmt->fetchAll();
|
||||
} catch (PDOException $e) {
|
||||
// Handle error, e.g., show an error message
|
||||
error_log("Error fetching candidates: " . $e->getMessage());
|
||||
$candidates = []; // Ensure $candidates is an array
|
||||
}
|
||||
function time_ago($datetime, $full = false) {
|
||||
$now = new DateTime;
|
||||
$ago = new DateTime($datetime);
|
||||
$diff = $now->diff($ago);
|
||||
|
||||
function getStatusClass($status) {
|
||||
switch ($status) {
|
||||
case 'Applied': return 'status-new';
|
||||
case 'Interviewing': return 'status-interview';
|
||||
case 'Hired': return 'status-hired';
|
||||
case 'Rejected': return 'status-rejected';
|
||||
case 'Offered': return 'status-offered';
|
||||
case 'To Do': return 'status-todo';
|
||||
case 'In Progress': return 'status-in-progress';
|
||||
case 'Done': return 'status-done';
|
||||
default: return '';
|
||||
$diff->w = floor($diff->d / 7);
|
||||
$diff->d -= $diff->w * 7;
|
||||
|
||||
$string = array(
|
||||
'y' => 'year',
|
||||
'm' => 'month',
|
||||
'w' => 'week',
|
||||
'd' => 'day',
|
||||
'h' => 'hour',
|
||||
'i' => 'minute',
|
||||
's' => 'second',
|
||||
);
|
||||
foreach ($string as $k => &$v) {
|
||||
if ($diff->$k) {
|
||||
$v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
|
||||
} else {
|
||||
unset($string[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$full) $string = array_slice($string, 0, 1);
|
||||
return $string ? implode(', ', $string) . ' ago' : 'just now';
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -155,29 +102,84 @@ function getStatusClass($status) {
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<!-- SEO & Meta Tags -->
|
||||
<title>FinMox Flow</title>
|
||||
<meta name="description" content="FinMox Flow - a multi-tenant SaaS platform for HR and Operations teams. Built with Flatlogic Generator.">
|
||||
<meta name="keywords" content="finmox, hr, operations, saas, candidate tracking, onboarding, automations, ai copilot, flatlogic">
|
||||
<title>Executive Dashboard - FinMox Flow</title>
|
||||
<meta name="description" content="Executive dashboard for FinMox Flow, providing key metrics and insights for HR and operations.">
|
||||
|
||||
<!-- Social Media Meta Tags -->
|
||||
<meta property="og:title" content="FinMox Flow">
|
||||
<meta property="og:description" content="A multi-tenant SaaS platform for HR and Operations teams.">
|
||||
<meta property="og:title" content="FinMox Flow Dashboard">
|
||||
<meta property="og:description" content="Key metrics for HR and operations.">
|
||||
<meta property="og:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
|
||||
|
||||
<!-- Stylesheets -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
|
||||
<style>
|
||||
.main-content {
|
||||
background-color: #f4f7fc;
|
||||
}
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
.metric-card .card-body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.metric-card .icon {
|
||||
font-size: 2.5rem;
|
||||
margin-right: 1rem;
|
||||
color: #0d6efd;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.metric-card .value {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
.metric-card .label {
|
||||
font-size: 1rem;
|
||||
color: #6c757d;
|
||||
}
|
||||
.metric-card .indicator {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.quick-actions .btn {
|
||||
padding: 0.75rem 1.5rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.activity-feed .activity-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.75rem 0;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
}
|
||||
.activity-feed .activity-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.activity-feed .icon {
|
||||
font-size: 1.5rem;
|
||||
margin-right: 1rem;
|
||||
color: #6c757d;
|
||||
}
|
||||
.at-risk-section .table {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="header d-flex justify-content-between align-items-center">
|
||||
<div class="logo">FinMox<span class="dot">.</span></div>
|
||||
<nav class="d-flex align-items-center">
|
||||
<a href="index.php" class="btn btn-outline-primary me-2">Home</a>
|
||||
<a href="index.php" class="btn btn-primary me-2">Home</a>
|
||||
<a href="chat.php" class="btn btn-outline-primary me-2">Chat</a>
|
||||
<a href="dashboard.php" class="btn btn-outline-primary me-2">Dashboard</a>
|
||||
<a href="workflows.php" class="btn btn-outline-primary me-3">Workflows</a>
|
||||
@ -197,246 +199,219 @@ function getStatusClass($status) {
|
||||
</header>
|
||||
|
||||
<main class="main-content">
|
||||
<div class="container-fluid">
|
||||
<?php if (hasPermission('view_candidates')): ?>
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Candidates</h1>
|
||||
<?php if (hasPermission('manage_candidates')): ?>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addCandidateModal">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-lg me-1" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2Z"/>
|
||||
</svg>
|
||||
Add Candidate
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<div class="container-fluid py-4">
|
||||
|
||||
<!-- TOP SECTION - Key Metrics -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card metric-card h-100">
|
||||
<div class="card-body">
|
||||
<div class="icon"><i class="bi bi-people-fill"></i></div>
|
||||
<div>
|
||||
<div class="value"><?php echo $totalActiveCandidates; ?></div>
|
||||
<div class="label">Total Active Candidates</div>
|
||||
<div class="indicator text-success">+<?php echo $newCandidatesThisWeek; ?> this week</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card metric-card h-100">
|
||||
<div class="card-body">
|
||||
<div class="icon"><i class="bi bi-calendar-check"></i></div>
|
||||
<div>
|
||||
<div class="value"><?php echo $interviewsThisWeek; ?></div>
|
||||
<div class="label">Interviews This Week</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card metric-card h-100">
|
||||
<div class="card-body">
|
||||
<div class="icon"><i class="bi bi-list-task"></i></div>
|
||||
<div>
|
||||
<div class="value"><?php echo $pendingTasks; ?></div>
|
||||
<div class="label">Pending Tasks</div>
|
||||
<?php if ($overdueTasksCount > 0): ?>
|
||||
<div class="indicator text-danger"><?php echo $overdueTasksCount; ?> overdue</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card metric-card h-100">
|
||||
<div class="card-body">
|
||||
<div class="icon"><i class="bi bi-person-plus-fill"></i></div>
|
||||
<div>
|
||||
<div class="value"><?php echo $newHiresThisMonth; ?></div>
|
||||
<div class="label">New Hires This Month</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="ps-4">Name</th>
|
||||
<th>Phone</th>
|
||||
<th>Status</th>
|
||||
<th class="text-end pe-4">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($candidates as $candidate): ?>
|
||||
<tr>
|
||||
<td class="ps-4">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<div class="candidate-name"><?php echo htmlspecialchars($candidate['name']); ?></div>
|
||||
<div class="candidate-email"><?php echo htmlspecialchars($candidate['email']); ?></div>
|
||||
</div>
|
||||
<!-- MIDDLE SECTION - Quick Actions -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center quick-actions">
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addCandidateModal"><i class="bi bi-plus-circle me-2"></i>Add New Candidate</button>
|
||||
<button class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#addTaskModal"><i class="bi bi-calendar-plus me-2"></i>Schedule Interview</button>
|
||||
<a href="#" class="btn btn-secondary"><i class="bi bi-file-earmark-text me-2"></i>View Weekly Report</a>
|
||||
<a href="workflows.php" class="btn btn-secondary"><i class="bi bi-diagram-3 me-2"></i>Manage Workflows</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- RECENT ACTIVITY FEED -->
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-white py-3">
|
||||
<h5 class="mb-0">Recent Activity</h5>
|
||||
</div>
|
||||
<div class="card-body activity-feed">
|
||||
<?php if (empty($recentActivities)): ?>
|
||||
<p class="text-center text-muted">No recent activity.</p>
|
||||
<?php else: ?>
|
||||
<?php foreach ($recentActivities as $activity): ?>
|
||||
<div class="activity-item">
|
||||
<div class="icon"><i class="bi bi-bell"></i></div>
|
||||
<div class="flex-grow-1">
|
||||
<div>
|
||||
<?php
|
||||
$action_desc = htmlspecialchars(ucfirst(str_replace('_', ' ', $activity['action'])));
|
||||
if ($activity['workflow_name']) {
|
||||
echo htmlspecialchars(ucfirst(str_replace('_', ' ', $activity['workflow_name'])));
|
||||
} else {
|
||||
echo $action_desc;
|
||||
}
|
||||
if ($activity['candidate_name']) {
|
||||
echo " for " . htmlspecialchars($activity['candidate_name']);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($candidate['phone'] ?? 'N/A'); ?></td>
|
||||
<td>
|
||||
<span class="status-badge <?php echo getStatusClass($candidate['status']); ?>">
|
||||
<?php echo htmlspecialchars($candidate['status']); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end pe-4">
|
||||
<a href="edit_candidate.php?id=<?php echo $candidate['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>" style="display: inline;">
|
||||
<input type="hidden" name="delete_candidate_id" value="<?php echo $candidate['id']; ?>">
|
||||
<button type="submit" name="delete_candidate" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this candidate?');">Delete</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<small class="text-muted"><?php echo time_ago($activity['executed_at']); ?></small>
|
||||
</div>
|
||||
<a href="workflows.php?highlight=<?php echo $activity['workflow_id']; ?>" class="btn btn-sm btn-outline-secondary">Details</a>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AT-RISK ITEMS -->
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-white py-3">
|
||||
<h5 class="mb-0">At-Risk Items</h5>
|
||||
</div>
|
||||
<div class="card-body at-risk-section">
|
||||
<?php if (!empty($overdueTasks)): ?>
|
||||
<h6><i class="bi bi-exclamation-triangle-fill text-danger me-2"></i>Overdue Tasks</h6>
|
||||
<div class="table-responsive mb-3">
|
||||
<table class="table table-sm">
|
||||
<tbody>
|
||||
<?php foreach ($overdueTasks as $task): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($task['title']); ?></td>
|
||||
<td><small><?php echo htmlspecialchars($task['candidate_name']); ?></small></td>
|
||||
<td class="text-danger"><small><?php echo date("M d", strtotime($task['due_date'])); ?></small></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($inactiveCandidates)): ?>
|
||||
<h6 class="mt-3"><i class="bi bi-person-fill-exclamation text-warning me-2"></i>Inactive Candidates (>7 days)</h6>
|
||||
<div class="table-responsive mb-3">
|
||||
<table class="table table-sm">
|
||||
<tbody>
|
||||
<?php foreach ($inactiveCandidates as $candidate): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($candidate['name']); ?></td>
|
||||
<td><small><?php echo htmlspecialchars($candidate['email']); ?></small></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($incompleteOnboarding)): ?>
|
||||
<h6 class="mt-3"><i class="bi bi-clipboard-x-fill text-info me-2"></i>Incomplete Onboarding</h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm">
|
||||
<tbody>
|
||||
<?php foreach ($incompleteOnboarding as $task): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($task['title']); ?></td>
|
||||
<td><small><?php echo htmlspecialchars($task['candidate_name']); ?></small></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (empty($overdueTasks) && empty($inactiveCandidates) && empty($incompleteOnboarding)): ?>
|
||||
<p class="text-center text-muted mt-3">No at-risk items found. Great job!</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (hasPermission('view_tasks')): ?>
|
||||
<div class="page-header mt-5">
|
||||
<h1 class="page-title">Tasks</h1>
|
||||
<?php if (hasPermission('manage_tasks')): ?>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addTaskModal">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-lg me-1" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2Z"/>
|
||||
</svg>
|
||||
Add Task
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="ps-4">Task Name</th>
|
||||
<th>Assigned To</th>
|
||||
<th>Due Date</th>
|
||||
<th>Status</th>
|
||||
<th class="text-end pe-4">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($tasks as $task): ?>
|
||||
<tr>
|
||||
<td class="ps-4"><?php echo htmlspecialchars($task['task_name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($task['candidate_name'] ?? 'N/A'); ?></td>
|
||||
<td><?php echo htmlspecialchars($task['due_date'] ?? 'N/A'); ?></td>
|
||||
<td>
|
||||
<span class="status-badge <?php echo getStatusClass($task['status']); ?>">
|
||||
<?php echo htmlspecialchars($task['status']); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end pe-4">
|
||||
<a href="edit_task.php?id=<?php echo $task['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||
<form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>" style="display: inline;">
|
||||
<input type="hidden" name="delete_task_id" value="<?php echo $task['id']; ?>">
|
||||
<button type="submit" name="delete_task" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this task?');">Delete</button>
|
||||
</form>
|
||||
<form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>" style="display: inline;">
|
||||
<input type="hidden" name="task_id" value="<?php echo $task['id']; ?>">
|
||||
<button type="submit" name="complete_task" class="btn btn-sm btn-success">Complete</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Add Candidate Modal -->
|
||||
<div class="modal fade" id="addCandidateModal" tabindex="-1" aria-labelledby="addCandidateModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addCandidateModalLabel">Add New Candidate</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>">
|
||||
<input type="hidden" name="add_candidate" value="1">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Name</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="phone" class="form-label">Phone</label>
|
||||
<input type="text" class="form-control" id="phone" name="phone">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="status" class="form-label">Status</label>
|
||||
<select class="form-select" id="status" name="status">
|
||||
<option value="Applied" selected>Applied</option>
|
||||
<option value="Interviewing">Interviewing</option>
|
||||
<option value="Offered">Offered</option>
|
||||
<option value="Hired">Hired</option>
|
||||
<option value="Rejected">Rejected</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="notes" class="form-label">Notes</label>
|
||||
<textarea class="form-control" id="notes" name="notes" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Save Candidate</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal fade" id="addCandidateModal" tabindex="-1" aria-labelledby="addCandidateModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addCandidateModalLabel">Add New Candidate</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="POST" action="index.php">
|
||||
<input type="hidden" name="add_candidate" value="1">
|
||||
<div class="mb-3"><label for="name" class="form-label">Name</label><input type="text" class="form-control" id="name" name="name" required></div>
|
||||
<div class="mb-3"><label for="email" class="form-label">Email</label><input type="email" class="form-control" id="email" name="email" required></div>
|
||||
<div class="mb-3"><label for="phone" class="form-label">Phone</label><input type="text" class="form-control" id="phone" name="phone"></div>
|
||||
<div class="mb-3"><label for="status" class="form-label">Status</label><select class="form-select" id="status" name="status"><option value="Applied" selected>Applied</option><option value="Interviewing">Interviewing</option><option value="Offered">Offered</option><option value="Hired">Hired</option><option value="Rejected">Rejected</option></select></div>
|
||||
<div class="mb-3"><label for="notes" class="form-label">Notes</label><textarea class="form-control" id="notes" name="notes" rows="3"></textarea></div>
|
||||
<div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button><button type="submit" class="btn btn-primary">Save Candidate</button></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Task Modal -->
|
||||
<div class="modal fade" id="addTaskModal" tabindex="-1" aria-labelledby="addTaskModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addTaskModalLabel">Add New Task</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>">
|
||||
<input type="hidden" name="add_task" value="1">
|
||||
<div class="mb-3">
|
||||
<label for="task_name" class="form-label">Task Name</label>
|
||||
<input type="text" class="form-control" id="task_name" name="task_name" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="candidate_id" class="form-label">Assign to Candidate</label>
|
||||
<select class="form-select" id="candidate_id" name="candidate_id" required>
|
||||
<option value="" disabled selected>Select a candidate</option>
|
||||
<?php foreach ($candidates as $candidate): ?>
|
||||
<option value="<?php echo $candidate['id']; ?>"><?php echo htmlspecialchars($candidate['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="due_date" class="form-label">Due Date</label>
|
||||
<input type="date" class="form-control" id="due_date" name="due_date">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="task_status" class="form-label">Status</label>
|
||||
<select class="form-select" id="task_status" name="status">
|
||||
<option value="To Do" selected>To Do</option>
|
||||
<option value="In Progress">In Progress</option>
|
||||
<option value="Done">Done</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="task_description" class="form-label">Description</label>
|
||||
<textarea class="form-control" id="task_description" name="description" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Save Task</button>
|
||||
</div>
|
||||
</form>
|
||||
<!-- Add Task Modal (for "Schedule Interview") -->
|
||||
<div class="modal fade" id="addTaskModal" tabindex="-1" aria-labelledby="addTaskModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addTaskModalLabel">Schedule Interview</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="POST" action="index.php">
|
||||
<input type="hidden" name="add_task" value="1">
|
||||
<div class="mb-3"><label for="task_name" class="form-label">Interview Title</label><input type="text" class="form-control" id="task_name" name="title" required value="Interview with "></div>
|
||||
<div class="mb-3"><label for="candidate_id" class="form-label">Candidate</label><select class="form-select" id="candidate_id" name="assigned_to" required><option value="" disabled selected>Select a candidate</option><?php foreach ($all_candidates as $candidate): ?><option value="<?php echo $candidate['id']; ?>"><?php echo htmlspecialchars($candidate['name']); ?></option><?php endforeach; ?></select></div>
|
||||
<div class="mb-3"><label for="due_date" class="form-label">Interview Date</label><input type="date" class="form-control" id="due_date" name="due_date" required></div>
|
||||
<div class="mb-3"><label for="task_description" class="form-label">Notes</label><textarea class="form-control" id="task_description" name="description" rows="3"></textarea></div>
|
||||
<div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button><button type="submit" class="btn btn-primary">Schedule</button></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
|
||||
<!-- AI Chat Interface -->
|
||||
<div id="chat-container" class="chat-container">
|
||||
<div id="chat-header" class="chat-header">
|
||||
<span>AI Assistant</span>
|
||||
<button id="close-chat" class="btn-close btn-sm" aria-label="Close"></button>
|
||||
</div>
|
||||
<div id="chat-body" class="chat-body">
|
||||
<!-- Chat messages will be appended here -->
|
||||
</div>
|
||||
<div id="chat-input-container" class="chat-input-container">
|
||||
<input type="text" id="chat-input" class="form-control" placeholder="Ask a question...">
|
||||
<button id="send-chat" class="btn btn-primary">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="chat-toggle" class="chat-toggle-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-chat-dots" viewBox="0 0 16 16">
|
||||
<path d="M5 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/>
|
||||
<path d="M2.165 15.803l-1.57-1.57a1 1 0 0 1 0-1.414L2.165 10.5l1.57 1.57-1.57 1.57zm1.57-1.57l-1.57-1.57a1 1 0 0 1 0-1.414l1.57-1.57 1.57 1.57-1.57 1.57zM12.235 2.165l1.57 1.57a1 1 0 0 1 0 1.414l-1.57 1.57-1.57-1.57 1.57-1.57z"/>
|
||||
<path d="M15.657 2.343a1 1 0 0 1 0 1.414l-1.57 1.57-1.57-1.57 1.57-1.57a1 1 0 0 1 1.414 0z"/>
|
||||
<path d="M.5 1a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1H2.707l-2.147 2.146a.5.5 0 0 0 .708.708L3.293 11H15a2 2 0 0 0 2-2V1a2 2 0 0 0-2-2H1.5A1.5 1.5 0 0 0 0 1.5v12.793a.5.5 0 0 0 .854.353L.5 1z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</body>
|
||||
</html>
|
||||
133
workflows.php
133
workflows.php
@ -16,23 +16,6 @@ require_once 'db/config.php';
|
||||
|
||||
$pdo = db();
|
||||
|
||||
// Handle form submission for new workflow
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_workflow']) && hasPermission('manage_workflows')) {
|
||||
$name = $_POST['name'] ?? '';
|
||||
$trigger = $_POST['trigger'] ?? '';
|
||||
|
||||
if (!empty($name) && !empty($trigger)) {
|
||||
try {
|
||||
$stmt = $pdo->prepare("INSERT INTO workflows (name, `trigger`) VALUES (?, ?)");
|
||||
$stmt->execute([$name, $trigger]);
|
||||
header("Location: " . $_SERVER['PHP_SELF']);
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Error adding workflow: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch workflows from the database
|
||||
$stmt = $pdo->query("SELECT * FROM workflows ORDER BY created_at DESC");
|
||||
$workflows = $stmt->fetchAll();
|
||||
@ -45,7 +28,24 @@ $workflows = $stmt->fetchAll();
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Workflows</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.11.3/font/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
<style>
|
||||
.workflow-card {
|
||||
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
||||
}
|
||||
.workflow-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.workflow-card .bi {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
.status-badge {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.3em 0.6em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header class="header d-flex justify-content-between align-items-center">
|
||||
@ -54,7 +54,7 @@ $workflows = $stmt->fetchAll();
|
||||
<a href="index.php" class="btn btn-outline-primary me-2">Home</a>
|
||||
<a href="chat.php" class="btn btn-outline-primary me-2">Chat</a>
|
||||
<a href="dashboard.php" class="btn btn-outline-primary me-2">Dashboard</a>
|
||||
<a href="workflows.php" class="btn btn-outline-primary me-3">Workflows</a>
|
||||
<a href="workflows.php" class="btn btn-primary me-3">Workflows</a>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" type="button" id="userDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<?php echo htmlspecialchars($_SESSION['username']); ?>
|
||||
@ -70,38 +70,79 @@ $workflows = $stmt->fetchAll();
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-fluid">
|
||||
<main class="container-fluid mt-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Workflows</h2>
|
||||
<h2 class="h2">Your Automation Workflows</h2>
|
||||
<?php if (hasPermission('manage_workflows')): ?>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addWorkflowModal">Add Workflow</button>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addWorkflowModal">Create New Workflow</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Trigger</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($workflows as $workflow): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($workflow['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($workflow['trigger']); ?></td>
|
||||
<td>
|
||||
<?php if (hasPermission('manage_workflows')): ?>
|
||||
<a href="workflow_actions.php?workflow_id=<?php echo $workflow['id']; ?>" class="btn btn-sm btn-outline-primary">Manage Actions</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-4 g-4">
|
||||
<!-- Smart Candidate Intake -->
|
||||
<div class="col">
|
||||
<div class="card h-100 workflow-card">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-inbox-fill text-primary"></i>
|
||||
<h5 class="card-title mt-3">Smart Candidate Intake</h5>
|
||||
<span class="badge bg-success status-badge">Active</span>
|
||||
<p class="card-text text-muted mt-2">"Automatically captures, enriches, and routes new candidates"</p>
|
||||
<p class="fw-bold">142 candidates processed this month</p>
|
||||
</div>
|
||||
<div class="card-footer bg-white text-center">
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">View Details</a>
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">Edit</a>
|
||||
<a href="#" class="btn btn-sm btn-outline-warning">Pause</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Interview Scheduling -->
|
||||
<div class="col">
|
||||
<div class="card h-100 workflow-card">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-calendar-check-fill text-success"></i>
|
||||
<h5 class="card-title mt-3">Interview Scheduling</h5>
|
||||
<p class="card-text text-muted mt-2">"Automates calendar checks and interview coordination"</p>
|
||||
<p class="fw-bold">28 interviews scheduled this month</p>
|
||||
</div>
|
||||
<div class="card-footer bg-white text-center">
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">View Details</a>
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">Edit</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Onboarding Automation -->
|
||||
<div class="col">
|
||||
<div class="card h-100 workflow-card">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-person-check-fill text-info"></i>
|
||||
<h5 class="card-title mt-3">Onboarding Automation</h5>
|
||||
<p class="card-text text-muted mt-2">"Creates and tracks onboarding tasks automatically"</p>
|
||||
<p class="fw-bold">5 active onboardings</p>
|
||||
</div>
|
||||
<div class="card-footer bg-white text-center">
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">View Details</a>
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">Edit</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Weekly Reports -->
|
||||
<div class="col">
|
||||
<div class="card h-100 workflow-card">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-bar-chart-line-fill text-warning"></i>
|
||||
<h5 class="card-title mt-3">Weekly Reports</h5>
|
||||
<p class="card-text text-muted mt-2">"AI-generated weekly summary for leadership"</p>
|
||||
<p class="fw-bold">Last report sent Friday 4pm</p>
|
||||
</div>
|
||||
<div class="card-footer bg-white text-center">
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">View Details</a>
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">Edit</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
@ -111,7 +152,7 @@ $workflows = $stmt->fetchAll();
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addWorkflowModalLabel">Add New Workflow</h5>
|
||||
<h5 class="modal-title" id="addWorkflowModalLabel">Create New Workflow</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user