frontend #5

Merged
ismail merged 6 commits from frontend into main 2025-10-07 18:36:18 +03:00
15 changed files with 254 additions and 1 deletions

Binary file not shown.

17
recruitment/decorators.py Normal file
View File

@ -0,0 +1,17 @@
from functools import wraps
from datetime import date
from django.shortcuts import redirect, get_object_or_404
from django.http import HttpResponseNotFound
def job_not_expired(view_func):
@wraps(view_func)
def _wrapped_view(request, job_id, *args, **kwargs):
from .models import JobPosting
job = get_object_or_404(JobPosting, pk=job_id)
if job.expiration_date and job.application_deadline< date.today():
return redirect('expired_job_page')
return view_func(request, job_id, *args, **kwargs)
return _wrapped_view

View File

@ -12,6 +12,7 @@ urlpatterns = [
path('jobs/<slug:slug>/update/', views.edit_job, name='job_update'),
# path('jobs/<slug:slug>/delete/', views., name='job_delete'),
path('jobs/<slug:slug>/', views.job_detail, name='job_detail'),
path('jobs/<slug:slug>/candidate/', views.job_detail_candidate, name='job_detail_candidate'),
# LinkedIn Integration URLs
path('jobs/<slug:slug>/post-to-linkedin/', views.post_to_linkedin, name='post_to_linkedin'),

View File

@ -242,7 +242,12 @@ def job_detail(request, slug):
'offer_count': offer_count,
}
return render(request, 'jobs/job_detail.html', context)
\
# job detail facing the candidate:
def job_detail_candidate(request,slug):
job=get_object_or_404(JobPosting,slug=slug)
return render(request,'jobs/job_detail_candidate.html',{'job':job})
def post_to_linkedin(request,slug):
"""Post a job to LinkedIn"""

View File

@ -0,0 +1,230 @@
{% extends "base.html" %}
{% block title %}{{ job.title }} - University ATS{% endblock %}
{% block customCSS %}
<style>
/* ---------------------------------------------------------------------- */
/* THEME STYLES (Keep from previous response) */
/* ---------------------------------------------------------------------- */
:root {
--kaauh-teal: #00636e;
--kaauh-teal-dark: #004a53;
--success: #198754;
/* Define a subtle background for mobile sticky bar */
--light-bg: #f8f9fa;
}
.btn-main-action {
background-color: var(--kaauh-teal);
color: white;
border: none;
transition: background-color 0.3s ease, transform 0.2s ease;
box-shadow: 0 4px 12px rgba(0, 99, 110, 0.3);
}
.btn-main-action:hover {
background-color: var(--kaauh-teal-dark);
color: white;
transform: translateY(-1px);
}
.bg-kaauh-teal-dark {
background-color: var(--kaauh-teal-dark) !important;
}
/* ---------------------------------------------------------------------- */
/* MOBILE RESPONSIVE STYLES */
/* ---------------------------------------------------------------------- */
/* 1. Mobile Fixed Footer Bar for Application */
@media (max-width: 991.98px) {
/* Fix the "Apply" button bar to the bottom on mobile/tablet */
.mobile-fixed-apply-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: 100%;
padding: 15px;
background-color: var(--light-bg); /* Use a light background */
border-top: 1px solid #ddd;
z-index: 1000; /* Ensure it stays above everything */
box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.08);
}
/* Add padding to the bottom of the body content to prevent it from hiding under the fixed bar */
body {
padding-bottom: 90px;
}
/* Adjust header font size for small screens */
.card-header h2 {
font-size: 1.25rem !important;
}
/* Change job overview grid to single column on small phones */
.row-cols-md-2 {
--bs-gutter-x: 1.5rem;
--bs-gutter-y: 1rem;
}
.row-cols-md-2 > .col {
flex: 0 0 100%; /* force to 1 column */
max-width: 100%;
}
}
</style>
{% endblock %}
{% block content %}
<div class="row mb-5">
<div class="col-lg-4 order-lg-2 order-1 d-none d-lg-block">
<div class="card shadow-sm sticky-top" style="top: 90px;">
<div class="card-header bg-kaauh-teal-dark text-white">
<h5 class="mb-0"><i class="fas fa-file-signature me-2"></i>Ready to Apply?</h5>
</div>
<div class="card-body text-center">
<p class="text-muted">Review the job details, then apply below.</p>
{% if job.form_template %}
<a href="{% url 'form_wizard' job.form_template.pk %}" class="btn btn-main-action btn-lg w-100">
<i class="fas fa-paper-plane me-2"></i> Apply for this Position
</a>
{% endif %}
{% comment %} <p class="text-muted mt-3 mb-0">
<small>Application ID: **{{ job.pk }}**</small>
</p> {% endcomment %}
</div>
</div>
</div>
<div class="col-lg-8 order-lg-1 order-2">
<div class="card shadow-sm">
<div class="card-header bg-kaauh-teal-dark text-white d-flex justify-content-between align-items-center">
<h2 class="h3 mb-0 fw-bold">{{ job.title }}</h2>
{% with status_class=job.status|lower %}
<span class="badge
{% if status_class == 'open' %}bg-success
{% elif status_class == 'closed' %}bg-danger
{% elif status_class == 'draft' %}bg-secondary
{% else %}bg-primary
{% endif %}
status-badge fw-bold p-2">
{{ job.get_status_display }}
</span>
{% endwith %}
</div>
<div class="card-body">
<h4 class="mb-3" style="color: var(--kaauh-teal-dark);">Job Overview</h4>
<div class="row row-cols-1 row-cols-md-2 g-3 mb-4">
{% if job.salary_range %}
<div class="col">
<i class="fas fa-money-bill-wave text-success me-2"></i>
<strong>Salary:</strong>
<span class="fw-bold text-success">{{ job.salary_range }}</span>
</div>
{% endif %}
<div class="col">
<i class="fas fa-calendar-alt text-muted me-2"></i>
<strong>Deadline:</strong>
{% if job.application_deadline %}
{{ job.application_deadline|date:"M d, Y" }}
{% if job.is_expired %}
<span class="badge bg-danger ms-2">EXPIRED</span>
{% endif %}
{% else %}
<span class="text-muted">Not specified</span>
{% endif %}
</div>
<div class="col">
<i class="fas fa-briefcase text-muted me-2"></i>
<strong>Job Type:</strong> {{ job.get_job_type_display }}
</div>
<div class="col">
<i class="fas fa-map-marker-alt text-muted me-2"></i>
<strong>Location:</strong> {{ job.get_location_display }}
</div>
<div class="col">
<i class="fas fa-building text-muted me-2"></i>
<strong>Department:</strong> {{ job.department|default:"Not specified" }}
</div>
<div class="col">
<i class="fas fa-hashtag text-muted me-2"></i>
<strong>JOB ID:</strong> {{ job.internal_job_id|default:"N/A" }}
</div>
<div class="col">
<i class="fas fa-desktop text-muted me-2"></i>
<strong>Workplace:</strong> {{ job.get_workplace_type_display }}
</div>
<div class="col">
<i class="fas fa-user-tie text-muted me-2"></i>
<strong>Created By:</strong> {{ job.created_by|default:"N/A" }}
</div>
</div>
{% if job.description %}
<hr class="my-4">
<div class="mb-4">
<h5 class="fw-bold" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-info-circle me-2"></i>Job Description
</h5>
<div class="text-secondary">{{ job.description|linebreaks }}</div>
</div>
{% endif %}
{% if job.qualifications %}
<hr class="my-4">
<div class="mb-4">
<h5 class="fw-bold" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-graduation-cap me-2"></i>Qualifications
</h5>
<div class="text-secondary">{{ job.qualifications|linebreaks }}</div>
</div>
{% endif %}
{% if job.benefits %}
<hr class="my-4">
<div class="mb-4">
<h5 class="fw-bold" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-hand-holding-usd me-2"></i>Benefits
</h5>
<div class="text-secondary">{{ job.benefits|linebreaks }}</div>
</div>
{% endif %}
{% if job.application_instructions %}
<hr class="my-4">
<div class="mb-4">
<h5 class="fw-bold" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-file-alt me-2"></i>Application Instructions
</h5>
<div class="text-secondary">{{ job.application_instructions|linebreaks }}</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<div class="mobile-fixed-apply-bar d-lg-none">
{% if job.form_template %}
<a href="{% url 'form_wizard' job.form_template.pk %}" class="btn btn-main-action btn-lg w-100">
<i class="fas fa-paper-plane me-2"></i> Apply for this Position
</a>
{% endif %}
</div>
{% endblock %}