Codingo / backend /templates /my_applications.html
husseinelsaadi's picture
style updated
4991915
raw
history blame
13.9 kB
{% extends "base.html" %}
{% block title %}My Applications - Codingo{% endblock %}
{% block content %}
<section class="content-section">
<div class="section-header">
<h2>My Applications</h2>
<p>Track and manage your job applications</p>
</div>
<ul class="breadcrumbs">
<li><a href="{{ url_for('index') }}">Home</a></li>
<li>My Applications</li>
</ul>
<!-- Interview Guidelines Section -->
<div class="interview-guidelines">
<div class="guidelines-header">
<h3><span class="icon">🎯</span> Important Interview Guidelines</h3>
</div>
<div class="guidelines-content">
<div class="guideline-item">
<span class="guideline-icon">⚑</span>
<div class="guideline-text">
<strong>One-time opportunity:</strong> The interview can be taken only once, so please be well-prepared.
</div>
</div>
<div class="guideline-item">
<span class="guideline-icon">🎧</span>
<div class="guideline-text">
<strong>Environment:</strong> Ensure you're in a quiet space with a stable internet connection.
</div>
</div>
<div class="guideline-item">
<span class="guideline-icon">πŸ“‹</span>
<div class="guideline-text">
<strong>Purpose:</strong> This helps companies shortlist the most relevant candidates for the role.
</div>
</div>
<div class="guideline-item">
<span class="guideline-icon">🎯</span>
<div class="guideline-text">
<strong>Customization:</strong> Questions are tailored based on your CV and job requirements.
</div>
</div>
<div class="guideline-item">
<span class="guideline-icon">⏱️</span>
<div class="guideline-text">
<strong>Duration:</strong> 10-15 minutes including general and skill-based questions.
</div>
</div>
</div>
</div>
<!-- Applications Grid -->
<div class="applications-container">
{% if applications %}
<div class="applications-grid">
{% for application in applications %}
<div class="application-card" data-status="{{ application.status }}">
<div class="card-status-badge status-{{ application.status.lower().replace(' ', '-') }}">
{{ application.status }}
</div>
<div class="application-header">
<h3>{{ application.job.role if application.job else 'Unknown Role' }}</h3>
<div class="company-info">
<span class="company-name">{{ application.job.company if application.job else '' }}</span>
{% if application.job and application.job.location %}
<span class="location">πŸ“ {{ application.job.location }}</span>
{% endif %}
</div>
</div>
<div class="application-body">
<div class="application-meta">
<span class="meta-item">
<i class="icon">πŸ“…</i>
Applied {{ application.date_applied.strftime('%B %d, %Y') }}
</span>
{% if application.job and application.job.seniority %}
<span class="meta-item">
<i class="icon">πŸ’Ό</i>
{{ application.job.seniority }}
</span>
{% endif %}
</div>
{% if application.job %}
<p class="job-description">
{{ application.job.description[:150] }}{% if application.job.description|length > 150 %}...{% endif %}
</p>
{% endif %}
</div>
<div class="application-footer">
{% if application.job %}
<a href="{{ url_for('job_detail', job_id=application.job.id) }}" class="btn btn-outline btn-sm">
<span class="btn-icon">πŸ‘οΈ</span> View Job
</a>
{% endif %}
{% if application.extracted_features %}
<a href="{{ url_for('interview_page', job_id=application.job.id) }}" class="btn btn-primary btn-sm">
<span class="btn-icon">🎀</span> Take Interview
</a>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="empty-state">
<div class="empty-state-icon">πŸ“‹</div>
<h3>No Applications Yet</h3>
<p>You haven't applied to any jobs yet. Start exploring opportunities!</p>
<a href="{{ url_for('jobs') }}" class="btn btn-primary">
<span class="btn-icon">πŸ”</span> Browse Jobs
</a>
</div>
{% endif %}
</div>
<!-- Stats Section -->
{% if applications %}
<div class="applications-stats">
<div class="stat-card">
<div class="stat-number">{{ applications|length }}</div>
<div class="stat-label">Total Applications</div>
</div>
<div class="stat-card">
<div class="stat-number">{{ applications|selectattr('status', 'equalto', 'pending')|list|length }}</div>
<div class="stat-label">Pending Review</div>
</div>
<div class="stat-card">
<div class="stat-number">{{ applications|selectattr('extracted_features')|list|length }}</div>
<div class="stat-label">Ready for Interview</div>
</div>
</div>
{% endif %}
</section>
<style>
/* Section Header */
.section-header {
text-align: center;
margin-bottom: 3rem;
}
.section-header h2 {
font-size: 2.5rem;
color: var(--primary);
margin-bottom: 0.5rem;
position: relative;
display: inline-block;
}
.section-header h2::after {
content: '';
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 3px;
background: linear-gradient(to right, var(--primary), var(--accent));
}
.section-header p {
color: #666;
font-size: 1.1rem;
}
/* Interview Guidelines */
.interview-guidelines {
background: linear-gradient(135deg, #f5f7ff 0%, #e8ecff 100%);
border-radius: 12px;
padding: 2rem;
margin: 2rem 0;
box-shadow: 0 5px 15px rgba(67, 97, 238, 0.1);
border: 1px solid rgba(67, 97, 238, 0.1);
}
.guidelines-header {
margin-bottom: 1.5rem;
}
.guidelines-header h3 {
color: var(--primary);
font-size: 1.5rem;
margin: 0;
display: flex;
align-items: center;
gap: 0.5rem;
}
.guidelines-header .icon {
font-size: 1.75rem;
}
.guidelines-content {
display: grid;
gap: 1rem;
}
.guideline-item {
display: flex;
align-items: flex-start;
gap: 1rem;
padding: 0.75rem;
background: white;
border-radius: 8px;
transition: all 0.3s ease;
}
.guideline-item:hover {
transform: translateX(5px);
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05);
}
.guideline-icon {
font-size: 1.5rem;
min-width: 2rem;
display: flex;
align-items: center;
justify-content: center;
}
.guideline-text {
flex: 1;
line-height: 1.6;
}
.guideline-text strong {
color: var(--primary);
}
/* Applications Container */
.applications-container {
margin: 3rem 0;
}
/* Applications Grid */
.applications-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 1.5rem;
}
/* Application Card */
.application-card {
background: white;
border-radius: 12px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
position: relative;
transition: all 0.3s ease;
overflow: hidden;
display: flex;
flex-direction: column;
}
.application-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12);
}
/* Status Badge */
.card-status-badge {
position: absolute;
top: 1rem;
right: 1rem;
padding: 0.25rem 0.75rem;
border-radius: 20px;
font-size: 0.875rem;
font-weight: 600;
text-transform: uppercase;
}
.status-pending {
background-color: #fff3cd;
color: #856404;
}
.status-approved {
background-color: #d4edda;
color: #155724;
}
.status-rejected {
background-color: #f8d7da;
color: #721c24;
}
.status-interview-scheduled {
background-color: #d1ecf1;
color: #0c5460;
}
/* Application Header */
.application-header {
padding: 1.5rem 1.5rem 0;
}
.application-header h3 {
color: var(--primary);
margin: 0 0 0.5rem 0;
font-size: 1.5rem;
}
.company-info {
display: flex;
flex-wrap: wrap;
gap: 1rem;
color: #666;
font-size: 0.95rem;
}
.company-name {
font-weight: 600;
color: var(--dark);
}
/* Application Body */
.application-body {
padding: 1rem 1.5rem;
flex: 1;
}
.application-meta {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-bottom: 1rem;
font-size: 0.9rem;
color: #666;
}
.meta-item {
display: flex;
align-items: center;
gap: 0.25rem;
}
.meta-item .icon {
font-size: 1rem;
}
.job-description {
color: #495057;
line-height: 1.6;
margin: 0;
}
/* Application Footer */
.application-footer {
padding: 0 1.5rem 1.5rem;
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
}
.btn-sm {
padding: 0.5rem 1rem;
font-size: 0.9rem;
}
/* Empty State */
.empty-state {
text-align: center;
padding: 4rem 2rem;
background: #f8f9fa;
border-radius: 12px;
border: 2px dashed #dee2e6;
}
.empty-state-icon {
font-size: 4rem;
margin-bottom: 1rem;
opacity: 0.5;
}
.empty-state h3 {
color: var(--primary);
margin-bottom: 0.5rem;
}
.empty-state p {
color: #666;
margin-bottom: 2rem;
}
/* Stats Section */
.applications-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1.5rem;
margin-top: 3rem;
}
.stat-card {
background: white;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
text-align: center;
transition: all 0.3s ease;
}
.stat-card:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);
}
.stat-number {
font-size: 2.5rem;
font-weight: 700;
color: var(--primary);
margin-bottom: 0.5rem;
}
.stat-label {
color: #666;
font-size: 1rem;
}
/* Responsive Design */
@media (max-width: 768px) {
.section-header h2 {
font-size: 2rem;
}
.interview-guidelines {
padding: 1.5rem;
}
.guidelines-header h3 {
font-size: 1.25rem;
}
.guideline-item {
padding: 0.5rem;
}
.guideline-icon {
font-size: 1.25rem;
}
.applications-grid {
grid-template-columns: 1fr;
}
.application-card {
margin-bottom: 1rem;
}
.applications-stats {
grid-template-columns: 1fr;
}
.stat-card {
padding: 1.5rem;
}
}
@media (max-width: 480px) {
.company-info {
flex-direction: column;
gap: 0.5rem;
}
.application-meta {
flex-direction: column;
gap: 0.5rem;
}
.application-footer {
flex-direction: column;
}
.application-footer .btn {
width: 100%;
justify-content: center;
}
}
/* Loading Animation */
@keyframes shimmer {
0% {
background-position: -1000px 0;
}
100% {
background-position: 1000px 0;
}
}
.loading {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 1000px 100%;
animation: shimmer 2s infinite;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Add animation to cards on page load
const cards = document.querySelectorAll('.application-card');
cards.forEach((card, index) => {
setTimeout(() => {
card.style.opacity = '0';
card.style.transform = 'translateY(20px)';
card.style.animation = 'fadeInUp 0.5s ease forwards';
}, index * 100);
});
// Filter functionality (if needed in future)
const statusBadges = document.querySelectorAll('.card-status-badge');
statusBadges.forEach(badge => {
badge.addEventListener('click', function() {
const status = this.textContent.trim();
// Add filter logic here if needed
});
});
});
// Animation keyframes
const style = document.createElement('style');
style.textContent = `
@keyframes fadeInUp {
to {
opacity: 1;
transform: translateY(0);
}
}
`;
document.head.appendChild(style);
</script>
{% endblock %}