add open position system
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
<?php $item = $item ?? []; ?>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="title">Title</label>
|
||||
<input id="title" name="title" class="form-control" value="<?= esc(old('title', $item['title'] ?? '')) ?>" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="department">Department</label>
|
||||
<input id="department" name="department" class="form-control" value="<?= esc(old('department', $item['department'] ?? '')) ?>">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="location">Location</label>
|
||||
<input id="location" name="location" class="form-control" value="<?= esc(old('location', $item['location'] ?? '')) ?>">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="employment_type">Employment Type</label>
|
||||
<input id="employment_type" name="employment_type" class="form-control" value="<?= esc(old('employment_type', $item['employment_type'] ?? '')) ?>">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label" for="description">Description</label>
|
||||
<textarea id="description" name="description" class="form-control" rows="6"><?= esc(old('description', $item['description'] ?? '')) ?></textarea>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label" for="requirements">Requirements</label>
|
||||
<textarea id="requirements" name="requirements" class="form-control" rows="6"><?= esc(old('requirements', $item['requirements'] ?? '')) ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,62 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h2>Job Applications</h2>
|
||||
<a href="<?= site_url('administrator/job-postings/positions') ?>" class="btn btn-outline-secondary">Positions</a>
|
||||
</div>
|
||||
<?php if (session('success')): ?><div class="alert alert-success"><?= esc(session('success')) ?></div><?php endif; ?>
|
||||
<?php if (session('error')): ?><div class="alert alert-danger"><?= esc(session('error')) ?></div><?php endif; ?>
|
||||
<form method="get" class="row g-2 mb-4">
|
||||
<div class="col-md-4">
|
||||
<select name="position_id" class="form-select">
|
||||
<option value="">All positions</option>
|
||||
<?php foreach ($positions as $position): ?>
|
||||
<option value="<?= esc($position['position_id']) ?>" <?= $selectedPosition === $position['position_id'] ? 'selected' : '' ?>><?= esc($position['title']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<select name="status" class="form-select">
|
||||
<option value="">All statuses</option>
|
||||
<?php foreach ($statuses as $status): ?>
|
||||
<option value="<?= esc($status) ?>" <?= $selectedStatus === $status ? 'selected' : '' ?>><?= esc(ucfirst($status)) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-auto"><button class="btn btn-outline-primary" type="submit">Filter</button></div>
|
||||
</form>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered align-middle no-mgmt-sticky">
|
||||
<thead><tr><th>Applicant</th><th>Position</th><th>Position ID</th><th>Email</th><th>Phone</th><th>Submitted</th><th>Status / Notes</th><th>Resume</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($applications as $application): ?>
|
||||
<tr>
|
||||
<td><?= esc(trim($application['first_name'] . ' ' . $application['last_name'])) ?></td>
|
||||
<td><?= esc($application['position_title'] ?? '') ?></td>
|
||||
<td><?= esc(substr((string) ($application['position_id'] ?? ''), 0, 8)) ?></td>
|
||||
<td><a href="mailto:<?= esc($application['email']) ?>"><?= esc($application['email']) ?></a></td>
|
||||
<td><?= esc($application['phone']) ?></td>
|
||||
<td><?= esc($application['submitted_at']) ?></td>
|
||||
<td style="min-width: 280px;">
|
||||
<form action="<?= site_url('administrator/job-postings/applications/' . $application['application_id']) ?>" method="post">
|
||||
<?= csrf_field() ?>
|
||||
<select name="status" class="form-select form-select-sm mb-2">
|
||||
<?php foreach ($statuses as $status): ?>
|
||||
<option value="<?= esc($status) ?>" <?= $application['status'] === $status ? 'selected' : '' ?>><?= esc(ucfirst($status)) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<textarea name="admin_notes" class="form-control form-control-sm mb-2" rows="2"><?= esc($application['admin_notes'] ?? '') ?></textarea>
|
||||
<button class="btn btn-sm btn-primary" type="submit">Save</button>
|
||||
</form>
|
||||
</td>
|
||||
<td><a class="btn btn-sm btn-outline-secondary" href="<?= site_url('administrator/job-postings/applications/' . $application['application_id'] . '/resume') ?>">Download</a></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?php $isEdit = !empty($position['position_id']); ?>
|
||||
<div class="container mt-4">
|
||||
<h2><?= $isEdit ? 'Edit Job Position' : 'New Job Position' ?></h2>
|
||||
<?php if (session('errors')): ?>
|
||||
<div class="alert alert-danger"><?php foreach ((array) session('errors') as $error): ?><div><?= esc($error) ?></div><?php endforeach; ?></div>
|
||||
<?php endif; ?>
|
||||
<form action="<?= $isEdit ? site_url('administrator/job-postings/positions/' . $position['position_id']) : site_url('administrator/job-postings/positions') ?>" method="post">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="template_id" value="<?= esc(old('template_id', $position['template_id'] ?? '')) ?>">
|
||||
<?= view('jobs/admin/_posting_fields', ['item' => $position ?? []]) ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="status">Status</label>
|
||||
<select id="status" name="status" class="form-select">
|
||||
<?php foreach ($statuses as $status): ?>
|
||||
<option value="<?= esc($status) ?>" <?= old('status', $position['status'] ?? 'draft') === $status ? 'selected' : '' ?>><?= esc(ucfirst($status)) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Save Position</button>
|
||||
<a href="<?= site_url('administrator/job-postings/positions') ?>" class="btn btn-outline-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h2>Open Positions</h2>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="<?= site_url('administrator/job-postings/applications') ?>" class="btn btn-outline-secondary">Applications</a>
|
||||
<a href="<?= site_url('administrator/job-postings/templates') ?>" class="btn btn-primary">New Position</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (session('success')): ?><div class="alert alert-success"><?= esc(session('success')) ?></div><?php endif; ?>
|
||||
<?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>Actions</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($positions as $position): ?>
|
||||
<tr>
|
||||
<td><?= esc($position['title']) ?></td>
|
||||
<td><?= esc($position['department'] ?? '') ?></td>
|
||||
<td><?= esc($position['location'] ?? '') ?></td>
|
||||
<td><?= esc($position['employment_type'] ?? '') ?></td>
|
||||
<td><?= esc(ucfirst($position['status'])) ?></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 ($position['status'] === 'open'): ?>
|
||||
<a class="btn btn-sm btn-outline-secondary" href="<?= site_url('careers/' . $position['position_id']) ?>">Public View</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,47 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?php $isEdit = !empty($template); ?>
|
||||
<div class="container mt-4">
|
||||
<h2><?= $isEdit ? 'Edit Job Template' : 'New Job Template' ?></h2>
|
||||
<?php if (session('errors')): ?>
|
||||
<div class="alert alert-danger"><?php foreach ((array) session('errors') as $error): ?><div><?= esc($error) ?></div><?php endforeach; ?></div>
|
||||
<?php endif; ?>
|
||||
<form action="<?= $isEdit ? site_url('administrator/job-postings/templates/' . $template['template_id']) : site_url('administrator/job-postings/templates') ?>" method="post">
|
||||
<?= csrf_field() ?>
|
||||
<?= view('jobs/admin/_posting_fields', ['item' => $template ?? []]) ?>
|
||||
<?php if ($isEdit): ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="save_mode">Save Mode</label>
|
||||
<select id="save_mode" name="save_mode" class="form-select">
|
||||
<option value="overwrite">Overwrite current version</option>
|
||||
<option value="new_version">Save as new version</option>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<button type="submit" class="btn btn-primary">Save Template</button>
|
||||
<a href="<?= site_url('administrator/job-postings/templates') ?>" class="btn btn-outline-secondary">Cancel</a>
|
||||
</form>
|
||||
<?php if ($isEdit && !empty($versions)): ?>
|
||||
<h3 class="h5 mt-5">Version History</h3>
|
||||
<table class="table table-sm table-bordered">
|
||||
<thead><tr><th>Version</th><th>Saved At</th><th>Actions</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($versions as $version): ?>
|
||||
<tr>
|
||||
<td><?= esc($version['version']) ?></td>
|
||||
<td><?= esc($version['saved_at']) ?></td>
|
||||
<td>
|
||||
<form action="<?= site_url('administrator/job-postings/templates/versions/' . $version['version_id'] . '/restore') ?>" method="post">
|
||||
<?= csrf_field() ?>
|
||||
<button class="btn btn-sm btn-outline-primary" type="submit">Restore</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,53 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h2>Job Templates</h2>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="<?= site_url('administrator/job-postings/positions') ?>" class="btn btn-outline-secondary">Open Positions</a>
|
||||
<a href="<?= site_url('administrator/job-postings/templates/new') ?>" class="btn btn-primary">New Template</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (session('success')): ?><div class="alert alert-success"><?= esc(session('success')) ?></div><?php endif; ?>
|
||||
<?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>Version</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($templates as $template): ?>
|
||||
<tr>
|
||||
<td><?= esc($template['title']) ?></td>
|
||||
<td><?= esc($template['department'] ?? '') ?></td>
|
||||
<td><?= esc($template['location'] ?? '') ?></td>
|
||||
<td><?= esc($template['employment_type'] ?? '') ?></td>
|
||||
<td><?= esc($template['version']) ?></td>
|
||||
<td><?= !empty($template['is_active']) ? 'Active' : 'Archived' ?></td>
|
||||
<td class="d-flex gap-2">
|
||||
<a class="btn btn-sm btn-outline-primary" href="<?= site_url('administrator/job-postings/templates/' . $template['template_id'] . '/edit') ?>">Edit</a>
|
||||
<a class="btn btn-sm btn-outline-success" href="<?= site_url('administrator/job-postings/positions/new?template_id=' . $template['template_id']) ?>">Create Position</a>
|
||||
<?php if (!empty($template['is_active'])): ?>
|
||||
<form action="<?= site_url('administrator/job-postings/templates/' . $template['template_id'] . '/archive') ?>" method="post">
|
||||
<?= csrf_field() ?>
|
||||
<button class="btn btn-sm btn-outline-danger" type="submit">Archive</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,187 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('styles') ?>
|
||||
<style>
|
||||
.job-apply-page {
|
||||
max-width: 920px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.job-apply-page h1 {
|
||||
font-family: "Inter", sans-serif;
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
margin-bottom: 2rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.job-apply-page .form-label {
|
||||
font-family: "Heebo", sans-serif;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.job-apply-page .btn-primary {
|
||||
background-color: #198754;
|
||||
border-color: #198754;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.job-apply-page .btn-primary:hover {
|
||||
background-color: #146c43;
|
||||
border-color: #146c43;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.job-apply-page .field-error {
|
||||
min-height: 1.25rem;
|
||||
}
|
||||
</style>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<div class="container py-5">
|
||||
<a href="<?= site_url('careers/' . $position['position_id']) ?>" class="btn btn-outline-secondary btn-sm mb-4">Back to position</a>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8 job-apply-page">
|
||||
<h1>Apply: <?= esc($position['title']) ?></h1>
|
||||
<?php if (session('error')): ?><div class="alert alert-danger"><?= esc(session('error')) ?></div><?php endif; ?>
|
||||
<?php if (session('errors')): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php foreach ((array) session('errors') as $error): ?>
|
||||
<div><?= esc($error) ?></div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<p class="text-secondary mb-3">(All fields with * are required)</p>
|
||||
<form action="<?= site_url('careers/' . $position['position_id'] . '/apply') ?>" method="post" enctype="multipart/form-data" class="mt-4">
|
||||
<?= csrf_field() ?>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="first_name">First Name*</label>
|
||||
<input id="first_name" name="first_name" class="form-control" maxlength="30" pattern="[A-Za-z\s-]{2,30}" placeholder="First Name*" title="2-30 characters. Letters, spaces, and dashes only." value="<?= esc(old('first_name')) ?>" required>
|
||||
<div class="form-text text-muted">2-30 characters. Letters, spaces, and dashes only.</div>
|
||||
<div id="first_name-error" class="text-danger small field-error"></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="last_name">Last Name*</label>
|
||||
<input id="last_name" name="last_name" class="form-control" maxlength="30" pattern="[A-Za-z\s-]{2,30}" placeholder="Last Name*" title="2-30 characters. Letters, spaces, and dashes only." value="<?= esc(old('last_name')) ?>" required>
|
||||
<div class="form-text text-muted">2-30 characters. Letters, spaces, and dashes only.</div>
|
||||
<div id="last_name-error" class="text-danger small field-error"></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="email">Email*</label>
|
||||
<input id="email" type="email" name="email" class="form-control" maxlength="50" placeholder="Email*" value="<?= esc(old('email')) ?>" required>
|
||||
<div class="form-text text-muted">Valid email format, maximum 50 characters.</div>
|
||||
<div id="email-error" class="text-danger small field-error"></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="phone">Phone*</label>
|
||||
<input id="phone" type="tel" name="phone" class="form-control" minlength="10" maxlength="20" inputmode="tel" pattern="[\d\s\-\(\)\.]+" placeholder="Phone*" title="Enter a valid 10-digit phone number, for example 123-456-7890" value="<?= esc(old('phone')) ?>" required>
|
||||
<div class="form-text text-muted">Enter a 10-digit phone number, for example 123-456-7890.</div>
|
||||
<div id="phone-error" class="text-danger small field-error"></div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label" for="resume">Resume*</label>
|
||||
<input id="resume" type="file" name="resume" class="form-control" accept=".pdf,.doc,.docx" required>
|
||||
<div class="form-text">PDF, DOC, or DOCX. Maximum size 5 MB.</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-4">Submit Application</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const form = document.querySelector('.job-apply-page form');
|
||||
const fields = {
|
||||
first_name: {
|
||||
element: document.getElementById('first_name'),
|
||||
validate: value => /^[A-Za-z\s-]{2,30}$/.test(value),
|
||||
message: 'First name must be 2-30 characters and use only letters, spaces, and dashes.'
|
||||
},
|
||||
last_name: {
|
||||
element: document.getElementById('last_name'),
|
||||
validate: value => /^[A-Za-z\s-]{2,30}$/.test(value),
|
||||
message: 'Last name must be 2-30 characters and use only letters, spaces, and dashes.'
|
||||
},
|
||||
email: {
|
||||
element: document.getElementById('email'),
|
||||
validate: value => value.length <= 50 && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
|
||||
message: 'Please enter a valid email address, maximum 50 characters.'
|
||||
},
|
||||
phone: {
|
||||
element: document.getElementById('phone'),
|
||||
validate: value => value.replace(/\D/g, '').length === 10,
|
||||
message: 'Please enter a valid 10-digit phone number.'
|
||||
}
|
||||
};
|
||||
|
||||
function setFieldState(input, valid, message) {
|
||||
const error = document.getElementById(input.id + '-error');
|
||||
const hasValue = input.value.trim() !== '';
|
||||
|
||||
input.classList.toggle('is-valid', valid && hasValue);
|
||||
input.classList.toggle('is-invalid', !valid && hasValue);
|
||||
|
||||
if (error) {
|
||||
error.textContent = !valid && hasValue ? message : '';
|
||||
}
|
||||
}
|
||||
|
||||
function formatPhone(input) {
|
||||
const digits = input.value.replace(/\D/g, '').slice(0, 10);
|
||||
let formatted = digits;
|
||||
if (digits.length > 3) {
|
||||
formatted = digits.slice(0, 3) + '-' + digits.slice(3);
|
||||
}
|
||||
if (digits.length > 6) {
|
||||
formatted = digits.slice(0, 3) + '-' + digits.slice(3, 6) + '-' + digits.slice(6);
|
||||
}
|
||||
input.value = formatted;
|
||||
}
|
||||
|
||||
function validateField(name) {
|
||||
const config = fields[name];
|
||||
if (!config || !config.element) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name === 'phone') {
|
||||
formatPhone(config.element);
|
||||
}
|
||||
|
||||
const value = config.element.value.trim();
|
||||
const valid = config.validate(value);
|
||||
setFieldState(config.element, valid, config.message);
|
||||
return valid;
|
||||
}
|
||||
|
||||
Object.keys(fields).forEach(name => {
|
||||
const input = fields[name].element;
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
|
||||
input.addEventListener('input', () => validateField(name));
|
||||
input.addEventListener('blur', () => validateField(name));
|
||||
});
|
||||
|
||||
if (form) {
|
||||
form.addEventListener('submit', function (event) {
|
||||
const ok = Object.keys(fields).every(validateField);
|
||||
if (!ok) {
|
||||
event.preventDefault();
|
||||
const firstInvalid = form.querySelector('.is-invalid');
|
||||
if (firstInvalid) {
|
||||
firstInvalid.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<div class="container py-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-7">
|
||||
<div class="alert alert-success">Thank you. Your application has been received.</div>
|
||||
<p>We will review your submission and follow up if there is a match for the role.</p>
|
||||
<a href="<?= site_url('careers') ?>" class="btn btn-primary">Return to Openings</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,110 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('styles') ?>
|
||||
<style>
|
||||
.job-posting-copy,
|
||||
.job-posting-copy p,
|
||||
.job-posting-copy li {
|
||||
font-family: "Heebo", sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.job-posting-copy h2,
|
||||
.job-posting-copy h3 {
|
||||
font-family: "Inter", sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?php
|
||||
$renderPostingText = static function (?string $text): string {
|
||||
$lines = preg_split('/\r\n|\r|\n/', trim((string) $text));
|
||||
$html = '';
|
||||
$paragraph = [];
|
||||
$list = [];
|
||||
|
||||
$flushParagraph = static function () use (&$html, &$paragraph): void {
|
||||
if ($paragraph === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$html .= '<p>' . esc(implode(' ', $paragraph)) . '</p>';
|
||||
$paragraph = [];
|
||||
};
|
||||
|
||||
$flushList = static function () use (&$html, &$list): void {
|
||||
if ($list === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$html .= '<ul>';
|
||||
foreach ($list as $item) {
|
||||
$html .= '<li>' . esc($item) . '</li>';
|
||||
}
|
||||
$html .= '</ul>';
|
||||
$list = [];
|
||||
};
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$line = trim((string) $line);
|
||||
if ($line === '') {
|
||||
$flushParagraph();
|
||||
$flushList();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_ends_with($line, ':')) {
|
||||
$flushParagraph();
|
||||
$flushList();
|
||||
$html .= '<h3 class="h4 mt-4">' . esc(rtrim($line, ':')) . '</h3>';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_starts_with($line, '- ')) {
|
||||
$flushParagraph();
|
||||
$list[] = substr($line, 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
$flushList();
|
||||
$paragraph[] = $line;
|
||||
}
|
||||
|
||||
$flushParagraph();
|
||||
$flushList();
|
||||
|
||||
return $html;
|
||||
};
|
||||
?>
|
||||
|
||||
<div class="container py-5">
|
||||
<a href="<?= site_url('careers') ?>" class="btn btn-outline-secondary btn-sm mb-4">Back to openings</a>
|
||||
<div class="row g-4">
|
||||
<div class="col-lg-8 job-posting-copy">
|
||||
<h1><?= esc($position['title']) ?></h1>
|
||||
<p class="text-muted">
|
||||
<?= esc($position['department'] ?? '') ?>
|
||||
<?php if (!empty($position['location'])): ?> · <?= esc($position['location']) ?><?php endif; ?>
|
||||
<?php if (!empty($position['employment_type'])): ?> · <?= esc($position['employment_type']) ?><?php endif; ?>
|
||||
</p>
|
||||
<h2 class="h4 mt-4">Description</h2>
|
||||
<div><?= $renderPostingText($position['description'] ?? '') ?></div>
|
||||
<h2 class="h4 mt-4">Requirements</h2>
|
||||
<div><?= $renderPostingText($position['requirements'] ?? '') ?></div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2 class="h5">Apply for this position</h2>
|
||||
<p class="text-muted">Submit your contact information and resume for review.</p>
|
||||
<a href="<?= site_url('careers/' . $position['position_id'] . '/apply') ?>" class="btn btn-primary w-100">Apply Now</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
Reference in New Issue
Block a user