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="application-container"> | |
<div class="card application-card"> | |
<div class="card-header"> | |
<h2>Submit Your Application</h2> | |
<p>Please upload your resume and fill in the required information below.</p> | |
</div> | |
<div class="card-body"> | |
<form method="POST" enctype="multipart/form-data" id="application-form"> | |
<!-- Resume Upload Section --> | |
<div class="upload-section"> | |
<div class="form-group"> | |
<label for="resume"> | |
<i class="upload-icon">π</i> | |
Upload Resume | |
</label> | |
<div class="file-input-wrapper"> | |
<input type="file" name="resume" id="resume" class="file-input" required accept=".pdf,.doc,.docx"> | |
<div class="file-input-display"> | |
<span class="file-placeholder">Choose file... (PDF, DOCX)</span> | |
<span class="file-name"></span> | |
</div> | |
</div> | |
<button type="button" id="parse-resume" class="btn btn-secondary mt-2"> | |
<span class="btn-icon">π</span> Parse Resume | |
</button> | |
</div> | |
</div> | |
<!-- Personal Information --> | |
<div class="form-section"> | |
<h3 class="section-title">Personal Information</h3> | |
<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> | |
</div> | |
<!-- Professional Details --> | |
<div class="form-section"> | |
<h3 class="section-title">Professional Details</h3> | |
<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> | |
<small class="form-text">Separate skills with commas</small> | |
</div> | |
<div class="form-group"> | |
<label for="experience">Experience</label> | |
<textarea name="experience" id="experience" class="form-control" rows="4" | |
placeholder="e.g. 3 years at TechCorp as a Backend Developer" required></textarea> | |
<small class="form-text">List your relevant work experience</small> | |
</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> | |
<small class="form-text">Include degrees, certifications, and relevant coursework</small> | |
</div> | |
</div> | |
<!-- Submit Section --> | |
<div class="application-actions"> | |
<button type="submit" class="btn btn-primary btn-lg"> | |
<span class="btn-icon">β</span> Submit Application | |
</button> | |
<a href="{{ url_for('job_detail', job_id=job.id) }}" class="btn btn-outline"> | |
<span class="btn-icon">β</span> Back to Job Details | |
</a> | |
</div> | |
</form> | |
</div> | |
</div> | |
<!-- Job Summary Sidebar --> | |
<div class="job-summary-sidebar"> | |
<div class="card"> | |
<div class="card-header"> | |
<h3>Job Summary</h3> | |
</div> | |
<div class="card-body"> | |
<div class="summary-item"> | |
<strong>Role:</strong> {{ job.role }} | |
</div> | |
<div class="summary-item"> | |
<strong>Company:</strong> {{ job.company }} | |
</div> | |
{% if job.seniority %} | |
<div class="summary-item"> | |
<strong>Seniority:</strong> {{ job.seniority }} | |
</div> | |
{% endif %} | |
{% if job.location %} | |
<div class="summary-item"> | |
<strong>Location:</strong> {{ job.location }} | |
</div> | |
{% endif %} | |
{% if job.salary %} | |
<div class="summary-item"> | |
<strong>Salary:</strong> {{ job.salary }} | |
</div> | |
{% endif %} | |
</div> | |
</div> | |
</div> | |
</div> | |
</section> | |
<style> | |
/* Application Container */ | |
.application-container { | |
display: grid; | |
grid-template-columns: 1fr; | |
gap: 2rem; | |
} | |
@media (min-width: 992px) { | |
.application-container { | |
grid-template-columns: 2fr 1fr; | |
} | |
} | |
/* Card Enhancements */ | |
.application-card { | |
background: white; | |
border-radius: 12px; | |
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); | |
overflow: hidden; | |
} | |
.application-card .card-header { | |
background: linear-gradient(135deg, var(--primary), var(--secondary)); | |
color: white; | |
padding: 2rem; | |
} | |
.application-card .card-header h2 { | |
margin: 0 0 0.5rem 0; | |
font-size: 1.75rem; | |
} | |
.application-card .card-header p { | |
margin: 0; | |
opacity: 0.9; | |
} | |
.application-card .card-body { | |
padding: 2rem; | |
} | |
/* Form Sections */ | |
.form-section { | |
margin-bottom: 2.5rem; | |
} | |
.section-title { | |
font-size: 1.25rem; | |
color: var(--primary); | |
margin-bottom: 1.5rem; | |
padding-bottom: 0.5rem; | |
border-bottom: 2px solid #e9ecef; | |
} | |
/* Form Elements */ | |
.form-group { | |
margin-bottom: 1.5rem; | |
} | |
.form-group label { | |
font-weight: 600; | |
color: var(--dark); | |
margin-bottom: 0.5rem; | |
display: flex; | |
align-items: center; | |
gap: 0.5rem; | |
} | |
.form-control { | |
width: 100%; | |
padding: 0.875rem; | |
font-size: 1rem; | |
border-radius: 8px; | |
border: 2px solid #e9ecef; | |
transition: all 0.3s ease; | |
background-color: #f8f9fa; | |
} | |
.form-control:focus { | |
outline: none; | |
border-color: var(--primary); | |
background-color: white; | |
box-shadow: 0 0 0 4px rgba(67, 97, 238, 0.1); | |
} | |
.form-text { | |
display: block; | |
margin-top: 0.5rem; | |
color: #6c757d; | |
font-size: 0.875rem; | |
} | |
/* File Upload Styling */ | |
.upload-section { | |
background-color: #f8f9fa; | |
padding: 1.5rem; | |
border-radius: 8px; | |
margin-bottom: 2rem; | |
} | |
.upload-icon { | |
font-size: 1.5rem; | |
} | |
.file-input-wrapper { | |
position: relative; | |
overflow: hidden; | |
display: inline-block; | |
width: 100%; | |
} | |
.file-input { | |
position: absolute; | |
left: -9999px; | |
} | |
.file-input-display { | |
display: block; | |
padding: 0.875rem; | |
border: 2px dashed var(--primary); | |
border-radius: 8px; | |
background-color: white; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
text-align: center; | |
} | |
.file-input-wrapper:hover .file-input-display { | |
border-color: var(--secondary); | |
background-color: #f8f9fa; | |
} | |
.file-placeholder { | |
color: #6c757d; | |
} | |
.file-name { | |
color: var(--primary); | |
font-weight: 500; | |
} | |
/* Button Enhancements */ | |
.btn { | |
display: inline-flex; | |
align-items: center; | |
gap: 0.5rem; | |
padding: 0.75rem 1.5rem; | |
font-weight: 500; | |
border-radius: 8px; | |
transition: all 0.3s ease; | |
} | |
.btn-lg { | |
padding: 1rem 2rem; | |
font-size: 1.1rem; | |
} | |
.btn-secondary { | |
background: #6c757d; | |
color: white; | |
border: none; | |
} | |
.btn-secondary:hover { | |
background: #5a6268; | |
transform: translateY(-2px); | |
} | |
.btn-icon { | |
font-size: 1.2rem; | |
} | |
/* Application Actions */ | |
.application-actions { | |
display: flex; | |
gap: 1rem; | |
margin-top: 2rem; | |
padding-top: 2rem; | |
border-top: 2px solid #e9ecef; | |
flex-wrap: wrap; | |
} | |
/* Job Summary Sidebar */ | |
.job-summary-sidebar .card { | |
position: sticky; | |
top: 2rem; | |
} | |
.job-summary-sidebar .card-header { | |
background-color: #f8f9fa; | |
padding: 1rem 1.5rem; | |
} | |
.job-summary-sidebar .card-header h3 { | |
margin: 0; | |
font-size: 1.2rem; | |
color: var(--primary); | |
} | |
.summary-item { | |
padding: 0.75rem 0; | |
border-bottom: 1px solid #e9ecef; | |
} | |
.summary-item:last-child { | |
border-bottom: none; | |
} | |
/* Responsive Adjustments */ | |
@media (max-width: 768px) { | |
.application-card .card-header { | |
padding: 1.5rem; | |
} | |
.application-card .card-body { | |
padding: 1.5rem; | |
} | |
.form-section { | |
margin-bottom: 2rem; | |
} | |
.application-actions { | |
flex-direction: column; | |
} | |
.application-actions .btn { | |
width: 100%; | |
justify-content: center; | |
} | |
.job-summary-sidebar { | |
order: -1; | |
} | |
} | |
/* Loading State */ | |
.btn:disabled { | |
opacity: 0.6; | |
cursor: not-allowed; | |
} | |
/* Success Animation */ | |
@keyframes successPulse { | |
0% { | |
box-shadow: 0 0 0 0 rgba(46, 204, 113, 0.4); | |
} | |
70% { | |
box-shadow: 0 0 0 10px rgba(46, 204, 113, 0); | |
} | |
100% { | |
box-shadow: 0 0 0 0 rgba(46, 204, 113, 0); | |
} | |
} | |
.application-success { | |
animation: successPulse 2s infinite; | |
} | |
</style> | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
// File input handling | |
const fileInput = document.getElementById('resume'); | |
const fileDisplay = document.querySelector('.file-input-display'); | |
const filePlaceholder = document.querySelector('.file-placeholder'); | |
const fileName = document.querySelector('.file-name'); | |
fileInput.addEventListener('change', function() { | |
if (this.files && this.files[0]) { | |
filePlaceholder.style.display = 'none'; | |
fileName.textContent = this.files[0].name; | |
fileName.style.display = 'block'; | |
fileDisplay.style.borderStyle = 'solid'; | |
fileDisplay.style.borderColor = 'var(--success)'; | |
} | |
}); | |
// Parse resume functionality | |
const parseBtn = document.getElementById('parse-resume'); | |
if (parseBtn) { | |
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; | |
} | |
// Show loading state | |
parseBtn.disabled = true; | |
parseBtn.innerHTML = '<span class="btn-icon">β³</span> Parsing...'; | |
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) { | |
// Populate fields with animation | |
const fields = [ | |
{ id: 'full-name', value: data.name }, | |
{ id: 'skills', value: data.skills }, | |
{ id: 'education', value: data.education }, | |
{ id: 'experience', value: data.experience } | |
]; | |
fields.forEach((field, index) => { | |
if (field.value && document.getElementById(field.id)) { | |
setTimeout(() => { | |
const element = document.getElementById(field.id); | |
element.value = field.value; | |
element.style.borderColor = 'var(--success)'; | |
setTimeout(() => { | |
element.style.borderColor = ''; | |
}, 1000); | |
}, index * 200); | |
} | |
}); | |
// Show success message | |
parseBtn.innerHTML = '<span class="btn-icon">β</span> Parsed Successfully'; | |
parseBtn.classList.add('btn-success'); | |
} | |
}) | |
.catch(err => { | |
console.error(err); | |
alert('Unable to parse resume. Please fill in the fields manually.'); | |
}) | |
.finally(() => { | |
setTimeout(() => { | |
parseBtn.disabled = false; | |
parseBtn.innerHTML = '<span class="btn-icon">π</span> Parse Resume'; | |
parseBtn.classList.remove('btn-success'); | |
}, 2000); | |
}); | |
}); | |
} | |
// Form validation | |
const form = document.getElementById('application-form'); | |
form.addEventListener('submit', function(e) { | |
const submitBtn = form.querySelector('button[type="submit"]'); | |
submitBtn.disabled = true; | |
submitBtn.innerHTML = '<span class="btn-icon">β³</span> Submitting...'; | |
}); | |
}); | |
</script> | |
{% endblock %} |