Compare commits

...

12 Commits

Author SHA1 Message Date
Flatlogic Bot
c42fdade52 Auto commit: 2025-09-17T15:46:15.288Z 2025-09-17 15:46:15 +00:00
Flatlogic Bot
0ad162d6ac Auto commit: 2025-09-17T15:26:17.516Z 2025-09-17 15:26:17 +00:00
Flatlogic Bot
34e0e19b90 Auto commit: 2025-09-17T13:46:48.892Z 2025-09-17 13:46:48 +00:00
Flatlogic Bot
45c8b07916 Auto commit: 2025-09-17T13:42:40.993Z 2025-09-17 13:42:40 +00:00
Flatlogic Bot
f1eee42c9d Auto commit: 2025-09-17T13:37:17.849Z 2025-09-17 13:37:17 +00:00
Flatlogic Bot
8a6343f8da Auto commit: 2025-09-17T13:33:19.941Z 2025-09-17 13:33:19 +00:00
Flatlogic Bot
5fa7c3442b Auto commit: 2025-09-17T13:30:15.962Z 2025-09-17 13:30:15 +00:00
Flatlogic Bot
08116d4507 Auto commit: 2025-09-17T13:27:14.550Z 2025-09-17 13:27:14 +00:00
Flatlogic Bot
56f007f2d4 Auto commit: 2025-09-17T13:25:58.228Z 2025-09-17 13:25:58 +00:00
Flatlogic Bot
60d1724dfc Auto commit: 2025-09-17T13:11:08.932Z 2025-09-17 13:11:08 +00:00
Flatlogic Bot
0389138555 Auto commit: 2025-09-17T13:02:28.922Z 2025-09-17 13:02:28 +00:00
Flatlogic Bot
98fc2669af Auto commit: 2025-09-17T12:59:18.702Z 2025-09-17 12:59:18 +00:00
18 changed files with 1760 additions and 123 deletions

121
admin/add-job.php Normal file
View File

@ -0,0 +1,121 @@
<?php
session_start();
if (!isset($_SESSION['user'])) {
header('Location: login.php');
exit;
}
require_once __DIR__ . '/../db/config.php';
$error_message = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title = trim($_POST['title'] ?? '');
$department = trim($_POST['department'] ?? '');
$location = trim($_POST['location'] ?? '');
$type = trim($_POST['type'] ?? '');
$description = trim($_POST['description'] ?? '');
$requirements = trim($_POST['requirements'] ?? '');
$benefits = trim($_POST['benefits'] ?? '');
if (empty($title) || empty($department) || empty($location) || empty($type) || empty($description)) {
$error_message = 'Please fill in all fields.';
} else {
$requirements_arr = array_filter(array_map('trim', explode("\n", $requirements)));
$benefits_arr = array_filter(array_map('trim', explode("\n", $benefits)));
try {
$pdo = db();
$stmt = $pdo->prepare("INSERT INTO jobs (title, department, location, type, description, requirements, benefits) VALUES (?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$title, $department, $location, $type, $description, json_encode($requirements_arr), json_encode($benefits_arr)]);
header('Location: jobs.php');
exit;
} catch (PDOException $e) {
$error_message = 'Database error: ' . $e->getMessage();
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin - Add Job</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>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="index.php">CosmicHire Admin</a>
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="applications.php">Applications</a>
</li>
<li class="nav-item">
<a class="nav-link" href="jobs.php">Jobs</a>
</li>
</ul>
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
</ul>
</div>
</nav>
<main class="container my-5">
<h1 class="h2 mb-4">Add New Job</h1>
<?php if ($error_message): ?>
<div class="alert alert-danger"><?php echo $error_message; ?></div>
<?php endif; ?>
<form method="post">
<div class="card p-4">
<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="row">
<div class="col-md-6 mb-3">
<label for="department" class="form-label">Department</label>
<input type="text" class="form-control" id="department" name="department" required>
</div>
<div class="col-md-6 mb-3">
<label for="location" class="form-label">Location</label>
<input type="text" class="form-control" id="location" name="location" required>
</div>
</div>
<div class="mb-3">
<label for="type" class="form-label">Type</label>
<select class="form-select" id="type" name="type" required>
<option value="Full-time">Full-time</option>
<option value="Part-time">Part-time</option>
<option value="Contract">Contract</option>
<option value="Internship">Internship</option>
</select>
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<textarea class="form-control" id="description" name="description" rows="5" required></textarea>
</div>
<div class="mb-3">
<label for="requirements" class="form-label">Requirements</label>
<textarea class="form-control" id="requirements" name="requirements" rows="5"></textarea>
<div class="form-text">Enter one requirement per line.</div>
</div>
<div class="mb-3">
<label for="benefits" class="form-label">Benefits</label>
<textarea class="form-control" id="benefits" name="benefits" rows="5"></textarea>
<div class="form-text">Enter one benefit per line.</div>
</div>
<div class="d-flex justify-content-end">
<a href="jobs.php" class="btn btn-secondary me-2">Cancel</a>
<button type="submit" class="btn btn-primary">Add Job</button>
</div>
</div>
</form>
</main>
</body>
</html>

125
admin/applications.php Normal file
View File

@ -0,0 +1,125 @@
<?php
session_start();
if (!isset($_SESSION['user'])) {
header('Location: login.php');
exit;
}
require_once __DIR__ . '/../db/config.php';
// Fetch job titles from the database
$pdo = db();
$stmt = $pdo->query("SELECT id, title FROM jobs");
$jobs_data = $stmt->fetchAll();
$job_titles = array_column($jobs_data, 'title', 'id');
// Fetch job titles from the database
$pdo = db();
$stmt = $pdo->query("SELECT id, title FROM jobs");
$jobs_data = $stmt->fetchAll();
$job_titles = array_column($jobs_data, 'title', 'id');
// Pagination settings
$results_per_page = 10;
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$page = max(1, $page);
$offset = ($page - 1) * $results_per_page;
// Get total number of applications
$total_results = $pdo->query("SELECT COUNT(*) FROM applications")->fetchColumn();
$total_pages = ceil($total_results / $results_per_page);
// Fetch applications for the current page
$stmt = $pdo->prepare("SELECT id, job_id, name, email, resume_path, applied_at FROM applications ORDER BY applied_at DESC LIMIT :limit OFFSET :offset");
$stmt->bindValue(':limit', $results_per_page, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$applications = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin - Applications</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>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="index.php">CosmicHire Admin</a>
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" href="applications.php">Applications</a>
</li>
<li class="nav-item">
<a class="nav-link" href="jobs.php">Jobs</a>
</li>
</ul>
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
</ul>
</div>
</nav>
<main class="container my-5">
<h1 class="h2 mb-4">Submitted Applications</h1>
<div class="card">
<div class="table-responsive">
<table class="table table-striped table-hover mb-0">
<thead>
<tr>
<th>Job Title</th>
<th>Name</th>
<th>Email</th>
<th>Applied At</th>
<th>Resume</th>
</tr>
</thead>
<tbody>
<?php if (empty($applications)): ?>
<tr>
<td colspan="5" class="text-center">No applications found.</td>
</tr>
<?php else: ?>
<?php foreach ($applications as $app): ?>
<tr>
<td><?php echo htmlspecialchars($job_titles[$app['job_id']] ?? 'Unknown Job'); ?></td>
<td><?php echo htmlspecialchars($app['name']); ?></td>
<td><?php echo htmlspecialchars($app['email']); ?></td>
<td><?php echo date('M d, Y h:i A', strtotime($app['applied_at'])); ?></td>
<td><a href="download.php?id=<?php echo $app['id']; ?>" class="btn btn-sm btn-outline-primary">Download</a></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<?php if ($total_pages > 1): ?>
<div class="card-footer d-flex justify-content-center">
<nav aria-label="Page navigation">
<ul class="pagination mb-0">
<li class="page-item <?php if ($page <= 1) echo 'disabled'; ?>">
<a class="page-link" href="?page=<?php echo $page - 1; ?>">Previous</a>
</li>
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
<li class="page-item <?php if ($page == $i) echo 'active'; ?>">
<a class="page-link" href="?page=<?php echo $i; ?>"><?php echo $i; ?></a>
</li>
<?php endfor; ?>
<li class="page-item <?php if ($page >= $total_pages) echo 'disabled'; ?>">
<a class="page-link" href="?page=<?php echo $page + 1; ?>">Next</a>
</li>
</ul>
</nav>
</div>
<?php endif; ?>
</div>
</main>
</body>
</html>

23
admin/delete-job.php Normal file
View File

@ -0,0 +1,23 @@
<?php
session_start();
if (!isset($_SESSION['user'])) {
header('Location: login.php');
exit;
}
require_once __DIR__ . '/../db/config.php';
$job_id = $_GET['id'] ?? null;
if ($job_id) {
try {
$pdo = db();
$stmt = $pdo->prepare("DELETE FROM jobs WHERE id = ?");
$stmt->execute([$job_id]);
} catch (PDOException $e) {
// Optional: log the error
}
}
header('Location: jobs.php');
exit;

43
admin/download.php Normal file
View File

@ -0,0 +1,43 @@
<?php
session_start();
if (!isset($_SESSION['user'])) {
http_response_code(403);
die('Forbidden');
}
require_once __DIR__ . '/../db/config.php';
$app_id = $_GET['id'] ?? null;
if (!$app_id) {
http_response_code(400);
die('Bad Request');
}
$pdo = db();
$stmt = $pdo->prepare("SELECT resume_path FROM applications WHERE id = ?");
$stmt->execute([$app_id]);
$application = $stmt->fetch();
if (!$application) {
http_response_code(404);
die('Application not found.');
}
$resume_path = $application['resume_path'];
if (!file_exists($resume_path)) {
http_response_code(404);
die('Resume file not found.');
}
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($resume_path) . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($resume_path));
readfile($resume_path);
exit;

144
admin/edit-job.php Normal file
View File

@ -0,0 +1,144 @@
<?php
session_start();
if (!isset($_SESSION['user'])) {
header('Location: login.php');
exit;
}
require_once __DIR__ . '/../db/config.php';
$job_id = $_GET['id'] ?? null;
if (!$job_id) {
header('Location: jobs.php');
exit;
}
$pdo = db();
$error_message = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title = trim($_POST['title'] ?? '');
$department = trim($_POST['department'] ?? '');
$location = trim($_POST['location'] ?? '');
$type = trim($_POST['type'] ?? '');
$description = trim($_POST['description'] ?? '');
$requirements = trim($_POST['requirements'] ?? '');
$benefits = trim($_POST['benefits'] ?? '');
if (empty($title) || empty($department) || empty($location) || empty($type) || empty($description)) {
$error_message = 'Please fill in all fields.';
} else {
$requirements_arr = array_filter(array_map('trim', explode("\n", $requirements)));
$benefits_arr = array_filter(array_map('trim', explode("\n", $benefits)));
try {
$stmt = $pdo->prepare("UPDATE jobs SET title = ?, department = ?, location = ?, type = ?, description = ?, requirements = ?, benefits = ? WHERE id = ?");
$stmt->execute([$title, $department, $location, $type, $description, json_encode($requirements_arr), json_encode($benefits_arr), $job_id]);
header('Location: jobs.php');
exit;
} catch (PDOException $e) {
$error_message = 'Database error: ' . $e->getMessage();
}
}
} else {
$stmt = $pdo->prepare("SELECT * FROM jobs WHERE id = ?");
$stmt->execute([$job_id]);
$job = $stmt->fetch();
if (!$job) {
header('Location: jobs.php');
exit;
}
$title = $job['title'];
$department = $job['department'];
$location = $job['location'];
$type = $job['type'];
$description = $job['description'];
$requirements = implode("\n", json_decode($job['requirements'], true));
$benefits = implode("\n", json_decode($job['benefits'], true));
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin - Edit Job</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>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="index.php">CosmicHire Admin</a>
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="applications.php">Applications</a>
</li>
<li class="nav-item">
<a class="nav-link" href="jobs.php">Jobs</a>
</li>
</ul>
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
</ul>
</div>
</nav>
<main class="container my-5">
<h1 class="h2 mb-4">Edit Job</h1>
<?php if ($error_message): ?>
<div class="alert alert-danger"><?php echo $error_message; ?></div>
<?php endif; ?>
<form method="post">
<div class="card p-4">
<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input type="text" class="form-control" id="title" name="title" value="<?php echo htmlspecialchars($title); ?>" required>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="department" class="form-label">Department</label>
<input type="text" class="form-control" id="department" name="department" value="<?php echo htmlspecialchars($department); ?>" required>
</div>
<div class="col-md-6 mb-3">
<label for="location" class="form-label">Location</label>
<input type="text" class="form-control" id="location" name="location" value="<?php echo htmlspecialchars($location); ?>" required>
</div>
</div>
<div class="mb-3">
<label for="type" class="form-label">Type</label>
<select class="form-select" id="type" name="type" required>
<option value="Full-time" <?php if ($type === 'Full-time') echo 'selected'; ?>>Full-time</option>
<option value="Part-time" <?php if ($type === 'Part-time') echo 'selected'; ?>>Part-time</option>
<option value="Contract" <?php if ($type === 'Contract') echo 'selected'; ?>>Contract</option>
<option value="Internship" <?php if ($type === 'Internship') echo 'selected'; ?>>Internship</option>
</select>
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<textarea class="form-control" id="description" name="description" rows="5" required><?php echo htmlspecialchars($description); ?></textarea>
</div>
<div class="mb-3">
<label for="requirements" class="form-label">Requirements</label>
<textarea class="form-control" id="requirements" name="requirements" rows="5"><?php echo htmlspecialchars($requirements); ?></textarea>
<div class="form-text">Enter one requirement per line.</div>
</div>
<div class="mb-3">
<label for="benefits" class="form-label">Benefits</label>
<textarea class="form-control" id="benefits" name="benefits" rows="5"><?php echo htmlspecialchars($benefits); ?></textarea>
<div class="form-text">Enter one benefit per line.</div>
</div>
<div class="d-flex justify-content-end">
<a href="jobs.php" class="btn btn-secondary me-2">Cancel</a>
<button type="submit" class="btn btn-primary">Save Changes</button>
</div>
</div>
</form>
</main>
</body>
</html>

105
admin/index.php Normal file
View File

@ -0,0 +1,105 @@
<?php
session_start();
if (!isset($_SESSION['user'])) {
header('Location: login.php');
exit;
}
require_once __DIR__ . '/../db/config.php';
$pdo = db();
// Get stats
$total_jobs = $pdo->query("SELECT COUNT(*) FROM jobs")->fetchColumn();
$total_applications = $pdo->query("SELECT COUNT(*) FROM applications")->fetchColumn();
// Get recent applications
$stmt = $pdo->query("SELECT a.id, a.name, a.email, j.title AS job_title FROM applications a JOIN jobs j ON a.job_id = j.id ORDER BY a.applied_at DESC LIMIT 5");
$recent_applications = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin - 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>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="index.php">CosmicHire Admin</a>
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="applications.php">Applications</a>
</li>
<li class="nav-item">
<a class="nav-link" href="jobs.php">Jobs</a>
</li>
</ul>
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
</ul>
</div>
</nav>
<main class="container my-5">
<h1 class="h2 mb-4">Dashboard</h1>
<div class="row">
<div class="col-md-6">
<div class="card text-center mb-4">
<div class="card-body">
<h5 class="card-title">Total Jobs</h5>
<p class="card-text display-4"><?php echo $total_jobs; ?></p>
<a href="jobs.php" class="btn btn-primary">Manage Jobs</a>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card text-center mb-4">
<div class="card-body">
<h5 class="card-title">Total Applications</h5>
<p class="card-text display-4"><?php echo $total_applications; ?></p>
<a href="applications.php" class="btn btn-primary">Manage Applications</a>
</div>
</div>
</div>
</div>
<h2 class="h3 mb-4">Recent Applications</h2>
<div class="card">
<div class="table-responsive">
<table class="table table-striped table-hover mb-0">
<thead>
<tr>
<th>Job Title</th>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<?php if (empty($recent_applications)): ?>
<tr>
<td colspan="3" class="text-center">No recent applications.</td>
</tr>
<?php else: ?>
<?php foreach ($recent_applications as $app): ?>
<tr>
<td><?php echo htmlspecialchars($app['job_title']); ?></td>
<td><?php echo htmlspecialchars($app['name']); ?></td>
<td><?php echo htmlspecialchars($app['email']); ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</main>
</body>
</html>

121
admin/jobs.php Normal file
View File

@ -0,0 +1,121 @@
<?php
session_start();
if (!isset($_SESSION['user'])) {
header('Location: login.php');
exit;
}
require_once __DIR__ . '/../db/config.php';
$pdo = db();
// Pagination settings
$results_per_page = 10;
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$page = max(1, $page);
$offset = ($page - 1) * $results_per_page;
// Get total number of jobs
$total_results = $pdo->query("SELECT COUNT(*) FROM jobs")->fetchColumn();
$total_pages = ceil($total_results / $results_per_page);
// Fetch jobs for the current page
$stmt = $pdo->prepare("SELECT * FROM jobs ORDER BY created_at DESC LIMIT :limit OFFSET :offset");
$stmt->bindValue(':limit', $results_per_page, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$jobs = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin - Jobs</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>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="index.php">CosmicHire Admin</a>
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="applications.php">Applications</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="jobs.php">Jobs</a>
</li>
</ul>
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
</ul>
</div>
</nav>
<main class="container my-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h2">Manage Jobs</h1>
<a href="add-job.php" class="btn btn-primary">Add New Job</a>
</div>
<div class="card">
<div class="table-responsive">
<table class="table table-striped table-hover mb-0">
<thead>
<tr>
<th>Title</th>
<th>Department</th>
<th>Location</th>
<th>Type</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($jobs)): ?>
<tr>
<td colspan="5" class="text-center">No jobs found.</td>
</tr>
<?php else: ?>
<?php foreach ($jobs as $job): ?>
<tr>
<td><?php echo htmlspecialchars($job['title']); ?></td>
<td><?php echo htmlspecialchars($job['department']); ?></td>
<td><?php echo htmlspecialchars($job['location']); ?></td>
<td><?php echo htmlspecialchars($job['type']); ?></td>
<td>
<a href="edit-job.php?id=<?php echo $job['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
<a href="delete-job.php?id=<?php echo $job['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this job?')">Delete</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<?php if ($total_pages > 1): ?>
<div class="card-footer d-flex justify-content-center">
<nav aria-label="Page navigation">
<ul class="pagination mb-0">
<li class="page-item <?php if ($page <= 1) echo 'disabled'; ?>">
<a class="page-link" href="?page=<?php echo $page - 1; ?>">Previous</a>
</li>
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
<li class="page-item <?php if ($page == $i) echo 'active'; ?>">
<a class="page-link" href="?page=<?php echo $i; ?>"><?php echo $i; ?></a>
</li>
<?php endfor; ?>
<li class="page-item <?php if ($page >= $total_pages) echo 'disabled'; ?>">
<a class="page-link" href="?page=<?php echo $page + 1; ?>">Next</a>
</li>
</ul>
</nav>
</div>
<?php endif; ?>
</div>
</main>
</body>
</html>

74
admin/login.php Normal file
View File

@ -0,0 +1,74 @@
<?php
session_start();
require_once __DIR__ . '/../db/config.php';
$error_message = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
if (empty($username) || empty($password)) {
$error_message = 'Please enter both username and password.';
} else {
try {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
$_SESSION['user'] = $user['username'];
header('Location: index.php');
exit;
} else {
$error_message = 'Invalid username or password.';
}
} catch (PDOException $e) {
$error_message = 'Database error. Please try again later.';
// Optional: Log the detailed error: error_log($e->getMessage());
}
}
}
if (isset($_SESSION['user'])) {
header('Location: index.php');
exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Login - CosmicHire</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>
<body>
<main class="container my-5">
<div class="row justify-content-center">
<div class="col-lg-5">
<div class="card p-4">
<h1 class="h3 mb-3 text-center">Admin Login</h1>
<?php if ($error_message): ?>
<div class="alert alert-danger"><?php echo $error_message; ?></div>
<?php endif; ?>
<form method="post">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary w-100">Login</button>
</form>
</div>
</div>
</div>
</main>
</body>
</html>

6
admin/logout.php Normal file
View File

@ -0,0 +1,6 @@
<?php
session_start();
session_unset();
session_destroy();
header('Location: login.php');
exit;

178
apply.php Normal file
View File

@ -0,0 +1,178 @@
<?php
// Disable caching
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Expires: 0");
require_once __DIR__ . '/mail/MailService.php';
require_once __DIR__ . '/db/config.php';
$job_id = $_GET['id'] ?? null;
$job = null;
if ($job_id) {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM jobs WHERE id = ?");
$stmt->execute([$job_id]);
$job = $stmt->fetch();
}
// Redirect if job not found
if (!$job) {
header("Location: careers.php");
exit;
}
$success_message = '';
$error_message = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
$resume = $_FILES['resume'] ?? null;
if (empty($name) || empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL) || empty($resume) || $resume['error'] !== UPLOAD_ERR_OK) {
$error_message = 'Please fill in all fields and upload a valid resume.';
} else {
// Handle file upload
$upload_dir = __DIR__ . '/uploads/resumes/';
$file_extension = pathinfo($resume['name'], PATHINFO_EXTENSION);
$safe_filename = uniqid('resume_', true) . '.' . $file_extension;
$upload_path = $upload_dir . $safe_filename;
if (move_uploaded_file($resume['tmp_name'], $upload_path)) {
try {
// Save application to database
$pdo = db();
$stmt = $pdo->prepare("INSERT INTO applications (job_id, name, email, resume_path) VALUES (?, ?, ?, ?)");
$stmt->execute([$job_id, $name, $email, $upload_path]);
// Send email notification
$to = getenv('MAIL_TO') ?: 'your-email@example.com'; // Fallback email
$subject = "New Application for " . $job['title'];
$html_content = "<p>A new application has been submitted for the position of <strong>" . htmlspecialchars($job['title']) . "</strong>.</p>"
. "<p><strong>Applicant Name:</strong> " . htmlspecialchars($name) . "</p>"
. "<p><strong>Applicant Email:</strong> " . htmlspecialchars($email) . "</p>"
. "<p>The resume has been saved to the server.</p>";
$text_content = "New Application for " . $job['title'] . "\n"
. "Applicant Name: " . $name . "\n"
. "Applicant Email: " . $email;
$result = MailService::sendMail($to, $subject, $html_content, $text_content);
if (!empty($result['success'])) {
// Send confirmation email to applicant
$applicant_subject = "Your Application for " . $job['title'];
$applicant_html_content = "<p>Dear " . htmlspecialchars($name) . ",</p>"
. "<p>Thank you for applying for the position of <strong>" . htmlspecialchars($job['title']) . "</strong> at CosmicHire.</p>"
. "<p>We have received your application and will be in touch shortly if your qualifications match our requirements.</p>"
. "<p>Best regards,<br>The CosmicHire Team</p>";
$applicant_text_content = "Dear " . $name . ",\n\nThank you for applying for the position of " . $job['title'] . " at CosmicHire.\n\nWe have received your application and will be in touch shortly if your qualifications match our requirements.\n\nBest regards,\nThe CosmicHire Team";
MailService::sendMail($email, $applicant_subject, $applicant_html_content, $applicant_text_content);
$success_message = 'Your application has been submitted successfully! A confirmation email has been sent to you.';
} else {
$error_message = 'Your application was saved, but there was an error sending the notification email.';
// Optional: Log the detailed error: error_log($result['error']);
}
} catch (PDOException $e) {
$error_message = 'There was a database error. Please try again later.';
// Optional: Log the detailed error: error_log($e->getMessage());
}
} else {
$error_message = 'There was an error uploading your resume. Please try again.';
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Apply for <?php echo htmlspecialchars($job['title']); ?> - CosmicHire</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
<meta name="robots" content="noindex, nofollow">
</head>
<body>
<!-- Header -->
<nav class="navbar navbar-expand-lg navbar-light">
<div class="container">
<a class="navbar-brand" href="index.php">CosmicHire</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="index.php">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="careers.php">Open Positions</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Application Form -->
<main class="container my-5">
<div class="row justify-content-center">
<div class="col-lg-8">
<h1 class="mb-4">Apply for <?php echo htmlspecialchars($job['title']); ?></h1>
<?php if ($success_message): ?>
<div class="alert alert-success">
<?php echo $success_message; ?>
</div>
<?php endif; ?>
<?php if ($error_message): ?>
<div class="alert alert-danger">
<?php echo $error_message; ?>
</div>
<?php endif; ?>
<?php if (!$success_message): ?>
<form action="apply.php?id=<?php echo htmlspecialchars($job['id']); ?>" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label for="name" class="form-label">Full 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 Address</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="resume" class="form-label">Resume (PDF, DOC, DOCX)</label>
<input type="file" class="form-control" id="resume" name="resume" accept=".pdf,.doc,.docx" required>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="consent" required>
<label class="form-check-label" for="consent">I consent to my data being processed for this application.</label>
</div>
<button type="submit" class="btn btn-primary">Submit Application</button>
<a href="job-details.php?id=<?php echo htmlspecialchars($job['id']); ?>" class="btn btn-secondary">Cancel</a>
</form>
<?php endif; ?>
</div>
</div>
</main>
<!-- Footer -->
<footer class="footer">
<div class="container">
<p>&copy; <?php echo date('Y'); ?> CosmicHire. All Rights Reserved.</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

175
assets/css/custom.css Normal file
View File

@ -0,0 +1,175 @@
/* General Body Styles */
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background-color: #F9F9F9;
color: #333333;
}
/* Navbar */
.navbar {
background-color: #FFFFFF;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.navbar-brand {
font-weight: 700;
color: #4A90E2 !important;
}
.navbar-brand img {
height: 30px;
}
/* Hero Section */
.hero-section {
background: #222 url('https://picsum.photos/seed/milkyway/1600/800') no-repeat center center;
background-size: cover;
color: white;
padding: 6rem 0;
text-align: center;
position: relative;
}
.hero-section::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.hero-section .container {
position: relative;
z-index: 2;
}
.hero-section h1 {
font-weight: 700;
font-size: 3.5rem;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
}
.hero-section p {
font-size: 1.25rem;
opacity: 0.9;
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.7);
}
/* Job Listings */
.job-listings {
padding: 4rem 0;
}
.job-card {
background-color: #FFFFFF;
border: 1px solid #EAEAEA;
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 1.5rem;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
}
.job-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 20px rgba(0,0,0,0.08);
}
.job-card h5 {
color: #4A90E2;
font-weight: 600;
}
.job-card .badge {
border-radius: 6px;
font-weight: 500;
padding: 0.4em 0.7em;
}
/* Buttons */
.btn-primary {
background-color: #4A90E2;
border-color: #4A90E2;
border-radius: 12px;
padding: 0.75rem 1.5rem;
font-weight: 600;
transition: background-color 0.3s ease;
}
.btn-primary:hover {
background-color: #357ABD;
border-color: #357ABD;
}
.btn-secondary {
background-color: #50E3C2;
border-color: #50E3C2;
color: #fff;
border-radius: 12px;
padding: 0.75rem 1.5rem;
font-weight: 600;
transition: background-color 0.2s;
}
.btn-secondary:hover {
background-color: #40B59A;
border-color: #40B59A;
}
/* Footer */
.footer {
background-color: #FFFFFF;
padding: 2rem 0;
margin-top: 4rem;
border-top: 1px solid #EAEAEA;
text-align: center;
font-size: 0.9rem;
color: #666;
}
/* Search Form Toggle */
#search-toggle-btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
#job-search-form {
transition: all 0.3s ease-in-out;
}
/* Job Details Page */
.job-header {
background: linear-gradient(135deg, #4A90E2 0%, #50E3C2 100%);
color: white;
padding: 4rem 0;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
}
.job-header h1 {
font-weight: 700;
}
.card {
border-radius: 12px;
border: none;
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}
.breadcrumb-item a {
color: #4A90E2;
text-decoration: none;
}
.list-group-item {
border: none;
padding-left: 0;
}
.list-group-item i {
color: #50E3C2;
margin-right: 10px;
}

128
assets/js/main.js Normal file
View File

@ -0,0 +1,128 @@
document.addEventListener('DOMContentLoaded', function () {
// 1. Gentle animations on scroll for job cards
const jobCards = document.querySelectorAll('.job-card');
if (jobCards.length > 0) {
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.animation = 'fadeInUp 0.5s ease-out forwards';
observer.unobserve(entry.target);
}
});
}, { threshold: 0.1 });
jobCards.forEach(card => {
card.style.opacity = '0'; // Start transparent
observer.observe(card);
});
// Add keyframes for the animation dynamically
const style = document.createElement('style');
style.innerHTML = `
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
`;
document.head.appendChild(style);
}
// 2. Toggle for the job search form
const searchToggleBtn = document.getElementById('search-toggle-btn');
const jobSearchForm = document.getElementById('job-search-form');
if (searchToggleBtn && jobSearchForm) {
searchToggleBtn.addEventListener('click', function () {
jobSearchForm.classList.toggle('d-none');
const isHidden = jobSearchForm.classList.contains('d-none');
if (isHidden) {
searchToggleBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
Search Job Listings`;
} else {
searchToggleBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
Close Search`;
}
});
}
// 3. Toggle for the new job search form
const toggleBtn = document.getElementById('toggle-search-form');
const searchForm = document.getElementById('job-search-form');
if (toggleBtn && searchForm) {
toggleBtn.addEventListener('click', function() {
if (searchForm.style.display === 'none') {
searchForm.style.display = 'block';
} else {
searchForm.style.display = 'none';
}
});
}
// 4. Handle search form submission
const searchFormElement = document.getElementById('job-search-form');
if (searchFormElement) {
searchFormElement.addEventListener('submit', function(event) {
event.preventDefault();
const titleQuery = this.querySelector('input[placeholder="Job title"]').value.toLowerCase().trim();
const locationQuery = this.querySelector('input[placeholder="Location"]').value.toLowerCase().trim();
const typeQuery = this.querySelector('select').value;
const allJobCards = document.querySelectorAll('.job-card');
const noResults = document.getElementById('no-results');
let matches = 0;
allJobCards.forEach(function(card) {
const title = card.querySelector('h5').textContent.toLowerCase();
const location = card.querySelector('p').textContent.toLowerCase();
const type = card.querySelector('.badge').textContent;
const titleMatch = title.includes(titleQuery);
const locationMatch = location.includes(locationQuery);
const typeMatch = (typeQuery === 'All') || (typeQuery.toLowerCase() === type.toLowerCase());
if (titleMatch && locationMatch && typeMatch) {
card.parentElement.style.display = '';
matches++;
} else {
card.parentElement.style.display = 'none';
}
});
if (matches === 0) {
noResults.style.display = 'block';
} else {
noResults.style.display = 'none';
}
});
}
// 5. Handle search reset
const resetBtn = document.getElementById('reset-search');
if (resetBtn) {
resetBtn.addEventListener('click', function() {
const searchFormElement = document.getElementById('job-search-form');
searchFormElement.querySelector('input[placeholder="Job title"]').value = '';
searchFormElement.querySelector('input[placeholder="Location"]').value = '';
searchFormElement.querySelector('select').selectedIndex = 0;
const allJobCards = document.querySelectorAll('.job-card');
allJobCards.forEach(function(card) {
card.parentElement.style.display = '';
});
const noResults = document.getElementById('no-results');
noResults.style.display = 'none';
});
}
});

145
careers.php Normal file
View File

@ -0,0 +1,145 @@
<?php
// Disable caching
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Expires: 0");
require_once __DIR__ . '/db/config.php';
$pdo = db();
$stmt = $pdo->query("SELECT * FROM jobs ORDER BY created_at DESC");
$jobs = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Careers - CosmicHire</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
<meta name="description" content="Find your next career opportunity with us. Browse open positions and apply today.">
<meta name="robots" content="index, follow">
</head>
<body>
<!-- Header -->
<nav class="navbar navbar-expand-lg navbar-light">
<div class="container">
<a class="navbar-brand" href="index.php">CosmicHire</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="index.php">Home</a>
</li>
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="careers.php">Open Positions</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Hero Section -->
<header class="hero-section">
<div class="container">
<h1>Find Your Next Opportunity</h1>
<p class="lead mb-4">Join our team and help us build the future of work.</p>
<div class="col-md-8 mx-auto">
<div class="d-grid">
<button class="btn btn-primary btn-lg" type="button" id="toggle-search-form">Search Jobs</button>
</div>
<form id="job-search-form" class="mt-4" style="display: none;">
<div class="row g-3">
<div class="col-md-5">
<input type="text" class="form-control" placeholder="Job title">
</div>
<div class="col-md-4">
<input type="text" class="form-control" placeholder="Location">
</div>
<div class="col-md-3">
<select class="form-select">
<option selected>All</option>
<option value="full-time">Full-time</option>
<option value="part-time">Part-time</option>
<option value="contract">Contract</option>
</select>
</div>
</div>
<div class="d-grid mt-3">
<button class="btn btn-secondary" type="submit">Find Jobs</button>
<button class="btn btn-outline-secondary mt-2" type="button" id="reset-search">Reset</button>
</div>
</form>
</div>
</div>
</header>
<!-- Job Listings -->
<main class="job-listings">
<div class="container">
<h2 class="text-center mb-5">Current Openings</h2>
<div class="row">
<?php foreach ($jobs as $job): ?>
<div class="col-md-6 col-lg-4">
<div class="job-card">
<h5><?php echo htmlspecialchars($job['title']); ?></h5>
<p class="mb-2 text-muted">
<?php echo htmlspecialchars($job['department']); ?> &middot; <?php echo htmlspecialchars($job['location']); ?>
</p>
<span class="badge bg-light text-dark border"><?php echo htmlspecialchars($job['type']); ?></span>
<a href="job-details.php?id=<?php echo $job['id']; ?>" class="btn btn-primary mt-3 stretched-link">View Details</a>
</div>
</div>
<?php endforeach; ?>
</div>
<div id="no-results" class="text-center" style="display: none;">
<p class="lead">No jobs found matching your criteria.</p>
</div>
</div>
</main>
<!-- Why Join Us & Benefits Sections -->
<section class="container my-5">
<div class="row align-items-center">
<div class="col-md-6">
<img src="https://picsum.photos/seed/smiling-team/800/600" class="img-fluid rounded" alt="A smiling and relaxed team in a casual work environment.">
</div>
<div class="col-md-6">
<h3>Why Join Us?</h3>
<p>We are a passionate team dedicated to creating a better work environment for everyone. We value collaboration, innovation, and a people-first culture. Join us to make a real impact.</p>
</div>
</div>
</section>
<section class="container my-5">
<div class="row align-items-center flex-row-reverse">
<div class="col-md-6">
<img src="https://picsum.photos/seed/stars/800/600" class="img-fluid rounded" alt="A beautiful image of a starry night sky, representing the vast opportunities at our company.">
</div>
<div class="col-md-6">
<h3>Our Benefits</h3>
<p>We offer competitive salaries, comprehensive health benefits, flexible work hours, and a generous vacation policy. We believe in investing in our employees' well-being and professional growth.</p>
</div>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="container">
<p>&copy; <?php echo date('Y'); ?> CosmicHire. All Rights Reserved.</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
</body>
</html>

View File

@ -0,0 +1,24 @@
<?php
require_once __DIR__ . '/../config.php';
function migrate_003_create_applications_table() {
try {
$pdo = db();
$sql = "
CREATE TABLE IF NOT EXISTS `applications` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`job_id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`resume_path` varchar(255) NOT NULL,
`applied_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
";
$pdo->exec($sql);
echo "Migration 003: Applications table created successfully.\n";
} catch (PDOException $e) {
die("Migration 003 failed: " . $e->getMessage() . "\n");
}
}

View File

@ -0,0 +1,27 @@
<?php
require_once __DIR__ . '/../config.php';
function migrate_004_create_jobs_table() {
try {
$pdo = db();
$sql = "
CREATE TABLE IF NOT EXISTS `jobs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`department` varchar(255) NOT NULL,
`location` varchar(255) NOT NULL,
`type` varchar(255) NOT NULL,
`description` text NOT NULL,
`requirements` json NOT NULL,
`benefits` json NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
";
$pdo->exec($sql);
echo "Migration 004: Jobs table created successfully.\n";
} catch (PDOException $e) {
die("Migration 004 failed: " . $e->getMessage() . "\n");
}
}

245
index.php
View File

@ -1,131 +1,144 @@
<?php
declare(strict_types=1);
@ini_set('display_errors', '1');
@error_reporting(E_ALL);
@date_default_timezone_set('UTC');
// Disable caching
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Expires: 0");
require_once __DIR__ . '/db/config.php';
$pdo = db();
$stmt = $pdo->query("SELECT * FROM jobs ORDER BY created_at DESC");
$jobs = $stmt->fetchAll();
$phpVersion = PHP_VERSION;
$now = date('Y-m-d H:i:s');
?>
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>New Style</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CosmicHire</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% { background-position: 0% 0%; }
100% { background-position: 100% 100%; }
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
}
.loader {
margin: 1.25rem auto 1.25rem;
width: 48px;
height: 48px;
border: 3px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.hint {
opacity: 0.9;
}
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; border: 0;
}
h1 {
font-size: 3rem;
font-weight: 700;
margin: 0 0 1rem;
letter-spacing: -1px;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
}
code {
background: rgba(0,0,0,0.2);
padding: 2px 6px;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
footer {
position: absolute;
bottom: 1rem;
font-size: 0.8rem;
opacity: 0.7;
}
</style>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
<meta name="description" content="Find your next career opportunity with us. Browse open positions and apply today.">
<meta name="robots" content="index, follow">
</head>
<body>
<main>
<div class="card">
<h1>Analyzing your requirements and generating your website…</h1>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<span class="sr-only">Loading…</span>
<!-- Header -->
<nav class="navbar navbar-expand-lg navbar-light">
<div class="container">
<a class="navbar-brand" href="index.php">CosmicHire</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="index.php">Home</a>
</li>
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="careers.php">Open Positions</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Hero Section -->
<header class="hero-section">
<div class="container">
<h1>Find Your Next Opportunity</h1>
<p class="lead mb-4">Join our team and help us build the future of work.</p>
<div class="col-md-8 mx-auto">
<div class="d-grid">
<button class="btn btn-primary btn-lg" type="button" id="toggle-search-form">Search Jobs</button>
</div>
<form id="job-search-form" class="mt-4" style="display: none;">
<div class="row g-3">
<div class="col-md-5">
<input type="text" class="form-control" placeholder="Job title">
</div>
<div class="col-md-4">
<input type="text" class="form-control" placeholder="Location">
</div>
<div class="col-md-3">
<select class="form-select">
<option selected>All</option>
<option value="full-time">Full-time</option>
<option value="part-time">Part-time</option>
</select>
</div>
</div>
<div class="d-grid mt-3">
<button class="btn btn-secondary" type="submit">Find Jobs</button>
<button class="btn btn-outline-secondary mt-2" type="button" id="reset-search">Reset</button>
</div>
</form>
</div>
</div>
</header>
<!-- Job Listings -->
<main class="job-listings">
<div class="container">
<h2 class="text-center mb-5">Current Openings</h2>
<div class="row">
<?php foreach ($jobs as $job): ?>
<div class="col-md-6 col-lg-4">
<div class="job-card">
<h5><?php echo htmlspecialchars($job['title']); ?></h5>
<p class="mb-2 text-muted">
<?php echo htmlspecialchars($job['department']); ?> &middot; <?php echo htmlspecialchars($job['location']); ?>
</p>
<span class="badge bg-light text-dark border"><?php echo htmlspecialchars($job['type']); ?></span>
<a href="job-details.php?id=<?php echo $job['id']; ?>" class="btn btn-primary mt-3 stretched-link">View Details</a>
</div>
</div>
<?php endforeach; ?>
</div>
<div id="no-results" class="text-center" style="display: none;">
<p class="lead">No jobs found matching your criteria.</p>
</div>
<p class="hint">Flatlogic AI is collecting your requirements and applying the first changes.</p>
<p class="hint">This page will update automatically as the plan is implemented.</p>
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
</div>
</main>
<footer>
Page updated: <?= htmlspecialchars($now) ?> (UTC)
<!-- Why Join Us & Benefits Sections -->
<section class="container my-5">
<div class="row align-items-center">
<div class="col-md-6">
<img src="https://picsum.photos/seed/smiling-team/800/600" class="img-fluid rounded" alt="A smiling and relaxed team in a casual work environment.">
</div>
<div class="col-md-6">
<h3>Why Join Us?</h3>
<p>We are a passionate team dedicated to creating a better work environment for everyone. We value collaboration, innovation, and a people-first culture. Join us to make a real impact.</p>
</div>
</div>
</section>
<section class="container my-5">
<div class="row align-items-center flex-row-reverse">
<div class="col-md-6">
<img src="https://picsum.photos/seed/stars/800/600" class="img-fluid rounded" alt="A beautiful image of a starry night sky, representing the vast opportunities at our company.">
</div>
<div class="col-md-6">
<h3>Our Benefits</h3>
<p>We offer competitive salaries, comprehensive health benefits, flexible work hours, and a generous vacation policy. We believe in investing in our employees' well-being and professional growth.</p>
</div>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="container">
<p>&copy; <?php echo date('Y'); ?> CosmicHire. All Rights Reserved.</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
</body>
</html>

185
job-details.php Normal file
View File

@ -0,0 +1,185 @@
<?php
// Disable caching
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Expires: 0");
require_once __DIR__ . '/db/config.php';
$job_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
$job = null;
if ($job_id > 0) {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM jobs WHERE id = ?");
$stmt->execute([$job_id]);
$job = $stmt->fetch();
}
if ($job) {
$job['requirements'] = json_decode($job['requirements'], true);
$job['benefits'] = json_decode($job['benefits'], true);
}
// SEO and page metadata
$page_title = $job ? htmlspecialchars($job['title']) . ' - CosmicHire' : 'Job Not Found';
$page_description = $job ? 'Apply for the ' . htmlspecialchars($job['title']) . ' position at CosmicHire. Location: ' . htmlspecialchars($job['location']) : 'The job you are looking for could not be found.';
$page_keywords = 'jobs, careers, hiring, ' . ($job ? htmlspecialchars($job['title']) : '');
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo $page_title; ?></title>
<meta name="description" content="<?php echo $page_description; ?>">
<meta name="keywords" content="<?php echo $page_keywords; ?>">
<link rel="icon" href="https://flatlogic.com/assets/favicon.ico">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://flatlogic.com/">
<meta property="og:title" content="<?php echo $page_title; ?>">
<meta property="og:description" content="<?php echo $page_description; ?>">
<meta property="og:image" content="https://flatlogic.com/assets/share.png">
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="https://flatlogic.com/">
<meta property="twitter:title" content="<?php echo $page_title; ?>">
<meta property="twitter:description" content="<?php echo $page_description; ?>">
<meta property="twitter:image" content="https://flatlogic.com/assets/share.png">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.css">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
<?php if ($job): ?>
<script type="application/ld+json">
{
"@context" : "https://schema.org/",
"@type" : "JobPosting",
"title" : "<?php echo htmlspecialchars($job['title']); ?>",
"description" : "<?php echo htmlspecialchars($job['description']); ?>",
"hiringOrganization" : {
"@type" : "Organization",
"name" : "CosmicHire",
"sameAs" : "https://flatlogic.com/",
"logo" : "https://flatlogic.com/assets/logo.svg"
},
"datePosted" : "<?php echo date('Y-m-d', strtotime($job['created_at'])); ?>",
"employmentType" : "<?php echo strtoupper(str_replace('-', '_', $job['type'])); ?>",
"jobLocation": {
"@type": "Place",
"address": {
"@type": "PostalAddress",
"addressLocality": "<?php echo htmlspecialchars($job['location']); ?>"
}
}
}
</script>
<?php endif; ?>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="index.php">
<img src="https://flatlogic.com/assets/logo.svg" alt="CosmicHire Logo">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="index.php">Home</a>
</li>
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="careers.php">Open Positions</a>
</li>
</ul>
</div>
</div>
</nav>
<?php if ($job): ?>
<header class="job-header text-center">
<div class="container">
<p class="mb-2"><span class="badge bg-light text-dark"><?php echo htmlspecialchars($job['department']); ?></span></p>
<h1><?php echo htmlspecialchars($job['title']); ?></h1>
<p class="lead">
<i data-feather="map-pin" class="me-1" style="width: 1em; height: 1em;"></i> <?php echo htmlspecialchars($job['location']); ?>
</p>
</div>
</header>
<main class="container mt-5">
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="index.php">Home</a></li>
<li class="breadcrumb-item"><a href="careers.php">Careers</a></li>
<li class="breadcrumb-item active" aria-current="page"><?php echo htmlspecialchars($job['title']); ?></li>
</ol>
</nav>
<div class="row">
<div class="col-lg-8">
<div class="card p-4 mb-4">
<h2 class="h4 mb-3">Job Description</h2>
<p><?php echo nl2br(htmlspecialchars($job['description'])); ?></p>
<h2 class="h4 mt-4 mb-3">Requirements</h2>
<ul class="list-group list-group-flush">
<?php foreach ($job['requirements'] as $requirement): ?>
<li class="list-group-item d-flex align-items-start">
<i data-feather="check-circle" class="me-2 mt-1" style="width: 1.2em; height: 1.2em;"></i>
<span><?php echo htmlspecialchars($requirement); ?></span>
</li>
<?php endforeach; ?>
</ul>
<h2 class="h4 mt-4 mb-3">Benefits</h2>
<ul class="list-group list-group-flush">
<?php foreach ($job['benefits'] as $benefit): ?>
<li class="list-group-item d-flex align-items-start">
<i data-feather="gift" class="me-2 mt-1" style="width: 1.2em; height: 1.2em;"></i>
<span><?php echo htmlspecialchars($benefit); ?></span>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
<div class="col-lg-4">
<div class="card p-4 sticky-top" style="top: 20px;">
<h3 class="h5 mb-3">Interested?</h3>
<p class="text-muted">Apply now to join our team and make an impact.</p>
<a href="apply.php?id=<?php echo $job['id']; ?>" class="btn btn-primary w-100">Apply Now</a>
</div>
</div>
</div>
</main>
<?php else: ?>
<main class="container mt-5 text-center">
<div class="card p-5">
<h1 class="display-4">Job Not Found</h1>
<p class="lead">Sorry, the job you are looking for does not exist or has been filled.</p>
<a href="careers.php" class="btn btn-primary mt-3">View All Open Positions</a>
</div>
</main>
<?php endif; ?>
<footer class="text-center text-muted">
<div class="container">
<p>&copy; <?php echo date('Y'); ?> CosmicHire. All rights reserved.</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
<script>
feather.replace();
</script>
</body>
</html>