Merge pull request 'job list table' (#11) from frontend into main
Reviewed-on: #11
This commit is contained in:
commit
ce15603802
Binary file not shown.
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -195,9 +195,9 @@ class JobPostingForm(forms.ModelForm):
|
|||||||
fields = [
|
fields = [
|
||||||
'title', 'department', 'job_type', 'workplace_type',
|
'title', 'department', 'job_type', 'workplace_type',
|
||||||
'location_city', 'location_state', 'location_country',
|
'location_city', 'location_state', 'location_country',
|
||||||
'description', 'qualifications', 'salary_range', 'benefits'
|
'description', 'qualifications', 'salary_range', 'benefits','application_start_date'
|
||||||
,'application_deadline', 'application_instructions',
|
,'application_deadline', 'application_instructions',
|
||||||
'position_number', 'reporting_to', 'start_date', 'status',
|
'position_number', 'reporting_to', 'joining_date', 'status',
|
||||||
'created_by','open_positions','hash_tags'
|
'created_by','open_positions','hash_tags'
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
@ -247,6 +247,10 @@ class JobPostingForm(forms.ModelForm):
|
|||||||
# 'placeholder': 'https://university.edu/careers/job123',
|
# 'placeholder': 'https://university.edu/careers/job123',
|
||||||
# 'required': True
|
# 'required': True
|
||||||
# }),
|
# }),
|
||||||
|
'application_start_date': forms.DateInput(attrs={
|
||||||
|
'class': 'form-control',
|
||||||
|
'type': 'date'
|
||||||
|
}),
|
||||||
'application_deadline': forms.DateInput(attrs={
|
'application_deadline': forms.DateInput(attrs={
|
||||||
'class': 'form-control',
|
'class': 'form-control',
|
||||||
'type': 'date'
|
'type': 'date'
|
||||||
@ -272,7 +276,7 @@ class JobPostingForm(forms.ModelForm):
|
|||||||
'class': 'form-control',
|
'class': 'form-control',
|
||||||
'placeholder': 'Department Chair, Director, etc.'
|
'placeholder': 'Department Chair, Director, etc.'
|
||||||
}),
|
}),
|
||||||
'start_date': forms.DateInput(attrs={
|
'joining_date': forms.DateInput(attrs={
|
||||||
'class': 'form-control',
|
'class': 'form-control',
|
||||||
'type': 'date'
|
'type': 'date'
|
||||||
}),
|
}),
|
||||||
@ -333,31 +337,31 @@ class JobPostingForm(forms.ModelForm):
|
|||||||
raise forms.ValidationError('Please enter a valid URL (e.g., https://example.com)')
|
raise forms.ValidationError('Please enter a valid URL (e.g., https://example.com)')
|
||||||
return url
|
return url
|
||||||
|
|
||||||
def clean(self):
|
# def clean(self):
|
||||||
"""Cross-field validation"""
|
# """Cross-field validation"""
|
||||||
cleaned_data = super().clean()
|
# cleaned_data = super().clean()
|
||||||
|
|
||||||
# Validate dates
|
# # Validate dates
|
||||||
start_date = cleaned_data.get('start_date')
|
# start_date = cleaned_data.get('start_date')
|
||||||
application_deadline = cleaned_data.get('application_deadline')
|
# application_deadline = cleaned_data.get('application_deadline')
|
||||||
|
|
||||||
# Perform cross-field validation only if both fields have values
|
# # Perform cross-field validation only if both fields have values
|
||||||
if start_date and application_deadline:
|
# if start_date and application_deadline:
|
||||||
if application_deadline > start_date:
|
# if application_deadline > start_date:
|
||||||
self.add_error('application_deadline',
|
# self.add_error('application_deadline',
|
||||||
'The application deadline must be set BEFORE the job start date.')
|
# 'The application deadline must be set BEFORE the job start date.')
|
||||||
|
|
||||||
# # Validate that if status is ACTIVE, we have required fields
|
# # # Validate that if status is ACTIVE, we have required fields
|
||||||
# status = cleaned_data.get('status')
|
# # status = cleaned_data.get('status')
|
||||||
# if status == 'ACTIVE':
|
# # if status == 'ACTIVE':
|
||||||
# if not cleaned_data.get('application_url'):
|
# # if not cleaned_data.get('application_url'):
|
||||||
# self.add_error('application_url',
|
# # self.add_error('application_url',
|
||||||
# 'Application URL is required for active jobs.')
|
# # 'Application URL is required for active jobs.')
|
||||||
# if not cleaned_data.get('description'):
|
# # if not cleaned_data.get('description'):
|
||||||
# self.add_error('description',
|
# # self.add_error('description',
|
||||||
# 'Job description is required for active jobs.')
|
# # 'Job description is required for active jobs.')
|
||||||
|
|
||||||
return cleaned_data
|
# return cleaned_data
|
||||||
|
|
||||||
class JobPostingImageForm(forms.ModelForm):
|
class JobPostingImageForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
18
recruitment/migrations/0002_alter_jobposting_status.py
Normal file
18
recruitment/migrations/0002_alter_jobposting_status.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-10-12 10:50
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('recruitment', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='jobposting',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(choices=[('DRAFT', 'Draft'), ('ACTIVE', 'Active'), ('CLOSED', 'Closed'), ('CANCELLED', 'Cancelled'), ('ARCHIVED', 'Archived')], default='DRAFT', max_length=20),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-10-12 13:18
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('recruitment', '0002_alter_jobposting_status'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='jobposting',
|
||||||
|
old_name='start_date',
|
||||||
|
new_name='joining_date',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='jobposting',
|
||||||
|
name='application_start_date',
|
||||||
|
field=models.DateField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -98,6 +98,7 @@ class JobPosting(Base):
|
|||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
|
application_start_date=models.DateField(null=True, blank=True)
|
||||||
application_deadline = models.DateField(null=True, blank=True)
|
application_deadline = models.DateField(null=True, blank=True)
|
||||||
application_instructions =CKEditor5Field(
|
application_instructions =CKEditor5Field(
|
||||||
blank=True, null=True,config_name='extends'
|
blank=True, null=True,config_name='extends'
|
||||||
@ -150,7 +151,7 @@ class JobPosting(Base):
|
|||||||
reporting_to = models.CharField(
|
reporting_to = models.CharField(
|
||||||
max_length=100, blank=True, help_text="Who this position reports to"
|
max_length=100, blank=True, help_text="Who this position reports to"
|
||||||
)
|
)
|
||||||
start_date = models.DateField(null=True, blank=True, help_text="Desired start date")
|
joining_date = models.DateField(null=True, blank=True, help_text="Desired start date")
|
||||||
open_positions = models.PositiveIntegerField(
|
open_positions = models.PositiveIntegerField(
|
||||||
default=1, help_text="Number of open positions for this job"
|
default=1, help_text="Number of open positions for this job"
|
||||||
)
|
)
|
||||||
@ -228,7 +229,7 @@ class JobPosting(Base):
|
|||||||
parts.append(self.location_city)
|
parts.append(self.location_city)
|
||||||
if self.location_state:
|
if self.location_state:
|
||||||
parts.append(self.location_state)
|
parts.append(self.location_state)
|
||||||
if self.location_country and self.location_country != "United States":
|
if self.location_country:
|
||||||
parts.append(self.location_country)
|
parts.append(self.location_country)
|
||||||
return ", ".join(parts) if parts else "Not specified"
|
return ", ".join(parts) if parts else "Not specified"
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@ -15,6 +15,7 @@ urlpatterns = [
|
|||||||
path('jobs/<slug:slug>/', views.job_detail, name='job_detail'),
|
path('jobs/<slug:slug>/', views.job_detail, name='job_detail'),
|
||||||
path('jobs/<slug:slug>/candidate/', views.job_detail_candidate, name='job_detail_candidate'),
|
path('jobs/<slug:slug>/candidate/', views.job_detail_candidate, name='job_detail_candidate'),
|
||||||
path('jobs/<slug:slug>/candidate/application/success', views.application_success, name='application_success'),
|
path('jobs/<slug:slug>/candidate/application/success', views.application_success, name='application_success'),
|
||||||
|
path('careers/',views.kaauh_career,name='kaauh_career'),
|
||||||
|
|
||||||
|
|
||||||
# LinkedIn Integration URLs
|
# LinkedIn Integration URLs
|
||||||
|
|||||||
@ -277,17 +277,19 @@ def job_detail(request, slug):
|
|||||||
|
|
||||||
|
|
||||||
# Get all candidates for this job, ordered by most recent
|
# Get all candidates for this job, ordered by most recent
|
||||||
candidates = job.candidates.all().order_by("-created_at")
|
applicants = job.candidates.all().order_by("-created_at")
|
||||||
|
|
||||||
# Count candidates by stage for summary statistics
|
# Count candidates by stage for summary statistics
|
||||||
total_candidates = candidates.count()
|
total_applicant = applicants.count()
|
||||||
applied_count = candidates.filter(stage="Applied").count()
|
applied_count = applicants.filter(stage="Applied").count()
|
||||||
interview_count = candidates.filter(stage="Interview").count()
|
interview_count = applicants.filter(stage="Interview").count()
|
||||||
offer_count = candidates.filter(stage="Offer").count()
|
offer_count = applicants.filter(stage="Offer").count()
|
||||||
|
|
||||||
status_form = JobPostingStatusForm(instance=job)
|
status_form = JobPostingStatusForm(instance=job)
|
||||||
image_upload_form=JobPostingImageForm(instance=job)
|
image_upload_form=JobPostingImageForm(instance=job)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 2. Check for POST request (Status Update Submission)
|
# 2. Check for POST request (Status Update Submission)
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
|
||||||
@ -309,8 +311,8 @@ def job_detail(request, slug):
|
|||||||
|
|
||||||
context = {
|
context = {
|
||||||
"job": job,
|
"job": job,
|
||||||
"candidates": candidates,
|
"applicants": applicants,
|
||||||
"total_candidates": total_candidates,
|
"total_applicants": total_applicant,
|
||||||
"applied_count": applied_count,
|
"applied_count": applied_count,
|
||||||
"interview_count": interview_count,
|
"interview_count": interview_count,
|
||||||
"offer_count": offer_count,
|
"offer_count": offer_count,
|
||||||
@ -339,6 +341,16 @@ def job_image_upload(request, slug):
|
|||||||
return redirect('job_detail', slug=job.slug)
|
return redirect('job_detail', slug=job.slug)
|
||||||
|
|
||||||
|
|
||||||
|
def kaauh_career(request):
|
||||||
|
active_jobs = JobPosting.objects.select_related(
|
||||||
|
'form_template'
|
||||||
|
).filter(
|
||||||
|
status='ACTIVE',
|
||||||
|
form_template__is_active=True
|
||||||
|
)
|
||||||
|
|
||||||
|
return render(request,'jobs/career.html',{'active_jobs':active_jobs})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# job detail facing the candidate:
|
# job detail facing the candidate:
|
||||||
@ -952,6 +964,8 @@ def submit_form(request, template_id):
|
|||||||
resume=resume.get_file if resume.is_file else None,
|
resume=resume.get_file if resume.is_file else None,
|
||||||
job=submission.template.job,
|
job=submission.template.job,
|
||||||
)
|
)
|
||||||
|
return redirect('application_success')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Candidate creation failed,{e}")
|
logger.error(f"Candidate creation failed,{e}")
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -92,6 +92,8 @@ class JobCandidatesListView(LoginRequiredMixin, ListView):
|
|||||||
context_object_name = 'candidates'
|
context_object_name = 'candidates'
|
||||||
paginate_by = 10
|
paginate_by = 10
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
# Get the job by slug
|
# Get the job by slug
|
||||||
self.job = get_object_or_404(models.JobPosting, slug=self.kwargs['slug'])
|
self.job = get_object_or_404(models.JobPosting, slug=self.kwargs['slug'])
|
||||||
@ -99,6 +101,11 @@ class JobCandidatesListView(LoginRequiredMixin, ListView):
|
|||||||
# Filter candidates for this specific job
|
# Filter candidates for this specific job
|
||||||
queryset = models.Candidate.objects.filter(job=self.job)
|
queryset = models.Candidate.objects.filter(job=self.job)
|
||||||
|
|
||||||
|
if self.request.GET.get('stage'):
|
||||||
|
stage=self.request.GET.get('stage')
|
||||||
|
queryset=queryset.filter(stage=stage)
|
||||||
|
|
||||||
|
|
||||||
# Handle search
|
# Handle search
|
||||||
search_query = self.request.GET.get('search', '')
|
search_query = self.request.GET.get('search', '')
|
||||||
if search_query:
|
if search_query:
|
||||||
|
|||||||
@ -22,7 +22,15 @@
|
|||||||
--kaauh-border: #eaeff3;
|
--kaauh-border: #eaeff3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* NEW CLASS FOR WIDER CONTENT */
|
||||||
|
.max-width-1600 {
|
||||||
|
max-width: 1600px;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
padding-right: var(--bs-gutter-x, 0.75rem); /* Add Bootstrap padding for responsiveness */
|
||||||
|
padding-left: var(--bs-gutter-x, 0.75rem);
|
||||||
|
}
|
||||||
|
|
||||||
/* === Top Bar === */
|
/* === Top Bar === */
|
||||||
.top-bar {
|
.top-bar {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
@ -45,7 +53,7 @@
|
|||||||
padding: 0.25rem 0.5rem;
|
padding: 0.25rem 0.5rem;
|
||||||
}
|
}
|
||||||
.top-bar .logo-container img {
|
.top-bar .logo-container img {
|
||||||
height: 40px;
|
height: 60px;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +76,10 @@
|
|||||||
background-color: var(--kaauh-teal) !important;
|
background-color: var(--kaauh-teal) !important;
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,0.12);
|
box-shadow: 0 2px 6px rgba(0,0,0,0.12);
|
||||||
}
|
}
|
||||||
|
/* Change the outer navbar container to fluid, rely on inner max-width */
|
||||||
|
.navbar-dark > .container {
|
||||||
|
max-width: 100%; /* Override default container width */
|
||||||
|
}
|
||||||
.nav-link {
|
.nav-link {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
@ -205,7 +217,8 @@
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
||||||
}
|
}
|
||||||
main.container {
|
/* The main content width is already handled by the inline style, but making it explicit here */
|
||||||
|
main.container-fluid {
|
||||||
min-height: calc(100vh - 200px);
|
min-height: calc(100vh - 200px);
|
||||||
padding: 1.5rem 0;
|
padding: 1.5rem 0;
|
||||||
}
|
}
|
||||||
@ -235,244 +248,265 @@
|
|||||||
<body class="d-flex flex-column min-vh-100" hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
|
<body class="d-flex flex-column min-vh-100" hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
|
||||||
|
|
||||||
<div class="top-bar d-none d-md-block">
|
<div class="top-bar d-none d-md-block">
|
||||||
<div class="container d-flex justify-content-between align-items-center gap-2">
|
{# Changed container to container-fluid and added max-width-1600 to inner div #}
|
||||||
<div class="d-flex align-items-center gap-3 social-icons">
|
<div class="container-fluid">
|
||||||
{% comment %} <span class="text-muted">{% trans "Follow Us:" %}</span>
|
<div class="d-flex justify-content-between align-items-center gap-2 max-width-1600">
|
||||||
<a href="#" aria-label="Facebook"><i class="fab fa-facebook-f"></i></a>
|
<div class="d-flex align-items-center gap-3 social-icons">
|
||||||
<a href="#" aria-label="Twitter"><i class="fab fa-twitter"></i></a>
|
{% comment %} <span class="text-muted">{% trans "Follow Us:" %}</span>
|
||||||
<a href="#" aria-label="Instagram"><i class="fab fa-instagram"></i></a> {% endcomment %}
|
<a href="#" aria-label="Facebook"><i class="fab fa-facebook-f"></i></a>
|
||||||
</div>
|
<a href="#" aria-label="Twitter"><i class="fab fa-twitter"></i></a>
|
||||||
<div class="contact-info d-flex gap-3">
|
<a href="#" aria-label="Instagram"><i class="fab fa-instagram"></i></a> {% endcomment %}
|
||||||
{% comment %} <div class="contact-item">
|
</div>
|
||||||
<i class="fas fa-envelope text-primary"></i>
|
<div class="contact-info d-flex gap-3">
|
||||||
<span>info@kaauh.edu.sa</span>
|
{% comment %} <div class="contact-item">
|
||||||
|
<i class="fas fa-envelope text-primary"></i>
|
||||||
|
<span>info@kaauh.edu.sa</span>
|
||||||
|
</div>
|
||||||
|
<div class="contact-item">
|
||||||
|
<i class="fas fa-phone text-primary"></i>
|
||||||
|
<span>+966 11 820 0000</span>
|
||||||
|
</div> {% endcomment %}
|
||||||
|
</div>
|
||||||
|
<div class="logo-container d-flex gap-2">
|
||||||
|
<img src="{% static 'image/vision.svg' %}" alt="{% trans 'Saudi Vision 2030' %}" loading="lazy">
|
||||||
|
<div class="kaauh-logo-container d-flex flex-column flex-md-row align-items-center gap-2 ms-4">
|
||||||
|
<div class="hospital-text text-center text-md-start me-3">
|
||||||
|
<div class="ar small">جامعة الأميرة نورة بنت عبدالرحمن الأكاديمية</div>
|
||||||
|
<div class="ar small">ومستشفى الملك عبدالله بن عبدالعزيز التخصصي</div>
|
||||||
|
<div class="en small">Princess Nourah bint Abdulrahman University</div>
|
||||||
|
<div class="en small">King Abdullah bin Abdulaziz University Hospital</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<img src="{% static 'image/kaauh.png' %}" alt="KAAUH Logo" style="max-height: 100px;max-width:100px;">
|
||||||
</div>
|
</div>
|
||||||
<div class="contact-item">
|
|
||||||
<i class="fas fa-phone text-primary"></i>
|
|
||||||
<span>+966 11 820 0000</span>
|
|
||||||
</div> {% endcomment %}
|
|
||||||
</div>
|
|
||||||
<div class="logo-container d-flex gap-2">
|
|
||||||
<img src="{% static 'image/vision.svg' %}" alt="{% trans 'Saudi Vision 2030' %}" loading="lazy">
|
|
||||||
<img src="{% static 'image/hospital_logo_3.png' %}" alt="{% trans 'King Abdullah Academic University Hospital' %}" loading="lazy">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark sticky-top">
|
<nav class="navbar navbar-expand-lg navbar-dark sticky-top">
|
||||||
<div class="container">
|
{# Changed container to container-fluid and added max-width-1600 to inner div #}
|
||||||
<a class="navbar-brand text-white" href="{% url 'dashboard' %}">
|
<div class="container-fluid">
|
||||||
<img src="{% static 'image/kaauh.jpeg' %}" alt="{% trans 'Saudi Vision 2030' %}" style="width: 60px; height: 60px;">
|
<div class="navbar-content-wrapper max-width-1600 d-flex justify-content-between align-items-center" style="width: 100%;">
|
||||||
</a>
|
<a class="navbar-brand text-white d-none d-md-block" href="{% url 'dashboard' %}">
|
||||||
|
<img src="{% static 'image/kaauh_green1.png' %}" alt="{% trans 'kaauh logo green bg' %}" style="width: 60px; height: 60px;">
|
||||||
|
</a>
|
||||||
|
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||||
aria-controls="navbarNav" aria-expanded="false" aria-label="{% trans 'Toggle navigation' %}">
|
aria-controls="navbarNav" aria-expanded="false" aria-label="{% trans 'Toggle navigation' %}">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
{% comment %} <li class="nav-item">
|
{% comment %} <li class="nav-item">
|
||||||
<a class="nav-link {% if request.resolver_match.url_name == 'dashboard' %}active{% endif %}" href="{% url 'dashboard' %}">
|
<a class="nav-link {% if request.resolver_match.url_name == 'dashboard' %}active{% endif %}" href="{% url 'dashboard' %}">
|
||||||
<span class="d-flex align-items-center gap-2">
|
<span class="d-flex align-items-center gap-2">
|
||||||
{% include "icons/dashboard.html" %}
|
{% include "icons/dashboard.html" %}
|
||||||
{% trans "Dashboard" %}
|
{% trans "Dashboard" %}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li> {% endcomment %}
|
</li> {% endcomment %}
|
||||||
<li class="nav-item me-2">
|
<li class="nav-item me-2">
|
||||||
<a class="nav-link {% if request.resolver_match.url_name == 'job_list' %}active{% endif %}" href="{% url 'job_list' %}">
|
<a class="nav-link {% if request.resolver_match.url_name == 'job_list' %}active{% endif %}" href="{% url 'job_list' %}">
|
||||||
<span class="d-flex align-items-center gap-2">
|
<span class="d-flex align-items-center gap-2">
|
||||||
{% include "icons/jobs.html" %}
|
{% include "icons/jobs.html" %}
|
||||||
{% trans "Jobs" %}
|
{% trans "Jobs" %}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item me-2">
|
|
||||||
<a class="nav-link {% if request.resolver_match.url_name == 'candidate_list' %}active{% endif %}" href="{% url 'candidate_list' %}">
|
<li class="nav-item me-2">
|
||||||
<span class="d-flex align-items-center gap-2">
|
<a class="nav-link {% if request.resolver_match.url_name == 'form_templates_list' %}active{% endif %}" href="{% url 'form_templates_list' %}">
|
||||||
{% include "icons/users.html" %}
|
<span class="d-flex align-items-center gap-2">
|
||||||
{% trans "Candidates" %}
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||||
</span>
|
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" />
|
||||||
</a>
|
</svg>
|
||||||
</li>
|
|
||||||
<li class="nav-item me-2">
|
{% trans "Form Templates" %}
|
||||||
<a class="nav-link {% if request.resolver_match.url_name == 'training_list' %}active{% endif %}" href="{% url 'training_list' %}">
|
</span>
|
||||||
<span class="d-flex align-items-center gap-2">
|
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-item me-2">
|
||||||
|
<a class="nav-link {% if request.resolver_match.url_name == 'candidate_list' %}active{% endif %}" href="{% url 'candidate_list' %}">
|
||||||
|
<span class="d-flex align-items-center gap-2">
|
||||||
|
{% include "icons/users.html" %}
|
||||||
|
{% trans "Candidates" %}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-item me-2">
|
||||||
|
<a class="nav-link {% if request.resolver_match.url_name == 'list_meetings' %}active{% endif %}" href="{% url 'list_meetings' %}">
|
||||||
|
<span class="d-flex align-items-center gap-2">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="m15.75 10.5 4.72-4.72a.75.75 0 0 1 1.28.53v11.38a.75.75 0 0 1-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 0 0 2.25-2.25v-9a2.25 2.25 0 0 0-2.25-2.25h-9A2.25 2.25 0 0 0 2.25 7.5v9a2.25 2.25 0 0 0 2.25 2.25Z" />
|
||||||
</svg>
|
|
||||||
|
|
||||||
{% trans "Training" %}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item me-2">
|
|
||||||
<a class="nav-link {% if request.resolver_match.url_name == 'list_meetings' %}active{% endif %}" href="{% url 'list_meetings' %}">
|
|
||||||
<span class="d-flex align-items-center gap-2">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m15.75 10.5 4.72-4.72a.75.75 0 0 1 1.28.53v11.38a.75.75 0 0 1-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 0 0 2.25-2.25v-9a2.25 2.25 0 0 0-2.25-2.25h-9A2.25 2.25 0 0 0 2.25 7.5v9a2.25 2.25 0 0 0 2.25 2.25Z" />
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
{% trans "Meetings" %}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item me-2">
|
|
||||||
<a class="nav-link {% if request.resolver_match.url_name == 'form_templates_list' %}active{% endif %}" href="{% url 'form_templates_list' %}">
|
|
||||||
<span class="d-flex align-items-center gap-2">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" />
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
{% trans "Form Templates" %}
|
{% trans "Meetings" %}
|
||||||
</span>
|
|
||||||
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item dropdown ms-2">
|
|
||||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
|
|
||||||
data-bs-offset="0, 8" data-bs-auto-close="outside">
|
|
||||||
{% trans "More" %}
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu" data-bs-popper="static">
|
|
||||||
<li><a class="dropdown-item" href="#"><i class="fas fa-calendar me-2"></i> {% trans "Meetings" %}</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#"><i class="fas fa-clock me-2"></i> {% trans "Schedule" %}</a></li>
|
|
||||||
<li><hr class="dropdown-divider"></li>
|
|
||||||
<li><a class="dropdown-item" href="#"><i class="fas fa-briefcase me-2"></i> {% trans "Active Jobs" %}</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#"><i class="fas fa-file-alt me-2"></i> {% trans "Draft Jobs" %}</a></li>
|
|
||||||
<li><hr class="dropdown-divider"></li>
|
|
||||||
<li><a class="dropdown-item" href="#"><i class="fas fa-users me-2"></i> {% trans "All Candidates" %}</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#"><i class="fas fa-user-plus me-2"></i> {% trans "New Candidates" %}</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
<ul class="navbar-nav me-2">
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a class="language-toggle-btn dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
|
|
||||||
data-bs-offset="0, 8" aria-expanded="false" aria-label="{% trans 'Toggle language menu' %}">
|
|
||||||
<i class="fas fa-globe"></i>
|
|
||||||
<span class="d-none d-lg-inline">{{ LANGUAGE_CODE|upper }}</span>
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-end" data-bs-popper="static">
|
|
||||||
|
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<form action="{% url 'set_language' %}" method="post" class="d-inline">{% csrf_token %}
|
|
||||||
<input name="next" type="hidden" value="{{ request.get_full_path }}">
|
|
||||||
<button name="language" value="en" class="dropdown-item {% if LANGUAGE_CODE == 'en' %}active bg-light-subtle{% endif %}" type="submit">
|
|
||||||
<span class="me-2">🇺🇸</span> English
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<form action="{% url 'set_language' %}" method="post" class="d-inline">{% csrf_token %}
|
|
||||||
<input name="next" type="hidden" value="{{ request.get_full_path }}">
|
|
||||||
<button name="language" value="ar" class="dropdown-item {% if LANGUAGE_CODE == 'ar' %}active bg-light-subtle{% endif %}" type="submit">
|
|
||||||
<span class="me-2">🇸🇦</span> العربية (Arabic)
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="navbar-nav ms-4">
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<button
|
|
||||||
class="nav-link p-0 border-0 bg-transparent dropdown-toggle"
|
|
||||||
type="button"
|
|
||||||
data-bs-toggle="dropdown"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-label="{% trans 'Toggle user menu' %}"
|
|
||||||
data-bs-auto-close="outside"
|
|
||||||
data-bs-offset="0, 8"
|
|
||||||
>
|
|
||||||
{% if user.profile.profile_image %}
|
|
||||||
<img src="{{ user.profile.profile_image.url }}" alt="{{ user.username }}" class="profile-avatar"
|
|
||||||
style="width: 36px; height: 36px; object-fit: cover; background-color: var(--kaauh-teal); display: inline-block; vertical-align: middle;"
|
|
||||||
title="{% trans 'Your account' %}">
|
|
||||||
{% else %}
|
|
||||||
<div class="profile-avatar" title="{% trans 'Your account' %}">
|
|
||||||
{{ user.username|first|upper }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% comment %} <span class="ms-2 d-none d-lg-inline fw-semibold">{{ user.username }}</span> {% endcomment %}
|
|
||||||
</button>
|
|
||||||
<ul
|
|
||||||
class="dropdown-menu dropdown-menu-end py-0 shadow border-0 rounded-3"
|
|
||||||
data-bs-popper="static"
|
|
||||||
style="min-width: 240px;"
|
|
||||||
>
|
|
||||||
<li class="px-4 py-3 ">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<div class="me-3 d-flex align-items-center justify-content-center" style="min-width: 48px;">
|
|
||||||
{% if user.profile.profile_image %}
|
|
||||||
<img src="{{ user.profile.profile_image.url }}" alt="{{ user.username }}" class="profile-avatar shadow-sm border"
|
|
||||||
style="width: 44px; height: 44px; object-fit: cover; background-color: var(--kaauh-teal); display: block;"
|
|
||||||
title="{% trans 'Your account' %}">
|
|
||||||
{% else %}
|
|
||||||
<div class="profile-avatar shadow-sm border d-flex align-items-center justify-content-center"
|
|
||||||
style="width: 44px; height: 44px; background-color: var(--kaauh-teal); font-size: 1.2rem;">
|
|
||||||
{{ user.username|first|upper }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="fw-semibold text-dark">{{ user.get_full_name|default:user.username }}</div>
|
|
||||||
<div class="text-muted small">{{ user.email|truncatechars:24 }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li><hr class="dropdown-divider my-1"></li>
|
|
||||||
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-user-circle me-3 text-primary fs-5"></i> <span>{% trans "My Profile" %}</span></a></li>
|
|
||||||
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-cog me-3 text-primary fs-5"></i> <span>{% trans "Settings" %}</span></a></li>
|
|
||||||
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-history me-3 text-primary fs-5"></i> <span>{% trans "Activity Log" %}</span></a></li>
|
|
||||||
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-question-circle me-3 text-primary fs-5"></i> <span>{% trans "Help & Support" %}</span></a></li>
|
|
||||||
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#">
|
|
||||||
{% if not request.session.linkedin_authenticated %}
|
|
||||||
<ul class="navbar-nav ms-auto">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="{% url 'linkedin_login' %}">
|
|
||||||
<i class="fab fa-linkedin me-1"></i> {% trans "Connect LinkedIn" %}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
{% else %}
|
|
||||||
<i class="fab fa-linkedin text-primary me-1"></i>
|
|
||||||
<span class="text-primary d-none d-lg-inline ms-auto me-3">
|
|
||||||
{% trans "LinkedIn Connected" %}
|
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
</a>
|
||||||
</a></li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
<li class="nav-item me-2">
|
||||||
|
<a class="nav-link {% if request.resolver_match.url_name == 'training_list' %}active{% endif %}" href="{% url 'training_list' %}">
|
||||||
|
<span class="d-flex align-items-center gap-2">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
<li><hr class="dropdown-divider my-1"></li>
|
{% trans "Training" %}
|
||||||
<li>
|
</span>
|
||||||
<form method="post" action="" class="d-inline">
|
</a>
|
||||||
{% csrf_token %}
|
</li>
|
||||||
<button
|
|
||||||
type="submit"
|
<li class="nav-item dropdown ms-2">
|
||||||
class="dropdown-item py-2 px-4 text-danger d-flex align-items-center border-0 bg-transparent text-start"
|
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
|
||||||
aria-label="{% trans 'Sign out' %}"
|
data-bs-offset="0, 8" data-bs-auto-close="outside">
|
||||||
>
|
{% trans "More" %}
|
||||||
<i class="fas fa-sign-out-alt me-3 fs-5"></i>
|
</a>
|
||||||
<span>{% trans "Sign Out" %}</span>
|
<ul class="dropdown-menu" data-bs-popper="static">
|
||||||
</button>
|
<li><a class="dropdown-item" href="#"><i class="fas fa-calendar me-2"></i> {% trans "Meetings" %}</a></li>
|
||||||
</form>
|
<li><a class="dropdown-item" href="#"><i class="fas fa-clock me-2"></i> {% trans "Schedule" %}</a></li>
|
||||||
</li>
|
<li><hr class="dropdown-divider"></li>
|
||||||
</ul>
|
<li><a class="dropdown-item" href="#"><i class="fas fa-briefcase me-2"></i> {% trans "Active Jobs" %}</a></li>
|
||||||
</li>
|
<li><a class="dropdown-item" href="#"><i class="fas fa-file-alt me-2"></i> {% trans "Draft Jobs" %}</a></li>
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li><a class="dropdown-item" href="#"><i class="fas fa-users me-2"></i> {% trans "All Candidates" %}</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#"><i class="fas fa-user-plus me-2"></i> {% trans "New Candidates" %}</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="navbar-nav me-2">
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="language-toggle-btn dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
|
||||||
|
data-bs-offset="0, 8" aria-expanded="false" aria-label="{% trans 'Toggle language menu' %}">
|
||||||
|
<i class="fas fa-globe"></i>
|
||||||
|
<span class="d-none d-lg-inline">{{ LANGUAGE_CODE|upper }}</span>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end" data-bs-popper="static">
|
||||||
|
|
||||||
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<form action="{% url 'set_language' %}" method="post" class="d-inline">{% csrf_token %}
|
||||||
|
<input name="next" type="hidden" value="{{ request.get_full_path }}">
|
||||||
|
<button name="language" value="en" class="dropdown-item {% if LANGUAGE_CODE == 'en' %}active bg-light-subtle{% endif %}" type="submit">
|
||||||
|
<span class="me-2">🇺🇸</span> English
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<form action="{% url 'set_language' %}" method="post" class="d-inline">{% csrf_token %}
|
||||||
|
<input name="next" type="hidden" value="{{ request.get_full_path }}">
|
||||||
|
<button name="language" value="ar" class="dropdown-item {% if LANGUAGE_CODE == 'ar' %}active bg-light-subtle{% endif %}" type="submit">
|
||||||
|
<span class="me-2">🇸🇦</span> العربية (Arabic)
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<ul class="navbar-nav ms-4">
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<button
|
||||||
|
class="nav-link p-0 border-0 bg-transparent dropdown-toggle"
|
||||||
|
type="button"
|
||||||
|
data-bs-toggle="dropdown"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-label="{% trans 'Toggle user menu' %}"
|
||||||
|
data-bs-auto-close="outside"
|
||||||
|
data-bs-offset="0, 8"
|
||||||
|
>
|
||||||
|
{% if user.profile.profile_image %}
|
||||||
|
<img src="{{ user.profile.profile_image.url }}" alt="{{ user.username }}" class="profile-avatar"
|
||||||
|
style="width: 36px; height: 36px; object-fit: cover; background-color: var(--kaauh-teal); display: inline-block; vertical-align: middle;"
|
||||||
|
title="{% trans 'Your account' %}">
|
||||||
|
{% else %}
|
||||||
|
<div class="profile-avatar" title="{% trans 'Your account' %}">
|
||||||
|
{{ user.username|first|upper }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% comment %} <span class="ms-2 d-none d-lg-inline fw-semibold">{{ user.username }}</span> {% endcomment %}
|
||||||
|
</button>
|
||||||
|
<ul
|
||||||
|
class="dropdown-menu dropdown-menu-end py-0 shadow border-0 rounded-3"
|
||||||
|
data-bs-popper="static"
|
||||||
|
style="min-width: 240px;"
|
||||||
|
>
|
||||||
|
<li class="px-4 py-3 ">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="me-3 d-flex align-items-center justify-content-center" style="min-width: 48px;">
|
||||||
|
{% if user.profile.profile_image %}
|
||||||
|
<img src="{{ user.profile.profile_image.url }}" alt="{{ user.username }}" class="profile-avatar shadow-sm border"
|
||||||
|
style="width: 44px; height: 44px; object-fit: cover; background-color: var(--kaauh-teal); display: block;"
|
||||||
|
title="{% trans 'Your account' %}">
|
||||||
|
{% else %}
|
||||||
|
<div class="profile-avatar shadow-sm border d-flex align-items-center justify-content-center"
|
||||||
|
style="width: 44px; height: 44px; background-color: var(--kaauh-teal); font-size: 1.2rem;">
|
||||||
|
{{ user.username|first|upper }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="fw-semibold text-dark">{{ user.get_full_name|default:user.username }}</div>
|
||||||
|
<div class="text-muted small">{{ user.email|truncatechars:24 }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li><hr class="dropdown-divider my-1"></li>
|
||||||
|
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-user-circle me-3 text-primary fs-5"></i> <span>{% trans "My Profile" %}</span></a></li>
|
||||||
|
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-cog me-3 text-primary fs-5"></i> <span>{% trans "Settings" %}</span></a></li>
|
||||||
|
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-history me-3 text-primary fs-5"></i> <span>{% trans "Activity Log" %}</span></a></li>
|
||||||
|
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-question-circle me-3 text-primary fs-5"></i> <span>{% trans "Help & Support" %}</span></a></li>
|
||||||
|
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#">
|
||||||
|
{% if not request.session.linkedin_authenticated %}
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'linkedin_login' %}">
|
||||||
|
<i class="fab fa-linkedin me-1"></i> {% trans "Connect LinkedIn" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<i class="fab fa-linkedin text-primary me-1"></i>
|
||||||
|
<span class="text-primary d-none d-lg-inline ms-auto me-3">
|
||||||
|
{% trans "LinkedIn Connected" %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</a></li>
|
||||||
|
|
||||||
|
<li><hr class="dropdown-divider my-1"></li>
|
||||||
|
<li>
|
||||||
|
<form method="post" action="" class="d-inline">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="dropdown-item py-2 px-4 text-danger d-flex align-items-center border-0 bg-transparent text-start"
|
||||||
|
aria-label="{% trans 'Sign out' %}"
|
||||||
|
>
|
||||||
|
<i class="fas fa-sign-out-alt me-3 fs-5"></i>
|
||||||
|
<span>{% trans "Sign Out" %}</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<main class="container flex-grow-1">
|
<main class="container-fluid flex-grow-1" style="max-width: 1600px; margin: 0 auto;">
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
{% for message in messages %}
|
{% for message in messages %}
|
||||||
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
||||||
@ -484,14 +518,24 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
<footer class="footer mt-auto">
|
|
||||||
<div class="container text-center">
|
<footer class="mt-auto">
|
||||||
<p class="mb-0">
|
<div class="footer-bottom py-3 small text-muted" style="background-color: #00363a;">
|
||||||
© {% now "Y" %} {% trans "King Abdullah Academic University Hospital (KAAUH)." %}<br>
|
<div class="container-fluid">
|
||||||
<small>{% trans "All rights reserved." %}</small>
|
<div class="d-flex justify-content-between align-items-center flex-wrap max-width-1600">
|
||||||
</p>
|
<p class="mb-0 text-white-50">
|
||||||
|
© {% now "Y" %} {% trans "King Abdullah Academic University Hospital (KAAUH)." %}
|
||||||
|
{% trans "All rights reserved." %}
|
||||||
|
</p>
|
||||||
|
<a class="text-decoration-none" href="https://tenhal.sa/" target='_blank'>
|
||||||
|
<p class="mb-0 text-white-50">
|
||||||
|
{% trans "Powered by" %} <strong class="text-white">Tenhal</strong>
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
{% include 'includes/delete_modal.html' %}
|
{% include 'includes/delete_modal.html' %}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,9 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>ATS Form Builder - Vanilla JS</title>
|
<title>ATS Form Builder - Vanilla JS</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Updated CSS styles with a new Teal/Aqua theme */
|
/* Updated CSS styles with a new Teal/Aqua theme */
|
||||||
:root {
|
:root {
|
||||||
@ -771,8 +773,22 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Main Content Area -->
|
<!-- Main Content Area -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
|
<nav>
|
||||||
|
<div class="bread" style="color: #6c757d; font-size: 0.9rem;">
|
||||||
|
<span class="me-2">
|
||||||
|
<a href="{% url 'dashboard' %}" style="color: #6c757d !important; text-decoration: none !important;">Home</a>
|
||||||
|
/
|
||||||
|
</span>
|
||||||
|
<span class="me-2">
|
||||||
|
<a href="{% url 'job_list' %}" style="color: #6c757d !important; text-decoration: none !important;">Jobs</a>
|
||||||
|
/
|
||||||
|
</span>
|
||||||
|
<span style="color: #6c757d; font-weight: 600;">Form Builder</span>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<h1 id="formTitle">Resume Application Form</h1>
|
<h1 id="formTitle">Resume Application Form</h1>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button class="btn btn-outline" id="formSettingsBtn">
|
<button class="btn btn-outline" id="formSettingsBtn">
|
||||||
<i class="fas fa-cog"></i> Settings
|
<i class="fas fa-cog"></i> Settings
|
||||||
@ -961,7 +977,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
// Application State
|
// Application State
|
||||||
const state = {
|
const state = {
|
||||||
draggedStageIndex: null,
|
draggedStageIndex: null,
|
||||||
|
|||||||
@ -1,45 +1,198 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load i18n static %}
|
||||||
|
|
||||||
{% load form_filters %}
|
{% load form_filters %}
|
||||||
|
|
||||||
{% block title %}{{ form.name }} - Submission Details{% endblock %}
|
{% block title %}{{ form.name }} - Submission Details{% endblock %}
|
||||||
|
|
||||||
|
{% block customCSS %}
|
||||||
|
<style>
|
||||||
|
/* ================================================= */
|
||||||
|
/* THEME VARIABLES AND GLOBAL STYLES */
|
||||||
|
/* ================================================= */
|
||||||
|
:root {
|
||||||
|
--kaauh-teal: #00636e; /* Primary */
|
||||||
|
--kaauh-teal-dark: #004a53;
|
||||||
|
--kaauh-border: #eaeff3;
|
||||||
|
--kaauh-primary-text: #343a40;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Primary Color Overrides */
|
||||||
|
.text-primary { color: var(--kaauh-teal) !important; }
|
||||||
|
.text-info { color: #17a2b8 !important; }
|
||||||
|
.text-success { color: #28a745 !important; }
|
||||||
|
.text-secondary { color: #6c757d !important; }
|
||||||
|
.bg-info { background-color: #17a2b8 !important; }
|
||||||
|
.bg-secondary { background-color: #6c757d !important; }
|
||||||
|
|
||||||
|
/* Card enhancements */
|
||||||
|
.card {
|
||||||
|
border: 1px solid var(--kaauh-border);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
background-color: #f8f9fa; /* Light background */
|
||||||
|
border-bottom: 1px solid var(--kaauh-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Action Button Style */
|
||||||
|
.btn-main-action {
|
||||||
|
background-color: var(--kaauh-teal);
|
||||||
|
border-color: var(--kaauh-teal);
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.btn-main-action:hover {
|
||||||
|
background-color: var(--kaauh-teal-dark);
|
||||||
|
border-color: var(--kaauh-teal-dark);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Secondary outline button */
|
||||||
|
.btn-outline-secondary {
|
||||||
|
color: var(--kaauh-teal-dark);
|
||||||
|
border-color: var(--kaauh-teal);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.btn-outline-secondary:hover {
|
||||||
|
background-color: var(--kaauh-teal-dark);
|
||||||
|
color: white;
|
||||||
|
border-color: var(--kaauh-teal-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================= */
|
||||||
|
/* RESPONSES TABLE SPECIFIC STYLES (Horizontal Layout) */
|
||||||
|
/* ================================================= */
|
||||||
|
|
||||||
|
/* Main table container */
|
||||||
|
.table-submission {
|
||||||
|
margin-bottom: 0;
|
||||||
|
border: none;
|
||||||
|
table-layout: auto; /* Allow columns to resize based on content */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fixed first column (the row headers) */
|
||||||
|
.table-submission th:first-child,
|
||||||
|
.table-submission td:first-child {
|
||||||
|
background-color: #f0f4f7; /* Slightly darker than header */
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--kaauh-primary-text);
|
||||||
|
width: 150px;
|
||||||
|
min-width: 150px;
|
||||||
|
position: sticky; /* Keep it visible when scrolling right */
|
||||||
|
left: 0;
|
||||||
|
z-index: 2;
|
||||||
|
border-right: 1px solid var(--kaauh-border);
|
||||||
|
}
|
||||||
|
.table-submission th:first-child {
|
||||||
|
top: 0; /* Important for sticky header/row-header intersection */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Field Label Header Row (Top Row) */
|
||||||
|
.table-submission thead th {
|
||||||
|
font-weight: 600;
|
||||||
|
background-color: #e9ecef; /* Light gray for headers */
|
||||||
|
color: var(--kaauh-primary-text);
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid var(--kaauh-border);
|
||||||
|
border-bottom: 2px solid var(--kaauh-teal); /* Highlight the bottom of the header */
|
||||||
|
padding: 0.75rem 0.5rem;
|
||||||
|
}
|
||||||
|
.table-submission thead th:not(:first-child) {
|
||||||
|
min-width: 200px; /* Give response columns space */
|
||||||
|
max-width: 300px;
|
||||||
|
white-space: normal;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Data Cells */
|
||||||
|
.table-submission tbody td {
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 0.75rem 0.75rem;
|
||||||
|
border: 1px solid var(--kaauh-border);
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Styling for multi-value responses */
|
||||||
|
.table-submission .badge {
|
||||||
|
font-weight: 500;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* File display */
|
||||||
|
.table-submission .fa-file {
|
||||||
|
color: var(--kaauh-teal);
|
||||||
|
}
|
||||||
|
.table-submission .btn-outline-primary {
|
||||||
|
color: var(--kaauh-teal);
|
||||||
|
border-color: var(--kaauh-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid">
|
|
||||||
|
<div class="container-fluid py-4">
|
||||||
|
<nav aria-label="breadcrumb">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'job_detail' submission.template.job.slug %}">Job Detail</a></li>
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'form_builder' submission.template.pk%}">Form Template</a></li>
|
||||||
|
<li class="breadcrumb-item active" aria-current="page">Submission Details</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h2>Submission Details</h2>
|
<h2 class="text-primary fw-bold">{% trans "Submission Details" %}</h2>
|
||||||
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-secondary">
|
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-secondary">
|
||||||
<i class="fas fa-arrow-left"></i> Back to Submissions
|
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Submissions" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Basic Information -->
|
<div class="card shadow-sm mb-4">
|
||||||
<div class="card mb-3">
|
<div class="card-header">
|
||||||
<div class="card-body">
|
<h5 class="mb-0">{% trans "Submission Metadata" %}</h5>
|
||||||
<div class="row">
|
</div>
|
||||||
|
<div class="card-body small">
|
||||||
|
<div class="row g-3">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<strong>Submission ID:</strong> {{ submission.id }}
|
<i class="fas fa-fingerprint me-2 text-primary"></i>
|
||||||
|
<strong>{% trans "Submission ID:" %}</strong> <span class="text-secondary">{{ submission.id }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<strong>Submitted:</strong> {{ submission.submitted_at|date:"M d, Y H:i" }}
|
<i class="fas fa-calendar-check me-2 text-primary"></i>
|
||||||
|
<strong>{% trans "Submitted:" %}</strong> <span class="text-secondary">{{ submission.submitted_at|date:"M d, Y H:i" }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<strong>Form:</strong> {{ form.name }}
|
<i class="fas fa-file-alt me-2 text-primary"></i>
|
||||||
|
<strong>{% trans "Form:" %}</strong> <span class="text-secondary">{{ submission.template.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if submission.applicant_name or submission.applicant_email %}
|
{% if submission.applicant_name or submission.applicant_email %}
|
||||||
<div class="row mt-2">
|
<div class="row g-3 mt-1">
|
||||||
{% if submission.applicant_name %}
|
{% if submission.applicant_name %}
|
||||||
<div class="col-md-6">
|
<div class="col-md-4">
|
||||||
<strong>Applicant Name:</strong> {{ submission.applicant_name }}
|
<i class="fas fa-user me-2 text-primary"></i>
|
||||||
|
<strong>{% trans "Applicant Name:" %}</strong> <span class="text-secondary">{{ submission.applicant_name }}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if submission.applicant_email %}
|
{% if submission.applicant_email %}
|
||||||
<div class="col-md-6">
|
<div class="col-md-4">
|
||||||
<strong>Email:</strong> {{ submission.applicant_email }}
|
<i class="fas fa-envelope me-2 text-primary"></i>
|
||||||
|
<strong>{% trans "Email:" %}</strong> <span class="text-secondary">{{ submission.applicant_email }}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
@ -47,19 +200,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Responses Table -->
|
<div class="card shadow-sm">
|
||||||
<div class="card">
|
<div class="card-header">
|
||||||
<div class="card-body">
|
<h5 class="mb-0">{% trans "Form Responses" %}</h5>
|
||||||
<h5 class="mb-3">Responses</h5>
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
{% with submission=submission %}
|
{% with submission=submission %}
|
||||||
{% get_all_responses_flat submission as flat_responses %}
|
{% get_all_responses_flat submission as flat_responses %}
|
||||||
|
|
||||||
{% if flat_responses %}
|
{% if flat_responses %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-submission table-hover">
|
||||||
<thead class="table-light">
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" style="width: 150px;">Field Label</th>
|
<th scope="col">{% trans "Field Property" %}</th>
|
||||||
{% for response in flat_responses %}
|
{% for response in flat_responses %}
|
||||||
<th scope="col">{{ response.field_label }}</th>
|
<th scope="col">{{ response.field_label }}</th>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@ -67,50 +221,50 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>Response Value</strong></td>
|
<td><strong>{% trans "Response Value" %}</strong></td>
|
||||||
{% for response in flat_responses %}
|
{% for response in flat_responses %}
|
||||||
<td>
|
<td>
|
||||||
{% if response.uploaded_file %}
|
{% if response.uploaded_file %}
|
||||||
<div>
|
<div>
|
||||||
<span class="text-primary"><i class="fas fa-file"></i> {{ response.uploaded_file.name }}</span>
|
<span class="d-block text-truncate" style="max-width: 180px;"><i class="fas fa-file me-1"></i> {{ response.uploaded_file.name }}</span>
|
||||||
<a href="{{ response.uploaded_file.url }}" class="btn btn-sm btn-outline-primary ms-2" target="_blank" title="Download File">
|
<a href="{{ response.uploaded_file.url }}" class="btn btn-sm btn-outline-secondary mt-1" target="_blank" title="{% trans 'Download File' %}">
|
||||||
<i class="fas fa-download"></i>
|
<i class="fas fa-download"></i> {% trans "Download" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% elif response.value %}
|
{% elif response.value %}
|
||||||
{% if response.field_type == 'checkbox' and response.value|length > 0 %}
|
{% if response.field_type == 'checkbox' and response.value|length > 0 %}
|
||||||
<div>
|
<div class="d-flex flex-wrap gap-1">
|
||||||
{% for val in response.value %}
|
{% for val in response.value %}
|
||||||
<span class="badge bg-secondary me-1">{{ val }}</span>
|
<span class="badge bg-secondary">{{ val }}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% elif response.field_type == 'radio' or response.field_type == 'select' %}
|
{% elif response.field_type == 'radio' or response.field_type == 'select' %}
|
||||||
<span class="badge bg-info">{{ response.value }}</span>
|
<span class="badge bg-info">{{ response.value }}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="mb-0">{{ response.value|linebreaksbr }}</p>
|
<p class="mb-0 small text-wrap">{{ response.value|linebreaksbr }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="text-muted">Not provided</span>
|
<span class="text-muted small">{% trans "Not provided" %}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>Stage</strong></td>
|
<td><strong>{% trans "Associated Stage" %}</strong></td>
|
||||||
{% for response in flat_responses %}
|
{% for response in flat_responses %}
|
||||||
<td>
|
<td>
|
||||||
{{ response.stage_name|default:"N/A" }}
|
<span class="small text-secondary">{{ response.stage_name|default:"N/A" }}</span>
|
||||||
</td>
|
</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>Required</strong></td>
|
<td><strong>{% trans "Field Required" %}</strong></td>
|
||||||
{% for response in flat_responses %}
|
{% for response in flat_responses %}
|
||||||
<td>
|
<td>
|
||||||
{% if response.required %}
|
{% if response.required %}
|
||||||
<span class="text-danger"><i class="fas fa-asterisk"></i> Yes</span>
|
<span class="text-danger small"><i class="fas fa-asterisk"></i> {% trans "Yes" %}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span>No</span>
|
<span class="small text-success">{% trans "No" %}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@ -119,43 +273,14 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text-center text-muted py-4">
|
<div class="text-center text-muted py-5 px-3">
|
||||||
<p>No responses found for this submission.</p>
|
<i class="fas fa-exclamation-circle fa-2x mb-3"></i>
|
||||||
|
<p class="lead">{% trans "No response fields were found for this submission." %}</p>
|
||||||
|
<p class="small">{% trans "This may occur if the form template was modified or responses were cleared." %}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_css %}
|
|
||||||
<style>
|
|
||||||
/* Minimal styling */
|
|
||||||
.table th {
|
|
||||||
border-top: none;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #495057;
|
|
||||||
vertical-align: top;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.table td {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
.response-value {
|
|
||||||
max-width: 300px;
|
|
||||||
}
|
|
||||||
.table th:first-child,
|
|
||||||
.table td:first-child {
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
.table-striped > tbody > tr:nth-of-type(odd) > td {
|
|
||||||
background-color: rgba(0, 0, 0, 0.02);
|
|
||||||
}
|
|
||||||
.table-bordered th,
|
|
||||||
.table-bordered td {
|
|
||||||
border: 1px solid #dee2e6;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
@ -25,7 +25,7 @@
|
|||||||
background-color: var(--kaauh-teal);
|
background-color: var(--kaauh-teal);
|
||||||
border-color: var(--kaauh-teal);
|
border-color: var(--kaauh-teal);
|
||||||
color: white;
|
color: white;
|
||||||
font-weight: 600;
|
font-weight: 900 ;
|
||||||
padding: 0.375rem 0.75rem;
|
padding: 0.375rem 0.75rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
@ -251,7 +251,7 @@
|
|||||||
<div class="card-view">
|
<div class="card-view">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
{% for submission in page_obj %}
|
{% for submission in page_obj %}
|
||||||
<div class="col-lg-4 col-md-6">
|
<div class="col-12">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3 class="h5 mb-2">{% trans "Submission" %} #{{ submission.id }}</h3>
|
<h3 class="h5 mb-2">{% trans "Submission" %} #{{ submission.id }}</h3>
|
||||||
@ -328,7 +328,7 @@
|
|||||||
<p class="text-muted mb-4">
|
<p class="text-muted mb-4">
|
||||||
{% trans "There are no submissions for this form template yet." %}
|
{% trans "There are no submissions for this form template yet." %}
|
||||||
</p>
|
</p>
|
||||||
<a href="{% url 'form_templates_list' %}" class="btn btn-main-action">
|
<a href="{% url 'form_templates_list' %}" class="btn btn-main-action btn-sm">
|
||||||
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Templates" %}
|
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Templates" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -148,7 +148,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid py-4">
|
<div class="container-fluid py-4">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h1 class="h3 mb-0" style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||||
<i class="fas fa-file-alt me-2"></i>{% trans "Form Templates" %}
|
<i class="fas fa-file-alt me-2"></i>{% trans "Form Templates" %}
|
||||||
</h1>
|
</h1>
|
||||||
<button type="button" class="btn btn-main-action" data-bs-toggle="modal" data-bs-target="#createTemplateModal">
|
<button type="button" class="btn btn-main-action" data-bs-toggle="modal" data-bs-target="#createTemplateModal">
|
||||||
|
|||||||
@ -591,7 +591,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wizard-footer">
|
<div class="wizard-footer mt-2">
|
||||||
<button
|
<button
|
||||||
id="backBtn"
|
id="backBtn"
|
||||||
class="nav-btn btn-back"
|
class="nav-btn btn-back"
|
||||||
|
|||||||
9
templates/jobs/applicants_of_stage.html
Normal file
9
templates/jobs/applicants_of_stage.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{{stage}}
|
||||||
|
{% for applicant in applicants_of_stage %}
|
||||||
|
|
||||||
|
|
||||||
|
{{applicant}}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
628
templates/jobs/base_public.html
Normal file
628
templates/jobs/base_public.html
Normal file
@ -0,0 +1,628 @@
|
|||||||
|
{% load i18n static %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ LANGUAGE_CODE }}" dir="{% if LANGUAGE_CODE == 'ar' %}rtl{% else %}ltr{% endif %}">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{% block title %}{% trans 'Careers' %} - KAAUH{% endblock %}</title>
|
||||||
|
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--kaauh-teal: #00636e;
|
||||||
|
--kaauh-teal-dark: #004a53;
|
||||||
|
--kaauh-light-bg: #f9fbfd;
|
||||||
|
--kaauh-border: #eaeff3;
|
||||||
|
--kaauh-green-dark: #00363a;
|
||||||
|
--kaauh-nav-bg: #004a53;
|
||||||
|
--kaauh-dark-nav-active: #00363a;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-width-container {
|
||||||
|
max-width: 1600px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Header Top Info === */
|
||||||
|
.header-top-info {
|
||||||
|
background-color: white;
|
||||||
|
padding: 15px 0;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: #333;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .section-divider {
|
||||||
|
border-inline-start: 1px solid #ddd;
|
||||||
|
height: 60px;
|
||||||
|
margin: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .follow-us-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.header-top-info .social-icon-circle {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--kaauh-teal);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 1rem;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
.header-top-info .social-icon-circle:hover {
|
||||||
|
background-color: var(--kaauh-teal-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .contact-block {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .contact-icon-block {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 15px;
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
.header-top-info .contact-icon {
|
||||||
|
font-size: 2rem;
|
||||||
|
color: var(--kaauh-teal);
|
||||||
|
margin-inline-end: 15px;
|
||||||
|
}
|
||||||
|
.header-top-info .contact-details {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
.header-top-info .contact-details span:first-child {
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--kaauh-teal);
|
||||||
|
}
|
||||||
|
.header-top-info .contact-details span:last-child {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .logo-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
.header-top-info .vision-logo-container {
|
||||||
|
border-inline-start: 1px solid #ddd;
|
||||||
|
padding-inline-start: 20px;
|
||||||
|
min-height: 60px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.header-top-info .vision-logo {
|
||||||
|
max-height: 50px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.header-top-info .kaauh-logo-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-inline-start: 1px solid #ddd;
|
||||||
|
padding-inline-start: 20px;
|
||||||
|
}
|
||||||
|
.header-top-info .kaauh-logo-container img {
|
||||||
|
max-height: 80px;
|
||||||
|
width: auto;
|
||||||
|
margin-inline-end: 10px;
|
||||||
|
}
|
||||||
|
.header-top-info .hospital-text {
|
||||||
|
line-height: 1.2;
|
||||||
|
text-align: initial;
|
||||||
|
}
|
||||||
|
.header-top-info .hospital-text .ar {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--kaauh-teal-dark);
|
||||||
|
}
|
||||||
|
.header-top-info .hospital-text .en {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Main Navbar === */
|
||||||
|
.navbar-main {
|
||||||
|
background-color: var(--kaauh-nav-bg);
|
||||||
|
padding: 0;
|
||||||
|
min-height: 60px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.navbar-main .nav-link {
|
||||||
|
color: white !important;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
padding: 1.1rem 1.2rem;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
border-inline-end: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.navbar-main .nav-link:hover,
|
||||||
|
.navbar-main .nav-link.active {
|
||||||
|
background-color: var(--kaauh-dark-nav-active);
|
||||||
|
border-inline-end: 1px solid var(--kaauh-dark-nav-active);
|
||||||
|
}
|
||||||
|
.navbar-main .nav-icons-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--kaauh-dark-nav-active);
|
||||||
|
height: 100%;
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
.navbar-main .nav-icon {
|
||||||
|
color: white;
|
||||||
|
padding: 0 15px;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
.navbar-main .nav-icon:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.navbar-main .profile-icon {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
.navbar-main .lang-switch {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.navbar-main .dropdown-menu {
|
||||||
|
border-radius: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
border: none;
|
||||||
|
box-shadow: 0 4px 10px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
.navbar-main .dropdown-item:hover {
|
||||||
|
background-color: var(--kaauh-light-bg);
|
||||||
|
color: var(--kaauh-teal-dark);
|
||||||
|
}
|
||||||
|
.navbar-toggler {
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.navbar-toggler:focus {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.navbar-toggler-icon {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
.navbar-main .collapse {
|
||||||
|
justify-content: flex-start !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Footer === */
|
||||||
|
.footer-main {
|
||||||
|
background-color: var(--kaauh-green-dark);
|
||||||
|
color: white;
|
||||||
|
padding-top: 3rem;
|
||||||
|
}
|
||||||
|
.footer-main a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
.footer-main a:hover {
|
||||||
|
color: var(--kaauh-teal);
|
||||||
|
}
|
||||||
|
.footer-main h5 {
|
||||||
|
color: var(--kaauh-teal);
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
.footer-main .social-icons a {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-inline-end: 15px;
|
||||||
|
}
|
||||||
|
.footer-main .contact-info,
|
||||||
|
.footer-main .app-download {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
.footer-bottom {
|
||||||
|
background-color: #00282b;
|
||||||
|
padding: 1rem 0;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
.footer-bottom strong {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.footer-main .col-lg-3, .footer-main .col-lg-5 {
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
}
|
||||||
|
.footer-main .vision-logo {
|
||||||
|
max-width: 100px;
|
||||||
|
}
|
||||||
|
.footer-main .app-store-badge,
|
||||||
|
.footer-main .play-store-badge {
|
||||||
|
max-width: 150px;
|
||||||
|
height: auto;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Hero Section === */
|
||||||
|
.hero-section {
|
||||||
|
height: 50vh;
|
||||||
|
background: url('{% static "image/hospital-bg.jpg" %}') no-repeat center center;
|
||||||
|
background-size: cover;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.hero-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
.hero-content {
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.hero-content h1 {
|
||||||
|
font-size: 3rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.breadcrumb-section {
|
||||||
|
padding: 10px 0;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
.breadcrumb-item a {
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
.breadcrumb-item.active {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--kaauh-teal-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === RTL Adjustments === */
|
||||||
|
html[dir="rtl"] {
|
||||||
|
text-align: right;
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .max-width-container {
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .header-top-info .section-divider {
|
||||||
|
border-inline-start: none;
|
||||||
|
border-inline-end: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .header-top-info .contact-icon {
|
||||||
|
margin-inline-end: 0;
|
||||||
|
margin-inline-start: 15px;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .header-top-info .contact-details {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .header-top-info .vision-logo-container {
|
||||||
|
border-inline-start: none;
|
||||||
|
border-inline-end: 1px solid #ddd;
|
||||||
|
padding-inline-start: 0;
|
||||||
|
padding-inline-end: 20px;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .header-top-info .kaauh-logo-container {
|
||||||
|
border-inline-start: none;
|
||||||
|
border-inline-end: 1px solid #ddd;
|
||||||
|
padding-inline-start: 0;
|
||||||
|
padding-inline-end: 20px;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .header-top-info .kaauh-logo-container img {
|
||||||
|
margin-inline-end: 0;
|
||||||
|
margin-inline-start: 10px;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .header-top-info .hospital-text {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .navbar-main .nav-link {
|
||||||
|
border-inline-end: none;
|
||||||
|
border-inline-start: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .navbar-main .nav-link:hover,
|
||||||
|
html[dir="rtl"] .navbar-main .nav-link.active {
|
||||||
|
border-inline-start: 1px solid var(--kaauh-dark-nav-active);
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .nav-icons i {
|
||||||
|
margin-inline-start: 10px;
|
||||||
|
margin-inline-end: 0;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .top-bar .social-icons a {
|
||||||
|
margin-inline-start: 0;
|
||||||
|
margin-inline-end: 10px;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .footer-main .social-icons a {
|
||||||
|
margin-inline-start: 15px;
|
||||||
|
margin-inline-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Responsive Adjustments for Small Screens === */
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
.header-top-info .max-width-container {
|
||||||
|
flex-direction: column !important;
|
||||||
|
align-items: flex-start !important;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .follow-us-section,
|
||||||
|
.header-top-info .d-flex.align-items-center.flex-grow-1.justify-content-end {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .contact-block,
|
||||||
|
.header-top-info .logo-section {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .section-divider {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .kaauh-logo-container img {
|
||||||
|
max-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .hospital-text .ar,
|
||||||
|
.header-top-info .hospital-text .en {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .contact-icon {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .contact-icon-block {
|
||||||
|
min-height: auto;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 575.98px) {
|
||||||
|
.header-top-info .kaauh-logo-container,
|
||||||
|
.header-top-info .vision-logo-container {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .hospital-text {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .kaauh-logo-container img {
|
||||||
|
max-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .follow-us-section span,
|
||||||
|
.header-top-info .contact-details span {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-top-info .social-icon-circle {
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-content h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% block customCSS %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body class="d-flex flex-column min-vh-100">
|
||||||
|
|
||||||
|
<!-- Responsive Header Top Info -->
|
||||||
|
<div class="header-top-info">
|
||||||
|
<div class="max-width-container d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center gap-3">
|
||||||
|
|
||||||
|
<div class="follow-us-section d-flex flex-wrap align-items-center gap-2">
|
||||||
|
<span>{% trans "Follow Us On:" %}</span>
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<a href="#" class="social-icon-circle"><i class="fab fa-facebook-f"></i></a>
|
||||||
|
<a href="#" class="social-icon-circle"><i class="fab fa-twitter"></i></a>
|
||||||
|
<a href="#" class="social-icon-circle"><i class="fab fa-instagram"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex flex-column flex-md-row align-items-start align-items-md-center gap-3 w-100 w-md-auto">
|
||||||
|
<div class="d-flex flex-wrap justify-content-between gap-3">
|
||||||
|
<div class="contact-icon-block d-flex align-items-center">
|
||||||
|
<i class="fas fa-headset contact-icon"></i>
|
||||||
|
<div class="contact-details ms-2">
|
||||||
|
<span>24/7 {% trans "Online Support" %}</span>
|
||||||
|
<span class="d-block d-md-inline">info@kaauh.edu.sa</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="contact-icon-block d-flex align-items-center">
|
||||||
|
<i class="fas fa-phone-alt contact-icon"></i>
|
||||||
|
<div class="contact-details ms-2">
|
||||||
|
<span>{% trans "Contact Us Free" %}</span>
|
||||||
|
<span class="d-block d-md-inline">+966118200000</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="logo-section d-flex flex-wrap align-items-center gap-3 mt-2 mt-md-0">
|
||||||
|
|
||||||
|
<div class="kaauh-logo-container d-flex flex-column flex-md-row align-items-center gap-2">
|
||||||
|
<img src="{% static 'image/vision.svg' %}" alt="Vision 2030" class="vision-logo" style="min-height: 70px; min-width:300px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="logo-section d-flex flex-wrap align-items-center gap-3 mt-2 mt-md-0 ms-6">
|
||||||
|
|
||||||
|
<div class="kaauh-logo-container d-flex flex-column flex-md-row align-items-center gap-2 ms-4">
|
||||||
|
<div class="hospital-text text-center text-md-start me-3">
|
||||||
|
<div class="ar">جامعة الأميرة نورة بنت عبدالرحمن الأكاديمية</div>
|
||||||
|
<div class="ar">ومستشفى الملك عبدالله بن عبدالعزيز التخصصي</div>
|
||||||
|
<div class="en">Princess Nourah bint Abdulrahman University</div>
|
||||||
|
<div class="en">King Abdullah bin Abdulaziz University Hospital</div>
|
||||||
|
</div>
|
||||||
|
<img src="{% static 'image/kaauh.png' %}" alt="KAAUH Logo" style="max-height: 80px;min-width:80px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Navigation -->
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark navbar-main">
|
||||||
|
<div class="max-width-container d-flex justify-content-between align-items-stretch w-100">
|
||||||
|
<button class="navbar-toggler ms-auto" type="button" data-bs-toggle="collapse" data-bs-target="#publicNavCollapse"
|
||||||
|
aria-controls="publicNavCollapse" aria-expanded="false" aria-label="{% trans 'Toggle navigation' %}">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="collapse navbar-collapse" id="publicNavCollapse">
|
||||||
|
<ul class="navbar-nav mb-2 mb-lg-0">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">{% trans "About KAAUH" %}</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
{% trans "Patients & Visitor" %}
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a class="dropdown-item" href="#">{% trans "Find a Doctor" %}</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#">{% trans "Visiting Hours" %}</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
{% trans "Training & Education" %}
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a class="dropdown-item" href="#">{% trans "Courses" %}</a></li>
|
||||||
|
<li><a class="dropdown-item" href="#">{% trans "Residency" %}</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" href="{% url 'kaauh_career' %}">{% trans "Careers" %}</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">{% trans "Gallery" %}</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">{% trans "Connect" %}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-icons-group d-none d-lg-flex">
|
||||||
|
<a href="#" class="nav-icon profile-icon"><i class="fas fa-user-circle"></i></a>
|
||||||
|
<a href="#" class="nav-icon lang-switch">ع</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="flex-grow-1">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="footer-main mt-auto">
|
||||||
|
<div class="max-width-container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-3 col-md-6 app-download">
|
||||||
|
<h5 class="text-white-50">{% trans "Download our mobile app" %}</h5>
|
||||||
|
<p>{% trans "Get the latest updates and services on the go." %}</p>
|
||||||
|
<div class="d-flex flex-column gap-2 mt-3">
|
||||||
|
<a href="#"><img src="{% static 'image/google-play-badge.png' %}" alt="Google Play" class="play-store-badge"></a>
|
||||||
|
<a href="#"><img src="{% static 'image/app-store-badge.png' %}" alt="App Store" class="app-store-badge"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-lg-2 col-md-6">
|
||||||
|
<h5>{% trans "Information" %}</h5>
|
||||||
|
<ul class="list-unstyled">
|
||||||
|
<li><a href="#">{% trans "About the Hospital" %}</a></li>
|
||||||
|
<li><a href="{% url 'kaauh_career' %}">{% trans "Careers" %}</a></li>
|
||||||
|
<li><a href="#">{% trans "Today's Clinic Hours" %}</a></li>
|
||||||
|
<li><a href="#">{% trans "Support Us" %}</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-lg-3 col-md-6">
|
||||||
|
<h5>{% trans "Need Help" %}</h5>
|
||||||
|
<ul class="list-unstyled">
|
||||||
|
<li><a href="#">{% trans "Support and Services" %}</a></li>
|
||||||
|
<li><a href="#">{% trans "Contact Us" %}</a></li>
|
||||||
|
<li><a href="#">{% trans "FAQ" %}</a></li>
|
||||||
|
<li><a href="#">{% trans "Sitemap" %}</a></li>
|
||||||
|
</ul>
|
||||||
|
<div class="contact-info mt-3">
|
||||||
|
<i class="fas fa-phone-alt me-2 text-white-50"></i> <strong class="text-white">966118200000</strong><br>
|
||||||
|
<i class="fas fa-envelope me-2 text-white-50"></i> <a href="mailto:info@kaauh.edu.sa">info@kaauh.edu.sa</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-lg-4 col-md-6">
|
||||||
|
<h5>{% trans "Contact & Address" %}</h5>
|
||||||
|
<p>{% trans "KAAUH Campus, Riyadh, Saudi Arabia" %}</p>
|
||||||
|
<p class="small text-white-50">{% trans "Postal Code 11564, King Fahd Road, Al-Rabi District." %}</p>
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center justify-content-start gap-3 mt-4">
|
||||||
|
<img src="{% static 'image/vision.svg' %}" alt="Vision 2030" class="vision-logo">
|
||||||
|
<div class="social-icons">
|
||||||
|
<a href="#"><i class="fab fa-facebook-f"></i></a>
|
||||||
|
<a href="#"><i class="fab fa-twitter"></i></a>
|
||||||
|
<a href="#"><i class="fab fa-instagram"></i></a>
|
||||||
|
<a href="#"><i class="fab fa-youtube"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-bottom mt-5">
|
||||||
|
<div class="max-width-container d-flex justify-content-between align-items-center flex-wrap">
|
||||||
|
<p class="mb-0">
|
||||||
|
© {% now "Y" %} {% trans "King Abdullah Academic University Hospital (KAAUH)." %}
|
||||||
|
{% trans "All rights reserved." %}
|
||||||
|
</p>
|
||||||
|
<p class="mb-0">
|
||||||
|
{% trans "Powered by" %} <strong class="text-white">Tenhal</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
{% block customJS %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
154
templates/jobs/career.html
Normal file
154
templates/jobs/career.html
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
{% extends "jobs/base_public.html" %}
|
||||||
|
{% load i18n static %}
|
||||||
|
|
||||||
|
{% block customCSS %}
|
||||||
|
<style>
|
||||||
|
/* Custom style for the job list table */
|
||||||
|
.job-listing-section {
|
||||||
|
padding: 3rem 0;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.job-table {
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 15px rgba(0,0,0,0.08);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.job-table thead th {
|
||||||
|
background-color: var(--kaauh-teal-dark);
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
text-align: start;
|
||||||
|
border-bottom: 2px solid var(--kaauh-teal);
|
||||||
|
}
|
||||||
|
.job-table tbody td {
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-bottom: 1px solid var(--kaauh-border);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--kaauh-primary-text);
|
||||||
|
}
|
||||||
|
.job-table tbody tr:hover {
|
||||||
|
background-color: var(--kaauh-light-bg);
|
||||||
|
}
|
||||||
|
.job-link-cell {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
text-align: center; /* Center the button in its cell */
|
||||||
|
}
|
||||||
|
.job-link-cell i {
|
||||||
|
color: var(--kaauh-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply Button */
|
||||||
|
.btn-apply {
|
||||||
|
background-color: var(--kaauh-teal);
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.4rem 1.2rem;
|
||||||
|
border-radius: 5px;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
min-width: 80px;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
border: 1px solid var(--kaauh-teal);
|
||||||
|
}
|
||||||
|
.btn-apply:hover {
|
||||||
|
background-color: var(--kaauh-teal-dark);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.hero-section{
|
||||||
|
background-image: url("{% static 'image/kaauh_banner.png' %}");
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hero Text Positioning */
|
||||||
|
.hero-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.arabic-title {
|
||||||
|
font-size: 4rem;
|
||||||
|
font-weight: 900;
|
||||||
|
line-height: 1;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RTL specific table alignment */
|
||||||
|
html[dir="rtl"] .job-table thead th {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
html[dir="rtl"] .job-link-cell {
|
||||||
|
text-align: center; /* Ensure button remains centered in RTL */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="hero-section">
|
||||||
|
<div class="hero-overlay"></div>
|
||||||
|
<div class="hero-content">
|
||||||
|
<p class="text-uppercase small fw-bold mb-1">
|
||||||
|
{% trans "Home Page" %}
|
||||||
|
</p>
|
||||||
|
<h1 class="arabic-title">
|
||||||
|
{% if LANGUAGE_CODE == 'ar' %}التوظيف{% else %}Careers{% endif %}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="job-listing-section">
|
||||||
|
<div class="max-width-container">
|
||||||
|
<h2 class="h3 mb-4 text-center" style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||||
|
{% trans "Open Positions" %}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="job-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" style="width: 10%;">{% trans "Job ID" %}</th>
|
||||||
|
<th scope="col">{% trans "Job Title" %}</th>
|
||||||
|
<th scope="col" style="width: 10%;">{% trans "Hiring" %}</th>
|
||||||
|
<th scope="col" style="width: 15%;">{% trans "Posting Date" %}</th>
|
||||||
|
<th scope="col" style="width: 15%;">{% trans "Apply Before" %}</th>
|
||||||
|
<th scope="col" style="width: 10%;">{% trans "Apply" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% comment %} Django loop would typically go here: {% for job in jobs %} {% endcomment %}
|
||||||
|
{% for job in active_jobs %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-nowrap">{{job.internal_job_id}}</td>
|
||||||
|
<td class="text-nowrap">{{job.title}}</td>
|
||||||
|
<td>{{job.open_positions}}</td>
|
||||||
|
<td>{{job.application_start_date}}</td>
|
||||||
|
<td>{{job.application_deadline}}</td>
|
||||||
|
<td class="job-link-cell">
|
||||||
|
<a href="{% url 'job_detail_candidate' job.slug %}" class="btn-apply">{% trans "Apply" %}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center mt-5">
|
||||||
|
<a href="#" class="btn btn-lg btn-secondary">
|
||||||
|
<i class="fas fa-list-alt me-2"></i> {% trans "View All Openings" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@ -3,286 +3,387 @@
|
|||||||
|
|
||||||
{% block title %}{{ job.title }} - Applicants{% endblock %}
|
{% block title %}{{ job.title }} - Applicants{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block customCSS %}
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<style>
|
||||||
<div>
|
/* ================================================= */
|
||||||
<h1 class="h3 mb-1">
|
/* THEME VARIABLES AND GLOBAL STYLES */
|
||||||
<a href="{% url 'job_detail' job.slug %}" class="text-decoration-none">
|
/* ================================================= */
|
||||||
<i class="fas fa-arrow-left me-2"></i>
|
:root {
|
||||||
</a>
|
--kaauh-teal: #00636e; /* Primary */
|
||||||
Applicants for "{{ job.title }}"
|
--kaauh-teal-dark: #004a53;
|
||||||
</h1>
|
--kaauh-border: #eaeff3;
|
||||||
<nav aria-label="breadcrumb">
|
--kaauh-primary-text: #343a40;
|
||||||
<ol class="breadcrumb">
|
}
|
||||||
<li class="breadcrumb-item"><a href="{% url 'dashboard' %}">Dashboard</a></li>
|
|
||||||
<li class="breadcrumb-item"><a href="{% url 'job_list' %}">Jobs</a></li>
|
|
||||||
<li class="breadcrumb-item"><a href="{% url 'job_detail' job.slug %}">{{ job.title }}</a></li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">Applicants</li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-success">
|
|
||||||
<i class="fas fa-user-plus"></i> Add New Applicant
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Job Summary Card -->
|
/* Primary Color Overrides */
|
||||||
<div class="card mb-4">
|
.text-primary { color: var(--kaauh-teal) !important; }
|
||||||
<div class="card-body">
|
.text-info { color: #17a2b8 !important; }
|
||||||
<div class="row">
|
.text-success { color: #28a745 !important; }
|
||||||
<div class="col-md-8">
|
.text-secondary { color: #6c757d !important; }
|
||||||
<h5 class="card-title mb-3">{{ job.title }}</h5>
|
.bg-primary { background-color: var(--kaauh-teal) !important; }
|
||||||
<div class="row">
|
.bg-info { background-color: #17a2b8 !important; }
|
||||||
<div class="col-md-6">
|
.bg-success { background-color: #28a745 !important; }
|
||||||
<small class="text-muted">Department:</small>
|
.bg-secondary { background-color: #6c757d !important; }
|
||||||
<div>{{ job.department|default:"Not specified" }}</div>
|
.bg-warning { background-color: #ffc107 !important; }
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
/* Card enhancements */
|
||||||
<small class="text-muted">Location:</small>
|
.card {
|
||||||
<div>{{ job.get_location_display }}</div>
|
border: 1px solid var(--kaauh-border);
|
||||||
</div>
|
border-radius: 0.75rem;
|
||||||
<div class="col-md-6">
|
overflow: hidden;
|
||||||
<small class="text-muted">Job Type:</small>
|
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||||
<div>{{ job.get_job_type_display }}</div>
|
background-color: white;
|
||||||
</div>
|
}
|
||||||
<div class="col-md-6">
|
|
||||||
<small class="text-muted">Workplace:</small>
|
.card-header {
|
||||||
<div>{{ job.get_workplace_type_display }}</div>
|
font-weight: 600;
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
background-color: #f8f9fa; /* Light background */
|
||||||
|
border-bottom: 1px solid var(--kaauh-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Action Button Style */
|
||||||
|
.btn-main-action {
|
||||||
|
background-color: var(--kaauh-teal);
|
||||||
|
border-color: var(--kaauh-teal);
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.6rem 1.2rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.btn-main-action:hover {
|
||||||
|
background-color: var(--kaauh-teal-dark);
|
||||||
|
border-color: var(--kaauh-teal-dark);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Secondary outline button */
|
||||||
|
.btn-outline-secondary {
|
||||||
|
color: var(--kaauh-teal-dark);
|
||||||
|
border-color: var(--kaauh-teal);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.btn-outline-secondary:hover {
|
||||||
|
background-color: var(--kaauh-teal-dark);
|
||||||
|
color: white;
|
||||||
|
border-color: var(--kaauh-teal-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table styling */
|
||||||
|
.table-hover tbody tr:hover {
|
||||||
|
background-color: #f3f7f9;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.table thead th {
|
||||||
|
color: #6c757d;
|
||||||
|
font-weight: 600;
|
||||||
|
border-bottom: 2px solid var(--kaauh-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card view specific styling */
|
||||||
|
.card-view .card-header {
|
||||||
|
background-color: var(--kaauh-teal);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.card-view .card-footer {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-top: 1px solid var(--kaauh-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding: 0.4em 0.8em;
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.7px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container-fluid py-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<div>
|
||||||
|
<h1 class="h3 mb-1 fw-bold">
|
||||||
|
<a href="{% url 'job_detail' job.slug %}" class="text-primary text-decoration-none">
|
||||||
|
<i class="fas fa-arrow-left me-2"></i>
|
||||||
|
</a>
|
||||||
|
{% trans "Applicants for" %} "{{ job.title }}"
|
||||||
|
</h1>
|
||||||
|
<nav aria-label="breadcrumb">
|
||||||
|
<ol class="breadcrumb mb-0 small">
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'dashboard' %}" class="text-secondary">{% trans "Dashboard" %}</a></li>
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'job_list' %}" class="text-secondary">{% trans "Jobs" %}</a></li>
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'job_detail' job.slug %}" class="text-secondary">{{ job.title }}</a></li>
|
||||||
|
<li class="breadcrumb-item active" aria-current="page">{% trans "Applicants" %}</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action">
|
||||||
|
<i class="fas fa-user-plus"></i> {% trans "Add New Applicant" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card shadow-sm mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row align-items-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<h5 class="fw-bold mb-3 text-primary">{{ job.title }}</h5>
|
||||||
|
<div class="row small text-secondary g-2">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<i class="fas fa-building me-2 text-info"></i> <strong>{% trans "Department:" %}</strong> {{ job.department|default:"N/A" }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<i class="fas fa-map-pin me-2 text-info"></i> <strong>{% trans "Location:" %}</strong> {{ job.get_location_display }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<i class="fas fa-briefcase me-2 text-info"></i> <strong>{% trans "Job Type:" %}</strong> {{ job.get_job_type_display }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<i class="fas fa-globe me-2 text-info"></i> <strong>{% trans "Workplace:" %}</strong> {{ job.get_workplace_type_display }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col-md-4 text-end border-start ps-4">
|
||||||
<div class="col-md-4">
|
<span class="badge status-badge mb-2 bg-{% if job.status == 'ACTIVE' %}success{% elif job.status == 'DRAFT' or job.status == 'ARCHIVED' %}secondary{% elif job.status == 'CLOSED' %}warning{% else %}danger{% endif %}">
|
||||||
<div class="text-end">
|
|
||||||
<span class="badge bg-{{ job.status|lower }} status-badge">
|
|
||||||
{{ job.get_status_display }}
|
{{ job.get_status_display }}
|
||||||
</span>
|
</span>
|
||||||
{% if candidates %}
|
{% if candidates %}
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<small class="text-muted">Total Applicants:</small>
|
<small class="text-muted d-block">{% trans "Total Applicants" %}:</small>
|
||||||
<h4 class="text-primary mb-0">{{ candidates.count }}</h4>
|
<h3 class="text-primary fw-bold mb-0">{{ candidates.count }}</h3>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Search and Filters -->
|
<div class="card shadow-sm mb-4">
|
||||||
<div class="card mb-4">
|
<div class="card-body">
|
||||||
<div class="card-body">
|
<form method="get" class="row g-3">
|
||||||
<form method="get" class="row g-3">
|
<div class="col-md-6">
|
||||||
<div class="col-md-6">
|
<label for="search" class="form-label small text-muted">{% trans "Search Applicants" %}</label>
|
||||||
<label for="search" class="form-label">Search Applicants</label>
|
<div class="input-group">
|
||||||
<div class="input-group">
|
<span class="input-group-text"><i class="fas fa-search text-primary"></i></span>
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<input type="text" class="form-control" id="search" name="search"
|
||||||
<input type="text" class="form-control" id="search" name="search"
|
placeholder="{% trans 'Search by name, email, phone, or stage...' %}"
|
||||||
placeholder="Search by name, email, phone, or stage..."
|
value="{{ search_query }}">
|
||||||
value="{{ search_query }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3 d-flex align-items-end">
|
|
||||||
<button type="submit" class="btn btn-primary w-100">
|
|
||||||
<i class="fas fa-filter"></i> Search
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3 d-flex align-items-end">
|
|
||||||
<a href="{% url 'job_candidates_list' job.slug %}" class="btn btn-outline-secondary w-100">
|
|
||||||
<i class="fas fa-times"></i> Clear
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Candidates -->
|
|
||||||
{% if candidates %}
|
|
||||||
<div id="job-candidates-list">
|
|
||||||
{# View Switcher #}
|
|
||||||
{% include "includes/_list_view_switcher.html" with list_id="job-candidates-list" %}
|
|
||||||
|
|
||||||
{# Table View (Default) #}
|
|
||||||
<div class="table-view active">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
|
||||||
<h5 class="mb-0">Applicants ({{ candidates.count }})</h5>
|
|
||||||
<div class="d-flex gap-2">
|
|
||||||
<select class="form-select form-select-sm" style="width: auto;" onchange="window.location.href='?stage='+this.value+'&search={{ search_query }}'">
|
|
||||||
<option value="">All Stages</option>
|
|
||||||
<option value="Applied" {% if request.GET.stage == 'Applied' %}selected{% endif %}>Applied</option>
|
|
||||||
<option value="Interview" {% if request.GET.stage == 'Interview' %}selected{% endif %}>Interview</option>
|
|
||||||
<option value="Offer" {% if request.GET.stage == 'Offer' %}selected{% endif %}>Offer</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive">
|
<div class="col-md-3 d-flex align-items-end">
|
||||||
<table class="table table-hover">
|
<button type="submit" class="btn btn-main-action w-100">
|
||||||
<thead>
|
<i class="fas fa-filter"></i> {% trans "Filter Results" %}
|
||||||
<tr>
|
</button>
|
||||||
<th scope="col">
|
</div>
|
||||||
<input type="checkbox" class="form-check-input" id="selectAll">
|
<div class="col-md-3 d-flex align-items-end">
|
||||||
</th>
|
<a href="{% url 'job_candidates_list' job.slug %}" class="btn btn-outline-secondary w-100">
|
||||||
<th scope="col">Name</th>
|
<i class="fas fa-times"></i> {% trans "Clear Filters" %}
|
||||||
<th scope="col">Email</th>
|
</a>
|
||||||
<th scope="col">Phone</th>
|
</div>
|
||||||
<th scope="col">Stage</th>
|
</form>
|
||||||
<th scope="col">Applied Date</th>
|
</div>
|
||||||
<th scope="col" class="text-center">Actions</th>
|
</div>
|
||||||
</tr>
|
|
||||||
</thead>
|
{% if candidates %}
|
||||||
<tbody>
|
<div id="job-candidates-list">
|
||||||
{% for candidate in candidates %}
|
{# View Switcher (Assuming this template is customized to match the new UI style) #}
|
||||||
|
{% include "includes/_list_view_switcher.html" with list_id="job-candidates-list" %}
|
||||||
|
|
||||||
|
{# Table View (Default) #}
|
||||||
|
<div class="table-view active">
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="mb-0">{% trans "Applicants" %} ({{ candidates.count }})</h5>
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<select class="form-select form-select-sm" style="width: auto;" onchange="window.location.href='?stage='+this.value+'&search={{ search_query }}'">
|
||||||
|
<option value="">{% trans "All Stages" %}</option>
|
||||||
|
<option value="Applied" {% if request.GET.stage == 'Applied' %}selected{% endif %}>{% trans "Applied" %}</option>
|
||||||
|
<option value="Exam" {% if request.GET.stage == 'Exam' %}selected{% endif %}>{% trans "Exam" %}</option>
|
||||||
|
<option value="Interview" {% if request.GET.stage == 'Interview' %}selected{% endif %}>{% trans "Interview" %}</option>
|
||||||
|
<option value="Offer" {% if request.GET.stage == 'Offer' %}selected{% endif %}>{% trans "Offer" %}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover align-middle mb-0">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<th scope="col" class="ps-3">
|
||||||
<input type="checkbox" class="form-check-input candidate-checkbox" value="{{ candidate.slug }}">
|
<input type="checkbox" class="form-check-input" id="selectAll">
|
||||||
</td>
|
</th>
|
||||||
<td>
|
<th scope="col">{% trans "Name" %}</th>
|
||||||
<div>
|
<th scope="col">{% trans "Email" %}</th>
|
||||||
<strong>{{ candidate.first_name }} {{ candidate.last_name }}</strong>
|
<th scope="col">{% trans "Phone" %}</th>
|
||||||
</div>
|
<th scope="col">{% trans "Stage" %}</th>
|
||||||
</td>
|
<th scope="col">{% trans "Applied Date" %}</th>
|
||||||
<td>{{ candidate.email }}</td>
|
<th scope="col" class="text-center pe-3">{% trans "Actions" %}</th>
|
||||||
<td>{{ candidate.phone|default:"-" }}</td>
|
</tr>
|
||||||
<td>
|
</thead>
|
||||||
<span class="badge bg-{% if candidate.stage == 'Applied' %}primary{% elif candidate.stage == 'Interview' %}info{% elif candidate.stage == 'Offer' %}success{% else %}secondary{% endif %}">
|
<tbody>
|
||||||
{{ candidate.stage }}
|
{% for candidate in candidates %}
|
||||||
</span>
|
<tr>
|
||||||
</td>
|
<td class="ps-3">
|
||||||
<td>{{ candidate.created_at|date:"M d, Y" }}</td>
|
<input type="checkbox" class="form-check-input candidate-checkbox" value="{{ candidate.slug }}">
|
||||||
<td class="text-center">
|
</td>
|
||||||
<div class="btn-group" role="group">
|
<td>
|
||||||
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-primary btn-sm" title="View">
|
<strong class="text-primary">{{ candidate.first_name }} {{ candidate.last_name }}</strong>
|
||||||
<i class="fas fa-eye"></i>
|
</td>
|
||||||
|
<td>{{ candidate.email }}</td>
|
||||||
|
<td>{{ candidate.phone|default:"-" }}</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge bg-{% if candidate.stage == 'Applied' %}primary{% elif candidate.stage == 'Exam' %}info{% elif candidate.stage == 'Interview' %}warning text-dark{% elif candidate.stage == 'Offer' %}success{% else %}secondary{% endif %}">
|
||||||
|
{{ candidate.stage }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-secondary small">{{ candidate.created_at|date:"M d, Y" }}</td>
|
||||||
|
<td class="text-center pe-3">
|
||||||
|
<div class="btn-group" role="group">
|
||||||
|
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'View' %}">
|
||||||
|
<i class="fas fa-eye"></i>
|
||||||
|
</a>
|
||||||
|
{% if user.is_staff %}
|
||||||
|
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Edit' %}">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
|
||||||
|
data-bs-toggle="modal" data-bs-target="#deleteModal"
|
||||||
|
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
|
||||||
|
data-item-name="{{ candidate.first_name }} {{ candidate.last_name }}">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-footer d-flex justify-content-between align-items-center bg-light">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="me-3 small text-muted">{% trans "Selected" %}: <strong id="selectedCount">0</strong></span>
|
||||||
|
<button class="btn btn-sm btn-outline-secondary me-2" onclick="bulkAction('Interview')"
|
||||||
|
{% if not user.is_staff %}disabled{% endif %}>
|
||||||
|
<i class="fas fa-comments me-1"></i> {% trans "Mark Interview" %}
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-main-action" onclick="bulkAction('Offer')"
|
||||||
|
{% if not user.is_staff %}disabled{% endif %}>
|
||||||
|
<i class="fas fa-handshake me-1"></i> {% trans "Mark Offer" %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if is_paginated %}
|
||||||
|
<nav aria-label="Page navigation">
|
||||||
|
<ul class="pagination pagination-sm mb-0">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search_query %}&search={{ search_query }}{% endif %}" aria-label="Previous">
|
||||||
|
<span aria-hidden="true">«</span>
|
||||||
</a>
|
</a>
|
||||||
{% if user.is_staff %}
|
</li>
|
||||||
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-secondary btn-sm" title="Edit">
|
{% endif %}
|
||||||
|
|
||||||
|
{% for num in page_obj.paginator.page_range %}
|
||||||
|
{% if page_obj.number == num %}
|
||||||
|
<li class="page-item active"><span class="page-link bg-primary border-primary">{{ num }}</span></li>
|
||||||
|
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?page={{ num }}{% if search_query %}&search={{ search_query }}{% endif %}">{{ num }}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search_query %}&search={{ search_query }}{% endif %}" aria-label="Next">
|
||||||
|
<span aria-hidden="true">»</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# Card View #}
|
||||||
|
<div class="card-view">
|
||||||
|
<div class="row g-4">
|
||||||
|
{% for candidate in candidates %}
|
||||||
|
<div class="col-md-6 col-lg-4">
|
||||||
|
<div class="card h-100 shadow-sm">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<h5 class="h5 mb-1 text-white">{{ candidate.first_name }} {{ candidate.last_name }}</h5>
|
||||||
|
<small class="text-white-50">{{ candidate.email }}</small>
|
||||||
|
</div>
|
||||||
|
<span class="badge status-badge bg-{% if candidate.stage == 'Applied' %}bg-secondary{% elif candidate.stage == 'Exam' %}bg-info{% elif candidate.stage == 'Interview' %}bg-warning text-dark{% elif candidate.stage == 'Offer' %}bg-success{% else %}bg-secondary{% endif %}">
|
||||||
|
{{ candidate.stage }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body small text-secondary">
|
||||||
|
<p class="mb-2">
|
||||||
|
<i class="fas fa-phone me-2 text-primary"></i> <strong>{% trans "Phone" %}:</strong> {{ candidate.phone|default:"N/A" }}
|
||||||
|
</p>
|
||||||
|
<p class="mb-0">
|
||||||
|
<i class="fas fa-calendar-alt me-2 text-primary"></i> <strong>{% trans "Applied Date" %}:</strong> {{ candidate.created_at|date:"M d, Y" }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-secondary w-100">
|
||||||
|
<i class="fas fa-eye"></i> {% trans "View Profile" %}
|
||||||
|
</a>
|
||||||
|
{% if user.is_staff %}
|
||||||
|
<div class="btn-group" role="group">
|
||||||
|
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary" title="{% trans 'Edit' %}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<button type="button" class="btn btn-outline-danger btn-sm" title="Delete"
|
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
|
||||||
data-bs-toggle="deleteModal"
|
data-bs-toggle="modal" data-bs-target="#deleteModal"
|
||||||
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
|
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
|
||||||
data-item-name="{{ candidate.first_name }} {{ candidate.last_name }}">
|
data-item-name="{{ candidate.first_name }} {{ candidate.last_name }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
</div>
|
||||||
</div>
|
{% endif %}
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Bulk Actions -->
|
|
||||||
<div class="card-footer d-flex justify-content-between align-items-center">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<span class="me-3">Selected: <span id="selectedCount">0</span></span>
|
|
||||||
<button class="btn btn-sm btn-outline-primary me-2" onclick="bulkAction('interview')"
|
|
||||||
{% if not user.is_staff %}disabled{% endif %}>
|
|
||||||
<i class="fas fa-comments"></i> Mark as Interview
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-sm btn-success" onclick="bulkAction('offer')"
|
|
||||||
{% if not user.is_staff %}disabled{% endif %}>
|
|
||||||
<i class="fas fa-handshake"></i> Mark as Offer
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Pagination -->
|
|
||||||
{% if is_paginated %}
|
|
||||||
<nav aria-label="Page navigation">
|
|
||||||
<ul class="pagination pagination-sm mb-0">
|
|
||||||
{% if page_obj.has_previous %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search_query %}&search={{ search_query }}{% endif %}" aria-label="Previous">
|
|
||||||
<span aria-hidden="true">«</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% for num in page_obj.paginator.page_range %}
|
|
||||||
{% if page_obj.number == num %}
|
|
||||||
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
|
|
||||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?page={{ num }}{% if search_query %}&search={{ search_query }}{% endif %}">{{ num }}</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% if page_obj.has_next %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search_query %}&search={{ search_query }}{% endif %}" aria-label="Next">
|
|
||||||
<span aria-hidden="true">»</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# Card View #}
|
|
||||||
<div class="card-view">
|
|
||||||
<div class="row g-4">
|
|
||||||
{% for candidate in candidates %}
|
|
||||||
<div class="col-md-6 col-lg-4">
|
|
||||||
<div class="card h-100">
|
|
||||||
<div class="card-header">
|
|
||||||
<h5 class="h5 mb-1">{{ candidate.first_name }} {{ candidate.last_name }}</h5>
|
|
||||||
<small class="text-white-50">{{ candidate.email }}</small>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<p class="card-text">
|
|
||||||
<strong>{% trans "Phone" %}:</strong> {{ candidate.phone|default:"N/A" }}<br>
|
|
||||||
<strong>{% trans "Stage" %}:</strong> <span class="badge bg-{% if candidate.stage == 'Applied' %}primary{% elif candidate.stage == 'Interview' %}info{% elif candidate.stage == 'Offer' %}success{% else %}secondary{% endif %}">{{ candidate.stage }}</span><br>
|
|
||||||
<strong>{% trans "Applied Date" %}:</strong> {{ candidate.created_at|date:"M d, Y" }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
<div class="d-flex gap-2">
|
|
||||||
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-sm btn-outline-primary w-100">
|
|
||||||
<i class="fas fa-eye"></i> {% trans "View" %}
|
|
||||||
</a>
|
|
||||||
{% if user.is_staff %}
|
|
||||||
<div class="btn-group w-100" role="group">
|
|
||||||
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary" title="Edit">
|
|
||||||
<i class="fas fa-edit"></i>
|
|
||||||
</a>
|
|
||||||
<button type="button" class="btn btn-outline-danger btn-sm" title="Delete"
|
|
||||||
data-bs-toggle="deleteModal"
|
|
||||||
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
|
|
||||||
data-item-name="{{ candidate.first_name }} {{ candidate.last_name }}">
|
|
||||||
<i class="fas fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% endfor %}
|
||||||
{% endfor %}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% else %}
|
||||||
{% else %}
|
<div class="card shadow-sm">
|
||||||
<div class="text-center py-5">
|
<div class="text-center py-5">
|
||||||
<i class="fas fa-user-slash fa-3x text-muted mb-3"></i>
|
<i class="fas fa-user-slash fa-3x text-muted mb-3"></i>
|
||||||
<h4 class="text-muted">No applicants found</h4>
|
<h4 class="text-muted">{% trans "No applicants found" %}</h4>
|
||||||
<p class="text-muted">There are no candidates who have applied for this position yet.</p>
|
<p class="text-secondary">{% trans "There are no candidates who have applied for this position yet." %}</p>
|
||||||
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-primary">
|
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action mt-3">
|
||||||
<i class="fas fa-user-plus"></i> Add First Applicant
|
<i class="fas fa-user-plus"></i> {% trans "Add First Applicant" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<!-- Delete Modal -->
|
{% include "includes/delete_modal.html" %}
|
||||||
{% include "includes/delete_modal.html" %}
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
@ -320,7 +421,28 @@ function bulkAction(stage) {
|
|||||||
console.log('Updating candidates:', selectedCandidates, 'to stage:', stage);
|
console.log('Updating candidates:', selectedCandidates, 'to stage:', stage);
|
||||||
// For now, just show a message
|
// For now, just show a message
|
||||||
alert(`Bulk update functionality would mark ${selectedCandidates.length} candidates as ${stage}`);
|
alert(`Bulk update functionality would mark ${selectedCandidates.length} candidates as ${stage}`);
|
||||||
|
// After a successful AJAX request, you would likely reload the page or update the rows dynamically.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bootstrap Delete Modal Fix for dynamically loaded data attributes
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const deleteModal = document.getElementById('deleteModal');
|
||||||
|
if (deleteModal) {
|
||||||
|
deleteModal.addEventListener('show.bs.modal', function (event) {
|
||||||
|
const button = event.relatedTarget;
|
||||||
|
const deleteUrl = button.getAttribute('data-delete-url');
|
||||||
|
const itemName = button.getAttribute('data-item-name');
|
||||||
|
|
||||||
|
const modalTitle = deleteModal.querySelector('.modal-title');
|
||||||
|
const modalBody = deleteModal.querySelector('.modal-body p');
|
||||||
|
const deleteForm = deleteModal.querySelector('form');
|
||||||
|
|
||||||
|
modalTitle.textContent = `Delete ${itemName}`;
|
||||||
|
modalBody.innerHTML = `Are you sure you want to permanently delete the applicant <strong>${itemName}</strong>? This action cannot be undone.`;
|
||||||
|
deleteForm.action = deleteUrl;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1,18 +1,39 @@
|
|||||||
|
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
|
|
||||||
{% block title %}{{ job.title }} - University ATS{% endblock %}
|
{% block title %}{{ job.title }} - University ATS{% endblock %}
|
||||||
|
|
||||||
{% block customCSS %}
|
{% block customCSS %}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Custom styles for the Job Detail Page (using variables from base.html) */
|
/* ================================================= */
|
||||||
|
/* THEME VARIABLES AND GLOBAL STYLES */
|
||||||
|
/* ================================================= */
|
||||||
:root {
|
:root {
|
||||||
--kaauh-teal: #00636e;
|
--kaauh-teal: #00636e; /* Primary */
|
||||||
--kaauh-teal-dark: #004a53;
|
--kaauh-teal-dark: #004a53;
|
||||||
--kaauh-border: #eaeff3;
|
--kaauh-border: #eaeff3;
|
||||||
--kaauh-primary-text: #343a40;
|
--kaauh-primary-text: #343a40;
|
||||||
|
|
||||||
|
/* Custom Stage Colors for Tracker */
|
||||||
|
--stage-applied: var(--kaauh-teal); /* Teal */
|
||||||
|
--stage-exam: #17a2b8; /* Info Cyan */
|
||||||
|
--stage-interview: #ffc107; /* Warning Yellow */
|
||||||
|
--stage-offer: #28a745; /* Success Green */
|
||||||
|
--stage-inactive: #6c757d; /* Secondary Gray */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Primary Color Overrides */
|
||||||
|
.text-primary { color: var(--kaauh-teal) !important; }
|
||||||
|
.text-info { color: var(--stage-exam) !important; }
|
||||||
|
.text-success { color: var(--stage-offer) !important; }
|
||||||
|
.text-secondary { color: var(--stage-inactive) !important; }
|
||||||
|
.bg-success { background-color: var(--kaauh-teal) !important; }
|
||||||
|
.bg-warning { background-color: #ffc107 !important; }
|
||||||
|
.bg-secondary { background-color: #6c757d !important; }
|
||||||
|
.bg-danger { background-color: #dc3545 !important; }
|
||||||
|
|
||||||
/* Header styling */
|
/* Header styling */
|
||||||
.job-header-card {
|
.job-header-card {
|
||||||
background: linear-gradient(135deg, var(--kaauh-teal), #004d57);
|
background: linear-gradient(135deg, var(--kaauh-teal), #004d57);
|
||||||
@ -21,13 +42,11 @@
|
|||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
box-shadow: 0 4px 10px rgba(0,0,0,0.15);
|
box-shadow: 0 4px 10px rgba(0,0,0,0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.job-header-card h2 {
|
.job-header-card h2 {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1.8rem;
|
font-size: 1.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Status badge */
|
/* Status badge */
|
||||||
.status-badge {
|
.status-badge {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
@ -40,21 +59,6 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mapped color classes for status badges */
|
|
||||||
.bg-success { background-color: var(--kaauh-teal) !important; }
|
|
||||||
.bg-warning { background-color: #ffc107 !important; }
|
|
||||||
.bg-secondary { background-color: #6c757d !important; }
|
|
||||||
.bg-danger { background-color: #dc3545 !important; }
|
|
||||||
|
|
||||||
/* Fix for active tab text visibility */
|
|
||||||
.nav-tabs .nav-link.active,
|
|
||||||
.right-column-tabs .nav-link.active {
|
|
||||||
color: var(--kaauh-teal-dark) !important;
|
|
||||||
background-color: white !important;
|
|
||||||
border-bottom: 3px solid var(--kaauh-teal) !important;
|
|
||||||
font-weight: 600;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
/* Card enhancements */
|
/* Card enhancements */
|
||||||
.card {
|
.card {
|
||||||
border: 1px solid var(--kaauh-border);
|
border: 1px solid var(--kaauh-border);
|
||||||
@ -69,25 +73,15 @@
|
|||||||
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
|
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Standard Card Header (used for single cards or fallback) */
|
/* Standard Card Header */
|
||||||
.card-header {
|
.card-header {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
padding: 1rem 1.25rem;
|
padding: 1rem 1.25rem;
|
||||||
background-color: #f8f9fa; /* Light background */
|
background-color: #f8f9fa;
|
||||||
border-bottom: 1px solid var(--kaauh-border);
|
border-bottom: 1px solid var(--kaauh-border);
|
||||||
}
|
}
|
||||||
.card-header h5 {
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--kaauh-primary-text);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-footer {
|
/* Left Column Tabs Theming */
|
||||||
padding: 1rem 1.25rem;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
border-top: 1px solid var(--kaauh-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Left Column Tabs Theming (main details) */
|
|
||||||
.nav-tabs {
|
.nav-tabs {
|
||||||
border-bottom: 1px solid var(--kaauh-border);
|
border-bottom: 1px solid var(--kaauh-border);
|
||||||
background-color: #f8f9fa;
|
background-color: #f8f9fa;
|
||||||
@ -102,51 +96,20 @@
|
|||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
.nav-tabs .nav-link:hover {
|
|
||||||
color: var(--kaauh-teal);
|
|
||||||
border-color: #e9ecef;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
.nav-tabs .nav-link.active {
|
.nav-tabs .nav-link.active {
|
||||||
color: var(--kaauh-teal-dark);
|
color: var(--kaauh-teal-dark) !important;
|
||||||
background-color: white;
|
background-color: white !important;
|
||||||
border-bottom: 3px solid var(--kaauh-teal);
|
border-bottom: 3px solid var(--kaauh-teal) !important;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================================== */
|
/* Right Column Tabs */
|
||||||
/* RIGHT COLUMN TABS STYLING (IMPROVED) */
|
|
||||||
/* ==================================== */
|
|
||||||
|
|
||||||
.right-column-tabs {
|
.right-column-tabs {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
border-bottom: 1px solid var(--kaauh-border);
|
border-bottom: 1px solid var(--kaauh-border);
|
||||||
}
|
}
|
||||||
.right-column-tabs .nav-tabs {
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
border-bottom: none;
|
|
||||||
background-color: transparent;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.right-column-tabs .nav-item {
|
|
||||||
flex-grow: 1;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.right-column-tabs .nav-link {
|
|
||||||
padding: 0.9rem 1rem;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--kaauh-primary-text);
|
|
||||||
border-radius: 0;
|
|
||||||
border-right: 1px solid var(--kaauh-border);
|
|
||||||
border-bottom: 1px solid var(--kaauh-border);
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
}
|
|
||||||
.right-column-tabs .nav-item:last-child .nav-link {
|
|
||||||
border-right: none;
|
|
||||||
}
|
|
||||||
.right-column-tabs .nav-link.active {
|
.right-column-tabs .nav-link.active {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
color: var(--kaauh-teal-dark);
|
color: var(--kaauh-teal-dark);
|
||||||
@ -154,23 +117,24 @@
|
|||||||
border-right-color: transparent;
|
border-right-color: transparent;
|
||||||
margin-bottom: -1px;
|
margin-bottom: -1px;
|
||||||
}
|
}
|
||||||
.right-column-tabs .nav-link:not(.active):hover {
|
|
||||||
background-color: #f0f4f7;
|
/* Main Action Button Style */
|
||||||
color: var(--kaauh-teal);
|
.btn-main-action {
|
||||||
|
background-color: var(--kaauh-teal);
|
||||||
|
border-color: var(--kaauh-teal);
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.6rem 1.2rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
.right-column-tabs .tab-content {
|
.btn-outline-secondary {
|
||||||
padding: 1.5rem 1.25rem;
|
color: var(--kaauh-teal-dark);
|
||||||
background-color: white;
|
border-color: var(--kaauh-teal);
|
||||||
}
|
|
||||||
|
|
||||||
/* Section styling */
|
|
||||||
.job-section h5 {
|
|
||||||
color: var(--kaauh-teal);
|
|
||||||
font-weight: 700;
|
|
||||||
margin-bottom: 0.75rem;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
padding-bottom: 0.5rem;
|
|
||||||
border-bottom: 1px solid var(--kaauh-border);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Applicant stats */
|
/* Applicant stats */
|
||||||
@ -189,45 +153,6 @@
|
|||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Primary Color Overrides */
|
|
||||||
.text-primary { color: var(--kaauh-teal) !important; }
|
|
||||||
.text-info { color: #17a2b8 !important; }
|
|
||||||
.text-success { color: #28a745 !important; }
|
|
||||||
.text-secondary { color: #6c757d !important; }
|
|
||||||
|
|
||||||
/* Main Action Button Style */
|
|
||||||
.btn-main-action {
|
|
||||||
background-color: var(--kaauh-teal);
|
|
||||||
border-color: var(--kaauh-teal);
|
|
||||||
color: white;
|
|
||||||
font-weight: 600;
|
|
||||||
padding: 0.6rem 1.2rem;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.5rem;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-main-action:hover {
|
|
||||||
background-color: var(--kaauh-teal-dark);
|
|
||||||
border-color: var(--kaauh-teal-dark);
|
|
||||||
transform: translateY(-1px);
|
|
||||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Secondary outline button (for forms/back links) */
|
|
||||||
.btn-outline-secondary {
|
|
||||||
color: var(--kaauh-teal-dark);
|
|
||||||
border-color: var(--kaauh-teal);
|
|
||||||
}
|
|
||||||
.btn-outline-secondary:hover {
|
|
||||||
background-color: var(--kaauh-teal-dark);
|
|
||||||
color: white;
|
|
||||||
border-color: var(--kaauh-teal-dark);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Specific styling for the deadline box */
|
/* Specific styling for the deadline box */
|
||||||
.deadline-box {
|
.deadline-box {
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
@ -235,18 +160,143 @@
|
|||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Table styling for the Applicant preview */
|
/* ==================================== */
|
||||||
.table-applicants tbody tr:hover {
|
/* MULTI-COLORED CANDIDATE STAGE TRACKER */
|
||||||
background-color: #f3f9f9;
|
/* ==================================== */
|
||||||
|
|
||||||
|
.progress-stages {
|
||||||
|
position: relative;
|
||||||
|
padding: 1.5rem 0;
|
||||||
}
|
}
|
||||||
.table-applicants td {
|
|
||||||
border-top: 1px solid var(--kaauh-border);
|
.progress-stages a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stage-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
min-width: 60px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
color: var(--stage-inactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stage-icon {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #e9ecef;
|
||||||
|
color: var(--stage-inactive);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
z-index: 10;
|
||||||
|
border: 2px solid white;
|
||||||
|
box-shadow: 0 0 0 2px #e9ecef;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- STAGE SPECIFIC COLORS ---------------- */
|
||||||
|
|
||||||
|
/* APPLIED STAGE (Teal) */
|
||||||
|
.stage-item[data-stage="Applied"].completed .stage-icon,
|
||||||
|
.stage-item[data-stage="Applied"].active .stage-icon {
|
||||||
|
background-color: var(--stage-applied);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.stage-item[data-stage="Applied"].active { color: var(--stage-applied); }
|
||||||
|
|
||||||
|
/* EXAM STAGE (Cyan/Info) */
|
||||||
|
.stage-item[data-stage="Exam"].completed .stage-icon,
|
||||||
|
.stage-item[data-stage="Exam"].active .stage-icon {
|
||||||
|
background-color: var(--stage-exam);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.stage-item[data-stage="Exam"].active { color: var(--stage-exam); }
|
||||||
|
|
||||||
|
/* INTERVIEW STAGE (Yellow/Warning) */
|
||||||
|
.stage-item[data-stage="Interview"].completed .stage-icon,
|
||||||
|
.stage-item[data-stage="Interview"].active .stage-icon {
|
||||||
|
background-color: var(--stage-interview);
|
||||||
|
color: var(--kaauh-primary-text); /* Dark text for light background */
|
||||||
|
}
|
||||||
|
.stage-item[data-stage="Interview"].active { color: var(--stage-interview); }
|
||||||
|
|
||||||
|
/* OFFER STAGE (Green/Success) */
|
||||||
|
.stage-item[data-stage="Offer"].completed .stage-icon,
|
||||||
|
.stage-item[data-stage="Offer"].active .stage-icon {
|
||||||
|
background-color: var(--stage-offer);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.stage-item[data-stage="Offer"].active { color: var(--stage-offer); }
|
||||||
|
|
||||||
|
/* ---------------- GENERIC ACTIVE/COMPLETED STYLING ---------------- */
|
||||||
|
|
||||||
|
/* Active State (Applies glow/scale to current stage) */
|
||||||
|
.stage-item.active .stage-icon {
|
||||||
|
box-shadow: 0 0 0 4px rgba(0, 99, 110, 0.4);
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
.stage-item.active .stage-count {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Completed State (Applies dark text color to completed stages) */
|
||||||
|
.stage-item.completed {
|
||||||
|
color: var(--kaauh-primary-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connector Line */
|
||||||
|
.stage-connector {
|
||||||
|
flex-grow: 1;
|
||||||
|
height: 3px;
|
||||||
|
background-color: #e9ecef;
|
||||||
|
margin: 0 0.5rem;
|
||||||
|
position: relative;
|
||||||
|
top: -18px;
|
||||||
|
z-index: 1;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Line in completed state (Kept the line teal/primary for consistency) */
|
||||||
|
.stage-connector.completed {
|
||||||
|
background-color: var(--kaauh-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Labels and counts */
|
||||||
|
.stage-label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin-top: 0.4rem;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.stage-count {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: 0.1rem;
|
||||||
|
color: #6c757d;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="container-fluid py-4">
|
<div class="container-fluid py-4">
|
||||||
|
<nav aria-label="breadcrumb">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'dashboard' %}" class="text-secondary">Home</a></li>
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'job_list' %}" class="text-secondary">Jobs</a></li>
|
||||||
|
<li class="breadcrumb-item active" aria-current="page" class="text-secondary">Job Detail</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
|
|
||||||
{# LEFT COLUMN: JOB DETAILS WITH TABS #}
|
{# LEFT COLUMN: JOB DETAILS WITH TABS #}
|
||||||
@ -335,6 +385,23 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<i class="fas fa-edit me-2 text-primary"></i> <strong>{% trans "Updated At:" %}</strong> {{ job.updated_at|default:"N/A" }}
|
<i class="fas fa-edit me-2 text-primary"></i> <strong>{% trans "Updated At:" %}</strong> {{ job.updated_at|default:"N/A" }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-outline-secondary"
|
||||||
|
id="copyJobLinkButton"
|
||||||
|
data-url="{{ job.application_url }}">
|
||||||
|
<i class="fas fa-link me-1"></i>
|
||||||
|
{% trans "Copy and Share Public Link" %}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<span id="copyFeedback" class="text-success ms-2 small" style="display:none;">
|
||||||
|
{% trans "Copied!" %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<h5 class="text-muted mb-3">{% trans "Financial & Timeline" %}</h5>
|
<h5 class="text-muted mb-3">{% trans "Financial & Timeline" %}</h5>
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
@ -419,8 +486,70 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# RIGHT COLUMN: TABBED CARDS #}
|
{# RIGHT COLUMN: TABBED CARDS #}
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4 ">
|
||||||
<div class="card shadow-sm no-hover">
|
<div class="card shadow-sm no-hover mb-4">
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<h6 class="text-muted mb-4">{% trans "Applicant Tracking" %}</h6>
|
||||||
|
<div class="progress-stages">
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
|
||||||
|
{% comment %} STAGE 1: Applied {% endcomment %}
|
||||||
|
<a href="{% url 'job_candidates_list' job.slug %}?stage=Applied"
|
||||||
|
class="stage-item {% if current_stage == 'Applied' %}active{% endif %} {% if current_stage != 'Applied' and candidate.stage_history_has.Applied %}completed{% endif %}"
|
||||||
|
data-stage="Applied">
|
||||||
|
<div class="stage-icon">
|
||||||
|
<i class="fas fa-file-signature"></i>
|
||||||
|
</div>
|
||||||
|
<div class="stage-label">{% trans "Applied" %}</div>
|
||||||
|
<div class="stage-count">{{ applied_count|default:"0" }}</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{% comment %} CONNECTOR 1 -> 2 {% endcomment %}
|
||||||
|
<div class="stage-connector {% if current_stage != 'Applied' and candidate.stage_history_has.Exam %}completed{% endif %}"></div>
|
||||||
|
|
||||||
|
{% comment %} STAGE 2: Exam {% endcomment %}
|
||||||
|
<a href="{% url 'job_candidates_list' job.slug %}?stage=Exam"
|
||||||
|
class="stage-item {% if current_stage == 'Exam' %}active{% endif %} {% if current_stage != 'Exam' and candidate.stage_history_has.Exam %}completed{% endif %}"
|
||||||
|
data-stage="Exam">
|
||||||
|
<div class="stage-icon">
|
||||||
|
<i class="fas fa-clipboard-check"></i>
|
||||||
|
</div>
|
||||||
|
<div class="stage-label">{% trans "Exam" %}</div>
|
||||||
|
<div class="stage-count">{{ exam_count|default:"0" }}</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{% comment %} CONNECTOR 2 -> 3 {% endcomment %}
|
||||||
|
<div class="stage-connector {% if current_stage != 'Exam' and candidate.stage_history_has.Interview %}completed{% endif %}"></div>
|
||||||
|
|
||||||
|
{% comment %} STAGE 3: Interview {% endcomment %}
|
||||||
|
<a href="{% url 'job_candidates_list' job.slug %}?stage=Interview"
|
||||||
|
class="stage-item {% if current_stage == 'Interview' %}active{% endif %} {% if current_stage != 'Interview' and candidate.stage_history_has.Interview %}completed{% endif %}"
|
||||||
|
data-stage="Interview">
|
||||||
|
<div class="stage-icon">
|
||||||
|
<i class="fas fa-comments"></i>
|
||||||
|
</div>
|
||||||
|
<div class="stage-label">{% trans "Interview" %}</div>
|
||||||
|
<div class="stage-count">{{ interview_count|default:"0" }}</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{% comment %} CONNECTOR 3 -> 4 {% endcomment %}
|
||||||
|
<div class="stage-connector {% if current_stage != 'Interview' and candidate.stage_history_has.Offer %}completed{% endif %}"></div>
|
||||||
|
|
||||||
|
{% comment %} STAGE 4: Offer {% endcomment %}
|
||||||
|
<a href="{% url 'job_candidates_list' job.slug %}?stage=Offer"
|
||||||
|
class="stage-item {% if current_stage == 'Offer' %}active{% endif %} {% if current_stage != 'Offer' and candidate.stage_history_has.Offer %}completed{% endif %}"
|
||||||
|
data-stage="Offer">
|
||||||
|
<div class="stage-icon">
|
||||||
|
<i class="fas fa-handshake"></i>
|
||||||
|
</div>
|
||||||
|
<div class="stage-label">{% trans "Offer" %}</div>
|
||||||
|
<div class="stage-count">{{ offer_count|default:"0" }}</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card shadow-sm no-hover" style="height:400px;">
|
||||||
|
|
||||||
{# RIGHT TABS NAVIGATION #}
|
{# RIGHT TABS NAVIGATION #}
|
||||||
<ul class="nav nav-tabs right-column-tabs" id="rightJobTabs" role="tablist">
|
<ul class="nav nav-tabs right-column-tabs" id="rightJobTabs" role="tablist">
|
||||||
@ -431,7 +560,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="nav-item flex-fill" role="presentation">
|
<li class="nav-item flex-fill" role="presentation">
|
||||||
<button class="nav-link" id="manage-tab" data-bs-toggle="tab" data-bs-target="#manage-pane" type="button" role="tab" aria-controls="manage-pane" aria-selected="false">
|
<button class="nav-link" id="manage-tab" data-bs-toggle="tab" data-bs-target="#manage-pane" type="button" role="tab" aria-controls="manage-pane" aria-selected="false">
|
||||||
<i class="fas fa-cogs me-1 text-secondary"></i> {% trans "Manage" %}
|
<i class="fas fa-cogs me-1 text-secondary"></i> {% trans "Form Template" %}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item flex-fill" role="presentation">
|
<li class="nav-item flex-fill" role="presentation">
|
||||||
@ -445,8 +574,8 @@
|
|||||||
|
|
||||||
{# TAB 1: APPLICANTS CONTENT #}
|
{# TAB 1: APPLICANTS CONTENT #}
|
||||||
<div class="tab-pane fade show active" id="applicants-pane" role="tabpanel" aria-labelledby="applicants-tab">
|
<div class="tab-pane fade show active" id="applicants-pane" role="tabpanel" aria-labelledby="applicants-tab">
|
||||||
<h5 class="mb-3">{% trans "Candidates" %} (<span id="total_candidates">{{ total_candidates }}</span>)</h5>
|
<h5 class="mb-3">{% trans "Total Applicants" %} (<span id="total_candidates">{{ total_applicants }}</span>)</h5>
|
||||||
{% if total_candidates > 0 %}
|
{% if total_applicants > 0 %}
|
||||||
<div class="row mb-4 applicant-stats">
|
<div class="row mb-4 applicant-stats">
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<div class="stat-item">
|
<div class="stat-item">
|
||||||
@ -469,7 +598,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-12 mb-2">
|
<div class="col-12 mb-2">
|
||||||
<a href="{% url 'job_candidates_list' job.slug %}" class="btn btn-outline-secondary w-100">
|
<a href="{% url 'job_candidates_list' job.slug %}" class="btn btn-outline-secondary w-100">
|
||||||
{% trans "View All Applicants" %} ({{ total_candidates }})
|
{% trans "View All Applicants" %} ({{ total_applicants }})
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -477,7 +606,10 @@
|
|||||||
|
|
||||||
<div class="d-grid gap-2">
|
<div class="d-grid gap-2">
|
||||||
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action">
|
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action">
|
||||||
<i class="fas fa-user-plus"></i> {% trans "Create Candidate" %}
|
<i class="fas fa-user-plus"></i> {% trans "Create Applicant" %}
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'candidate_tier_management' job.slug %}" class="btn btn-main-action">
|
||||||
|
<i class="fas fa-layer-group"></i> {% trans "Manage Applicants" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -552,27 +684,25 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Applicant Form Management (Content from old card) #}
|
{% comment %} {# Applicant Form Management (Content from old card) #}
|
||||||
<h5 class="mb-3"><i class="fas fa-clipboard-list me-2 text-primary"></i>{% trans "Form Management" %}</h5>
|
<h5 class="mb-3"><i class="fas fa-clipboard-list me-2 text-primary"></i>{% trans "Form Management" %}</h5> {% endcomment %}
|
||||||
<div class="d-grid gap-2">
|
{% comment %} <div class="d-grid gap-2">
|
||||||
<p class="text-muted small mb-3">
|
<p class="text-muted small mb-3">
|
||||||
{% trans "Manage the custom application forms associated with this job posting." %}
|
{% trans "Manage the custom application forms associated with this job posting." %}
|
||||||
</p>
|
</p> {% endcomment %}
|
||||||
|
|
||||||
<a href="{% url 'create_form_template' %}" class="btn btn-main-action">
|
{% comment %} <a href="{% url 'create_form_template' %}" class="btn btn-main-action">
|
||||||
<i class="fas fa-plus-circle me-2"></i> {% trans "Create New Form" %}
|
<i class="fas fa-plus-circle me-2"></i> {% trans "Create New Form" %}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="" class="btn btn-outline-secondary">
|
<a href="" class="btn btn-outline-secondary">
|
||||||
<i class="fas fa-list-alt me-1"></i> {% trans "View All Existing Forms" %}
|
<i class="fas fa-list-alt me-1"></i> {% trans "View All Existing Forms" %}
|
||||||
</a>
|
</a> {% endcomment %}
|
||||||
|
|
||||||
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action">
|
{% comment %} <a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action">
|
||||||
<i class="fas fa-user-plus"></i> {% trans "Create Candidate" %}
|
<i class="fas fa-user-plus"></i> {% trans "Create Applicant" %}
|
||||||
</a>
|
</a> {% endcomment %}
|
||||||
<a href="{% url 'candidate_tier_management' job.slug %}" class="btn btn-main-action">
|
|
||||||
<i class="fas fa-layer-group"></i> {% trans "Manage Tiers" %}
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -636,3 +766,33 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block customJS%}
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('copyJobLinkButton').addEventListener('click', function() {
|
||||||
|
// 1. Get the URL from the data attribute
|
||||||
|
const urlToCopy = this.getAttribute('data-url');
|
||||||
|
|
||||||
|
// 2. Use the modern Clipboard API
|
||||||
|
navigator.clipboard.writeText(urlToCopy).then(() => {
|
||||||
|
|
||||||
|
// 3. Show feedback message
|
||||||
|
const feedback = document.getElementById('copyFeedback');
|
||||||
|
feedback.style.display = 'inline';
|
||||||
|
|
||||||
|
// 4. Hide feedback after 2 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
feedback.style.display = 'none';
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
}).catch(err => {
|
||||||
|
// Fallback for older browsers or security issues
|
||||||
|
console.error('Could not copy text: ', err);
|
||||||
|
alert("Copy failed. Please copy the URL manually: " + urlToCopy);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@ -13,6 +13,10 @@
|
|||||||
--kaauh-primary-text: #343a40;
|
--kaauh-primary-text: #343a40;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Primary Color Overrides */
|
||||||
|
.text-primary-theme { color: var(--kaauh-teal) !important; }
|
||||||
|
.bg-primary-theme { background-color: var(--kaauh-teal) !important; }
|
||||||
|
|
||||||
/* Enhanced Card Styling */
|
/* Enhanced Card Styling */
|
||||||
.card {
|
.card {
|
||||||
border: 1px solid var(--kaauh-border);
|
border: 1px solid var(--kaauh-border);
|
||||||
@ -20,7 +24,7 @@
|
|||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||||
transition: transform 0.2s, box-shadow 0.2s;
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
}
|
}
|
||||||
.card:hover {
|
.card:not(.no-hover):hover {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
|
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
@ -32,6 +36,9 @@
|
|||||||
color: white;
|
color: white;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-main-action:hover {
|
.btn-main-action:hover {
|
||||||
@ -51,17 +58,6 @@
|
|||||||
border-color: var(--kaauh-teal-dark);
|
border-color: var(--kaauh-teal-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Job Card Specifics */
|
|
||||||
.job-card .card-title {
|
|
||||||
color: var(--kaauh-teal-dark);
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 1.15rem;
|
|
||||||
}
|
|
||||||
.job-card .card-text i {
|
|
||||||
color: var(--kaauh-teal);
|
|
||||||
width: 1.25rem; /* Align icons vertically */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Status Badges */
|
/* Status Badges */
|
||||||
.status-badge {
|
.status-badge {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
@ -71,41 +67,100 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.7px;
|
letter-spacing: 0.7px;
|
||||||
}
|
}
|
||||||
/* Mapped color classes to theme */
|
.bg-DRAFT { background-color: #6c757d !important; }
|
||||||
.bg-draft { background-color: #6c757d !important; } /* secondary */
|
.bg-ACTIVE { background-color: var(--kaauh-teal) !important; }
|
||||||
.bg-active { background-color: var(--kaauh-teal) !important; } /* primary teal */
|
.bg-CLOSED { background-color: #dc3545 !important; }
|
||||||
.bg-closed { background-color: #dc3545 !important; } /* danger */
|
.bg-ARCHIVED { background-color: #343a40 !important; }
|
||||||
.bg-archived { background-color: #343a40 !important; } /* dark */
|
.bg-info { background-color: #17a2b8 !important; }
|
||||||
|
|
||||||
.bg-info { background-color: #17a2b8 !important; } /* LinkedIn badge */
|
/* --- TABLE ALIGNMENT AND SIZING FIXES --- */
|
||||||
|
.table {
|
||||||
|
table-layout: fixed; /* Ensures column widths are respected */
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.table thead th {
|
||||||
|
color: var(--kaauh-primary-text);
|
||||||
|
font-weight: 500; /* Lighter weight for smaller font */
|
||||||
|
font-size: 0.85rem; /* Smaller font size for header text */
|
||||||
|
vertical-align: middle;
|
||||||
|
border-bottom: 2px solid var(--kaauh-border);
|
||||||
|
padding: 0.5rem 0.25rem; /* Reduced vertical and horizontal padding */
|
||||||
|
}
|
||||||
|
.table-hover tbody tr:hover {
|
||||||
|
background-color: #f3f7f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optimized Main Table Column Widths (Total must be 100%) */
|
||||||
|
.table th:nth-child(1) { width: 22%; } /* Job ID (Tight) */
|
||||||
|
|
||||||
|
.table th:nth-child(2) { width: 12%; } /* Source (Tight) */
|
||||||
|
.table th:nth-child(3) { width: 8%; } /* Actions (Tight, icon buttons) */
|
||||||
|
.table th:nth-child(4) { width: 8%; } /* Form (Tight, icon buttons) */
|
||||||
|
.table th:nth-child(5) { width: 50%; } /* Candidate Metrics (colspan=7) */
|
||||||
|
|
||||||
/* Pagination Link Styling */
|
/* NESTED TABLE STYLING FOR CANDIDATE MANAGEMENT HEADER */
|
||||||
.pagination .page-item .page-link {
|
.nested-header-table {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
table-layout: fixed; /* CRITICAL for 1:1 data alignment */
|
||||||
|
}
|
||||||
|
.nested-header-table thead th {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 0.3rem 0 0.1rem 0; /* Reduced padding here too */
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
color: #6c757d;
|
||||||
|
font-size: 0.75rem; /* Even smaller font for nested headers */
|
||||||
|
width: calc(100% / 7);
|
||||||
|
}
|
||||||
|
/* Explicit widths are technically defined by the 1/7 rule, but keeping them for clarity/safety */
|
||||||
|
.nested-header-table thead th:nth-child(1),
|
||||||
|
.nested-header-table thead th:nth-child(2),
|
||||||
|
.nested-header-table thead th:nth-child(5) {
|
||||||
|
width: calc(100% / 7);
|
||||||
|
}
|
||||||
|
.nested-header-table thead th:nth-child(3),
|
||||||
|
.nested-header-table thead th:nth-child(4) {
|
||||||
|
width: calc(100% / 7 * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inner Nested Table (P/F) */
|
||||||
|
.nested-stage-metrics {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
.nested-stage-metrics thead th {
|
||||||
|
padding: 0.1rem 0; /* Very minimal padding */
|
||||||
|
font-weight: 600;
|
||||||
color: var(--kaauh-teal-dark);
|
color: var(--kaauh-teal-dark);
|
||||||
border-color: var(--kaauh-border);
|
font-size: 0.7rem; /* Smallest font size */
|
||||||
}
|
width: 50%;
|
||||||
.pagination .page-item.active .page-link {
|
|
||||||
background-color: var(--kaauh-teal);
|
|
||||||
border-color: var(--kaauh-teal);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.pagination .page-item:hover .page-link:not(.active) {
|
|
||||||
background-color: #e9ecef;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Filter & Search Layout Adjustments */
|
/* Main TH for Candidate Management Header */
|
||||||
.filter-buttons {
|
.candidate-management-header {
|
||||||
display: flex;
|
text-align: center;
|
||||||
gap: 0.5rem; /* Space between filter and clear buttons */
|
padding: 0;
|
||||||
|
border-left: 2px solid var(--kaauh-teal);
|
||||||
|
border-right: 1px solid var(--kaauh-border) !important;
|
||||||
}
|
}
|
||||||
.form-control-search {
|
|
||||||
/* Optional: Add slight shadow/focus effect to search bar */
|
/* Candidate Management Data Cells (7 columns total now) */
|
||||||
box-shadow: none;
|
.candidate-data-cell {
|
||||||
border-color: var(--kaauh-border);
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem; /* Keep data readable */
|
||||||
|
border-left: 1px solid var(--kaauh-border);
|
||||||
}
|
}
|
||||||
.form-control-search:focus {
|
.candidate-data-cell a {
|
||||||
border-color: var(--kaauh-teal);
|
display: block;
|
||||||
box-shadow: 0 0 0 0.1rem rgba(0, 99, 110, 0.25);
|
text-decoration: none;
|
||||||
|
padding: 0.4rem 0; /* Minimized vertical padding */
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -114,10 +169,10 @@
|
|||||||
<div class="container-fluid py-4">
|
<div class="container-fluid py-4">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||||
<i class="fas fa-briefcase me-2"></i> Job Postings
|
<i class="fas fa-briefcase me-2"></i> {% trans "Job Postings" %}
|
||||||
</h1>
|
</h1>
|
||||||
<a href="{% url 'job_create' %}" class="btn btn-main-action">
|
<a href="{% url 'job_create' %}" class="btn btn-main-action">
|
||||||
<i class="fas fa-plus me-1"></i> Create New Job
|
<i class="fas fa-plus me-1"></i> {% trans "Create New Job" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -125,7 +180,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label for="search" class="form-label small text-muted">Search by Title or Department</label>
|
<label for="search" class="form-label small text-muted">{% trans "Search by Title or Department" %}</label>
|
||||||
<div class="input-group input-group-lg mb-3">
|
<div class="input-group input-group-lg mb-3">
|
||||||
<form method="get" action="" class="w-100">
|
<form method="get" action="" class="w-100">
|
||||||
{% include 'includes/search_form.html' %}
|
{% include 'includes/search_form.html' %}
|
||||||
@ -133,117 +188,123 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
{% url 'job_list' as job_list_url %}
|
<form method="GET" class="row g-3 align-items-end" >
|
||||||
|
<div class="col-md-3">
|
||||||
<form method="GET" class="row g-3 align-items-end" >
|
<label for="status" class="form-label small text-muted">{% trans "Filter by Status" %}</label>
|
||||||
|
<select name="status" id="status" class="form-select form-select-sm">
|
||||||
<div class="col-md-3">
|
<option value="">{% trans "All Statuses" %}</option>
|
||||||
<label for="status" class="form-label small text-muted">Filter by Status</label>
|
<option value="DRAFT" {% if status_filter == 'DRAFT' %}selected{% endif %}>{% trans "Draft" %}</option>
|
||||||
<select name="status" id="status" class="form-select form-select-sm">
|
<option value="ACTIVE" {% if status_filter == 'ACTIVE' %}selected{% endif %}>{% trans "Active" %}</option>
|
||||||
<option value="">All Statuses</option>
|
<option value="CLOSED" {% if status_filter == 'CLOSED' %}selected{% endif %}>{% trans "Closed" %}</option>
|
||||||
<option value="DRAFT" {% if status_filter == 'DRAFT' %}selected{% endif %}>Draft</option>
|
<option value="ARCHIVED" {% if status_filter == 'ARCHIVED' %}selected{% endif %}>{% trans "Archived" %}</option>
|
||||||
<option value="PUBLISHED" {% if status_filter == 'PUBLISHED' %}selected{% endif %}>Published</option>
|
</select>
|
||||||
<option value="CLOSED" {% if status_filter == 'CLOSED' %}selected{% endif %}>Closed</option>
|
</div>
|
||||||
<option value="ARCHIVED" {% if status_filter == 'ARCHIVED' %}selected{% endif %}>Archived</option>
|
<div class="col-md-5">
|
||||||
</select>
|
<div class="filter-buttons">
|
||||||
</div>
|
<button type="submit" class="btn btn-main-action btn-sm">
|
||||||
|
<i class="fas fa-filter me-1"></i> {% trans "Apply Filters" %}
|
||||||
<div class="col-md-5">
|
</button>
|
||||||
<div class="filter-buttons">
|
<a href="{% url 'job_list' %}" class="btn btn-outline-secondary btn-sm">
|
||||||
<button type="submit" class="btn btn-main-action btn-lg">
|
<i class="fas fa-times me-1"></i> {% trans "Clear" %}
|
||||||
<i class="fas fa-filter me-1"></i> Apply Filters
|
</a>
|
||||||
</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if page_obj %}
|
{% comment %} --- START OF TABLE VIEW (Data relied upon context variable 'jobs') --- {% endcomment %}
|
||||||
<div id="job-list">
|
<div id="job-list">
|
||||||
{# View Switcher #}
|
{% comment %} Placeholder for View Switcher {% endcomment %}
|
||||||
{% include "includes/_list_view_switcher.html" with list_id="job-list" %}
|
{% include "includes/_list_view_switcher.html" with list_id="job-list" %}
|
||||||
|
|
||||||
{# Card View (Default) #}
|
<div class="table-view active">
|
||||||
<div class="card-view active row">
|
<div class="card shadow-sm">
|
||||||
{% for job in page_obj %}
|
<div class="table-responsive ">
|
||||||
<div class="col-md-6 col-lg-4 mb-4 ">
|
<table class="table table-hover align-middle mb-0 table-sm">
|
||||||
<div class="card job-card h-100">
|
|
||||||
<div class="card-body d-flex flex-column">
|
|
||||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
|
||||||
<h5 class="card-title flex-grow-1 me-3">{{ job.title }}</h5>
|
|
||||||
<span class="badge bg-{{ job.status|lower|striptags|yesno:'active,draft,closed,archived' }} status-badge">
|
|
||||||
{{ job.get_status_display }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="card-text text-muted small">
|
|
||||||
<i class="fas fa-building"></i> {{ job.department|default:"No Department" }}<br>
|
|
||||||
<i class="fas fa-map-marker-alt"></i> {{ job.get_location_display }}<br>
|
|
||||||
<i class="fas fa-clock"></i> {{ job.get_job_type_display }}<br>
|
|
||||||
<i class="fas fa-briefcase"></i> {{ job.get_source }}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="mt-auto pt-2 border-top">
|
|
||||||
{% if job.posted_to_linkedin %}
|
|
||||||
<span class="badge bg-info mb-2">
|
|
||||||
<i class="fab fa-linkedin me-1"></i> Posted to LinkedIn
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="d-flex gap-2">
|
|
||||||
<a href="{% url 'job_detail' job.slug %}" class="btn btn-sm btn-main-action">
|
|
||||||
<i class="fas fa-eye"></i> View
|
|
||||||
</a>
|
|
||||||
<a href="{% url 'job_update' job.slug %}" class="btn btn-sm btn-outline-secondary">
|
|
||||||
<i class="fas fa-edit"></i> Edit
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# Table View #}
|
|
||||||
<div class="table-view">
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">{% trans "Job Title" %}</th>
|
<th scope="col">{% trans "Job ID" %}</th>
|
||||||
<th scope="col">{% trans "Department" %}</th>
|
{% comment %} <th scope="col">{% trans "Job Title" %}</th>
|
||||||
<th scope="col">{% trans "Location" %}</th>
|
<th scope="col">{% trans "Status" %}</th> {% endcomment %}
|
||||||
<th scope="col">{% trans "Job Type" %}</th>
|
|
||||||
<th scope="col">{% trans "Status" %}</th>
|
|
||||||
<th scope="col">{% trans "Source" %}</th>
|
<th scope="col">{% trans "Source" %}</th>
|
||||||
<th scope="col" class="text-end">{% trans "Actions" %}</th>
|
<th scope="col">{% trans "Actions" %}</th>
|
||||||
|
<th scop="col" class="text-center">{% trans "Manage Forms" %}</th>
|
||||||
|
|
||||||
|
<th scope="col" colspan="7" class="candidate-management-header">
|
||||||
|
{% trans "Applicants Metrics" %}
|
||||||
|
<table class="nested-header-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 14.28%;">{% trans "Applied" %}</th>
|
||||||
|
<th style="width: 14.28%;">{% trans "Screened" %}</th>
|
||||||
|
|
||||||
|
<th colspan="2">{% trans "Exam" %}
|
||||||
|
<table class="nested-stage-metrics">
|
||||||
|
<thead>
|
||||||
|
<th>P</th>
|
||||||
|
<th>F</th>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th colspan="2">{% trans "Interview" %}
|
||||||
|
<table class="nested-stage-metrics">
|
||||||
|
<thead>
|
||||||
|
<th>P</th>
|
||||||
|
<th>F</th>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</th>
|
||||||
|
<th style="width: 14.28%;">{% trans "Offer" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for job in page_obj %}
|
{% comment %} This loop relies on the 'jobs' variable passed from the Django view {% endcomment %}
|
||||||
|
{% for job in jobs %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fw-medium">{{ job.title }}</td>
|
<td class="fw-medium text-primary-theme">{{ job }}</td>
|
||||||
<td>{{ job.department|default:"N/A" }}</td>
|
{% comment %} <td class="fw-medium text-primary-theme">{{ job.title }}</td>
|
||||||
<td>{{ job.get_location_display }}</td>
|
<td><span class="badge bg-{{ job.status }} status-badge">{{ job.status }}</span></td> {% endcomment %}
|
||||||
<td>{{ job.get_job_type_display }}</td>
|
|
||||||
<td><span class="badge bg-{{ job.status|lower|striptags|yesno:'active,draft,closed,archived' }} status-badge">{{ job.get_status_display }}</span></td>
|
|
||||||
<td>{{ job.get_source }}</td>
|
<td>{{ job.get_source }}</td>
|
||||||
<td class="text-end">
|
<td>
|
||||||
<div class="btn-group btn-group-sm" role="group">
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
<a href="{% url 'job_detail' job.slug %}" class="btn btn-outline-primary" title="View">
|
<a href="{% url 'job_detail' job.slug %}" class="btn btn-outline-secondary" title="{% trans 'View' %}">
|
||||||
<i class="fas fa-eye"></i>
|
<i class="fas fa-eye"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="{% url 'job_update' job.slug %}" class="btn btn-outline-secondary" title="Edit">
|
<a href="{% url 'job_update' job.slug %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="text-end">
|
||||||
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
|
<a href="{% url 'form_wizard' job.form_template.id %}" class="btn btn-outline-primary" title="{% trans 'Preview' %}">
|
||||||
|
<i class="fas fa-eye"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'form_builder' job.form_template.id %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'form_template_submissions_list' job.form_template.slug %}" class="btn btn-outline-secondary" title="{% trans 'Submissions' %}">
|
||||||
|
<i class="fas fa-file-alt"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
{# CANDIDATE MANAGEMENT DATA - 7 SEPARATE COLUMNS CORRESPONDING TO THE HEADER #}
|
||||||
|
<td class="candidate-data-cell text-primary-theme"><a href="#" class="text-primary-theme">{% if job.metrics.applied %}{{ job.metrics.applied }}{% else %}-{% endif %}</a></td>
|
||||||
|
<td class="candidate-data-cell text-info"><a href="#" class="text-info">{% if job.metrics.screening %}{{ job.metrics.screening }}{% else %}-{% endif %}</a></td>
|
||||||
|
<td class="candidate-data-cell text-success"><a href="#" class="text-success">{% if job.metrics.exam_p %}{{ job.metrics.exam_p }}{% else %}-{% endif %}</a></td>
|
||||||
|
<td class="candidate-data-cell text-danger"><a href="#" class="text-danger">{% if job.metrics.exam_f %}{{ job.metrics.exam_f }}{% else %}-{% endif %}</a></td>
|
||||||
|
<td class="candidate-data-cell text-success"><a href="#" class="text-success">{% if job.metrics.interview_p %}{{ job.metrics.interview_p }}{% else %}-{% endif %}</a></td>
|
||||||
|
<td class="candidate-data-cell text-danger"><a href="#" class="text-danger">{% if job.metrics.interview_f %}{{ job.metrics.interview_f }}{% else %}-{% endif %}</a></td>
|
||||||
|
<td class="candidate-data-cell text-success"><a href="#" class="text-success">{% if job.metrics.offer %}{{ job.metrics.offer }}{% else %}-{% endif %}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -251,45 +312,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% if page_obj.has_other_pages %}
|
|
||||||
<nav aria-label="Job pagination" class="mt-4">
|
{% comment %} Fallback/Empty State {% endcomment %}
|
||||||
<ul class="pagination justify-content-center">
|
{% if not jobs and not job_list_data and not page_obj %}
|
||||||
{% if page_obj.has_previous %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?page=1{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">First</a>
|
|
||||||
</li>
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">Previous</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<li class="page-item active">
|
|
||||||
<span class="page-link">{{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
{% if page_obj.has_next %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">Next</a>
|
|
||||||
</li>
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if status_filter %}&status={{ status_filter }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}">Last</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
<div class="text-center py-5 card shadow-sm">
|
<div class="text-center py-5 card shadow-sm">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<i class="fas fa-briefcase fa-3x mb-3" style="color: var(--kaauh-teal-dark);"></i>
|
<i class="fas fa-briefcase fa-3x mb-3" style="color: var(--kaauh-teal-dark);"></i>
|
||||||
<h3>No job postings found</h3>
|
<h3>{% trans "No job postings found" %}</h3>
|
||||||
<p class="text-muted">Create your first job posting to get started or adjust your filters.</p>
|
<p class="text-muted">{% trans "Create your first job posting to get started or adjust your filters." %}</p>
|
||||||
<a href="{% url 'job_create' %}" class="btn btn-main-action mt-3">
|
<a href="{% url 'job_create' %}" class="btn btn-main-action mt-3">
|
||||||
<i class="fas fa-plus me-1"></i> Create Job
|
<i class="fas fa-plus me-1"></i> {% trans "Create Job" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -116,7 +116,7 @@
|
|||||||
|
|
||||||
/* Primary Action Button (Create/Submit) */
|
/* Primary Action Button (Create/Submit) */
|
||||||
.btn-main-action {
|
.btn-main-action {
|
||||||
background-color: var(--kaauh-teal);
|
background-color: var(--kaauh-teal-dark);
|
||||||
border-color: var(--kaauh-teal);
|
border-color: var(--kaauh-teal);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
{% block customCSS %}
|
{% block customCSS %}
|
||||||
<style>
|
<style>
|
||||||
/* ================================================= */
|
/* ================================================= */
|
||||||
/* THEME VARIABLES AND GLOBAL STYLES (FROM JOB DETAIL) */
|
/* THEME VARIABLES AND GLOBAL STYLES */
|
||||||
/* ================================================= */
|
/* ================================================= */
|
||||||
:root {
|
:root {
|
||||||
--kaauh-teal: #00636e;
|
--kaauh-teal: #00636e;
|
||||||
@ -21,7 +21,7 @@
|
|||||||
.text-success { color: #28a745 !important; }
|
.text-success { color: #28a745 !important; }
|
||||||
.text-secondary { color: #6c757d !important; }
|
.text-secondary { color: #6c757d !important; }
|
||||||
|
|
||||||
/* Main Action Button Style */
|
/* Main Action Button Style (Used for Download Resume) */
|
||||||
.btn-main-action {
|
.btn-main-action {
|
||||||
background-color: var(--kaauh-teal);
|
background-color: var(--kaauh-teal);
|
||||||
border-color: var(--kaauh-teal);
|
border-color: var(--kaauh-teal);
|
||||||
@ -40,7 +40,7 @@
|
|||||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Outlined Button Styles */
|
/* Outlined Button Styles (Only used variants kept) */
|
||||||
.btn-outline-primary {
|
.btn-outline-primary {
|
||||||
color: var(--kaauh-teal);
|
color: var(--kaauh-teal);
|
||||||
border-color: var(--kaauh-teal);
|
border-color: var(--kaauh-teal);
|
||||||
@ -58,14 +58,6 @@
|
|||||||
color: white;
|
color: white;
|
||||||
border-color: var(--kaauh-teal-dark);
|
border-color: var(--kaauh-teal-dark);
|
||||||
}
|
}
|
||||||
.btn-outline-info {
|
|
||||||
color: #17a2b8;
|
|
||||||
border-color: #17a2b8;
|
|
||||||
}
|
|
||||||
.btn-outline-info:hover {
|
|
||||||
background-color: #17a2b8;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Card enhancements */
|
/* Card enhancements */
|
||||||
.card {
|
.card {
|
||||||
@ -121,70 +113,93 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Right Column Tabs (Parsed Data/Activity) */
|
/* Right Column Card (General styling) */
|
||||||
.right-column-card .nav-tabs {
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
border-bottom: none;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
.right-column-card .nav-link {
|
|
||||||
padding: 0.9rem 1rem;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--kaauh-primary-text);
|
|
||||||
border-right: 1px solid var(--kaauh-border);
|
|
||||||
border-bottom: 1px solid var(--kaauh-border);
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
}
|
|
||||||
.right-column-card .nav-item:last-child .nav-link {
|
|
||||||
border-right: none;
|
|
||||||
}
|
|
||||||
.right-column-card .nav-link.active {
|
|
||||||
background-color: white !important;
|
|
||||||
color: var(--kaauh-teal-dark) !important;
|
|
||||||
border-bottom: 3px solid var(--kaauh-teal);
|
|
||||||
border-right-color: transparent;
|
|
||||||
margin-bottom: -1px;
|
|
||||||
}
|
|
||||||
.right-column-card .tab-content {
|
.right-column-card .tab-content {
|
||||||
padding: 1.5rem 1.25rem;
|
padding: 1.5rem 1.25rem;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================================== */
|
/* ==================================== */
|
||||||
/* NEW: PARSED DATA GRID OPTIMIZATION */
|
/* NEW: Vertical Timeline Styling */
|
||||||
/* ==================================== */
|
/* ==================================== */
|
||||||
.parsed-data-item {
|
|
||||||
/* Ensure the border/bg container takes full width of the grid column */
|
/* Highlight box for the current stage */
|
||||||
width: 100%;
|
.current-stage {
|
||||||
|
border: 1px solid var(--kaauh-border);
|
||||||
|
background-color: #f0f8ff; /* Light, subtle blue background */
|
||||||
}
|
}
|
||||||
.parsed-data-item .data-value {
|
.current-stage .text-primary {
|
||||||
/* Allow data values to wrap without breaking the layout */
|
color: var(--kaauh-teal) !important;
|
||||||
word-wrap: break-word;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timeline {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 2rem;
|
||||||
|
}
|
||||||
|
.timeline::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 1.25rem;
|
||||||
|
width: 2px;
|
||||||
|
background-color: var(--kaauh-border);
|
||||||
|
}
|
||||||
|
.timeline-item {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
.timeline-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
z-index: 10;
|
||||||
|
border: 4px solid white;
|
||||||
|
}
|
||||||
|
.timeline-item:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom Timeline Background Classes for Stages (Using Bootstrap color palette) */
|
||||||
|
.timeline-bg-applied { background-color: var(--kaauh-teal) !important; }
|
||||||
|
.timeline-bg-exam { background-color: #17a2b8 !important; }
|
||||||
|
.timeline-bg-interview { background-color: #ffc107 !important; }
|
||||||
|
.timeline-bg-offer { background-color: #28a745 !important; }
|
||||||
|
.timeline-bg-rejected { background-color: #dc3545 !important; }
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid py-4">
|
<div class="container-fluid py-4">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
|
<nav aria-label="breadcrumb">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'dashboard' %}" class="text-secondary">Home</a></li>
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'job_detail' candidate.job.slug %}" class="text-secondary">Job:({{candidate.job.title}})</a></li>
|
||||||
|
<li class="breadcrumb-item active" aria-current="page" class="text-secondary">Applicant Detail</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
|
||||||
{# LEFT COLUMN: MAIN CANDIDATE DETAILS AND TABS #}
|
{# LEFT COLUMN: MAIN CANDIDATE DETAILS AND TABS #}
|
||||||
<div class="col-lg-8">
|
<div class="col-lg-8">
|
||||||
<div class="card shadow-sm no-hover">
|
<div class="card shadow-sm no-hover">
|
||||||
|
|
||||||
{# HEADER SECTION (The original Candidate Header Card content, redesigned) #}
|
{# HEADER SECTION #}
|
||||||
<div class="candidate-header-card">
|
<div class="candidate-header-card">
|
||||||
<div class="d-flex justify-content-between align-items-start flex-wrap">
|
<div class="d-flex justify-content-between align-items-start flex-wrap">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="h3 mb-2">{{ candidate.name }}</h1>
|
<h1 class="h3 mb-2">{{ candidate.name }}</h1>
|
||||||
<div class="d-flex align-items-center gap-2 mb-2">
|
<div class="d-flex align-items-center gap-2 mb-2">
|
||||||
<span class="badge {% if candidate.applied %}bg-success{% else %}bg-warning{% endif %}">
|
|
||||||
{{ candidate.applied|yesno:"Applied,Pending" }}
|
|
||||||
</span>
|
|
||||||
<span id="stageDisplay" class="badge"
|
<span id="stageDisplay" class="badge"
|
||||||
data-class="{'bg-primary': $stage == 'Applied', 'bg-info': $stage == 'Exam', 'bg-warning': $stage == 'Interview', 'bg-success': $stage == 'Offer'}"
|
data-class="{'bg-primary': $stage == 'Applied', 'bg-info': $stage == 'Exam', 'bg-warning': $stage == 'Interview', 'bg-success': $stage == 'Offer'}"
|
||||||
data-signals-stage="'{{ candidate.stage }}'">
|
data-signals-stage="'{{ candidate.stage }}'">
|
||||||
@ -196,7 +211,7 @@
|
|||||||
{% trans "Applied for:" %} <strong>{{ candidate.job.title }}</strong>
|
{% trans "Applied for:" %} <strong>{{ candidate.job.title }}</strong>
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
{# Action buttons moved to the right column, keeping only the most visible here for quick access if preferred #}
|
{# Change Stage button #}
|
||||||
{% if user.is_staff %}
|
{% if user.is_staff %}
|
||||||
<button type="button" class="btn btn-outline-light btn-sm mt-1" data-bs-toggle="modal" data-bs-target="#stageUpdateModal">
|
<button type="button" class="btn btn-outline-light btn-sm mt-1" data-bs-toggle="modal" data-bs-target="#stageUpdateModal">
|
||||||
<i class="fas fa-exchange-alt"></i> {% trans "Change Stage" %}
|
<i class="fas fa-exchange-alt"></i> {% trans "Change Stage" %}
|
||||||
@ -222,7 +237,7 @@
|
|||||||
{% if candidate.parsed_summary %}
|
{% if candidate.parsed_summary %}
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<button class="nav-link" id="summary-tab" data-bs-toggle="tab" data-bs-target="#summary-pane" type="button" role="tab" aria-controls="summary-pane" aria-selected="false">
|
<button class="nav-link" id="summary-tab" data-bs-toggle="tab" data-bs-target="#summary-pane" type="button" role="tab" aria-controls="summary-pane" aria-selected="false">
|
||||||
<i class="fas fa-chart-bar me-1"></i> {% trans "Summary" %}
|
<i class="fas fa-chart-bar me-1"></i> {% trans "Resume Summary" %}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -231,7 +246,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="tab-content" id="candidateTabsContent">
|
<div class="tab-content" id="candidateTabsContent">
|
||||||
|
|
||||||
{# TAB 1 CONTENT: CONTACT & DATES (Original Contact Card) #}
|
{# TAB 1 CONTENT: CONTACT & DATES #}
|
||||||
<div class="tab-pane fade show active" id="contact-pane" role="tabpanel" aria-labelledby="contact-tab">
|
<div class="tab-pane fade show active" id="contact-pane" role="tabpanel" aria-labelledby="contact-tab">
|
||||||
<h5 class="text-primary mb-4">{% trans "Core Details" %}</h5>
|
<h5 class="text-primary mb-4">{% trans "Core Details" %}</h5>
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
@ -271,7 +286,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# TAB 2 CONTENT: RESUME (Original Resume Card) #}
|
{# TAB 2 CONTENT: RESUME #}
|
||||||
{% if candidate.resume %}
|
{% if candidate.resume %}
|
||||||
<div class="tab-pane fade" id="resume-pane" role="tabpanel" aria-labelledby="resume-tab">
|
<div class="tab-pane fade" id="resume-pane" role="tabpanel" aria-labelledby="resume-tab">
|
||||||
<h5 class="text-primary mb-4">{% trans "Resume Document" %}</h5>
|
<h5 class="text-primary mb-4">{% trans "Resume Document" %}</h5>
|
||||||
@ -288,12 +303,12 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# TAB 3 CONTENT: PARSED SUMMARY (Original Parsed Summary Card) #}
|
{# TAB 3 CONTENT: PARSED SUMMARY #}
|
||||||
{% if candidate.parsed_summary %}
|
{% if candidate.parsed_summary %}
|
||||||
<div class="tab-pane fade" id="summary-pane" role="tabpanel" aria-labelledby="summary-tab">
|
<div class="tab-pane fade" id="summary-pane" role="tabpanel" aria-labelledby="summary-tab">
|
||||||
<h5 class="text-primary mb-4">{% trans "AI Generated Summary" %}</h5>
|
<h5 class="text-primary mb-4">{% trans "AI Generated Summary" %}</h5>
|
||||||
<div class="border-start border-primary ps-3 pt-1 pb-1">
|
<div class="border-start border-primary ps-3 pt-1 pb-1">
|
||||||
<p class="mb-0 text-secondary">{{ candidate.parsed_summary|linebreaks }}</p>
|
{% include 'includes/candidate_modal_body.html' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -303,18 +318,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# RIGHT COLUMN: ACTIONS AND PARSED DATA TABS #}
|
{# RIGHT COLUMN: ACTIONS AND CANDIDATE TIMELINE #}
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
|
|
||||||
{# ACTIONS CARD (The new consolidated action card) #}
|
{# ACTIONS CARD #}
|
||||||
{% if user.is_staff %}
|
{% if user.is_staff %}
|
||||||
<div class="card shadow-sm mb-4 p-3">
|
<div class="card shadow-sm mb-4 p-3">
|
||||||
<h5 class="text-muted mb-3"><i class="fas fa-cog me-2"></i>{% trans "Management Actions" %}</h5>
|
<h5 class="text-muted mb-3"><i class="fas fa-cog me-2"></i>{% trans "Management Actions" %}</h5>
|
||||||
<div class="d-grid gap-2">
|
<div class="d-grid gap-2">
|
||||||
{# MODAL TRIGGER #}
|
|
||||||
{% comment %} <button type="button" class="btn btn-main-action" data-bs-toggle="modal" data-bs-target="#stageUpdateModal">
|
|
||||||
<i class="fas fa-exchange-alt"></i> {% trans "Update Stage" %}
|
|
||||||
</button> {% endcomment %}
|
|
||||||
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-primary">
|
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-primary">
|
||||||
<i class="fas fa-edit"></i> {% trans "Edit Details" %}
|
<i class="fas fa-edit"></i> {% trans "Edit Details" %}
|
||||||
</a>
|
</a>
|
||||||
@ -328,52 +339,50 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# PARSED DATA TABS (Original Parsed Data Card, now tabbed) #}
|
{# ENHANCED: CANDIDATE JOURNEY TIMELINE CARD #}
|
||||||
{% if parsed %}
|
<div class="card shadow-sm timeline-card">
|
||||||
<div class="card right-column-card shadow-sm">
|
<div class="card-header bg-white border-bottom py-3">
|
||||||
<ul class="nav nav-tabs" id="parsedDataTabs" role="tablist">
|
<h5 class="mb-0 text-muted"><i class="fas fa-route me-2"></i>{% trans "Candidate Journey" %}</h5>
|
||||||
<li class="nav-item flex-fill" role="presentation">
|
</div>
|
||||||
<button class="nav-link active" id="data-tab" data-bs-toggle="tab" data-bs-target="#data-pane" type="button" role="tab" aria-controls="data-pane" aria-selected="true">
|
<div class="card-body p-4">
|
||||||
<i class="fas fa-database me-1"></i> {% trans "Parsed Data" %}
|
|
||||||
</button>
|
<h6 class="text-uppercase text-secondary mb-3">{% trans "Current Stage" %}</h6>
|
||||||
</li>
|
<div class="p-3 mb-4 rounded current-stage">
|
||||||
<li class="nav-item flex-fill" role="presentation">
|
<p class="mb-0 fw-bold fs-5 text-primary">{{ candidate.stage }}</p>
|
||||||
<button class="nav-link" id="activity-tab" data-bs-toggle="tab" data-bs-target="#activity-pane" type="button" role="tab" aria-controls="activity-pane" aria-selected="false">
|
<small class="text-muted d-block mt-1">
|
||||||
<i class="fas fa-history me-1"></i> {% trans "Activity" %}
|
{% trans "Latest status update:" %} {{ candidate.updated_at|date:"M d, Y" }}
|
||||||
</button>
|
</small>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="tab-content" id="parsedDataTabsContent">
|
<h6 class="text-uppercase text-secondary mb-3 pt-2 border-top">{% trans "Historical Timeline" %}</h6>
|
||||||
|
<div class="timeline">
|
||||||
{# TAB 1: PARSED DATA - UPDATED TO 2-COLUMN GRID #}
|
|
||||||
<div class="tab-pane fade show active" id="data-pane" role="tabpanel" aria-labelledby="data-tab">
|
|
||||||
<h6 class="text-muted small text-uppercase mb-3">{% trans "Structured Resume Data" %}</h6>
|
{# Base Status: Application Submitted (Always required) #}
|
||||||
<div class="row g-3">
|
<div class="timeline-item">
|
||||||
{% for key, value in parsed.items %}
|
<div class="timeline-icon timeline-bg-applied"><i class="fas fa-file-signature"></i></div>
|
||||||
<div class="col-md-6 parsed-data-item">
|
<div class="timeline-content">
|
||||||
<div class="p-3 border rounded h-100 bg-light">
|
<p class="timeline-stage fw-bold mb-0 ms-2">{% trans "Application Submitted" %}</p>
|
||||||
<h6 class="text-muted small text-uppercase mb-1">
|
<small class="text-muted">
|
||||||
<i class="fas fa-tag me-1 text-primary"></i> {{ key|title }}
|
<i class="far fa-calendar-alt me-1"></i> {{ candidate.created_at|date:"M d, Y" }}
|
||||||
</h6>
|
<span class="ms-2">|</span>
|
||||||
<p class="mb-0 text-dark small data-value">
|
<i class="far fa-clock ms-2 me-1"></i> {{ candidate.created_at|date:"h:i A" }}
|
||||||
{{ value|default:"N/A"|linebreaksbr }}
|
</small>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{# TAB 2: ACTIVITY (Placeholder) #}
|
{# Fallback if no history is explicitly logged #}
|
||||||
<div class="tab-pane fade" id="activity-pane" role="tabpanel" aria-labelledby="activity-tab">
|
{% if not candidate_stage_history %}
|
||||||
<p class="text-muted">
|
<p class="text-muted mt-3 mb-0 ps-3">
|
||||||
{% trans "Activity feed (e.g., stage changes, notes, interview history) will appear here." %}
|
{% trans "Detailed stage history logs are currently unavailable." %}
|
||||||
</p>
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,197 +1,138 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load static i18n %}
|
{% load static i18n %}
|
||||||
|
|
||||||
{% block title %}Candidate Tier Management - {{ job.title }} - ATS{% endblock %}
|
{% block title %}Candidate Management - {{ job.title }} - University ATS{% endblock %}
|
||||||
|
|
||||||
{% block customCSS %}
|
{% block customCSS %}
|
||||||
<style>
|
<style>
|
||||||
/* Minimal Tier Management Styles */
|
/* KAAT-S UI Variables */
|
||||||
|
:root {
|
||||||
|
--kaauh-teal: #00636e;
|
||||||
|
--kaauh-teal-dark: #004a53;
|
||||||
|
--kaauh-border: #eaeff3;
|
||||||
|
--kaauh-primary-text: #343a40;
|
||||||
|
--kaauh-success: #28a745; /* Standard success for positive actions */
|
||||||
|
--kaauh-info: #17a2b8; /* Standard info/exam badge */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 1. Main Container & Card Styling */
|
||||||
|
.kaauh-card {
|
||||||
|
border: 1px solid var(--kaauh-border);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
.tier-controls {
|
.tier-controls {
|
||||||
background-color: #f8f9fa;
|
background-color: var(--kaauh-border); /* Light background for control sections */
|
||||||
padding: 1rem;
|
border-radius: 0.5rem;
|
||||||
border-radius: 0.375rem;
|
padding: 1.25rem;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
.tier-controls .form-row {
|
|
||||||
display: flex;
|
/* 2. Button Styling (from reference) */
|
||||||
align-items: end;
|
.btn-main-action {
|
||||||
gap: 0.75rem;
|
background-color: var(--kaauh-teal);
|
||||||
}
|
border-color: var(--kaauh-teal);
|
||||||
.tier-controls .form-group {
|
|
||||||
flex: 1;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
.bulk-update-controls {
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
padding: 1rem;
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
.stage-groups {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
||||||
gap: 1rem;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
.stage-group {
|
|
||||||
border: 1px solid #dee2e6;
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.stage-group .stage-header {
|
|
||||||
background-color: #495057;
|
|
||||||
color: white;
|
color: white;
|
||||||
padding: 0.5rem 0.75rem;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
.stage-group .stage-body {
|
|
||||||
padding: 0.75rem;
|
|
||||||
min-height: 80px;
|
|
||||||
}
|
|
||||||
.stage-candidate {
|
|
||||||
padding: 0.375rem;
|
|
||||||
border-bottom: 1px solid #f1f3f4;
|
|
||||||
}
|
|
||||||
.stage-candidate:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
.match-score {
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #0056b3;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
.btn-sm {
|
.btn-main-action:hover {
|
||||||
font-size: 0.75rem;
|
background-color: var(--kaauh-teal-dark);
|
||||||
padding: 0.2rem 0.4rem;
|
border-color: var(--kaauh-teal-dark);
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
.btn-outline-secondary {
|
||||||
|
color: var(--kaauh-teal-dark);
|
||||||
|
border-color: var(--kaauh-teal);
|
||||||
|
}
|
||||||
|
.btn-outline-secondary:hover {
|
||||||
|
background-color: var(--kaauh-teal-dark);
|
||||||
|
color: white;
|
||||||
|
border-color: var(--kaauh-teal-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tab Styles for Tiers */
|
/* 3. Tab Styles (View Switcher) */
|
||||||
.nav-tabs {
|
.nav-pills .nav-link {
|
||||||
border-bottom: 1px solid #dee2e6;
|
color: var(--kaauh-teal-dark);
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
.nav-tabs .nav-link {
|
|
||||||
border: none;
|
|
||||||
color: #495057;
|
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 0.5rem 1rem;
|
border-radius: 0.5rem;
|
||||||
transition: all 0.2s;
|
transition: background-color 0.2s;
|
||||||
}
|
}
|
||||||
.nav-tabs .nav-link:hover {
|
.nav-pills .nav-link.active {
|
||||||
border: none;
|
background-color: var(--kaauh-teal);
|
||||||
background-color: #f8f9fa;
|
color: white;
|
||||||
}
|
|
||||||
.nav-tabs .nav-link.active {
|
|
||||||
color: #495057;
|
|
||||||
background-color: #fff;
|
|
||||||
border: none;
|
|
||||||
border-bottom: 2px solid #007bff;
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
.tier-1 .nav-link {
|
|
||||||
color: #155724;
|
|
||||||
}
|
|
||||||
.tier-1 .nav-link.active {
|
|
||||||
border-bottom-color: #28a745;
|
|
||||||
}
|
|
||||||
.tier-2 .nav-link {
|
|
||||||
color: #856404;
|
|
||||||
}
|
|
||||||
.tier-2 .nav-link.active {
|
|
||||||
border-bottom-color: #ffc107;
|
|
||||||
}
|
|
||||||
.tier-3 .nav-link {
|
|
||||||
color: #721c24;
|
|
||||||
}
|
|
||||||
.tier-3 .nav-link.active {
|
|
||||||
border-bottom-color: #dc3545;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Candidate Table Styles */
|
/* 4. Candidate Table Styling (Aligned with KAAT-S) */
|
||||||
.candidate-table {
|
.candidate-table {
|
||||||
width: 100%;
|
|
||||||
border-collapse: separate;
|
border-collapse: separate;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border-radius: 0.375rem;
|
border-radius: 0.5rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
||||||
}
|
}
|
||||||
.candidate-table thead {
|
.candidate-table thead {
|
||||||
background-color: #f8f9fa;
|
background-color: var(--kaauh-border);
|
||||||
}
|
}
|
||||||
.candidate-table th {
|
.candidate-table th {
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
text-align: left;
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.875rem;
|
color: var(--kaauh-teal-dark);
|
||||||
color: #495057;
|
border-bottom: 2px solid var(--kaauh-teal);
|
||||||
border-bottom: 1px solid #dee2e6;
|
|
||||||
}
|
}
|
||||||
.candidate-table td {
|
.candidate-table td {
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
border-bottom: 1px solid #f1f3f4;
|
border-bottom: 1px solid var(--kaauh-border);
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
.candidate-table tbody tr:hover {
|
.candidate-table tbody tr:hover {
|
||||||
background-color: #f8f9fa;
|
background-color: #f1f3f4;
|
||||||
}
|
|
||||||
.candidate-table tbody tr:last-child td {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
}
|
||||||
.candidate-name {
|
.candidate-name {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.95rem;
|
color: var(--kaauh-primary-text);
|
||||||
}
|
}
|
||||||
.candidate-details {
|
.candidate-details {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
color: #6c757d;
|
color: #6c757d;
|
||||||
}
|
}
|
||||||
.candidate-table-responsive {
|
|
||||||
overflow-x: auto;
|
/* 5. Badges (Status/Score) */
|
||||||
margin-bottom: 1rem;
|
.status-badge {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 0.3em 0.7em;
|
||||||
|
border-radius: 0.35rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
.bg-applicant { background-color: #6c757d; color: white; } /* Secondary */
|
||||||
|
.bg-candidate { background-color: var(--kaauh-success); color: white; } /* Success */
|
||||||
|
.bg-score { background-color: var(--kaauh-teal-dark); color: white; }
|
||||||
|
.bg-exam-status { background-color: var(--kaauh-info); color: white; }
|
||||||
|
|
||||||
|
/* 6. Stage Badges (More distinct from KAAT-S reference) */
|
||||||
.stage-badge {
|
.stage-badge {
|
||||||
padding: 0.125rem 0.5rem;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
font-size: 0.7rem;
|
|
||||||
font-weight: 600;
|
|
||||||
margin-left: 0.375rem;
|
|
||||||
}
|
|
||||||
.stage-Applied {
|
|
||||||
background-color: #e9ecef;
|
|
||||||
color: #495057;
|
|
||||||
}
|
|
||||||
.stage-Exam {
|
|
||||||
background-color: #cce5ff;
|
|
||||||
color: #004085;
|
|
||||||
}
|
|
||||||
.stage-Interview {
|
|
||||||
background-color: #d1ecf1;
|
|
||||||
color: #0c5460;
|
|
||||||
}
|
|
||||||
.stage-Offer {
|
|
||||||
background-color: #d4edda;
|
|
||||||
color: #155724;
|
|
||||||
}
|
|
||||||
.exam-controls {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.375rem;
|
|
||||||
margin-top: 0.375rem;
|
|
||||||
}
|
|
||||||
.exam-controls select,
|
|
||||||
.exam-controls input {
|
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
padding: 0.125rem 0.25rem;
|
padding: 0.25rem 0.6rem;
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
.tier-badge {
|
.stage-Applied { background-color: #e9ecef; color: #495057; }
|
||||||
|
.stage-Exam { background-color: #d1ecf1; color: #0c5460; } /* Light cyan/info */
|
||||||
|
.stage-Interview { background-color: #ffc107; color: #856404; } /* Yellow/warning */
|
||||||
|
.stage-Offer { background-color: #d4edda; color: #155724; } /* Light green/success */
|
||||||
|
|
||||||
|
/* Candidate Indicator (used for the single Potential Candidates list) */
|
||||||
|
.candidate-indicator-badge {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
padding: 0.125rem 0.375rem;
|
padding: 0.15rem 0.4rem;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
background-color: rgba(0,0,0,0.1);
|
font-weight: 700;
|
||||||
color: #495057;
|
margin-left: 0.5rem;
|
||||||
margin-left: 0.375rem;
|
background-color: var(--kaauh-teal);
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -200,12 +141,12 @@
|
|||||||
<div class="container py-4">
|
<div class="container py-4">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="h3 mb-1">
|
<h1 class="h3 mb-1" style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||||
<i class="fas fa-layer-group me-2"></i>
|
<i class="fas fa-layer-group me-2"></i>
|
||||||
{% trans "Candidate Tier Management" %} - {{ job.title }}
|
{% trans "Applicant Screening for Job:" %} - {{ job.title }} <small class="text-muted fs-6">{{job.internal_job_id}}<small>
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-muted mb-0">
|
<p class="text-muted mb-0">
|
||||||
Total Candidates: {{ total_candidates }}
|
Total Applicants: <span class="fw-bold">{{ total_candidates }}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<a href="{% url 'job_detail' job.slug %}" class="btn btn-outline-secondary">
|
<a href="{% url 'job_detail' job.slug %}" class="btn btn-outline-secondary">
|
||||||
@ -213,13 +154,25 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Tier Controls -->
|
<div class="tier-controls kaauh-card shadow-sm">
|
||||||
<div class="tier-controls">
|
<h4 class="h5 mb-3" style="color: var(--kaauh-teal-dark);">{% trans "Filter Potential Candidates" %}</h4>
|
||||||
<form method="post" class="mb-0">
|
<form method="post" class="mb-0">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="form-row">
|
<div class="row g-3 align-items-end">
|
||||||
<div class="form-group">
|
|
||||||
<label for="tier1_count">{% trans "Number of candidates in Tier 1 (Top N)" %}</label>
|
<div class="col-md-3 col-sm-6">
|
||||||
|
<label for="min_ai_score" class="form-label small text-muted">
|
||||||
|
{% trans "Minimum AI Score" %}
|
||||||
|
</label>
|
||||||
|
<input type="number" name="min_ai_score" id="min_ai_score" class="form-control"
|
||||||
|
value="{{ min_ai_score|default:'0' }}" min="0" max="100" step="1"
|
||||||
|
placeholder="e.g., 75">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-3 col-sm-6">
|
||||||
|
<label for="tier1_count" class="form-label small text-muted">
|
||||||
|
{% trans "Number of Potential Candidates (Top N)" %}
|
||||||
|
</label>
|
||||||
<input type="number" name="tier1_count" id="tier1_count" class="form-control"
|
<input type="number" name="tier1_count" id="tier1_count" class="form-control"
|
||||||
value="{{ tier1_count }}" min="1" max="{{ total_candidates }}">
|
value="{{ tier1_count }}" min="1" max="{{ total_candidates }}">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
125
templates/recruitment/partials/_candidate_table.html
Normal file
125
templates/recruitment/partials/_candidate_table.html
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% if candidates %}
|
||||||
|
<div class="candidate-table-responsive">
|
||||||
|
<form method="post" id="candidate-action-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
<table class="candidate-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{% trans "Name / Contact" %}</th>
|
||||||
|
<th scope="col">{% trans "AI Score" %}</th>
|
||||||
|
<th scope="col">{% trans "Status" %}</th>
|
||||||
|
<th scope="col">{% trans "Stage" %}</th>
|
||||||
|
<th scope="col" class="text-end">{% trans "Actions" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for candidate in candidates %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="candidate-name">{{ candidate.name }}</div>
|
||||||
|
<div class="candidate-details">
|
||||||
|
<i class="fas fa-envelope me-1"></i> {{ candidate.email|default:"N/A" }}<br>
|
||||||
|
<i class="fas fa-phone me-1"></i> {{ candidate.phone|default:"N/A" }}
|
||||||
|
</div>
|
||||||
|
{% if is_potential_view %}
|
||||||
|
{# Show candidate ID in this view to help with bulk update ID entry #}
|
||||||
|
<div class="candidate-details mt-1">
|
||||||
|
ID: **{{ candidate.id }}**
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="status-badge bg-score">
|
||||||
|
{{ candidate.match_score|default:"0" }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="status-badge
|
||||||
|
{% if candidate.applicant_status == 'Candidate' %}bg-candidate{% else %}bg-applicant{% endif %}">
|
||||||
|
{{ candidate.get_applicant_status_display }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="stage-badge stage-{{ candidate.stage }}">
|
||||||
|
{{ candidate.get_stage_display }}
|
||||||
|
</span>
|
||||||
|
{% if candidate.stage == "Exam" and candidate.exam_status %}
|
||||||
|
<br>
|
||||||
|
<span class="status-badge bg-exam-status mt-1">
|
||||||
|
{{ candidate.get_exam_status_display }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="text-end">
|
||||||
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
|
|
||||||
|
{# View Candidate Criteria/Details (Uses HTMX target #}
|
||||||
|
<button type="button" class="btn btn-main-action"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#candidateviewModal"
|
||||||
|
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}"
|
||||||
|
hx-target="#candidateviewModalBody"
|
||||||
|
title="{% trans 'View Details and Score Breakdown' %}">
|
||||||
|
<i class="fas fa-eye"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{# Individual actions (Shown if it's the filtered view OR if the applicant needs to be promoted) #}
|
||||||
|
{% if is_potential_view or candidate.applicant_status == 'Applicant' %}
|
||||||
|
{% if candidate.applicant_status == 'Applicant' %}
|
||||||
|
{# Mark as Candidate Button (Manual Selection/Promotion) #}
|
||||||
|
<button type="submit" name="mark_as_candidate"
|
||||||
|
class="btn btn-sm btn-success"
|
||||||
|
formaction="?candidate_id={{ candidate.id }}&action=mark_as_candidate"
|
||||||
|
title="{% trans 'Mark as Potential Candidate' %}">
|
||||||
|
<i class="fas fa-user-check"></i>
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# Stage Progression Dropdown #}
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button"
|
||||||
|
data-bs-toggle="dropdown" title="{% trans 'Move to Next Stage' %}">
|
||||||
|
<i class="fas fa-tasks"></i>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
|
{% for next_stage in candidate.get_available_stages %}
|
||||||
|
<li>
|
||||||
|
<button type="submit" name="update_stage"
|
||||||
|
class="dropdown-item"
|
||||||
|
formaction="?candidate_id={{ candidate.id }}&new_stage={{ next_stage }}">
|
||||||
|
{% trans "Move to" %} {{ next_stage }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% if candidate.stage == "Exam" %}
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li>
|
||||||
|
<button type="button" class="dropdown-item"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#examModal{{ candidate.id }}">
|
||||||
|
<i class="fas fa-clipboard-check me-1"></i> {% trans "Update Exam Status" %}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="text-center py-4 text-muted kaauh-card p-4">
|
||||||
|
<i class="fas fa-inbox fa-2x mb-2" style="color: var(--kaauh-teal);"></i>
|
||||||
|
<p class="mb-0">{% trans "No candidates found in this list." %}</p>
|
||||||
|
{% if is_potential_view %}
|
||||||
|
<p class="small">{% trans "Adjust your 'Top N' filter in the controls above or check the All Applicants list." %}</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
@ -4,8 +4,7 @@
|
|||||||
{% block title %}Create Training Material - {{ block.super }}{% endblock %}
|
{% block title %}Create Training Material - {{ block.super }}{% endblock %}
|
||||||
|
|
||||||
{% block customCSS %}
|
{% block customCSS %}
|
||||||
{# 💡 Required for Summernote if you added it, otherwise remove this line #}
|
|
||||||
{{ form.media.css }}
|
|
||||||
<style>
|
<style>
|
||||||
/* ================================================= */
|
/* ================================================= */
|
||||||
/* THEME VARIABLES AND GLOBAL STYLES */
|
/* THEME VARIABLES AND GLOBAL STYLES */
|
||||||
@ -21,9 +20,11 @@
|
|||||||
/* Primary Color Overrides */
|
/* Primary Color Overrides */
|
||||||
.text-primary { color: var(--kaauh-teal) !important; }
|
.text-primary { color: var(--kaauh-teal) !important; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Main Action Button Style */
|
/* Main Action Button Style */
|
||||||
.btn-main-action, .btn-primary {
|
.btn-main-action{
|
||||||
background-color: var(--kaauh-teal);
|
background-color: var(--kaauh-teal-dark); /* Changed to primary teal for main actions */
|
||||||
border-color: var(--kaauh-teal);
|
border-color: var(--kaauh-teal);
|
||||||
color: white;
|
color: white;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@ -34,7 +35,7 @@
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
.btn-main-action:hover, .btn-primary:hover {
|
.btn-main-action:hover, .btn-primary:hover {
|
||||||
background-color: var(--kaauh-teal-dark);
|
background-color: var(--kaauh-teal-dark); /* Darker on hover */
|
||||||
border-color: var(--kaauh-teal-dark);
|
border-color: var(--kaauh-teal-dark);
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||||
@ -129,15 +130,14 @@
|
|||||||
<form method="post" enctype="multipart/form-data" class="row">
|
<form method="post" enctype="multipart/form-data" class="row">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
|
|
||||||
{% crispy form %}
|
{% crispy form %}
|
||||||
|
|
||||||
|
{# Add the main action button here for consistency #}
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# 💡 Required for Summernote if you added it, otherwise remove this line #}
|
|
||||||
{{ form.media.js }}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Loading…
x
Reference in New Issue
Block a user