nov 20th, 2025 V.1

This commit is contained in:
Flatlogic Bot 2025-11-20 05:15:40 +00:00
parent 4d417098b6
commit e6fd5f2ecb
11 changed files with 578 additions and 416 deletions

421
app.php Normal file
View File

@ -0,0 +1,421 @@
<?php
require_once 'auth.php';
// Check if user is logged in
if (!is_logged_in()) {
header('Location: login.php');
exit;
}
require_once __DIR__ . '/db/config.php';
// Data Fetching for Dashboard
try {
$pdo = db();
// 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("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 = [];
}
function time_ago($datetime, $full = false) {
$now = new DateTime;
$ago = new DateTime($datetime);
$diff = $now->diff($ago);
$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">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Executive Dashboard - FinMox Flow</title>
<meta name="description" content="Executive dashboard for FinMox Flow, providing key metrics and insights for HR and operations.">
<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'); ?>">
<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">
<a href="app.php">
<img src="assets/pasted-20251120-051320-b2b0cdfa.png" alt="FinMox Logo" style="height: 32px;">
</a>
</div>
<nav class="d-flex align-items-center">
<a href="app.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>
<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']); ?>
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
<?php if (hasPermission('manage_roles')): ?>
<li><a class="dropdown-item" href="roles.php">Manage Roles</a></li>
<li><hr class="dropdown-divider"></li>
<?php endif; ?>
<li><a class="dropdown-item" href="logout.php">Logout</a></li>
</ul>
</div>
</nav>
</header>
<main class="main-content">
<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>
<!-- 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>
<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; ?>
<?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>
</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="app.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>
<!-- 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="app.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>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

@ -65,9 +65,13 @@ if (!is_logged_in()) {
<body>
<header class="header d-flex justify-content-between align-items-center">
<div class="logo">FinMox<span class="dot">.</span></div>
<div class="logo">
<a href="app.php">
<img src="assets/pasted-20251120-051320-b2b0cdfa.png" alt="FinMox Logo" style="height: 32px;">
</a>
</div>
<nav class="d-flex align-items-center">
<a href="index.php" class="btn btn-outline-primary me-2">Home</a>
<a href="app.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>

View File

@ -85,9 +85,13 @@ $completed_tasks = $pdo->query("SELECT COUNT(*) FROM tasks WHERE status = 'Compl
</head>
<body>
<header class="header d-flex justify-content-between align-items-center">
<div class="logo">FinMox<span class="dot">.</span></div>
<div class="logo">
<a href="app.php">
<img src="assets/pasted-20251120-051320-b2b0cdfa.png" alt="FinMox Logo" style="height: 32px;">
</a>
</div>
<nav class="d-flex align-items-center">
<a href="index.php" class="btn btn-outline-primary me-2">Home</a>
<a href="app.php" class="btn btn-outline-primary me-2">Home</a>
<a href="workflows.php" class="btn btn-outline-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">

View File

@ -8,7 +8,7 @@ if (!is_logged_in()) {
}
if (!hasPermission('manage_candidates')) {
header('Location: index.php');
header('Location: app.php');
exit;
}
@ -16,7 +16,7 @@ $pdo = db();
$candidate_id = $_GET['id'] ?? null;
if (!$candidate_id) {
header('Location: index.php');
header('Location: app.php');
exit;
}
@ -26,7 +26,7 @@ $stmt->execute([$candidate_id]);
$candidate = $stmt->fetch();
if (!$candidate) {
header('Location: index.php');
header('Location: app.php');
exit;
}
@ -42,7 +42,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_candidate']))
try {
$stmt = $pdo->prepare("UPDATE candidates SET name = ?, email = ?, phone = ?, status = ?, notes = ? WHERE id = ?");
$stmt->execute([$name, $email, $phone, $status, $notes, $candidate_id]);
header('Location: index.php');
header('Location: app.php');
exit;
} catch (PDOException $e) {
error_log("Error updating candidate: " . $e->getMessage());
@ -61,9 +61,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_candidate']))
</head>
<body>
<header class="header d-flex justify-content-between align-items-center">
<div class="logo">FinMox<span class="dot">.</span></div>
<div class="logo">
<a href="app.php">
<img src="assets/pasted-20251120-051320-b2b0cdfa.png" alt="FinMox Logo" style="height: 32px;">
</a>
</div>
<nav class="d-flex align-items-center">
<a href="index.php" class="btn btn-outline-primary me-2">Home</a>
<a href="app.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>
@ -115,7 +119,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_candidate']))
<textarea class="form-control" id="notes" name="notes" rows="3"><?php echo htmlspecialchars($candidate['notes']); ?></textarea>
</div>
<button type="submit" class="btn btn-primary">Update Candidate</button>
<a href="index.php" class="btn btn-secondary">Cancel</a>
<a href="app.php" class="btn btn-secondary">Cancel</a>
</form>
</div>
</div>

View File

@ -8,7 +8,7 @@ if (!is_logged_in()) {
}
if (!hasPermission('manage_roles')) {
header('Location: index.php');
header('Location: app.php');
exit;
}
@ -92,9 +92,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_permissions']))
</head>
<body>
<header class="header d-flex justify-content-between align-items-center">
<div class="logo">FinMox<span class="dot">.</span></div>
<div class="logo">
<a href="app.php">
<img src="assets/pasted-20251120-051320-b2b0cdfa.png" alt="FinMox Logo" style="height: 32px;">
</a>
</div>
<nav class="d-flex align-items-center">
<a href="index.php" class="btn btn-outline-primary me-2">Home</a>
<a href="app.php" class="btn btn-outline-primary me-2">Home</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>
<div class="dropdown">

View File

@ -8,7 +8,7 @@ if (!is_logged_in()) {
}
if (!hasPermission('manage_tasks')) {
header('Location: index.php');
header('Location: app.php');
exit;
}
@ -16,7 +16,7 @@ $pdo = db();
$task_id = $_GET['id'] ?? null;
if (!$task_id) {
header('Location: index.php');
header('Location: app.php');
exit;
}
@ -26,7 +26,7 @@ $stmt->execute([$task_id]);
$task = $stmt->fetch();
if (!$task) {
header('Location: index.php');
header('Location: app.php');
exit;
}
@ -46,7 +46,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_task'])) {
try {
$stmt = $pdo->prepare("UPDATE tasks SET task_name = ?, candidate_id = ?, due_date = ?, status = ?, description = ? WHERE id = ?");
$stmt->execute([$task_name, $candidate_id, $due_date, $status, $description, $task_id]);
header('Location: index.php');
header('Location: app.php');
exit;
} catch (PDOException $e) {
error_log("Error updating task: " . $e->getMessage());
@ -65,9 +65,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_task'])) {
</head>
<body>
<header class="header d-flex justify-content-between align-items-center">
<div class="logo">FinMox<span class="dot">.</span></div>
<div class="logo">
<a href="app.php">
<img src="assets/pasted-20251120-051320-b2b0cdfa.png" alt="FinMox Logo" style="height: 32px;">
</a>
</div>
<nav class="d-flex align-items-center">
<a href="index.php" class="btn btn-outline-primary me-2">Home</a>
<a href="app.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>
@ -122,7 +126,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_task'])) {
<textarea class="form-control" id="task_description" name="description" rows="3"><?php echo htmlspecialchars($task['description']); ?></textarea>
</div>
<button type="submit" class="btn btn-primary">Update Task</button>
<a href="index.php" class="btn btn-secondary">Cancel</a>
<a href="app.php" class="btn btn-secondary">Cancel</a>
</form>
</div>
</div>

487
index.php
View File

@ -1,417 +1,132 @@
<?php
require_once 'auth.php';
// Check if user is logged in
if (!is_logged_in()) {
header('Location: login.php');
exit;
}
require_once __DIR__ . '/db/config.php';
// Data Fetching for Dashboard
try {
$pdo = db();
// 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("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 = [];
}
function time_ago($datetime, $full = false) {
$now = new DateTime;
$ago = new DateTime($datetime);
$diff = $now->diff($ago);
$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">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Executive Dashboard - FinMox Flow</title>
<meta name="description" content="Executive dashboard for FinMox Flow, providing key metrics and insights for HR and operations.">
<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'); ?>">
<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(); ?>">
<title>FinMox | HR Automation Platform</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
.main-content {
background-color: #f4f7fc;
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
* {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
.card {
border: none;
border-radius: 0.75rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
body {
-webkit-font-smoothing: antialiased;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.07);
.btn-primary {
transition: all 0.2s ease;
}
.metric-card .card-body {
display: flex;
align-items: center;
.btn-primary:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.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;
.product-screenshot {
border: 1px solid #e5e7eb;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.08);
}
</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-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>
<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']); ?>
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
<?php if (hasPermission('manage_roles')): ?>
<li><a class="dropdown-item" href="roles.php">Manage Roles</a></li>
<li><hr class="dropdown-divider"></li>
<?php endif; ?>
<li><a class="dropdown-item" href="logout.php">Logout</a></li>
</ul>
<body class="bg-white">
<!-- Navigation -->
<nav class="border-b border-gray-200 bg-white sticky top-0 z-50">
<div class="max-w-6xl mx-auto px-6 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<img src="assets/pasted-20251120-051320-b2b0cdfa.png" alt="FinMox Logo" class="h-8 w-auto">
<span class="text-xl font-semibold text-gray-900">FinMox</span>
</div>
<div class="flex items-center gap-8">
<a href="#product" class="text-sm text-gray-600 hover:text-gray-900">Product</a>
<a href="#pricing" class="text-sm text-gray-600 hover:text-gray-900">Pricing</a>
<a href="/login.php" class="text-sm text-gray-600 hover:text-gray-900">Log in</a>
<a href="/register.php" class="btn-primary bg-black text-white px-4 py-2 rounded-lg text-sm font-medium">Register</a>
</div>
</div>
</nav>
</div>
</nav>
<!-- Hero Section -->
<header class="bg-white">
<div class="max-w-6xl mx-auto px-6 pt-24 pb-16">
<div class="text-center">
<h1 class="text-4xl md:text-6xl font-bold text-gray-900 leading-tight">Intelligent HR & Operations</h1>
<p class="mt-4 text-lg text-gray-600 max-w-2xl mx-auto">FinMox is an intelligent enterprise system that automates HR, compliance, and operations.</p>
<div class="mt-8 flex justify-center gap-4">
<a href="/register.php" class="btn-primary bg-black text-white px-6 py-3 rounded-lg font-medium">Get Started</a>
<a href="#product" class="bg-gray-100 text-gray-800 px-6 py-3 rounded-lg font-medium">Learn More</a>
</div>
</div>
</div>
</header>
<main class="main-content">
<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>
<!-- Product Section -->
<section id="product" class="bg-gray-50 py-20">
<div class="max-w-6xl mx-auto px-6">
<div class="text-center mb-12">
<h2 class="text-3xl md:text-4xl font-bold text-gray-900">A unified platform for growth</h2>
<p class="mt-3 text-lg text-gray-600">Manage candidates, tasks, and onboarding in one place.</p>
</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 class="product-screenshot">
<img src="assets/vm-shot-2025-11-11T05-29-19-670Z.jpg" alt="FinMox Dashboard Screenshot">
</div>
</div>
</section>
<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>
<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; ?>
<?php endif; ?>
</div>
<!-- Pricing Section -->
<section id="pricing" class="bg-white py-20">
<div class="max-w-6xl mx-auto px-6">
<div class="text-center mb-12">
<h2 class="text-3xl md:text-4xl font-bold text-gray-900">Pricing Plans</h2>
<p class="mt-3 text-lg text-gray-600">Choose the plan that's right for your team.</p>
</div>
<div class="grid md:grid-cols-3 gap-8">
<!-- Pricing Plan 1 -->
<div class="border border-gray-200 rounded-lg p-8">
<h3 class="text-xl font-semibold text-gray-900">Starter</h3>
<p class="mt-2 text-gray-600">For small teams just getting started.</p>
<div class="mt-6">
<span class="text-4xl font-bold">$49</span>
<span class="text-gray-600">/ month</span>
</div>
<a href="/register.php" class="mt-8 block w-full text-center btn-primary bg-black text-white px-6 py-3 rounded-lg font-medium">Get Started</a>
</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>
<!-- Pricing Plan 2 -->
<div class="border border-gray-200 rounded-lg p-8">
<h3 class="text-xl font-semibold text-gray-900">Business</h3>
<p class="mt-2 text-gray-600">For growing businesses that need more power.</p>
<div class="mt-6">
<span class="text-4xl font-bold">$99</span>
<span class="text-gray-600">/ month</span>
</div>
<a href="/register.php" class="mt-8 block w-full text-center btn-primary bg-black text-white px-6 py-3 rounded-lg font-medium">Get Started</a>
</div>
<!-- Pricing Plan 3 -->
<div class="border border-gray-200 rounded-lg p-8">
<h3 class="text-xl font-semibold text-gray-900">Enterprise</h3>
<p class="mt-2 text-gray-600">For large organizations with custom needs.</p>
<div class="mt-6">
<span class="text-4xl font-bold">Contact Us</span>
</div>
<a href="#" class="mt-8 block w-full text-center bg-gray-100 text-gray-800 px-6 py-3 rounded-lg font-medium">Contact Sales</a>
</div>
</div>
</div>
</main>
</section>
<!-- 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="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>
<!-- Footer -->
<footer class="bg-gray-50">
<div class="max-w-6xl mx-auto px-6 py-12">
<div class="flex justify-between items-center">
<p class="text-gray-600">&copy; 2025 FinMox. All rights reserved.</p>
<div class="flex gap-6">
<a href="#" class="text-sm text-gray-600 hover:text-gray-900">Terms</a>
<a href="#" class="text-sm text-gray-600 hover:text-gray-900">Privacy</a>
</div>
</div>
</div>
</div>
</footer>
<!-- 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>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
</html>

View File

@ -2,7 +2,7 @@
require_once 'auth.php';
if (is_logged_in()) {
header('Location: index.php');
header('Location: app.php');
exit;
}
@ -16,7 +16,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$error = 'Please fill in all fields.';
} else {
if (login_user($username, $password)) {
header('Location: index.php');
header('Location: app.php');
exit;
} else {
$error = 'Invalid username or password.';

View File

@ -9,7 +9,7 @@ if (!is_logged_in()) {
if (!hasPermission('manage_roles')) {
// Redirect to a generic "access denied" page or the home page
header('Location: index.php');
header('Location: app.php');
exit;
}
@ -48,9 +48,13 @@ $roles = $stmt->fetchAll();
</head>
<body>
<header class="header d-flex justify-content-between align-items-center">
<div class="logo">FinMox<span class="dot">.</span></div>
<div class="logo">
<a href="app.php">
<img src="assets/pasted-20251120-051320-b2b0cdfa.png" alt="FinMox Logo" style="height: 32px;">
</a>
</div>
<nav class="d-flex align-items-center">
<a href="index.php" class="btn btn-outline-primary me-2">Home</a>
<a href="app.php" class="btn btn-outline-primary me-2">Home</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>
<div class="dropdown">

View File

@ -8,7 +8,7 @@ if (!is_logged_in()) {
}
if (!hasPermission('view_workflows')) {
header('Location: index.php');
header('Location: app.php');
exit;
}
@ -119,11 +119,13 @@ $workflows = $stmt->fetchAll();
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16">
<div class="flex items-center">
<a href="index.php" class="text-2xl font-bold">FinMox<span class="text-blue-500">.</span></a>
<a href="app.php">
<img src="assets/pasted-20251120-051320-b2b0cdfa.png" alt="FinMox Logo" style="height: 32px;">
</a>
</div>
<div class="hidden md:block">
<div class="ml-10 flex items-baseline space-x-4">
<a href="index.php" class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Home</a>
<a href="app.php" class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Home</a>
<a href="dashboard.php" class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Dashboard</a>
<a href="workflows.php" class="bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Workflows</a>
@ -160,7 +162,7 @@ $workflows = $stmt->fetchAll();
<!-- Mobile menu, show/hide based on menu state. -->
<div class="md:hidden hidden" id="mobile-menu">
<div class="px-2 pt-2 pb-3 space-y-1 sm:px-3">
<a href="index.php" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Home</a>
<a href="app.php" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Home</a>
<a href="dashboard.php" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Dashboard</a>
<a href="workflows.php" class="bg-gray-900 text-white block px-3 py-2 rounded-md text-base font-medium" aria-current="page">Workflows</a>
</div>