Spaces:
Paused
Paused
{% extends "base.html" %} | |
{% block title %}Apply for {{ job.role }} - Codingo{% endblock %} | |
{% block hero %} | |
<section class="hero" style="padding: 3rem 1rem;"> | |
<div class="container"> | |
<div class="hero-content"> | |
<h1>Apply for {{ job.role }}</h1> | |
<p>{{ job.company }}{% if job.seniority %} • {{ job.seniority }}{% endif %}</p> | |
</div> | |
</div> | |
</section> | |
{% endblock %} | |
{% block content %} | |
<section class="content-section"> | |
<!-- <ul class="breadcrumbs"> | |
<li><a href="{{ url_for('index') }}">Home</a></li> | |
<li><a href="{{ url_for('jobs') }}">Jobs</a></li> | |
<li><a href="{{ url_for('job_detail', job_id=job.id) }}">{{ job.role }}</a></li> | |
<li>Apply</li> | |
</ul> --> | |
<div class="card"> | |
<div class="card-header"> | |
<h2>Submit Your Application</h2> | |
<p>Please upload your resume (PDF, DOCX). Your file will be saved securely for recruiters to review.</p> | |
</div> | |
<div class="card-body"> | |
<!-- Application Form --> | |
<form method="POST" enctype="multipart/form-data"> | |
<div class="form-group"> | |
<label for="resume">Upload Resume</label> | |
<!-- Resume upload remains mandatory. The file will be stored for recruiter review but is no longer parsed automatically. --> | |
<input type="file" name="resume" id="resume" class="form-control" required accept=".pdf,.doc,.docx"> | |
<!-- Parse Resume button sits beside the upload to allow users to extract information from their CV. It uses a | |
type="button" so that clicking it does not submit the form. The actual parsing logic is defined in | |
the script at the bottom of this template. --> | |
<button type="button" id="parse-resume" class="btn btn-secondary" style="margin-top:0.5rem;">Parse Resume</button> | |
</div> | |
<!-- Name field added to capture the applicant's full name. This input can be autofilled by the resume parser, | |
but remains editable so applicants can correct any mistakes. --> | |
<div class="form-group"> | |
<label for="full-name">Full Name</label> | |
<input type="text" name="full_name" id="full-name" class="form-control" placeholder="e.g. Jane Doe" required> | |
</div> | |
<!-- | |
Collect the candidate's skills, experience and education manually. | |
These fields allow applicants to highlight their background even when resume | |
parsing is disabled. Entries can be separated by commas, semicolons or newlines; | |
the backend will normalise them into lists. | |
--> | |
<div class="form-group"> | |
<label for="skills">Skills</label> | |
<textarea name="skills" id="skills" class="form-control" rows="3" placeholder="e.g. Python, Data Analysis, Project Management" required></textarea> | |
</div> | |
<div class="form-group"> | |
<label for="experience">Experience</label> | |
<textarea name="experience" id="experience" class="form-control" rows="3" placeholder="e.g. 3 years at TechCorp as a Backend Developer" required></textarea> | |
</div> | |
<div class="form-group"> | |
<label for="education">Education</label> | |
<textarea name="education" id="education" class="form-control" rows="3" placeholder="e.g. B.Sc. in Computer Science, M.Sc. in Data Science" required></textarea> | |
</div> | |
<!-- Interview guidelines removed from this page. They are now displayed on the | |
"My Applications" page so applicants see them before taking the interview. --> | |
<div class="application-actions" style="margin-top: 2rem;"> | |
<button type="submit" class="btn btn-primary">Submit Application</button> | |
</div> | |
</form> | |
<div style="margin-top: 1.5rem; text-align: center;"> | |
<a href="{{ url_for('job_detail', job_id=job.id) }}" class="btn btn-outline">Back to Job Details</a> | |
</div> | |
</div> | |
</div> | |
</section> | |
<style> | |
.form-group label { | |
font-weight: 600; | |
color: var(--primary); | |
margin-bottom: 0.5rem; | |
display: block; | |
} | |
.form-control { | |
width: 100%; | |
padding: 0.75rem; | |
font-size: 1rem; | |
border-radius: 6px; | |
border: 1px solid #ccc; | |
} | |
.application-actions { | |
text-align: center; | |
} | |
.btn-primary { | |
background: linear-gradient(135deg, var(--primary), var(--secondary)); | |
color: white; | |
padding: 0.75rem 1.5rem; | |
font-weight: 500; | |
border: none; | |
border-radius: 6px; | |
cursor: pointer; | |
} | |
.btn-primary:hover { | |
opacity: 0.9; | |
} | |
/* Secondary button styling used for the "Parse Resume" control */ | |
.btn-secondary { | |
background: var(--secondary); | |
color: white; | |
padding: 0.75rem 1.5rem; | |
font-weight: 500; | |
border: none; | |
border-radius: 6px; | |
cursor: pointer; | |
} | |
.btn-secondary:hover { | |
opacity: 0.9; | |
} | |
</style> | |
{# Resume parsing script: attaches click handler to the Parse Resume button. It performs an asynchronous | |
POST to a placeholder endpoint (`/parse_resume`) with the uploaded file and, upon success, | |
populates the corresponding form fields. Users can still edit the populated fields. #} | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
const parseBtn = document.getElementById('parse-resume'); | |
if (!parseBtn) return; | |
parseBtn.addEventListener('click', function() { | |
const resumeInput = document.getElementById('resume'); | |
if (!resumeInput || !resumeInput.files || resumeInput.files.length === 0) { | |
alert('Please upload your resume before parsing.'); | |
return; | |
} | |
const formData = new FormData(); | |
formData.append('resume', resumeInput.files[0]); | |
fetch('/parse_resume', { | |
method: 'POST', | |
body: formData | |
}).then(resp => resp.json()) | |
.then(data => { | |
if (data) { | |
if (data.name && document.getElementById('full-name')) { | |
document.getElementById('full-name').value = data.name; | |
} | |
if (data.skills && document.getElementById('skills')) { | |
document.getElementById('skills').value = data.skills; | |
} | |
if (data.education && document.getElementById('education')) { | |
document.getElementById('education').value = data.education; | |
} | |
if (data.experience && document.getElementById('experience')) { | |
document.getElementById('experience').value = data.experience; | |
} | |
} | |
}) | |
.catch(err => { | |
console.error(err); | |
alert('Unable to parse resume. Please try again later.'); | |
}); | |
}); | |
}); | |
</script> | |
{% endblock %} | |