fix job positions
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 48s
Tests / PHPUnit (push) Successful in 1m22s

This commit is contained in:
root
2026-09-03 13:01:36 -04:00
parent c70f6bdc6e
commit 9e2f858343
9 changed files with 75 additions and 5 deletions
+1
View File
@@ -224,6 +224,7 @@ $routes->get('/', 'View\UserController::home'); // Home page route
$routes->get('/about', 'View\UserController::about'); // About page route
$routes->get('/careers', 'View\JobPostingController::publicIndex'); // Careers page route
$routes->get('/careers/application-received', 'View\JobPostingController::applicationReceived');
$routes->get('/careers/(:segment)/details', 'View\JobPostingController::trackDetailsClick/$1');
$routes->get('/careers/(:segment)', 'View\JobPostingController::show/$1');
$routes->get('/careers/(:segment)/apply', 'View\JobPostingController::apply/$1');
$routes->post('/careers/(:segment)/apply', 'View\JobPostingController::submitApplication/$1');
@@ -47,6 +47,18 @@ class JobPostingController extends BaseController
return view('jobs/show', ['position' => $position]);
}
public function trackDetailsClick(string $positionId)
{
$position = $this->positions->where('position_id', $positionId)->where('status', 'open')->first();
if (!$position) {
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Position not found');
}
$this->positions->recordDetailsClick($positionId);
return redirect()->to(site_url('careers/' . rawurlencode($positionId)));
}
public function apply(string $positionId)
{
$position = $this->positions->where('position_id', $positionId)->where('status', 'open')->first();
@@ -63,6 +63,7 @@ class CreateJobPostings extends Migration
'status' => ['type' => 'VARCHAR', 'constraint' => 20, 'default' => 'draft'],
'posted_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
'posted_at' => ['type' => 'DATETIME', 'null' => true],
'details_click_count' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'default' => 0],
'created_at' => ['type' => 'DATETIME', 'null' => true],
'updated_at' => ['type' => 'DATETIME', 'null' => true],
]);
@@ -0,0 +1,32 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddDetailsClickCountToJobPositions extends Migration
{
public function up()
{
if (!$this->db->tableExists('job_positions') || $this->db->fieldExists('details_click_count', 'job_positions')) {
return;
}
$this->forge->addColumn('job_positions', [
'details_click_count' => [
'type' => 'INT',
'constraint' => 11,
'unsigned' => true,
'default' => 0,
'after' => 'posted_at',
],
]);
}
public function down()
{
if ($this->db->tableExists('job_positions') && $this->db->fieldExists('details_click_count', 'job_positions')) {
$this->forge->dropColumn('job_positions', 'details_click_count');
}
}
}
+10
View File
@@ -23,6 +23,7 @@ class JobPositionModel extends Model
'status',
'posted_by',
'posted_at',
'details_click_count',
'created_at',
'updated_at',
];
@@ -39,6 +40,15 @@ class JobPositionModel extends Model
->findAll();
}
public function recordDetailsClick(string $positionId): bool
{
return $this->builder()
->set('details_click_count', 'COALESCE(details_click_count, 0) + 1', false)
->where('position_id', $positionId)
->where('status', 'open')
->update();
}
public function adminPositions(): array
{
return $this
+14 -3
View File
@@ -226,7 +226,7 @@
border: 1px solid var(--line);
background: #ffffff;
height: 100%;
padding: 1.75rem;
padding: 1.75rem 1.75rem 3rem;
position: relative;
}
@@ -266,6 +266,16 @@
margin-bottom: 1rem;
}
.opening-clicks {
position: absolute;
right: 1.25rem;
bottom: 1rem;
color: var(--ink-soft);
font-size: 0.85rem;
font-weight: 600;
line-height: 1;
}
.opening-list {
padding-left: 1.1rem;
margin-bottom: 1.5rem;
@@ -347,7 +357,7 @@
<hr class="rule mx-auto">
<h2>Current Open Positions</h2>
<p class="mb-0">Review the available roles below and apply by creating an account.</p>
<p class="mb-0 fw-bold">All positions bellow are taking place at ISGL: 5 Courthouse Lane, Chelmsford, MA 01824</p>
<p class="mb-0 fw-bold">All positions are non-paid and take place at ISGL: 5 Courthouse Lane, Chelmsford, MA 01824</p>
</div>
<div class="row g-4">
<?php if (!empty($positions)): ?>
@@ -378,7 +388,8 @@
?>
<p class="mb-4"><?= esc($descriptionPreview) ?></p>
<?php endif; ?>
<a class="btn-brand-sm" href="<?= site_url('careers/' . $position['position_id']) ?>">View Details <i class="fa fa-arrow-right"></i></a>
<a class="btn-brand-sm" href="<?= site_url('careers/' . $position['position_id'] . '/details') ?>">View Details <i class="fa fa-arrow-right"></i></a>
<div class="opening-clicks"><?= esc(number_format((int) ($position['details_click_count'] ?? 0))) ?> views</div>
</article>
</div>
<?php endforeach; ?>
+2 -1
View File
@@ -13,7 +13,7 @@
<?php if (session('error')): ?><div class="alert alert-danger"><?= esc(session('error')) ?></div><?php endif; ?>
<div class="table-responsive">
<table class="table table-striped table-bordered no-mgmt-sticky">
<thead><tr><th>Title</th><th>Department</th><th>Location</th><th>Type</th><th>Status</th><th>Post Date</th><th>Actions</th></tr></thead>
<thead><tr><th>Title</th><th>Department</th><th>Location</th><th>Type</th><th>Status</th><th>Post Date</th><th>Detail Clicks</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($positions as $position): ?>
<?php
@@ -32,6 +32,7 @@
<td><?= esc($position['employment_type'] ?? '') ?></td>
<td><span class="badge <?= esc($statusBadgeClass) ?>"><?= esc(ucfirst($status)) ?></span></td>
<td><?= !empty($position['posted_at']) ? esc(date('M j, Y', strtotime((string) $position['posted_at']))) : '&mdash;' ?></td>
<td><?= esc(number_format((int) ($position['details_click_count'] ?? 0))) ?></td>
<td>
<a class="btn btn-sm btn-outline-primary" href="<?= site_url('administrator/job-postings/positions/' . $position['position_id'] . '/edit') ?>">Edit</a>
<?php if ($status === 'open'): ?>
+1
View File
@@ -94,6 +94,7 @@ $renderPostingText = static function (?string $text): string {
<?php if (!empty($position['location'])): ?> &middot; <?= esc($position['location']) ?><?php endif; ?>
<?php if (!empty($position['employment_type'])): ?> &middot; <?= esc($position['employment_type']) ?><?php endif; ?>
<?php if (!empty($position['posted_at'])): ?><br><?= esc(date('M j, Y', strtotime((string) $position['posted_at']))) ?><?php endif; ?>
<br><?= esc(number_format((int) ($position['details_click_count'] ?? 0))) ?> views
</p>
<h2 class="h4 mt-4">Description</h2>
<div><?= $renderPostingText($position['description'] ?? '') ?></div>
+2 -1
View File
@@ -255,7 +255,7 @@
<?php foreach ($openPositions as $position): ?>
<?php
$positionId = (string) ($position['position_id'] ?? '');
$detailsUrl = site_url('careers/' . rawurlencode($positionId));
$detailsUrl = site_url('careers/' . rawurlencode($positionId) . '/details');
$applyUrl = site_url('careers/' . rawurlencode($positionId) . '/apply');
$meta = array_filter([
$position['department'] ?? '',
@@ -278,6 +278,7 @@
<?php if (!empty($position['description'])): ?>
<div class="small text-muted"><?= esc($position['description']) ?></div>
<?php endif; ?>
<div class="small text-muted fw-semibold mt-2"><?= esc(number_format((int) ($position['details_click_count'] ?? 0))) ?> views</div>
</div>
<div class="d-flex align-items-start gap-2 flex-shrink-0">
<a class="btn btn-outline-secondary btn-sm" href="<?= esc($detailsUrl) ?>">Details</a>