add open position system
This commit is contained in:
@@ -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() ?>
|
||||
Reference in New Issue
Block a user