<?php
|
/**
|
* WPCode Snippet 2/4 — Frontend Forms (Join Us + Detailed Application)
|
* Name: IM - Frontend Forms
|
* Type: PHP Snippet
|
* Location: Run everywhere
|
*
|
* Dependency: Snippet 1 must be enabled first
|
*
|
* Usage:
|
* [im_joinus_form] → Join Us simple form (name + email)
|
* [im_apply_form] → Detailed application form (all fields)
|
*/
|
|
defined('ABSPATH') || exit;
|
|
/* ============================================================
|
Disable cache for pages with apply token
|
============================================================ */
|
add_action('template_redirect', function() {
|
if (!empty($_GET['im_apply_token'])) {
|
nocache_headers();
|
}
|
}, 1);
|
|
/* ============================================================
|
Shared CSS (output once for both forms)
|
============================================================ */
|
function im_enqueue_form_styles() {
|
static $done = false;
|
if ($done) return;
|
$done = true;
|
echo '<style>
|
.im-form-wrap{max-width:720px;margin:0 auto;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif}
|
.im-form{background:#fff;border:1px solid #e5e7eb;border-radius:14px;padding:40px 48px;box-shadow:0 4px 24px rgba(0,0,0,.06)}
|
@media(max-width:640px){.im-form{padding:28px 20px}}
|
.im-form h2{margin:0 0 6px;font-size:22px;font-weight:700;color:#111827}
|
.im-form .im-subtitle{color:#6b7280;font-size:15px;margin:0 0 32px}
|
.im-section-title{font-size:16px;font-weight:700;color:#009dff;margin:32px 0 16px;padding-bottom:8px;border-bottom:2px solid #d0f0ff}
|
.im-section-title:first-of-type{margin-top:0}
|
.im-field{margin-bottom:20px}
|
.im-field label{display:block;font-size:14px;font-weight:600;color:#374151;margin-bottom:6px}
|
.im-field label .req{color:#ef4444;margin-left:2px}
|
.im-field label .hint{font-weight:400;color:#9ca3af;font-size:12px;margin-left:6px}
|
.im-input,.im-select,.im-textarea{width:100%;padding:11px 14px;border:1.5px solid #d1d5db;border-radius:8px;font-size:15px;
|
color:#111827;background:#fff;transition:border-color .2s,box-shadow .2s;box-sizing:border-box;font-family:inherit}
|
.im-input:focus,.im-select:focus,.im-textarea:focus{outline:none;border-color:#009dff;box-shadow:0 0 0 3px rgba(0,157,255,.15)}
|
.im-input.error,.im-select.error,.im-textarea.error{border-color:#ef4444}
|
.im-textarea{resize:vertical;min-height:100px;line-height:1.6}
|
.im-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
|
@media(max-width:540px){.im-row{grid-template-columns:1fr}}
|
.im-radio-group,.im-check-group{display:flex;flex-wrap:wrap;gap:10px;margin-top:4px}
|
.im-radio-group label,.im-check-group label{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:400;
|
cursor:pointer;padding:8px 14px;border:1.5px solid #d1d5db;border-radius:8px;transition:all .15s;color:#374151;white-space:nowrap;position:relative}
|
.im-radio-group label:hover,.im-check-group label:hover{border-color:#009dff;background:#e6f9ff}
|
.im-radio-group input[type=radio],.im-check-group input[type=checkbox]{position:absolute;opacity:0;width:0;height:0;pointer-events:none}
|
.im-radio-group .im-ck,.im-check-group .im-ck{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;
|
border:2px solid #d1d5db;border-radius:4px;flex-shrink:0;transition:all .2s;background:#fff;position:relative}
|
.im-radio-group .im-ck{border-radius:50%}
|
.im-ck::after{content:"";display:block;opacity:0;transition:opacity .15s}
|
.im-check-group .im-ck::after{width:5px;height:9px;border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg);margin-top:-1px}
|
.im-radio-group .im-ck::after{width:8px;height:8px;border-radius:50%;background:#fff}
|
input:checked~.im-ck{background:linear-gradient(135deg,#009dff,#3de1fe,#53eee0);border-color:transparent}
|
input:checked~.im-ck::after{opacity:1}
|
.im-radio-group input:checked~span,.im-check-group input:checked~span{color:#009dff;font-weight:600}
|
.im-checkbox-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px;margin-top:4px}
|
.im-checkbox-grid label{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:400;
|
cursor:pointer;padding:8px 12px;border:1.5px solid #e5e7eb;border-radius:8px;transition:all .15s;color:#374151;position:relative}
|
.im-checkbox-grid label:hover{border-color:#009dff;background:#e6f9ff}
|
.im-checkbox-grid input[type=checkbox]{position:absolute;opacity:0;width:0;height:0;pointer-events:none}
|
.im-checkbox-grid .im-ck{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;
|
border:2px solid #d1d5db;border-radius:4px;flex-shrink:0;transition:all .2s;background:#fff}
|
.im-checkbox-grid .im-ck::after{content:"";width:4px;height:8px;border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg);opacity:0;transition:opacity .15s;margin-top:-1px}
|
.im-checkbox-grid input:checked~.im-ck{background:linear-gradient(135deg,#009dff,#3de1fe,#53eee0);border-color:transparent}
|
.im-checkbox-grid input:checked~.im-ck::after{opacity:1}
|
.im-checkbox-grid input:checked~span{color:#009dff;font-weight:600}
|
.im-upload-box{border:2px dashed #cbd5e1;border-radius:10px;padding:28px 20px;text-align:center;
|
cursor:pointer;background:#f8fafc;position:relative;transition:all .2s}
|
.im-upload-box:hover,.im-upload-box.drag{border-color:#009dff;background:#e6f9ff}
|
.im-upload-box input[type=file]{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%;height:100%}
|
.im-upload-box p{margin:0;color:#64748b;font-size:14px}
|
.im-upload-icon{font-size:28px;color:#94a3b8;margin-bottom:8px}
|
.im-file-list{margin-top:12px;text-align:left}
|
.im-file-item{font-size:13px;color:#374151;padding:4px 0;display:flex;align-items:center;gap:6px}
|
.im-file-item::before{content:"📎";font-size:12px}
|
.im-conditional{display:none}
|
.im-field-error{color:#ef4444;font-size:12px;margin-top:4px;display:block;animation:imFadeIn .3s ease}
|
.im-field.has-error .im-input,.im-field.has-error .im-select,.im-field.has-error .im-textarea,
|
.im-field.has-error .im-cs-trigger,.im-declaration.has-error,.im-field.has-error .im-upload-box{border-color:#ef4444}
|
.im-error-msg{color:#ef4444;font-size:12px;margin-top:4px;display:none}
|
.im-notice{padding:14px 18px;border-radius:8px;font-size:14px;margin-bottom:20px}
|
.im-notice.success{background:#d1fae5;color:#065f46;border:1px solid #6ee7b7}
|
.im-notice.error{background:#fee2e2;color:#991b1b;border:1px solid #fca5a5}
|
.im-notice.info{background:#e6f9ff;color:#007acc;border:1px solid #80d4ff}
|
.im-btn{display:inline-flex;align-items:center;gap:8px;padding:13px 32px;background:linear-gradient(135deg,#009dff,#3de1fe,#53eee0);color:#fff;
|
border:none;border-radius:8px;font-size:16px;font-weight:700;cursor:pointer;transition:all .3s;
|
font-family:inherit;margin-top:8px;text-shadow:0 1px 2px rgba(0,0,0,.1)}
|
.im-btn:hover{background:linear-gradient(135deg,#0088e0,#30cce8,#45ddd2);transform:translateY(-1px);box-shadow:0 4px 12px rgba(0,157,255,.3)}
|
.im-btn:disabled{background:#94a3b8;cursor:not-allowed;transform:none;box-shadow:none}
|
.im-btn-wrap{margin-top:28px;border-top:1px solid #f3f4f6;padding-top:24px}
|
.im-declaration{background:#f9fafb;border:1px solid #e5e7eb;border-radius:10px;padding:20px 24px;margin-top:24px}
|
.im-declaration label{display:flex;align-items:flex-start;gap:10px;font-size:14px;color:#374151;cursor:pointer;margin-bottom:12px;position:relative}
|
.im-declaration label:last-child{margin-bottom:0}
|
.im-declaration input[type=checkbox]{position:absolute;opacity:0;width:0;height:0;pointer-events:none}
|
.im-declaration .im-ck{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;
|
border:2px solid #d1d5db;border-radius:4px;flex-shrink:0;transition:all .2s;background:#fff;margin-top:1px}
|
.im-declaration .im-ck::after{content:"";width:5px;height:9px;border:solid #fff;border-width:0 2px 2px 0;
|
transform:rotate(45deg);opacity:0;transition:opacity .15s;margin-top:-1px}
|
.im-declaration input:checked~.im-ck{background:linear-gradient(135deg,#009dff,#3de1fe,#53eee0);border-color:transparent}
|
.im-declaration input:checked~.im-ck::after{opacity:1}
|
.im-step-badge{display:inline-block;background:#e6f9ff;color:#009dff;border:1px solid #80d4ff;
|
border-radius:20px;padding:4px 14px;font-size:13px;font-weight:600;margin-bottom:16px}
|
.im-cs{position:relative;width:100%}
|
.im-cs .im-select{display:none}
|
.im-cs-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;padding:11px 14px;
|
border:1.5px solid #d1d5db;border-radius:8px;font-size:15px;color:#111827;background:#fff;
|
cursor:pointer;transition:all .2s;box-sizing:border-box;font-family:inherit;outline:none;user-select:none}
|
.im-cs-trigger:hover{border-color:#009dff}
|
.im-cs.open .im-cs-trigger{border-color:#009dff;box-shadow:0 0 0 3px rgba(0,157,255,.15);border-radius:8px 8px 0 0}
|
.im-cs-text{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
.im-cs-ph{color:#9ca3af}
|
.im-cs-arrow{width:18px;height:18px;flex-shrink:0;margin-left:8px;transition:transform .25s ease;color:#9ca3af}
|
.im-cs.open .im-cs-arrow{transform:rotate(180deg);color:#009dff}
|
.im-cs-drop{position:absolute;top:100%;left:0;right:0;background:#fff;border:1.5px solid #009dff;border-top:none;
|
border-radius:0 0 8px 8px;z-index:100;visibility:hidden;opacity:0;transform:translateY(-6px);
|
transition:all .2s ease;pointer-events:none;max-height:280px;overflow-y:auto;
|
box-shadow:0 8px 24px rgba(0,157,255,.1)}
|
.im-cs.open .im-cs-drop{visibility:visible;opacity:1;transform:translateY(0);pointer-events:auto}
|
.im-cs-search-wrap{padding:8px 10px;border-bottom:1px solid #f3f4f6;position:sticky;top:0;background:#fff;z-index:1}
|
.im-cs-search{width:100%;padding:8px 12px;border:1.5px solid #e5e7eb;border-radius:6px;font-size:13px;font-family:inherit;
|
outline:none;box-sizing:border-box;transition:border-color .2s}
|
.im-cs-search:focus{border-color:#009dff}
|
.im-cs-opt{padding:10px 14px;cursor:pointer;font-size:14px;color:#374151;transition:background .1s,color .1s;
|
display:flex;align-items:center;gap:8px}
|
.im-cs-opt:hover{background:#e6f9ff;color:#009dff}
|
.im-cs-opt.sel{color:#009dff;font-weight:600;background:#f0faff}
|
.im-cs-opt.sel::before{content:"✓";font-size:12px;font-weight:700}
|
.im-cs-opt.hid{display:none}
|
.im-cs-empty{padding:20px 16px;text-align:center;color:#9ca3af;font-size:13px}
|
.im-cs-drop::-webkit-scrollbar{width:5px}
|
.im-cs-drop::-webkit-scrollbar-track{background:transparent}
|
.im-cs-drop::-webkit-scrollbar-thumb{background:#d1d5db;border-radius:3px}
|
.im-cs-drop::-webkit-scrollbar-thumb:hover{background:#9ca3af}
|
@keyframes imSpin{to{transform:rotate(360deg)}}
|
@keyframes imFadeIn{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}
|
.im-fade-in{animation:imFadeIn .5s ease}
|
.im-btn-loading{position:relative;color:transparent!important}
|
.im-btn-loading::after{content:"";position:absolute;width:20px;height:20px;top:50%;left:50%;margin:-10px 0 0 -10px;
|
border:3px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:imSpin .6s linear infinite}
|
</style>';
|
echo '<script>var imAjaxUrl="' . esc_url(admin_url('admin-ajax.php')) . '";</script>';
|
}
|
|
add_action('wp_ajax_im_get_cities', 'im_ajax_get_cities');
|
add_action('wp_ajax_nopriv_im_get_cities', 'im_ajax_get_cities');
|
function im_ajax_get_cities() {
|
global $wpdb;
|
$country_code = sanitize_text_field($_POST['country'] ?? '');
|
if (!$country_code) wp_send_json_success([]);
|
$cities = $wpdb->get_results($wpdb->prepare("SELECT name FROM cities WHERE country_code = %s ORDER BY name ASC", $country_code));
|
$res = [];
|
foreach ($cities as $c) $res[] = $c->name;
|
wp_send_json_success($res);
|
}
|
|
/* ============================================================
|
AJAX Handlers
|
============================================================ */
|
add_action('wp_ajax_im_joinus_submit', 'im_ajax_joinus');
|
add_action('wp_ajax_nopriv_im_joinus_submit', 'im_ajax_joinus');
|
function im_ajax_joinus() {
|
if (!wp_verify_nonce($_POST['im_joinus_nonce'] ?? '', 'im_joinus_submit')) {
|
wp_send_json_error(['message' => 'Security verification failed. Please refresh and try again.']);
|
}
|
$first = sanitize_text_field(trim($_POST['first_name'] ?? ''));
|
$last = sanitize_text_field(trim($_POST['last_name'] ?? ''));
|
$email = sanitize_email(trim($_POST['email'] ?? ''));
|
if (!$first || !$last || !$email) wp_send_json_error(['message' => 'Please fill in all required fields.']);
|
if (!is_email($email)) wp_send_json_error(['message' => 'Please enter a valid email address.']);
|
$id = IM_Candidate::create_from_joinus($first, $last, $email);
|
if (!$id) wp_send_json_error(['message' => 'Submission failed. Please try again later.']);
|
IM_Mailer::send_joinus_confirmation($id);
|
wp_send_json_success(['message' => 'ok']);
|
}
|
|
add_action('wp_ajax_im_apply_submit', 'im_ajax_apply');
|
add_action('wp_ajax_nopriv_im_apply_submit', 'im_ajax_apply');
|
function im_ajax_apply() {
|
$apply_token = sanitize_text_field($_POST['im_apply_token'] ?? '');
|
$candidate = $apply_token ? IM_Candidate::get_by_apply_token($apply_token) : null;
|
if (!$candidate) wp_send_json_error(['messages' => ['Invalid or expired application link.']]);
|
if (!wp_verify_nonce($_POST['im_apply_nonce'] ?? '', 'im_apply_submit_' . $candidate->id)) {
|
wp_send_json_error(['messages' => ['Security verification failed. Please refresh and try again.']]);
|
}
|
$errors = [];
|
$field_errors = [];
|
$required = [
|
'preferred_name'=>'Preferred Name','country'=>'Country','city'=>'City','phone'=>'Phone Number',
|
'degree_level'=>'Highest Degree Level','university'=>'University','major'=>'Major',
|
'grad_year'=>'Graduation Year','gpa'=>'GPA','languages'=>'English Fluency','teaching_exp'=>'Teaching Experience',
|
];
|
foreach ($required as $field => $label) {
|
if (empty(trim($_POST[$field] ?? ''))) $field_errors[$field] = "\"$label\" is required.";
|
}
|
if (empty($_POST['deans_list'])) $field_errors['deans_list'] = 'Please select an option.';
|
if (!isset($_POST['ca_highschool']) || $_POST['ca_highschool'] === '') $field_errors['ca_highschool'] = 'Please select an option.';
|
if (empty($_POST['subjects'])) $field_errors['subjects'] = 'Please select at least one teaching subject.';
|
if (empty($_FILES['transcript_files']['name'][0])) $field_errors['transcript_files'] = 'Transcript upload is required.';
|
if (empty($_POST['decl_truth'])) $field_errors['decl_truth'] = '';
|
if (empty($_POST['decl_privacy'])) $field_errors['decl_privacy'] = '';
|
$degree_level = sanitize_text_field($_POST['degree_level'] ?? '');
|
if (in_array($degree_level, ["Master's", "PhD"])) {
|
if (empty(trim($_POST['ug_university'] ?? ''))) $field_errors['ug_university'] = '"Undergraduate University" is required.';
|
if (empty(trim($_POST['ug_major'] ?? ''))) $field_errors['ug_major'] = '"Undergraduate Major" is required.';
|
if (empty(trim($_POST['ug_grad_year'] ?? ''))) $field_errors['ug_grad_year'] = '"Undergraduate Graduation Year" is required.';
|
}
|
$has_ach = (int)($_POST['has_achievement'] ?? 0);
|
$has_ca_hs = (int)($_POST['ca_highschool'] ?? 0);
|
if ($has_ca_hs && empty(trim($_POST['ca_highschool_name'] ?? ''))) {
|
$field_errors['ca_highschool_name'] = 'Please enter your high school name.';
|
}
|
if ($has_ach) {
|
if (empty($_POST['achievement_type'])) $field_errors['achievement_type'] = 'Please select an achievement type.';
|
if (($_POST['achievement_type'] ?? '') === 'other' && empty(trim($_POST['achievement_desc'] ?? ''))) {
|
$field_errors['achievement_desc'] = 'Please specify your achievement description.';
|
}
|
if (empty($_FILES['achievement_files']['name'][0])) {
|
$field_errors['achievement_files'] = 'Supporting documents must be uploaded when listing achievements.';
|
}
|
}
|
if ($field_errors) wp_send_json_error(['field_errors' => $field_errors]);
|
|
$data = [
|
'preferred_name'=>$_POST['preferred_name']??'','phone'=>$_POST['phone']??'',
|
'country'=>$_POST['country']??'','city'=>$_POST['city']??'',
|
'degree_level'=>$_POST['degree_level']??'','university'=>$_POST['university']??'','major'=>$_POST['major']??'',
|
'grad_year'=>$_POST['grad_year']??'','gpa'=>$_POST['gpa']??'','deans_list'=>(int)(($_POST['deans_list']??'')==='yes'),
|
'ug_university'=>$_POST['ug_university']??'','ug_major'=>$_POST['ug_major']??'','ug_grad_year'=>$_POST['ug_grad_year']??'',
|
'ms_university'=>$_POST['ms_university']??'','ms_major'=>$_POST['ms_major']??'','ms_grad_year'=>$_POST['ms_grad_year']??'',
|
'ca_highschool'=>$has_ca_hs,'ca_highschool_name'=>$_POST['ca_highschool_name']??'',
|
'languages'=>$_POST['languages']??'','teaching_exp'=>$_POST['teaching_exp']??'',
|
'has_achievement'=>$has_ach,'achievement_type'=>$_POST['achievement_type']??'',
|
'achievement_desc'=>$_POST['achievement_desc']??'','subjects'=>$_POST['subjects']??[],'extra_notes'=>$_POST['extra_notes']??'',
|
];
|
IM_Candidate::update_full($candidate->id, $data);
|
|
$upload_dir = wp_upload_dir();
|
$save_dir = $upload_dir['basedir'] . '/im-applications/' . $candidate->id;
|
wp_mkdir_p($save_dir);
|
file_put_contents($save_dir . '/index.html', '');
|
$allowed_mime = ['application/pdf','image/jpeg','image/png','image/jpg'];
|
foreach (['transcript_files','achievement_files','extra_files'] as $field) {
|
if (empty($_FILES[$field]['name'])) continue;
|
$files = $_FILES[$field];
|
$count = is_array($files['name']) ? count($files['name']) : 1;
|
for ($i = 0; $i < $count; $i++) {
|
$name = is_array($files['name']) ? $files['name'][$i] : $files['name'];
|
$tmp = is_array($files['tmp_name']) ? $files['tmp_name'][$i] : $files['tmp_name'];
|
$err = is_array($files['error']) ? $files['error'][$i] : $files['error'];
|
if ($err !== UPLOAD_ERR_OK || !$tmp) continue;
|
$finfo = finfo_open(FILEINFO_MIME_TYPE); $mime = finfo_file($finfo, $tmp); finfo_close($finfo);
|
if (!in_array($mime, $allowed_mime, true)) continue;
|
$ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
|
$dest = $save_dir . '/' . $field . '_' . $i . '_' . time() . '.' . $ext;
|
if (move_uploaded_file($tmp, $dest)) IM_Attachment::add($candidate->id, $dest, $name, $field);
|
}
|
}
|
IM_Mailer::send_apply_confirmation($candidate->id);
|
wp_send_json_success(['message' => 'ok']);
|
}
|
|
/* ============================================================
|
Shortcode 1: [im_joinus_form] — Join Us Simple Form
|
============================================================ */
|
add_shortcode('im_joinus_form', function() {
|
im_enqueue_form_styles();
|
ob_start();
|
?>
|
<div class="im-form-wrap" id="im-joinus-wrap">
|
<div class="im-form">
|
<span class="im-step-badge">Step 1 of 2</span>
|
<h2>Join Us</h2>
|
<p class="im-subtitle">Please provide your basic information below to receive a link to the detailed application form via email.</p>
|
<form method="post" id="im-joinus-form" novalidate>
|
<?php wp_nonce_field('im_joinus_submit', 'im_joinus_nonce'); ?>
|
<div class="im-row">
|
<div class="im-field">
|
<label>Last Name<span class="req">*</span></label>
|
<input class="im-input" type="text" name="last_name" required placeholder="e.g. Johnson">
|
</div>
|
<div class="im-field">
|
<label>First Name<span class="req">*</span></label>
|
<input class="im-input" type="text" name="first_name" required placeholder="e.g. Emily">
|
</div>
|
</div>
|
<div class="im-field">
|
<label>Email Address<span class="req">*</span></label>
|
<input class="im-input" type="email" name="email" required placeholder="your@email.com">
|
</div>
|
<div class="im-btn-wrap">
|
<button type="submit" class="im-btn">Submit</button>
|
</div>
|
</form>
|
</div>
|
</div>
|
<script>
|
(function(){
|
var form=document.getElementById('im-joinus-form');
|
if(!form)return;
|
form.addEventListener('submit',function(e){
|
e.preventDefault();
|
var btn=form.querySelector('.im-btn'),prev=form.querySelector('.im-notice');
|
if(prev)prev.remove();
|
btn.disabled=true;btn.classList.add('im-btn-loading');
|
var fd=new FormData(form);fd.append('action','im_joinus_submit');
|
fetch(imAjaxUrl,{method:'POST',body:fd}).then(function(r){return r.json();}).then(function(res){
|
if(res.success){
|
var w=document.getElementById('im-joinus-wrap');
|
w.innerHTML='<div class="im-form im-fade-in" style="text-align:center;padding:60px 40px">'
|
+'<div style="width:72px;height:72px;background:#d1fae5;color:#065f46;border-radius:50%;font-size:36px;line-height:72px;margin:0 auto 24px">✓</div>'
|
+'<h2 style="margin:0 0 12px">Application Received</h2>'
|
+'<p style="color:#6b7280;margin:0 0 8px">A confirmation email has been sent to your inbox.</p>'
|
+'<p style="color:#6b7280;margin:0">Please check your email and click the link to complete the detailed application form.</p></div>';
|
}else{
|
var d=document.createElement('div');d.className='im-notice error';d.textContent=res.data.message;
|
form.querySelector('.im-btn-wrap').before(d);
|
btn.disabled=false;btn.classList.remove('im-btn-loading');
|
}
|
}).catch(function(){btn.disabled=false;btn.classList.remove('im-btn-loading');alert('Network error. Please try again.');});
|
});
|
})();
|
</script>
|
<?php
|
return ob_get_clean();
|
});
|
|
/* ============================================================
|
Shortcode 2: [im_apply_form] — Detailed Application Form
|
============================================================ */
|
add_shortcode('im_apply_form', function() {
|
im_enqueue_form_styles();
|
ob_start();
|
|
$apply_token = sanitize_text_field($_GET['im_apply_token'] ?? '');
|
$candidate = $apply_token ? IM_Candidate::get_by_apply_token($apply_token) : null;
|
|
if (!$candidate):
|
// Check if the token exists but was already used (form already submitted)
|
$used = $apply_token ? IM_Candidate::get_by_apply_token_any($apply_token) : null;
|
if ($used && $used->apply_token_used): ?>
|
<div class="im-form-wrap">
|
<div class="im-form im-fade-in" style="text-align:center;padding:60px 40px">
|
<div style="width:72px;height:72px;background:#d1fae5;color:#065f46;border-radius:50%;font-size:36px;line-height:72px;margin:0 auto 24px">✓</div>
|
<h2 style="margin:0 0 12px">Application Already Submitted</h2>
|
<p style="color:#6b7280;margin:0 0 8px">You have already submitted your application form.</p>
|
<p style="color:#6b7280;margin:0">Our team will contact you after review, which typically takes 3–5 business days. Thank you for your patience!</p>
|
</div>
|
</div>
|
<?php else: ?>
|
<div class="im-form-wrap">
|
<div class="im-form" style="text-align:center;padding:60px 40px">
|
<div style="width:72px;height:72px;background:#fee2e2;color:#991b1b;border-radius:50%;
|
font-size:36px;line-height:72px;font-weight:700;margin:0 auto 24px">!</div>
|
<h2 style="margin:0 0 12px">Link Expired</h2>
|
<p style="color:#6b7280">This link has expired. Please fill out the Join Us form again, and we’ll send you a new application link shortly.</p>
|
</div>
|
</div>
|
<?php endif;
|
return ob_get_clean();
|
endif;
|
|
if (empty($candidate->apply_opened_at)) {
|
IM_Candidate::mark_apply_opened($candidate->id);
|
}
|
|
$p = [];
|
$degree = '';
|
$has_ach = -1;
|
?>
|
<div class="im-form-wrap" id="im-apply-wrap">
|
<div class="im-form">
|
<span class="im-step-badge">Step 2 of 2</span>
|
<h2>Application Form</h2>
|
<p class="im-subtitle">Hello, <?= esc_html($candidate->first_name) ?>! Please complete all the information below.</p>
|
<div class="im-notice error" id="im-apply-errors" style="display:none"></div>
|
|
<form method="post" enctype="multipart/form-data" id="im-apply-form" novalidate>
|
<?php wp_nonce_field('im_apply_submit_' . $candidate->id, 'im_apply_nonce'); ?>
|
<input type="hidden" name="im_apply_token" value="<?= esc_attr($apply_token) ?>">
|
|
<!-- ===== Part 1: Personal Information ===== -->
|
<div class="im-section-title">Part 1: Personal Information</div>
|
|
<div class="im-field">
|
<label>Preferred Name<span class="req">*</span>
|
<span class="hint">e.g. nickname or English name – this is how we'll address you</span>
|
</label>
|
<input class="im-input" type="text" name="preferred_name"
|
value="<?= esc_attr($p['preferred_name'] ?? '') ?>" placeholder="e.g. Alex" required>
|
</div>
|
|
<div class="im-row">
|
<div class="im-field">
|
<label>Country<span class="req">*</span></label>
|
<select class="im-select" name="country" id="im_country" required onchange="imLoadCities(this.value)">
|
<option value="">— Please Select —</option>
|
<?php
|
global $wpdb;
|
$countries = $wpdb->get_results("SELECT iso2, name FROM countries ORDER BY name ASC");
|
$sel_country = $p['country'] ?? '';
|
foreach ($countries as $c_row):
|
?>
|
<option value="<?= esc_attr($c_row->iso2) ?>" <?= $sel_country === $c_row->iso2 ? 'selected' : '' ?>>
|
<?= esc_html($c_row->name) ?>
|
</option>
|
<?php endforeach; ?>
|
</select>
|
</div>
|
<div class="im-field">
|
<label>City<span class="req">*</span></label>
|
<select class="im-select" name="city" id="im_city" required>
|
<option value="">— Please Select Country First —</option>
|
<?php
|
if ($sel_country):
|
$cities = $wpdb->get_results($wpdb->prepare("SELECT name FROM cities WHERE country_code = %s ORDER BY name ASC", $sel_country));
|
$sel_city = $p['city'] ?? '';
|
foreach ($cities as $c_row):
|
?>
|
<option value="<?= esc_attr($c_row->name) ?>" <?= $sel_city === $c_row->name ? 'selected' : '' ?>><?= esc_html($c_row->name) ?></option>
|
<?php endforeach; endif; ?>
|
</select>
|
</div>
|
</div>
|
|
<div class="im-row">
|
<div class="im-field">
|
<label>Phone Number<span class="req">*</span></label>
|
<input class="im-input" type="tel" name="phone"
|
value="<?= esc_attr($p['phone'] ?? '') ?>" placeholder="+1 416-xxx-xxxx">
|
</div>
|
<div class="im-field">
|
<label>Email</label>
|
<input class="im-input" type="email" value="<?= esc_attr($candidate->email) ?>" disabled>
|
</div>
|
</div>
|
|
<!-- ===== Part 2: Education Background ===== -->
|
<div class="im-section-title">Part 2: Education Background</div>
|
|
<div class="im-field">
|
<label>Highest Degree Level<span class="req">*</span></label>
|
<div class="im-radio-group">
|
<?php foreach (["Bachelor’s" => "Bachelor’s", "Master’s" => "Master’s", 'PhD' => 'PhD'] as $val => $lbl): ?>
|
<label>
|
<input type="radio" name="degree_level" value="<?= esc_attr($val) ?>"
|
<?= $degree === $val ? 'checked' : '' ?>
|
onchange="imToggleDegree(this.value)">
|
<span class="im-ck"></span>
|
<span><?= $lbl ?></span>
|
</label>
|
<?php endforeach; ?>
|
</div>
|
</div>
|
|
<div class="im-section-title" id="degree-main-label" style="margin-top:16px;display:none"></div>
|
|
<div class="im-row">
|
<div class="im-field">
|
<label>University / Institution<span class="req">*</span></label>
|
<input class="im-input" type="text" name="university"
|
value="<?= esc_attr($p['university'] ?? '') ?>" placeholder="e.g. University of Toronto">
|
</div>
|
<div class="im-field">
|
<label>Major / Field of Study<span class="req">*</span></label>
|
<input class="im-input" type="text" name="major"
|
value="<?= esc_attr($p['major'] ?? '') ?>" placeholder="e.g. Mathematics">
|
</div>
|
</div>
|
|
<div class="im-field">
|
<label>Graduation Year<span class="req">*</span></label>
|
<select class="im-select" name="grad_year" required>
|
<option value="">— Please Select —</option>
|
<?php for ($y = date('Y') + 4; $y >= 1990; $y--):
|
$sel_y = $p['grad_year'] ?? '';
|
?>
|
<option value="<?= $y ?>" <?= $sel_y == $y ? 'selected' : '' ?>><?= $y ?></option>
|
<?php endfor; ?>
|
</select>
|
</div>
|
|
<div class="im-field">
|
<label>GPA<span class="req">*</span></label>
|
<input class="im-input" type="number" step="0.01" min="0" name="gpa"
|
value="<?= esc_attr($p['gpa'] ?? '') ?>" placeholder="e.g. 3.85">
|
</div>
|
|
<div class="im-field">
|
<label>Dean's List Honors<span class="req">*</span></label>
|
<div class="im-radio-group">
|
<label>
|
<input type="radio" name="deans_list" value="yes" <?= ($p['deans_list'] ?? '') === 'yes' ? 'checked' : '' ?>>
|
<span class="im-ck"></span>
|
<span>Yes</span>
|
</label>
|
<label>
|
<input type="radio" name="deans_list" value="no" <?= ($p['deans_list'] ?? '') === 'no' ? 'checked' : '' ?>>
|
<span class="im-ck"></span>
|
<span>No</span>
|
</label>
|
</div>
|
</div>
|
|
<!-- Master's section (for PhD only, optional for direct PhD) -->
|
<div class="im-conditional" id="ms-section">
|
<div class="im-section-title" style="margin-top:16px">Master's Degree <span class="hint">(Optional) Skip if not applicable.</span></div>
|
<div class="im-row">
|
<div class="im-field">
|
<label>University</label>
|
<input class="im-input" type="text" name="ms_university"
|
value="<?= esc_attr($p['ms_university'] ?? '') ?>" placeholder="e.g. University of Toronto">
|
</div>
|
<div class="im-field">
|
<label>Major</label>
|
<input class="im-input" type="text" name="ms_major"
|
value="<?= esc_attr($p['ms_major'] ?? '') ?>" placeholder="e.g. Mathematics">
|
</div>
|
</div>
|
<div class="im-field">
|
<label>Graduation Year</label>
|
<select class="im-select" name="ms_grad_year">
|
<option value="">— Please Select —</option>
|
<?php for ($y = date('Y') + 4; $y >= 1990; $y--):
|
$sel_my = $p['ms_grad_year'] ?? '';
|
?>
|
<option value="<?= $y ?>" <?= $sel_my == $y ? 'selected' : '' ?>><?= $y ?></option>
|
<?php endfor; ?>
|
</select>
|
</div>
|
</div>
|
|
<!-- Undergraduate section (for Master's and PhD) -->
|
<div class="im-conditional" id="ug-section">
|
<div class="im-section-title" style="margin-top:16px">Undergraduate Degree</div>
|
<div class="im-row">
|
<div class="im-field">
|
<label>University<span class="req">*</span></label>
|
<input class="im-input" type="text" name="ug_university"
|
value="<?= esc_attr($p['ug_university'] ?? '') ?>" placeholder="e.g. University of Waterloo">
|
</div>
|
<div class="im-field">
|
<label>Major<span class="req">*</span></label>
|
<input class="im-input" type="text" name="ug_major"
|
value="<?= esc_attr($p['ug_major'] ?? '') ?>" placeholder="e.g. Computer Science">
|
</div>
|
</div>
|
<div class="im-field">
|
<label>Graduation Year<span class="req">*</span></label>
|
<select class="im-select" name="ug_grad_year">
|
<option value="">— Please Select —</option>
|
<?php for ($y = date('Y') + 2; $y >= 1990; $y--):
|
$sel_uy = $p['ug_grad_year'] ?? '';
|
?>
|
<option value="<?= $y ?>" <?= $sel_uy == $y ? 'selected' : '' ?>><?= $y ?></option>
|
<?php endfor; ?>
|
</select>
|
</div>
|
</div>
|
|
<div class="im-field">
|
<label>Do you have a Canadian high school background?<span class="req">*</span>
|
<span class="hint">e.g., OSSD or BC curriculum</span>
|
</label>
|
<div class="im-radio-group">
|
<label>
|
<input type="radio" name="ca_highschool" value="1"
|
<?= ($p['ca_highschool'] ?? '') === '1' ? 'checked' : '' ?>
|
onchange="imToggleCaHs(1)">
|
<span class="im-ck"></span>
|
<span>Yes</span>
|
</label>
|
<label>
|
<input type="radio" name="ca_highschool" value="0"
|
<?= ($p['ca_highschool'] ?? '') === '0' ? 'checked' : '' ?>
|
onchange="imToggleCaHs(0)">
|
<span class="im-ck"></span>
|
<span>No</span>
|
</label>
|
</div>
|
</div>
|
|
<div class="im-conditional" id="ca-hs-section">
|
<div class="im-field">
|
<label>High School<span class="req">*</span></label>
|
<input class="im-input" type="text" name="ca_highschool_name"
|
value="<?= esc_attr($p['ca_highschool_name'] ?? '') ?>" placeholder="e.g. Toronto Secondary School">
|
</div>
|
</div>
|
|
<div class="im-field">
|
<label>Transcript Upload<span class="req">*</span><span class="hint">PDF / JPG / PNG supported, multiple files allowed</span></label>
|
<div class="im-upload-box" id="transcript-box">
|
<div class="im-upload-icon">📄</div>
|
<p>Click to select or drag files here</p>
|
<input type="file" name="transcript_files[]" multiple accept=".pdf,.jpg,.jpeg,.png"
|
onchange="imShowFiles(this,'transcript-list')">
|
</div>
|
<div class="im-file-list" id="transcript-list"></div>
|
</div>
|
|
|
<!-- ===== Part 3: English Fluency ===== -->
|
<div class="im-section-title">Part 3: English Fluency</div>
|
<div class="im-field">
|
<label>English Fluency<span class="req">*</span></label>
|
<select class="im-select" name="languages" required>
|
<option value="">— Please Select —</option>
|
<option value="Native" <?= ($p['languages'] ?? '') === 'Native' ? 'selected' : '' ?>>Native</option>
|
<option value="Fluent" <?= ($p['languages'] ?? '') === 'Fluent' ? 'selected' : '' ?>>Fluent</option>
|
<option value="Basic" <?= ($p['languages'] ?? '') === 'Basic' ? 'selected' : '' ?>>Basic</option>
|
</select>
|
</div>
|
|
<!-- ===== Part 4: Experience & Achievements ===== -->
|
<div class="im-section-title">Part 4: Experience & Achievements</div>
|
|
<div class="im-field">
|
<label>Teaching Experience<span class="req">*</span>
|
<span class="hint">Please describe subjects, years, and student levels</span>
|
</label>
|
<textarea class="im-textarea" name="teaching_exp" rows="4"
|
placeholder="e.g. 3 years of high school math, taught Grade 10–12 students..."><?= esc_textarea($p['teaching_exp'] ?? '') ?></textarea>
|
</div>
|
|
<div class="im-field">
|
<label>Competition Awards & Certificates (Optional)<span class="req">*</span>
|
<span class="hint">Please list any competition awards, rankings, or certificates you have received</span>
|
</label>
|
<div class="im-radio-group">
|
<label>
|
<input type="radio" name="has_achievement" value="1"
|
<?= $has_ach === 1 ? 'checked' : '' ?>
|
onchange="imToggleAch(1)">
|
<span class="im-ck"></span>
|
<span>Yes</span>
|
</label>
|
<label>
|
<input type="radio" name="has_achievement" value="0"
|
<?= $has_ach === 0 ? 'checked' : '' ?>
|
onchange="imToggleAch(0)">
|
<span class="im-ck"></span>
|
<span>No</span>
|
</label>
|
</div>
|
</div>
|
|
<div class="im-conditional" id="ach-section">
|
<div class="im-field">
|
<label>Achievement Type<span class="req">*</span></label>
|
<select class="im-select" name="achievement_type" onchange="imToggleAchDesc(this.value)">
|
<option value="">— Please Select —</option>
|
<?php
|
$ach_types = ['Academic Competition Awards','Math Competition','Physics Competition','Chemistry Competition','Biology Competition','Computing Competition','Language Awards'];
|
$sel_at = $p['achievement_type'] ?? '';
|
foreach ($ach_types as $at):
|
?>
|
<option value="<?= esc_attr($at) ?>" <?= $sel_at === $at ? 'selected' : '' ?>><?= esc_html($at) ?></option>
|
<?php endforeach; ?>
|
<option value="other" <?= $sel_at === 'other' ? 'selected' : '' ?>>Other (please specify below)</option>
|
</select>
|
</div>
|
<div class="im-field im-conditional" id="ach-desc-group">
|
<label>Achievement Description<span class="req">*</span></label>
|
<textarea class="im-textarea" name="achievement_desc" rows="3"
|
placeholder="Please describe your awards, rankings, etc..."><?= esc_textarea($p['achievement_desc'] ?? '') ?></textarea>
|
</div>
|
<div class="im-field">
|
<label>Upload Supporting Documents<span class="req">*</span>
|
<span class="hint">PDF / JPG / PNG supported, multiple files allowed</span>
|
</label>
|
<div class="im-upload-box">
|
<div class="im-upload-icon">🏆</div>
|
<p>Click to select or drag supporting documents</p>
|
<input type="file" name="achievement_files[]" multiple accept=".pdf,.jpg,.jpeg,.png"
|
onchange="imShowFiles(this,'ach-list')">
|
</div>
|
<div class="im-file-list" id="ach-list"></div>
|
</div>
|
</div>
|
|
<!-- ===== Part 5: Teaching Subjects ===== -->
|
<div class="im-section-title">Part 5: Teaching Subjects (Select All That Apply)<span class="req">*</span></div>
|
|
<?php
|
// Fetch all subject_cats dynamically
|
$subject_cats = get_terms([
|
'taxonomy' => 'subject_cat',
|
'hide_empty' => false,
|
'orderby' => 'name'
|
]);
|
|
$sel_subjects = (array)($p['subjects'] ?? []);
|
|
if (!is_wp_error($subject_cats) && !empty($subject_cats)):
|
foreach ($subject_cats as $cat):
|
$subjects = get_posts([
|
'post_type' => 'subject',
|
'posts_per_page' => -1,
|
'tax_query' => [
|
[
|
'taxonomy' => 'subject_cat',
|
'field' => 'term_id',
|
'terms' => $cat->term_id
|
]
|
],
|
'orderby' => 'title',
|
'order' => 'ASC'
|
]);
|
if (empty($subjects)) continue;
|
?>
|
<div style="margin-bottom:20px">
|
<div style="font-size:13px;font-weight:700;color:#6b7280;margin-bottom:8px;
|
text-transform:uppercase;letter-spacing:.5px">
|
🔹 <?= esc_html($cat->name) ?>
|
</div>
|
<div class="im-checkbox-grid">
|
<?php foreach ($subjects as $sub):
|
$checked = in_array((string)$sub->ID, $sel_subjects, true) ? 'checked' : '';
|
?>
|
<label>
|
<input type="checkbox" name="subjects[]"
|
value="<?= esc_attr($sub->ID) ?>" <?= $checked ?>>
|
<span class="im-ck"></span>
|
<span><?= esc_html($sub->post_title) ?></span>
|
</label>
|
<?php endforeach; ?>
|
</div>
|
</div>
|
<?php endforeach; endif; ?>
|
|
<!-- ===== Part 6: Additional Documents ===== -->
|
<div class="im-section-title">Part 6: Additional Documents (Optional)</div>
|
<div class="im-field">
|
<div class="im-upload-box">
|
<div class="im-upload-icon">📎</div>
|
<p>Additional materials (resume, reference letters, etc.)</p>
|
<p style="font-size:12px;color:#9ca3af;margin-top:4px">PDF / JPG / PNG supported, multiple files allowed</p>
|
<input type="file" name="extra_files[]" multiple accept=".pdf,.jpg,.jpeg,.png"
|
onchange="imShowFiles(this,'extra-list')">
|
</div>
|
<div class="im-file-list" id="extra-list"></div>
|
</div>
|
<div class="im-field">
|
<label>Additional Notes</label>
|
<textarea class="im-textarea" name="extra_notes" rows="3"
|
placeholder="If you have anything else to add, please write here..."><?= esc_textarea($p['extra_notes'] ?? '') ?></textarea>
|
</div>
|
|
<!-- ===== Part 7: Declaration & Submission ===== -->
|
<div class="im-section-title">Part 7: Declaration & Submission</div>
|
<div class="im-declaration">
|
<label>
|
<input type="checkbox" name="decl_truth" value="1" <?= !empty($p['decl_truth']) ? 'checked' : '' ?>>
|
<span class="im-ck"></span>
|
<span>I confirm that all information and uploaded documents above are true and accurate. I am willing to bear the corresponding responsibility for any falsification.</span>
|
</label>
|
<label>
|
<input type="checkbox" name="decl_privacy" value="1" <?= !empty($p['decl_privacy']) ? 'checked' : '' ?>>
|
<span class="im-ck"></span>
|
<span>I agree that the company may collect my personal information solely for recruitment evaluation purposes, in accordance with the relevant privacy policy.</span>
|
</label>
|
</div>
|
|
<div class="im-btn-wrap">
|
<button type="submit" class="im-btn">Submit Application →</button>
|
</div>
|
</form>
|
</div>
|
</div>
|
|
<script>
|
function imToggleDegree(val) {
|
var mainLabel = document.getElementById('degree-main-label');
|
var msSection = document.getElementById('ms-section');
|
var ugSection = document.getElementById('ug-section');
|
if (val === "Bachelor’s") {
|
mainLabel.style.display = 'block';
|
mainLabel.textContent = 'Undergraduate Degree';
|
msSection.style.display = 'none';
|
ugSection.style.display = 'none';
|
} else if (val === "Master’s") {
|
mainLabel.style.display = 'block';
|
mainLabel.textContent = "Master’s Degree";
|
msSection.style.display = 'none';
|
ugSection.style.display = 'block';
|
} else if (val === 'PhD') {
|
mainLabel.style.display = 'block';
|
mainLabel.textContent = 'PhD Degree';
|
msSection.style.display = 'block';
|
ugSection.style.display = 'block';
|
} else {
|
mainLabel.style.display = 'none';
|
msSection.style.display = 'none';
|
ugSection.style.display = 'none';
|
}
|
}
|
function imToggleAch(val) {
|
document.getElementById('ach-section').style.display = val ? 'block' : 'none';
|
}
|
function imToggleCaHs(val) {
|
document.getElementById('ca-hs-section').style.display = val ? 'block' : 'none';
|
}
|
function imToggleAchDesc(val) {
|
var el = document.getElementById('ach-desc-group');
|
if (el) el.style.display = val === 'other' ? 'block' : 'none';
|
}
|
function imLoadCities(code) {
|
var citySel = document.getElementById('im_city');
|
if(!code) {
|
citySel.innerHTML='<option value="">— Please Select Country First —</option>';
|
_updateCs(citySel);
|
return;
|
}
|
citySel.innerHTML='<option value="">Loading...</option>';
|
_updateCs(citySel);
|
var fd=new FormData();fd.append('action','im_get_cities');fd.append('country',code);
|
fetch(imAjaxUrl,{method:'POST',body:fd}).then(r=>r.json()).then(res=>{
|
if(res.success){
|
var html='<option value="">— Please Select —</option>';
|
res.data.forEach(c=>html+='<option value="'+c+'">'+c+'</option>');
|
citySel.innerHTML=html;
|
_updateCs(citySel);
|
}
|
});
|
}
|
function _updateCs(sel) {
|
var csWrap = sel.parentNode;
|
if(csWrap && csWrap.classList.contains('im-cs')) {
|
csWrap.parentNode.insertBefore(sel, csWrap);
|
csWrap.remove();
|
sel.removeAttribute('data-cs-init');
|
}
|
if (window.imInitCS) window.imInitCS(sel);
|
}
|
|
function imShowFiles(input, listId) {
|
var el = document.getElementById(listId);
|
el.innerHTML = '';
|
Array.from(input.files).forEach(function(f) {
|
var d = document.createElement('div');
|
d.className = 'im-file-item';
|
d.textContent = f.name + ' (' + (f.size/1024).toFixed(0) + ' KB)';
|
el.appendChild(d);
|
});
|
}
|
document.querySelectorAll('.im-upload-box').forEach(function(box) {
|
box.addEventListener('dragover', function(e) { e.preventDefault(); box.classList.add('drag'); });
|
box.addEventListener('dragleave', function() { box.classList.remove('drag'); });
|
box.addEventListener('drop', function(e) {
|
e.preventDefault(); box.classList.remove('drag');
|
var input = box.querySelector('input[type=file]');
|
if (input && e.dataTransfer.files.length) {
|
input.files = e.dataTransfer.files;
|
var listId = input.getAttribute('onchange').match(/'([^']+)'/);
|
if (listId) imShowFiles(input, listId[1]);
|
}
|
});
|
});
|
(function(){
|
var deg = document.querySelector('input[name=degree_level]:checked');
|
if (deg) imToggleDegree(deg.value);
|
var ach = document.querySelector('input[name=has_achievement]:checked');
|
if (ach) imToggleAch(parseInt(ach.value));
|
var achD = document.querySelector('select[name=achievement_type]');
|
if (achD) imToggleAchDesc(achD.value);
|
var caHs = document.querySelector('input[name=ca_highschool]:checked');
|
if (caHs) imToggleCaHs(parseInt(caHs.value));
|
})();
|
|
/* ===== Custom Select Enhancement ===== */
|
(function(){
|
var ARROW='<svg class="im-cs-arrow" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"/></svg>';
|
window.imInitCS = function(sel) {
|
if(sel.dataset.csInit)return; sel.dataset.csInit='1';
|
var opts=sel.querySelectorAll('option'),searchable=opts.length>8;
|
var cur=sel.options[sel.selectedIndex],isPh=!cur||cur.value==='';
|
var wrap=document.createElement('div');wrap.className='im-cs';
|
var trig=document.createElement('div');trig.className='im-cs-trigger';trig.tabIndex=0;
|
trig.innerHTML='<span class="im-cs-text'+(isPh?' im-cs-ph':'')+'">'+(cur?cur.textContent.trim():'')+'</span>'+ARROW;
|
var drop=document.createElement('div');drop.className='im-cs-drop';var html='';
|
if(searchable)html+='<div class="im-cs-search-wrap"><input type="text" class="im-cs-search" placeholder="Search..."></div>';
|
html+='<div class="im-cs-opts">';opts.forEach(function(o){if(o.value==='')return;html+='<div class="im-cs-opt'+(o.selected?' sel':'')+'" data-val="'+o.value+'">'+o.textContent.trim()+'</div>';});html+='</div>';drop.innerHTML=html;
|
wrap.appendChild(trig);wrap.appendChild(drop);sel.parentNode.insertBefore(wrap,sel);wrap.appendChild(sel);sel.removeAttribute('required');
|
var textEl=trig.querySelector('.im-cs-text'),csOpts=drop.querySelectorAll('.im-cs-opt'),sInput=drop.querySelector('.im-cs-search');
|
trig.addEventListener('click',function(e){e.stopPropagation();document.querySelectorAll('.im-cs.open').forEach(function(o){if(o!==wrap)o.classList.remove('open');});wrap.classList.toggle('open');if(wrap.classList.contains('open')){if(sInput){setTimeout(function(){sInput.value='';sInput.dispatchEvent(new Event('input'));sInput.focus();},60);}var selOpt=drop.querySelector('.im-cs-opt.sel');if(selOpt){setTimeout(function(){selOpt.scrollIntoView({block:'nearest'});},60);}}});
|
csOpts.forEach(function(opt){opt.addEventListener('click',function(e){e.stopPropagation();sel.value=this.dataset.val;textEl.textContent=this.textContent.trim();textEl.classList.remove('im-cs-ph');csOpts.forEach(function(o){o.classList.remove('sel');});this.classList.add('sel');wrap.classList.remove('open');sel.dispatchEvent(new Event('change',{bubbles:true}));});});
|
if(sInput){sInput.addEventListener('input',function(){var q=this.value.toLowerCase(),has=false;csOpts.forEach(function(o){var m=o.textContent.toLowerCase().indexOf(q)>-1;o.classList.toggle('hid',!m);if(m)has=true;});var emp=drop.querySelector('.im-cs-empty');if(!has){if(!emp){emp=document.createElement('div');emp.className='im-cs-empty';emp.textContent='No results found';drop.querySelector('.im-cs-opts').appendChild(emp);}emp.style.display='';}else if(emp){emp.style.display='none';}});sInput.addEventListener('click',function(e){e.stopPropagation();});}
|
trig.addEventListener('keydown',function(e){if(e.key==='Enter'||e.key===' '){e.preventDefault();trig.click();}else if(e.key==='Escape'){wrap.classList.remove('open');}});
|
};
|
document.querySelectorAll('select.im-select').forEach(window.imInitCS);
|
document.addEventListener('click',function(){document.querySelectorAll('.im-cs.open').forEach(function(el){el.classList.remove('open');});});
|
})();
|
|
/* ===== Apply Form AJAX Submission ===== */
|
(function(){
|
var form=document.getElementById('im-apply-form');
|
if(!form)return;
|
|
function clearFieldErrors(){
|
form.querySelectorAll('.im-field-error').forEach(function(el){el.remove();});
|
form.querySelectorAll('.im-field.has-error,.im-declaration.has-error').forEach(function(el){el.classList.remove('has-error');});
|
}
|
function showFieldError(name,msg){
|
var input=form.querySelector('[name="'+name+'"]')||form.querySelector('[name="'+name+'[]"]');
|
if(!input)return;
|
var field=input.closest('.im-field')||input.closest('.im-declaration');
|
if(!field){field=input.closest('.im-checkbox-grid');if(field)field=field.parentNode;}
|
if(!field)return;
|
field.classList.add('has-error');
|
if(msg){var err=document.createElement('div');err.className='im-field-error';err.textContent=msg;
|
field.appendChild(err);}
|
}
|
|
form.addEventListener('submit',function(e){
|
e.preventDefault();
|
var btn=form.querySelector('.im-btn'),errBox=document.getElementById('im-apply-errors');
|
errBox.style.display='none';errBox.innerHTML='';
|
clearFieldErrors();
|
btn.disabled=true;btn.classList.add('im-btn-loading');
|
var fd=new FormData(form);fd.append('action','im_apply_submit');
|
var xhr=new XMLHttpRequest();
|
xhr.open('POST',imAjaxUrl);
|
xhr.onload=function(){
|
try{var res=JSON.parse(xhr.responseText);
|
if(res.success){
|
var w=document.getElementById('im-apply-wrap');
|
w.innerHTML='<div class="im-form im-fade-in" style="text-align:center;padding:60px 40px">'
|
+'<div style="width:72px;height:72px;background:#d1fae5;color:#065f46;border-radius:50%;font-size:36px;line-height:72px;margin:0 auto 24px">✓</div>'
|
+'<h2 style="margin:0 0 12px">Application Submitted!</h2>'
|
+'<p style="color:#6b7280;margin:0 0 8px">Thank you for your application.</p>'
|
+'<p style="color:#6b7280;margin:0">Our team will review your submission within 3–5 business days. If selected, interview instructions will be sent via email.</p></div>';
|
w.scrollIntoView({behavior:'smooth',block:'center'});
|
}else{
|
if(res.data.field_errors){
|
var fe=res.data.field_errors,first=null;
|
for(var k in fe){showFieldError(k,fe[k]);if(!first){var el=form.querySelector('[name="'+k+'"]')||form.querySelector('[name="'+k+'[]"]');if(el)first=el;}}
|
if(first){var st=first.closest('.im-field')||first.closest('.im-declaration');if(!st){st=first.closest('.im-checkbox-grid');if(st)st=st.parentNode;}if(st)st.scrollIntoView({behavior:'smooth',block:'center'});}
|
}else{
|
var msgs=res.data.messages||[res.data.message||'An error occurred.'];
|
errBox.innerHTML=msgs.map(function(m){return '<div>· '+m+'</div>';}).join('');
|
errBox.style.display='';errBox.scrollIntoView({behavior:'smooth',block:'center'});
|
}
|
btn.disabled=false;btn.classList.remove('im-btn-loading');
|
}}catch(ex){btn.disabled=false;btn.classList.remove('im-btn-loading');alert('An error occurred. Please try again.');}
|
};
|
xhr.onerror=function(){btn.disabled=false;btn.classList.remove('im-btn-loading');alert('Network error. Please try again.');};
|
xhr.send(fd);
|
});
|
})();
|
</script>
|
<?php
|
return ob_get_clean();
|
});
|