Compare commits
No commits in common. "ce156038023a572a900952ed87937dd6096fd470" and "c13450ae831debf1e124abe0b4d2b1bfc507ebd6" have entirely different histories.
ce15603802
...
c13450ae83
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 = [
|
||||
'title', 'department', 'job_type', 'workplace_type',
|
||||
'location_city', 'location_state', 'location_country',
|
||||
'description', 'qualifications', 'salary_range', 'benefits','application_start_date'
|
||||
'description', 'qualifications', 'salary_range', 'benefits'
|
||||
,'application_deadline', 'application_instructions',
|
||||
'position_number', 'reporting_to', 'joining_date', 'status',
|
||||
'position_number', 'reporting_to', 'start_date', 'status',
|
||||
'created_by','open_positions','hash_tags'
|
||||
]
|
||||
widgets = {
|
||||
@ -247,10 +247,6 @@ class JobPostingForm(forms.ModelForm):
|
||||
# 'placeholder': 'https://university.edu/careers/job123',
|
||||
# 'required': True
|
||||
# }),
|
||||
'application_start_date': forms.DateInput(attrs={
|
||||
'class': 'form-control',
|
||||
'type': 'date'
|
||||
}),
|
||||
'application_deadline': forms.DateInput(attrs={
|
||||
'class': 'form-control',
|
||||
'type': 'date'
|
||||
@ -276,7 +272,7 @@ class JobPostingForm(forms.ModelForm):
|
||||
'class': 'form-control',
|
||||
'placeholder': 'Department Chair, Director, etc.'
|
||||
}),
|
||||
'joining_date': forms.DateInput(attrs={
|
||||
'start_date': forms.DateInput(attrs={
|
||||
'class': 'form-control',
|
||||
'type': 'date'
|
||||
}),
|
||||
@ -337,31 +333,31 @@ class JobPostingForm(forms.ModelForm):
|
||||
raise forms.ValidationError('Please enter a valid URL (e.g., https://example.com)')
|
||||
return url
|
||||
|
||||
# def clean(self):
|
||||
# """Cross-field validation"""
|
||||
# cleaned_data = super().clean()
|
||||
def clean(self):
|
||||
"""Cross-field validation"""
|
||||
cleaned_data = super().clean()
|
||||
|
||||
# # Validate dates
|
||||
# start_date = cleaned_data.get('start_date')
|
||||
# application_deadline = cleaned_data.get('application_deadline')
|
||||
# Validate dates
|
||||
start_date = cleaned_data.get('start_date')
|
||||
application_deadline = cleaned_data.get('application_deadline')
|
||||
|
||||
# # Perform cross-field validation only if both fields have values
|
||||
# if start_date and application_deadline:
|
||||
# if application_deadline > start_date:
|
||||
# self.add_error('application_deadline',
|
||||
# 'The application deadline must be set BEFORE the job start date.')
|
||||
# Perform cross-field validation only if both fields have values
|
||||
if start_date and application_deadline:
|
||||
if application_deadline > start_date:
|
||||
self.add_error('application_deadline',
|
||||
'The application deadline must be set BEFORE the job start date.')
|
||||
|
||||
# # # Validate that if status is ACTIVE, we have required fields
|
||||
# # status = cleaned_data.get('status')
|
||||
# # if status == 'ACTIVE':
|
||||
# # if not cleaned_data.get('application_url'):
|
||||
# # self.add_error('application_url',
|
||||
# # 'Application URL is required for active jobs.')
|
||||
# # if not cleaned_data.get('description'):
|
||||
# # self.add_error('description',
|
||||
# # 'Job description is required for active jobs.')
|
||||
# # Validate that if status is ACTIVE, we have required fields
|
||||
# status = cleaned_data.get('status')
|
||||
# if status == 'ACTIVE':
|
||||
# if not cleaned_data.get('application_url'):
|
||||
# self.add_error('application_url',
|
||||
# 'Application URL is required for active jobs.')
|
||||
# if not cleaned_data.get('description'):
|
||||
# self.add_error('description',
|
||||
# 'Job description is required for active jobs.')
|
||||
|
||||
# return cleaned_data
|
||||
return cleaned_data
|
||||
|
||||
class JobPostingImageForm(forms.ModelForm):
|
||||
class Meta:
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
# 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),
|
||||
),
|
||||
]
|
||||
@ -1,23 +0,0 @@
|
||||
# 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,7 +98,6 @@ class JobPosting(Base):
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
application_start_date=models.DateField(null=True, blank=True)
|
||||
application_deadline = models.DateField(null=True, blank=True)
|
||||
application_instructions =CKEditor5Field(
|
||||
blank=True, null=True,config_name='extends'
|
||||
@ -151,7 +150,7 @@ class JobPosting(Base):
|
||||
reporting_to = models.CharField(
|
||||
max_length=100, blank=True, help_text="Who this position reports to"
|
||||
)
|
||||
joining_date = models.DateField(null=True, blank=True, help_text="Desired start date")
|
||||
start_date = models.DateField(null=True, blank=True, help_text="Desired start date")
|
||||
open_positions = models.PositiveIntegerField(
|
||||
default=1, help_text="Number of open positions for this job"
|
||||
)
|
||||
@ -229,7 +228,7 @@ class JobPosting(Base):
|
||||
parts.append(self.location_city)
|
||||
if self.location_state:
|
||||
parts.append(self.location_state)
|
||||
if self.location_country:
|
||||
if self.location_country and self.location_country != "United States":
|
||||
parts.append(self.location_country)
|
||||
return ", ".join(parts) if parts else "Not specified"
|
||||
|
||||
|
||||
Binary file not shown.
@ -15,7 +15,6 @@ urlpatterns = [
|
||||
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/application/success', views.application_success, name='application_success'),
|
||||
path('careers/',views.kaauh_career,name='kaauh_career'),
|
||||
|
||||
|
||||
# LinkedIn Integration URLs
|
||||
|
||||
@ -277,19 +277,17 @@ def job_detail(request, slug):
|
||||
|
||||
|
||||
# Get all candidates for this job, ordered by most recent
|
||||
applicants = job.candidates.all().order_by("-created_at")
|
||||
candidates = job.candidates.all().order_by("-created_at")
|
||||
|
||||
# Count candidates by stage for summary statistics
|
||||
total_applicant = applicants.count()
|
||||
applied_count = applicants.filter(stage="Applied").count()
|
||||
interview_count = applicants.filter(stage="Interview").count()
|
||||
offer_count = applicants.filter(stage="Offer").count()
|
||||
total_candidates = candidates.count()
|
||||
applied_count = candidates.filter(stage="Applied").count()
|
||||
interview_count = candidates.filter(stage="Interview").count()
|
||||
offer_count = candidates.filter(stage="Offer").count()
|
||||
|
||||
status_form = JobPostingStatusForm(instance=job)
|
||||
image_upload_form=JobPostingImageForm(instance=job)
|
||||
|
||||
|
||||
|
||||
# 2. Check for POST request (Status Update Submission)
|
||||
if request.method == 'POST':
|
||||
|
||||
@ -311,8 +309,8 @@ def job_detail(request, slug):
|
||||
|
||||
context = {
|
||||
"job": job,
|
||||
"applicants": applicants,
|
||||
"total_applicants": total_applicant,
|
||||
"candidates": candidates,
|
||||
"total_candidates": total_candidates,
|
||||
"applied_count": applied_count,
|
||||
"interview_count": interview_count,
|
||||
"offer_count": offer_count,
|
||||
@ -341,16 +339,6 @@ def job_image_upload(request, 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:
|
||||
@ -964,8 +952,6 @@ def submit_form(request, template_id):
|
||||
resume=resume.get_file if resume.is_file else None,
|
||||
job=submission.template.job,
|
||||
)
|
||||
return redirect('application_success')
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Candidate creation failed,{e}")
|
||||
pass
|
||||
|
||||
@ -92,8 +92,6 @@ class JobCandidatesListView(LoginRequiredMixin, ListView):
|
||||
context_object_name = 'candidates'
|
||||
paginate_by = 10
|
||||
|
||||
|
||||
|
||||
def get_queryset(self):
|
||||
# Get the job by slug
|
||||
self.job = get_object_or_404(models.JobPosting, slug=self.kwargs['slug'])
|
||||
@ -101,11 +99,6 @@ class JobCandidatesListView(LoginRequiredMixin, ListView):
|
||||
# Filter candidates for this specific 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
|
||||
search_query = self.request.GET.get('search', '')
|
||||
if search_query:
|
||||
|
||||
@ -22,15 +22,7 @@
|
||||
--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 {
|
||||
background-color: white;
|
||||
@ -53,7 +45,7 @@
|
||||
padding: 0.25rem 0.5rem;
|
||||
}
|
||||
.top-bar .logo-container img {
|
||||
height: 60px;
|
||||
height: 40px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
@ -76,10 +68,6 @@
|
||||
background-color: var(--kaauh-teal) !important;
|
||||
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 {
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
@ -217,8 +205,7 @@
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
||||
}
|
||||
/* The main content width is already handled by the inline style, but making it explicit here */
|
||||
main.container-fluid {
|
||||
main.container {
|
||||
min-height: calc(100vh - 200px);
|
||||
padding: 1.5rem 0;
|
||||
}
|
||||
@ -248,265 +235,244 @@
|
||||
<body class="d-flex flex-column min-vh-100" hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
|
||||
|
||||
<div class="top-bar d-none d-md-block">
|
||||
{# Changed container to container-fluid and added max-width-1600 to inner div #}
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex justify-content-between align-items-center gap-2 max-width-1600">
|
||||
<div class="d-flex align-items-center gap-3 social-icons">
|
||||
{% comment %} <span class="text-muted">{% trans "Follow Us:" %}</span>
|
||||
<a href="#" aria-label="Facebook"><i class="fab fa-facebook-f"></i></a>
|
||||
<a href="#" aria-label="Twitter"><i class="fab fa-twitter"></i></a>
|
||||
<a href="#" aria-label="Instagram"><i class="fab fa-instagram"></i></a> {% endcomment %}
|
||||
</div>
|
||||
<div class="contact-info d-flex gap-3">
|
||||
{% 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 class="container d-flex justify-content-between align-items-center gap-2">
|
||||
<div class="d-flex align-items-center gap-3 social-icons">
|
||||
{% comment %} <span class="text-muted">{% trans "Follow Us:" %}</span>
|
||||
<a href="#" aria-label="Facebook"><i class="fab fa-facebook-f"></i></a>
|
||||
<a href="#" aria-label="Twitter"><i class="fab fa-twitter"></i></a>
|
||||
<a href="#" aria-label="Instagram"><i class="fab fa-instagram"></i></a> {% endcomment %}
|
||||
</div>
|
||||
<div class="contact-info d-flex gap-3">
|
||||
{% 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">
|
||||
<img src="{% static 'image/hospital_logo_3.png' %}" alt="{% trans 'King Abdullah Academic University Hospital' %}" loading="lazy">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark sticky-top">
|
||||
{# Changed container to container-fluid and added max-width-1600 to inner div #}
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-content-wrapper max-width-1600 d-flex justify-content-between align-items-center" style="width: 100%;">
|
||||
<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>
|
||||
<div class="container">
|
||||
<a class="navbar-brand text-white" href="{% url 'dashboard' %}">
|
||||
<img src="{% static 'image/kaauh.jpeg' %}" alt="{% trans 'Saudi Vision 2030' %}" style="width: 60px; height: 60px;">
|
||||
</a>
|
||||
|
||||
<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' %}">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<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' %}">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
{% comment %} <li class="nav-item">
|
||||
<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">
|
||||
{% include "icons/dashboard.html" %}
|
||||
{% trans "Dashboard" %}
|
||||
</span>
|
||||
</a>
|
||||
</li> {% endcomment %}
|
||||
<li class="nav-item me-2">
|
||||
<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">
|
||||
{% include "icons/jobs.html" %}
|
||||
{% trans "Jobs" %}
|
||||
</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>
|
||||
|
||||
{% trans "Form Templates" %}
|
||||
</span>
|
||||
|
||||
</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">
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
{% comment %} <li class="nav-item">
|
||||
<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">
|
||||
{% include "icons/dashboard.html" %}
|
||||
{% trans "Dashboard" %}
|
||||
</span>
|
||||
</a>
|
||||
</li> {% endcomment %}
|
||||
<li class="nav-item me-2">
|
||||
<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">
|
||||
{% include "icons/jobs.html" %}
|
||||
{% trans "Jobs" %}
|
||||
</span>
|
||||
</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 == '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="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" />
|
||||
<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>
|
||||
|
||||
{% 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>
|
||||
|
||||
{% trans "Meetings" %}
|
||||
</span>
|
||||
</a>
|
||||
</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>
|
||||
{% trans "Form Templates" %}
|
||||
</span>
|
||||
|
||||
{% trans "Training" %}
|
||||
</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>
|
||||
</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 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 }}
|
||||
|
||||
<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>
|
||||
{% 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>
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
</nav>
|
||||
|
||||
|
||||
<main class="container-fluid flex-grow-1" style="max-width: 1600px; margin: 0 auto;">
|
||||
<main class="container flex-grow-1">
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
||||
@ -518,24 +484,14 @@
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer class="mt-auto">
|
||||
<div class="footer-bottom py-3 small text-muted" style="background-color: #00363a;">
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex justify-content-between align-items-center flex-wrap max-width-1600">
|
||||
<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>
|
||||
<footer class="footer mt-auto">
|
||||
<div class="container text-center">
|
||||
<p class="mb-0">
|
||||
© {% now "Y" %} {% trans "King Abdullah Academic University Hospital (KAAUH)." %}<br>
|
||||
<small>{% trans "All rights reserved." %}</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</footer>
|
||||
|
||||
{% include 'includes/delete_modal.html' %}
|
||||
|
||||
|
||||
@ -5,9 +5,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<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">
|
||||
|
||||
<style>
|
||||
/* Updated CSS styles with a new Teal/Aqua theme */
|
||||
:root {
|
||||
@ -773,22 +771,8 @@
|
||||
</div>
|
||||
<!-- Main Content Area -->
|
||||
<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">
|
||||
<h1 id="formTitle">Resume Application Form</h1>
|
||||
|
||||
<div>
|
||||
<button class="btn btn-outline" id="formSettingsBtn">
|
||||
<i class="fas fa-cog"></i> Settings
|
||||
@ -977,9 +961,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
// Application State
|
||||
const state = {
|
||||
draggedStageIndex: null,
|
||||
|
||||
@ -1,198 +1,45 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% load form_filters %}
|
||||
|
||||
{% 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 %}
|
||||
|
||||
<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="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2 class="text-primary fw-bold">{% trans "Submission Details" %}</h2>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h2>Submission Details</h2>
|
||||
<a href="{% url 'form_template_submissions_list' template.slug %}" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Submissions" %}
|
||||
<i class="fas fa-arrow-left"></i> Back to Submissions
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">{% trans "Submission Metadata" %}</h5>
|
||||
</div>
|
||||
<div class="card-body small">
|
||||
<div class="row g-3">
|
||||
<!-- Basic Information -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<i class="fas fa-fingerprint me-2 text-primary"></i>
|
||||
<strong>{% trans "Submission ID:" %}</strong> <span class="text-secondary">{{ submission.id }}</span>
|
||||
<strong>Submission ID:</strong> {{ submission.id }}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<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>
|
||||
<strong>Submitted:</strong> {{ submission.submitted_at|date:"M d, Y H:i" }}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<i class="fas fa-file-alt me-2 text-primary"></i>
|
||||
<strong>{% trans "Form:" %}</strong> <span class="text-secondary">{{ submission.template.name }}</span>
|
||||
<strong>Form:</strong> {{ form.name }}
|
||||
</div>
|
||||
</div>
|
||||
{% if submission.applicant_name or submission.applicant_email %}
|
||||
<div class="row g-3 mt-1">
|
||||
<div class="row mt-2">
|
||||
{% if submission.applicant_name %}
|
||||
<div class="col-md-4">
|
||||
<i class="fas fa-user me-2 text-primary"></i>
|
||||
<strong>{% trans "Applicant Name:" %}</strong> <span class="text-secondary">{{ submission.applicant_name }}</span>
|
||||
<div class="col-md-6">
|
||||
<strong>Applicant Name:</strong> {{ submission.applicant_name }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if submission.applicant_email %}
|
||||
<div class="col-md-4">
|
||||
<i class="fas fa-envelope me-2 text-primary"></i>
|
||||
<strong>{% trans "Email:" %}</strong> <span class="text-secondary">{{ submission.applicant_email }}</span>
|
||||
<div class="col-md-6">
|
||||
<strong>Email:</strong> {{ submission.applicant_email }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@ -200,20 +47,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">{% trans "Form Responses" %}</h5>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<!-- Responses Table -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3">Responses</h5>
|
||||
{% with submission=submission %}
|
||||
{% get_all_responses_flat submission as flat_responses %}
|
||||
|
||||
{% if flat_responses %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-submission table-hover">
|
||||
<thead>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th scope="col">{% trans "Field Property" %}</th>
|
||||
<th scope="col" style="width: 150px;">Field Label</th>
|
||||
{% for response in flat_responses %}
|
||||
<th scope="col">{{ response.field_label }}</th>
|
||||
{% endfor %}
|
||||
@ -221,50 +67,50 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>{% trans "Response Value" %}</strong></td>
|
||||
<td><strong>Response Value</strong></td>
|
||||
{% for response in flat_responses %}
|
||||
<td>
|
||||
{% if response.uploaded_file %}
|
||||
<div>
|
||||
<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-secondary mt-1" target="_blank" title="{% trans 'Download File' %}">
|
||||
<i class="fas fa-download"></i> {% trans "Download" %}
|
||||
<span class="text-primary"><i class="fas fa-file"></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">
|
||||
<i class="fas fa-download"></i>
|
||||
</a>
|
||||
</div>
|
||||
{% elif response.value %}
|
||||
{% if response.field_type == 'checkbox' and response.value|length > 0 %}
|
||||
<div class="d-flex flex-wrap gap-1">
|
||||
<div>
|
||||
{% for val in response.value %}
|
||||
<span class="badge bg-secondary">{{ val }}</span>
|
||||
<span class="badge bg-secondary me-1">{{ val }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% elif response.field_type == 'radio' or response.field_type == 'select' %}
|
||||
<span class="badge bg-info">{{ response.value }}</span>
|
||||
{% else %}
|
||||
<p class="mb-0 small text-wrap">{{ response.value|linebreaksbr }}</p>
|
||||
<p class="mb-0">{{ response.value|linebreaksbr }}</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted small">{% trans "Not provided" %}</span>
|
||||
<span class="text-muted">Not provided</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>{% trans "Associated Stage" %}</strong></td>
|
||||
<td><strong>Stage</strong></td>
|
||||
{% for response in flat_responses %}
|
||||
<td>
|
||||
<span class="small text-secondary">{{ response.stage_name|default:"N/A" }}</span>
|
||||
{{ response.stage_name|default:"N/A" }}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>{% trans "Field Required" %}</strong></td>
|
||||
<td><strong>Required</strong></td>
|
||||
{% for response in flat_responses %}
|
||||
<td>
|
||||
{% if response.required %}
|
||||
<span class="text-danger small"><i class="fas fa-asterisk"></i> {% trans "Yes" %}</span>
|
||||
<span class="text-danger"><i class="fas fa-asterisk"></i> Yes</span>
|
||||
{% else %}
|
||||
<span class="small text-success">{% trans "No" %}</span>
|
||||
<span>No</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
@ -273,14 +119,43 @@
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center text-muted py-5 px-3">
|
||||
<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 class="text-center text-muted py-4">
|
||||
<p>No responses found for this submission.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</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);
|
||||
border-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
font-weight: 900 ;
|
||||
font-weight: 600;
|
||||
padding: 0.375rem 0.75rem;
|
||||
border-radius: 0.5rem;
|
||||
transition: all 0.2s ease;
|
||||
@ -251,7 +251,7 @@
|
||||
<div class="card-view">
|
||||
<div class="row g-4">
|
||||
{% for submission in page_obj %}
|
||||
<div class="col-12">
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h3 class="h5 mb-2">{% trans "Submission" %} #{{ submission.id }}</h3>
|
||||
@ -328,7 +328,7 @@
|
||||
<p class="text-muted mb-4">
|
||||
{% trans "There are no submissions for this form template yet." %}
|
||||
</p>
|
||||
<a href="{% url 'form_templates_list' %}" class="btn btn-main-action btn-sm">
|
||||
<a href="{% url 'form_templates_list' %}" class="btn btn-main-action">
|
||||
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Templates" %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -148,7 +148,7 @@
|
||||
{% block content %}
|
||||
<div class="container-fluid py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||
<h1 class="h3 mb-0" style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||
<i class="fas fa-file-alt me-2"></i>{% trans "Form Templates" %}
|
||||
</h1>
|
||||
<button type="button" class="btn btn-main-action" data-bs-toggle="modal" data-bs-target="#createTemplateModal">
|
||||
|
||||
@ -591,7 +591,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wizard-footer mt-2">
|
||||
<div class="wizard-footer">
|
||||
<button
|
||||
id="backBtn"
|
||||
class="nav-btn btn-back"
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
{{stage}}
|
||||
{% for applicant in applicants_of_stage %}
|
||||
|
||||
|
||||
{{applicant}}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
@ -1,628 +0,0 @@
|
||||
{% 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>
|
||||
@ -1,154 +0,0 @@
|
||||
{% 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,387 +3,286 @@
|
||||
|
||||
{% block title %}{{ job.title }} - Applicants{% 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-primary { background-color: var(--kaauh-teal) !important; }
|
||||
.bg-info { background-color: #17a2b8 !important; }
|
||||
.bg-success { background-color: #28a745 !important; }
|
||||
.bg-secondary { background-color: #6c757d !important; }
|
||||
.bg-warning { background-color: #ffc107 !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.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" %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-1">
|
||||
<a href="{% url 'job_detail' job.slug %}" class="text-decoration-none">
|
||||
<i class="fas fa-arrow-left me-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
Applicants for "{{ job.title }}"
|
||||
</h1>
|
||||
<nav aria-label="breadcrumb">
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<!-- Job Summary Card -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h5 class="card-title mb-3">{{ job.title }}</h5>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<small class="text-muted">Department:</small>
|
||||
<div>{{ job.department|default:"Not specified" }}</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<small class="text-muted">Location:</small>
|
||||
<div>{{ job.get_location_display }}</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<small class="text-muted">Job Type:</small>
|
||||
<div>{{ job.get_job_type_display }}</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<small class="text-muted">Workplace:</small>
|
||||
<div>{{ job.get_workplace_type_display }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 text-end border-start ps-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>
|
||||
<div class="col-md-4">
|
||||
<div class="text-end">
|
||||
<span class="badge bg-{{ job.status|lower }} status-badge">
|
||||
{{ job.get_status_display }}
|
||||
</span>
|
||||
{% if candidates %}
|
||||
<div class="mt-2">
|
||||
<small class="text-muted d-block">{% trans "Total Applicants" %}:</small>
|
||||
<h3 class="text-primary fw-bold mb-0">{{ candidates.count }}</h3>
|
||||
<small class="text-muted">Total Applicants:</small>
|
||||
<h4 class="text-primary mb-0">{{ candidates.count }}</h4>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<form method="get" class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="search" class="form-label small text-muted">{% trans "Search Applicants" %}</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fas fa-search text-primary"></i></span>
|
||||
<input type="text" class="form-control" id="search" name="search"
|
||||
placeholder="{% trans 'Search by name, email, phone, or stage...' %}"
|
||||
value="{{ search_query }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 d-flex align-items-end">
|
||||
<button type="submit" class="btn btn-main-action w-100">
|
||||
<i class="fas fa-filter"></i> {% trans "Filter Results" %}
|
||||
</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> {% trans "Clear Filters" %}
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if candidates %}
|
||||
<div id="job-candidates-list">
|
||||
{# 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>
|
||||
<th scope="col" class="ps-3">
|
||||
<input type="checkbox" class="form-check-input" id="selectAll">
|
||||
</th>
|
||||
<th scope="col">{% trans "Name" %}</th>
|
||||
<th scope="col">{% trans "Email" %}</th>
|
||||
<th scope="col">{% trans "Phone" %}</th>
|
||||
<th scope="col">{% trans "Stage" %}</th>
|
||||
<th scope="col">{% trans "Applied Date" %}</th>
|
||||
<th scope="col" class="text-center pe-3">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for candidate in candidates %}
|
||||
<tr>
|
||||
<td class="ps-3">
|
||||
<input type="checkbox" class="form-check-input candidate-checkbox" value="{{ candidate.slug }}">
|
||||
</td>
|
||||
<td>
|
||||
<strong class="text-primary">{{ candidate.first_name }} {{ candidate.last_name }}</strong>
|
||||
</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>
|
||||
</li>
|
||||
{% 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>
|
||||
<!-- Search and Filters -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<form method="get" class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="search" class="form-label">Search Applicants</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||
<input type="text" class="form-control" id="search" name="search"
|
||||
placeholder="Search by name, email, phone, or stage..."
|
||||
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>
|
||||
|
||||
{# 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' %}">
|
||||
<!-- 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 class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">
|
||||
<input type="checkbox" class="form-check-input" id="selectAll">
|
||||
</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Email</th>
|
||||
<th scope="col">Phone</th>
|
||||
<th scope="col">Stage</th>
|
||||
<th scope="col">Applied Date</th>
|
||||
<th scope="col" class="text-center">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for candidate in candidates %}
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" class="form-check-input candidate-checkbox" value="{{ candidate.slug }}">
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<strong>{{ candidate.first_name }} {{ candidate.last_name }}</strong>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ candidate.email }}</td>
|
||||
<td>{{ candidate.phone|default:"-" }}</td>
|
||||
<td>
|
||||
<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>
|
||||
</td>
|
||||
<td>{{ candidate.created_at|date:"M d, Y" }}</td>
|
||||
<td class="text-center">
|
||||
<div class="btn-group" role="group">
|
||||
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-primary btn-sm" title="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="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"
|
||||
<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>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</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>
|
||||
{% else %}
|
||||
<div class="card shadow-sm">
|
||||
<div class="text-center py-5">
|
||||
<i class="fas fa-user-slash fa-3x text-muted mb-3"></i>
|
||||
<h4 class="text-muted">{% trans "No applicants found" %}</h4>
|
||||
<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-main-action mt-3">
|
||||
<i class="fas fa-user-plus"></i> {% trans "Add First Applicant" %}
|
||||
</a>
|
||||
|
||||
{# 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>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="fas fa-user-slash fa-3x text-muted mb-3"></i>
|
||||
<h4 class="text-muted">No applicants found</h4>
|
||||
<p class="text-muted">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">
|
||||
<i class="fas fa-user-plus"></i> Add First Applicant
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% include "includes/delete_modal.html" %}
|
||||
</div>
|
||||
<!-- Delete Modal -->
|
||||
{% include "includes/delete_modal.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
@ -421,28 +320,7 @@ function bulkAction(stage) {
|
||||
console.log('Updating candidates:', selectedCandidates, 'to stage:', stage);
|
||||
// For now, just show a message
|
||||
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>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@ -1,39 +1,18 @@
|
||||
|
||||
{% extends "base.html" %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% block title %}{{ job.title }} - University ATS{% endblock %}
|
||||
|
||||
{% block customCSS %}
|
||||
|
||||
<style>
|
||||
/* ================================================= */
|
||||
/* THEME VARIABLES AND GLOBAL STYLES */
|
||||
/* ================================================= */
|
||||
/* Custom styles for the Job Detail Page (using variables from base.html) */
|
||||
:root {
|
||||
--kaauh-teal: #00636e; /* Primary */
|
||||
--kaauh-teal: #00636e;
|
||||
--kaauh-teal-dark: #004a53;
|
||||
--kaauh-border: #eaeff3;
|
||||
--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 */
|
||||
.job-header-card {
|
||||
background: linear-gradient(135deg, var(--kaauh-teal), #004d57);
|
||||
@ -42,11 +21,13 @@
|
||||
padding: 1.5rem;
|
||||
box-shadow: 0 4px 10px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.job-header-card h2 {
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
/* Status badge */
|
||||
.status-badge {
|
||||
font-size: 0.9rem;
|
||||
@ -59,6 +40,21 @@
|
||||
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 {
|
||||
border: 1px solid var(--kaauh-border);
|
||||
@ -73,15 +69,25 @@
|
||||
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
/* Standard Card Header */
|
||||
/* Standard Card Header (used for single cards or fallback) */
|
||||
.card-header {
|
||||
font-weight: 600;
|
||||
padding: 1rem 1.25rem;
|
||||
background-color: #f8f9fa;
|
||||
background-color: #f8f9fa; /* Light background */
|
||||
border-bottom: 1px solid var(--kaauh-border);
|
||||
}
|
||||
.card-header h5 {
|
||||
font-weight: 600;
|
||||
color: var(--kaauh-primary-text);
|
||||
}
|
||||
|
||||
/* Left Column Tabs Theming */
|
||||
.card-footer {
|
||||
padding: 1rem 1.25rem;
|
||||
background-color: #f8f9fa;
|
||||
border-top: 1px solid var(--kaauh-border);
|
||||
}
|
||||
|
||||
/* Left Column Tabs Theming (main details) */
|
||||
.nav-tabs {
|
||||
border-bottom: 1px solid var(--kaauh-border);
|
||||
background-color: #f8f9fa;
|
||||
@ -96,20 +102,51 @@
|
||||
margin-right: 0.5rem;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.nav-tabs .nav-link:hover {
|
||||
color: var(--kaauh-teal);
|
||||
border-color: #e9ecef;
|
||||
background-color: #fff;
|
||||
}
|
||||
.nav-tabs .nav-link.active {
|
||||
color: var(--kaauh-teal-dark) !important;
|
||||
background-color: white !important;
|
||||
border-bottom: 3px solid var(--kaauh-teal) !important;
|
||||
color: var(--kaauh-teal-dark);
|
||||
background-color: white;
|
||||
border-bottom: 3px solid var(--kaauh-teal);
|
||||
font-weight: 600;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Right Column Tabs */
|
||||
/* ==================================== */
|
||||
/* RIGHT COLUMN TABS STYLING (IMPROVED) */
|
||||
/* ==================================== */
|
||||
|
||||
.right-column-tabs {
|
||||
padding: 0;
|
||||
margin-bottom: 0;
|
||||
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 {
|
||||
background-color: white;
|
||||
color: var(--kaauh-teal-dark);
|
||||
@ -117,24 +154,23 @@
|
||||
border-right-color: transparent;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
.right-column-tabs .nav-link:not(.active):hover {
|
||||
background-color: #f0f4f7;
|
||||
color: var(--kaauh-teal);
|
||||
}
|
||||
.btn-outline-secondary {
|
||||
color: var(--kaauh-teal-dark);
|
||||
border-color: var(--kaauh-teal);
|
||||
.right-column-tabs .tab-content {
|
||||
padding: 1.5rem 1.25rem;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
@ -153,6 +189,45 @@
|
||||
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 */
|
||||
.deadline-box {
|
||||
padding: 0.75rem;
|
||||
@ -160,143 +235,18 @@
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
/* ==================================== */
|
||||
/* MULTI-COLORED CANDIDATE STAGE TRACKER */
|
||||
/* ==================================== */
|
||||
|
||||
.progress-stages {
|
||||
position: relative;
|
||||
padding: 1.5rem 0;
|
||||
/* Table styling for the Applicant preview */
|
||||
.table-applicants tbody tr:hover {
|
||||
background-color: #f3f9f9;
|
||||
}
|
||||
|
||||
.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;
|
||||
.table-applicants td {
|
||||
border-top: 1px solid var(--kaauh-border);
|
||||
}
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
|
||||
|
||||
<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">
|
||||
|
||||
{# LEFT COLUMN: JOB DETAILS WITH TABS #}
|
||||
@ -385,23 +335,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" }}
|
||||
</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>
|
||||
<h5 class="text-muted mb-3">{% trans "Financial & Timeline" %}</h5>
|
||||
<div class="row g-3">
|
||||
@ -486,70 +419,8 @@
|
||||
</div>
|
||||
|
||||
{# RIGHT COLUMN: TABBED CARDS #}
|
||||
<div class="col-lg-4 ">
|
||||
<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;">
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow-sm no-hover">
|
||||
|
||||
{# RIGHT TABS NAVIGATION #}
|
||||
<ul class="nav nav-tabs right-column-tabs" id="rightJobTabs" role="tablist">
|
||||
@ -560,7 +431,7 @@
|
||||
</li>
|
||||
<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">
|
||||
<i class="fas fa-cogs me-1 text-secondary"></i> {% trans "Form Template" %}
|
||||
<i class="fas fa-cogs me-1 text-secondary"></i> {% trans "Manage" %}
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item flex-fill" role="presentation">
|
||||
@ -574,8 +445,8 @@
|
||||
|
||||
{# TAB 1: APPLICANTS CONTENT #}
|
||||
<div class="tab-pane fade show active" id="applicants-pane" role="tabpanel" aria-labelledby="applicants-tab">
|
||||
<h5 class="mb-3">{% trans "Total Applicants" %} (<span id="total_candidates">{{ total_applicants }}</span>)</h5>
|
||||
{% if total_applicants > 0 %}
|
||||
<h5 class="mb-3">{% trans "Candidates" %} (<span id="total_candidates">{{ total_candidates }}</span>)</h5>
|
||||
{% if total_candidates > 0 %}
|
||||
<div class="row mb-4 applicant-stats">
|
||||
<div class="col-4">
|
||||
<div class="stat-item">
|
||||
@ -598,7 +469,7 @@
|
||||
</div>
|
||||
<div class="col-12 mb-2">
|
||||
<a href="{% url 'job_candidates_list' job.slug %}" class="btn btn-outline-secondary w-100">
|
||||
{% trans "View All Applicants" %} ({{ total_applicants }})
|
||||
{% trans "View All Applicants" %} ({{ total_candidates }})
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -606,10 +477,7 @@
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action">
|
||||
<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" %}
|
||||
<i class="fas fa-user-plus"></i> {% trans "Create Candidate" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -684,25 +552,27 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% 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> {% endcomment %}
|
||||
{% comment %} <div class="d-grid gap-2">
|
||||
{# 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>
|
||||
<div class="d-grid gap-2">
|
||||
<p class="text-muted small mb-3">
|
||||
{% trans "Manage the custom application forms associated with this job posting." %}
|
||||
</p> {% endcomment %}
|
||||
</p>
|
||||
|
||||
{% comment %} <a href="{% url 'create_form_template' %}" class="btn btn-main-action">
|
||||
<a href="{% url 'create_form_template' %}" class="btn btn-main-action">
|
||||
<i class="fas fa-plus-circle me-2"></i> {% trans "Create New Form" %}
|
||||
</a>
|
||||
|
||||
<a href="" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-list-alt me-1"></i> {% trans "View All Existing Forms" %}
|
||||
</a> {% endcomment %}
|
||||
</a>
|
||||
|
||||
{% comment %} <a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action">
|
||||
<i class="fas fa-user-plus"></i> {% trans "Create Applicant" %}
|
||||
</a> {% endcomment %}
|
||||
|
||||
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action">
|
||||
<i class="fas fa-user-plus"></i> {% trans "Create Candidate" %}
|
||||
</a>
|
||||
<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>
|
||||
|
||||
@ -766,33 +636,3 @@
|
||||
</div>
|
||||
|
||||
{% 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,10 +13,6 @@
|
||||
--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 */
|
||||
.card {
|
||||
border: 1px solid var(--kaauh-border);
|
||||
@ -24,7 +20,7 @@
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
.card:not(.no-hover):hover {
|
||||
.card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
|
||||
}
|
||||
@ -36,9 +32,6 @@
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.btn-main-action:hover {
|
||||
@ -58,6 +51,17 @@
|
||||
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-badge {
|
||||
font-size: 0.8rem;
|
||||
@ -67,100 +71,41 @@
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.7px;
|
||||
}
|
||||
.bg-DRAFT { background-color: #6c757d !important; }
|
||||
.bg-ACTIVE { background-color: var(--kaauh-teal) !important; }
|
||||
.bg-CLOSED { background-color: #dc3545 !important; }
|
||||
.bg-ARCHIVED { background-color: #343a40 !important; }
|
||||
.bg-info { background-color: #17a2b8 !important; }
|
||||
/* Mapped color classes to theme */
|
||||
.bg-draft { background-color: #6c757d !important; } /* secondary */
|
||||
.bg-active { background-color: var(--kaauh-teal) !important; } /* primary teal */
|
||||
.bg-closed { background-color: #dc3545 !important; } /* danger */
|
||||
.bg-archived { background-color: #343a40 !important; } /* dark */
|
||||
|
||||
/* --- 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) */
|
||||
.bg-info { background-color: #17a2b8 !important; } /* LinkedIn badge */
|
||||
|
||||
/* NESTED TABLE STYLING FOR CANDIDATE MANAGEMENT HEADER */
|
||||
.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;
|
||||
/* Pagination Link Styling */
|
||||
.pagination .page-item .page-link {
|
||||
color: var(--kaauh-teal-dark);
|
||||
font-size: 0.7rem; /* Smallest font size */
|
||||
width: 50%;
|
||||
border-color: var(--kaauh-border);
|
||||
}
|
||||
.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;
|
||||
}
|
||||
|
||||
/* Main TH for Candidate Management Header */
|
||||
.candidate-management-header {
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
border-left: 2px solid var(--kaauh-teal);
|
||||
border-right: 1px solid var(--kaauh-border) !important;
|
||||
/* Filter & Search Layout Adjustments */
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
gap: 0.5rem; /* Space between filter and clear buttons */
|
||||
}
|
||||
|
||||
/* Candidate Management Data Cells (7 columns total now) */
|
||||
.candidate-data-cell {
|
||||
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 {
|
||||
/* Optional: Add slight shadow/focus effect to search bar */
|
||||
box-shadow: none;
|
||||
border-color: var(--kaauh-border);
|
||||
}
|
||||
.candidate-data-cell a {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
padding: 0.4rem 0; /* Minimized vertical padding */
|
||||
.form-control-search:focus {
|
||||
border-color: var(--kaauh-teal);
|
||||
box-shadow: 0 0 0 0.1rem rgba(0, 99, 110, 0.25);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
@ -169,10 +114,10 @@
|
||||
<div class="container-fluid py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||
<i class="fas fa-briefcase me-2"></i> {% trans "Job Postings" %}
|
||||
<i class="fas fa-briefcase me-2"></i> Job Postings
|
||||
</h1>
|
||||
<a href="{% url 'job_create' %}" class="btn btn-main-action">
|
||||
<i class="fas fa-plus me-1"></i> {% trans "Create New Job" %}
|
||||
<i class="fas fa-plus me-1"></i> Create New Job
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -180,7 +125,7 @@
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<label for="search" class="form-label small text-muted">{% trans "Search by Title or Department" %}</label>
|
||||
<label for="search" class="form-label small text-muted">Search by Title or Department</label>
|
||||
<div class="input-group input-group-lg mb-3">
|
||||
<form method="get" action="" class="w-100">
|
||||
{% include 'includes/search_form.html' %}
|
||||
@ -188,123 +133,117 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<form method="GET" class="row g-3 align-items-end" >
|
||||
<div class="col-md-3">
|
||||
<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">
|
||||
<option value="">{% trans "All Statuses" %}</option>
|
||||
<option value="DRAFT" {% if status_filter == 'DRAFT' %}selected{% endif %}>{% trans "Draft" %}</option>
|
||||
<option value="ACTIVE" {% if status_filter == 'ACTIVE' %}selected{% endif %}>{% trans "Active" %}</option>
|
||||
<option value="CLOSED" {% if status_filter == 'CLOSED' %}selected{% endif %}>{% trans "Closed" %}</option>
|
||||
<option value="ARCHIVED" {% if status_filter == 'ARCHIVED' %}selected{% endif %}>{% trans "Archived" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="filter-buttons">
|
||||
<button type="submit" class="btn btn-main-action btn-sm">
|
||||
<i class="fas fa-filter me-1"></i> {% trans "Apply Filters" %}
|
||||
</button>
|
||||
<a href="{% url 'job_list' %}" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="fas fa-times me-1"></i> {% trans "Clear" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% url 'job_list' as job_list_url %}
|
||||
|
||||
<form method="GET" class="row g-3 align-items-end" >
|
||||
|
||||
<div class="col-md-3">
|
||||
<label for="status" class="form-label small text-muted">Filter by Status</label>
|
||||
<select name="status" id="status" class="form-select form-select-sm">
|
||||
<option value="">All Statuses</option>
|
||||
<option value="DRAFT" {% if status_filter == 'DRAFT' %}selected{% endif %}>Draft</option>
|
||||
<option value="PUBLISHED" {% if status_filter == 'PUBLISHED' %}selected{% endif %}>Published</option>
|
||||
<option value="CLOSED" {% if status_filter == 'CLOSED' %}selected{% endif %}>Closed</option>
|
||||
<option value="ARCHIVED" {% if status_filter == 'ARCHIVED' %}selected{% endif %}>Archived</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<div class="filter-buttons">
|
||||
<button type="submit" class="btn btn-main-action btn-lg">
|
||||
<i class="fas fa-filter me-1"></i> Apply Filters
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% comment %} --- START OF TABLE VIEW (Data relied upon context variable 'jobs') --- {% endcomment %}
|
||||
<div id="job-list">
|
||||
{% comment %} Placeholder for View Switcher {% endcomment %}
|
||||
{% include "includes/_list_view_switcher.html" with list_id="job-list" %}
|
||||
{% if page_obj %}
|
||||
<div id="job-list">
|
||||
{# View Switcher #}
|
||||
{% include "includes/_list_view_switcher.html" with list_id="job-list" %}
|
||||
|
||||
<div class="table-view active">
|
||||
<div class="card shadow-sm">
|
||||
<div class="table-responsive ">
|
||||
<table class="table table-hover align-middle mb-0 table-sm">
|
||||
{# Card View (Default) #}
|
||||
<div class="card-view active row">
|
||||
{% for job in page_obj %}
|
||||
<div class="col-md-6 col-lg-4 mb-4 ">
|
||||
<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>
|
||||
<tr>
|
||||
<th scope="col">{% trans "Job ID" %}</th>
|
||||
{% comment %} <th scope="col">{% trans "Job Title" %}</th>
|
||||
<th scope="col">{% trans "Status" %}</th> {% endcomment %}
|
||||
<th scope="col">{% trans "Job Title" %}</th>
|
||||
<th scope="col">{% trans "Department" %}</th>
|
||||
<th scope="col">{% trans "Location" %}</th>
|
||||
<th scope="col">{% trans "Job Type" %}</th>
|
||||
<th scope="col">{% trans "Status" %}</th>
|
||||
<th scope="col">{% trans "Source" %}</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>
|
||||
<th scope="col" class="text-end">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% comment %} This loop relies on the 'jobs' variable passed from the Django view {% endcomment %}
|
||||
{% for job in jobs %}
|
||||
{% for job in page_obj %}
|
||||
<tr>
|
||||
<td class="fw-medium text-primary-theme">{{ job }}</td>
|
||||
{% comment %} <td class="fw-medium text-primary-theme">{{ job.title }}</td>
|
||||
<td><span class="badge bg-{{ job.status }} status-badge">{{ job.status }}</span></td> {% endcomment %}
|
||||
<td class="fw-medium">{{ job.title }}</td>
|
||||
<td>{{ job.department|default:"N/A" }}</td>
|
||||
<td>{{ job.get_location_display }}</td>
|
||||
<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>
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<a href="{% url 'job_detail' job.slug %}" class="btn btn-outline-secondary" title="{% trans 'View' %}">
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
<a href="{% url 'job_update' job.slug %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
</div>
|
||||
</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' %}">
|
||||
<a href="{% url 'job_detail' job.slug %}" class="btn btn-outline-primary" title="View">
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
<a href="{% url 'form_builder' job.form_template.id %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
|
||||
<a href="{% url 'job_update' job.slug %}" class="btn btn-outline-secondary" title="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>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@ -312,20 +251,45 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% comment %} Fallback/Empty State {% endcomment %}
|
||||
{% if not jobs and not job_list_data and not page_obj %}
|
||||
|
||||
{% if page_obj.has_other_pages %}
|
||||
<nav aria-label="Job pagination" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% 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="card-body">
|
||||
<i class="fas fa-briefcase fa-3x mb-3" style="color: var(--kaauh-teal-dark);"></i>
|
||||
<h3>{% trans "No job postings found" %}</h3>
|
||||
<p class="text-muted">{% trans "Create your first job posting to get started or adjust your filters." %}</p>
|
||||
<h3>No job postings found</h3>
|
||||
<p class="text-muted">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">
|
||||
<i class="fas fa-plus me-1"></i> {% trans "Create Job" %}
|
||||
<i class="fas fa-plus me-1"></i> Create Job
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@ -116,7 +116,7 @@
|
||||
|
||||
/* Primary Action Button (Create/Submit) */
|
||||
.btn-main-action {
|
||||
background-color: var(--kaauh-teal-dark);
|
||||
background-color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
{% block customCSS %}
|
||||
<style>
|
||||
/* ================================================= */
|
||||
/* THEME VARIABLES AND GLOBAL STYLES */
|
||||
/* THEME VARIABLES AND GLOBAL STYLES (FROM JOB DETAIL) */
|
||||
/* ================================================= */
|
||||
:root {
|
||||
--kaauh-teal: #00636e;
|
||||
@ -21,7 +21,7 @@
|
||||
.text-success { color: #28a745 !important; }
|
||||
.text-secondary { color: #6c757d !important; }
|
||||
|
||||
/* Main Action Button Style (Used for Download Resume) */
|
||||
/* Main Action Button Style */
|
||||
.btn-main-action {
|
||||
background-color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
@ -40,7 +40,7 @@
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
/* Outlined Button Styles (Only used variants kept) */
|
||||
/* Outlined Button Styles */
|
||||
.btn-outline-primary {
|
||||
color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
@ -58,6 +58,14 @@
|
||||
color: white;
|
||||
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 {
|
||||
@ -113,93 +121,70 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Right Column Card (General styling) */
|
||||
/* Right Column Tabs (Parsed Data/Activity) */
|
||||
.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 {
|
||||
padding: 1.5rem 1.25rem;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
||||
/* ==================================== */
|
||||
/* NEW: Vertical Timeline Styling */
|
||||
/* NEW: PARSED DATA GRID OPTIMIZATION */
|
||||
/* ==================================== */
|
||||
|
||||
/* Highlight box for the current stage */
|
||||
.current-stage {
|
||||
border: 1px solid var(--kaauh-border);
|
||||
background-color: #f0f8ff; /* Light, subtle blue background */
|
||||
.parsed-data-item {
|
||||
/* Ensure the border/bg container takes full width of the grid column */
|
||||
width: 100%;
|
||||
}
|
||||
.current-stage .text-primary {
|
||||
color: var(--kaauh-teal) !important;
|
||||
.parsed-data-item .data-value {
|
||||
/* Allow data values to wrap without breaking the layout */
|
||||
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>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-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 #}
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow-sm no-hover">
|
||||
|
||||
{# HEADER SECTION #}
|
||||
{# HEADER SECTION (The original Candidate Header Card content, redesigned) #}
|
||||
<div class="candidate-header-card">
|
||||
<div class="d-flex justify-content-between align-items-start flex-wrap">
|
||||
<div>
|
||||
<h1 class="h3 mb-2">{{ candidate.name }}</h1>
|
||||
<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"
|
||||
data-class="{'bg-primary': $stage == 'Applied', 'bg-info': $stage == 'Exam', 'bg-warning': $stage == 'Interview', 'bg-success': $stage == 'Offer'}"
|
||||
data-signals-stage="'{{ candidate.stage }}'">
|
||||
@ -211,7 +196,7 @@
|
||||
{% trans "Applied for:" %} <strong>{{ candidate.job.title }}</strong>
|
||||
</small>
|
||||
</div>
|
||||
{# Change Stage button #}
|
||||
{# Action buttons moved to the right column, keeping only the most visible here for quick access if preferred #}
|
||||
{% if user.is_staff %}
|
||||
<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" %}
|
||||
@ -237,7 +222,7 @@
|
||||
{% if candidate.parsed_summary %}
|
||||
<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">
|
||||
<i class="fas fa-chart-bar me-1"></i> {% trans "Resume Summary" %}
|
||||
<i class="fas fa-chart-bar me-1"></i> {% trans "Summary" %}
|
||||
</button>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -246,7 +231,7 @@
|
||||
<div class="card-body">
|
||||
<div class="tab-content" id="candidateTabsContent">
|
||||
|
||||
{# TAB 1 CONTENT: CONTACT & DATES #}
|
||||
{# TAB 1 CONTENT: CONTACT & DATES (Original Contact Card) #}
|
||||
<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>
|
||||
<div class="row g-4">
|
||||
@ -286,7 +271,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# TAB 2 CONTENT: RESUME #}
|
||||
{# TAB 2 CONTENT: RESUME (Original Resume Card) #}
|
||||
{% if candidate.resume %}
|
||||
<div class="tab-pane fade" id="resume-pane" role="tabpanel" aria-labelledby="resume-tab">
|
||||
<h5 class="text-primary mb-4">{% trans "Resume Document" %}</h5>
|
||||
@ -303,12 +288,12 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# TAB 3 CONTENT: PARSED SUMMARY #}
|
||||
{# TAB 3 CONTENT: PARSED SUMMARY (Original Parsed Summary Card) #}
|
||||
{% if candidate.parsed_summary %}
|
||||
<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>
|
||||
<div class="border-start border-primary ps-3 pt-1 pb-1">
|
||||
{% include 'includes/candidate_modal_body.html' %}
|
||||
<p class="mb-0 text-secondary">{{ candidate.parsed_summary|linebreaks }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -318,14 +303,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# RIGHT COLUMN: ACTIONS AND CANDIDATE TIMELINE #}
|
||||
{# RIGHT COLUMN: ACTIONS AND PARSED DATA TABS #}
|
||||
<div class="col-lg-4">
|
||||
|
||||
{# ACTIONS CARD #}
|
||||
{# ACTIONS CARD (The new consolidated action card) #}
|
||||
{% if user.is_staff %}
|
||||
<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>
|
||||
<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">
|
||||
<i class="fas fa-edit"></i> {% trans "Edit Details" %}
|
||||
</a>
|
||||
@ -339,50 +328,52 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# ENHANCED: CANDIDATE JOURNEY TIMELINE CARD #}
|
||||
<div class="card shadow-sm timeline-card">
|
||||
<div class="card-header bg-white border-bottom py-3">
|
||||
<h5 class="mb-0 text-muted"><i class="fas fa-route me-2"></i>{% trans "Candidate Journey" %}</h5>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
|
||||
<h6 class="text-uppercase text-secondary mb-3">{% trans "Current Stage" %}</h6>
|
||||
<div class="p-3 mb-4 rounded current-stage">
|
||||
<p class="mb-0 fw-bold fs-5 text-primary">{{ candidate.stage }}</p>
|
||||
<small class="text-muted d-block mt-1">
|
||||
{% trans "Latest status update:" %} {{ candidate.updated_at|date:"M d, Y" }}
|
||||
</small>
|
||||
</div>
|
||||
{# PARSED DATA TABS (Original Parsed Data Card, now tabbed) #}
|
||||
{% if parsed %}
|
||||
<div class="card right-column-card shadow-sm">
|
||||
<ul class="nav nav-tabs" id="parsedDataTabs" role="tablist">
|
||||
<li class="nav-item flex-fill" role="presentation">
|
||||
<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">
|
||||
<i class="fas fa-database me-1"></i> {% trans "Parsed Data" %}
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item flex-fill" role="presentation">
|
||||
<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">
|
||||
<i class="fas fa-history me-1"></i> {% trans "Activity" %}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h6 class="text-uppercase text-secondary mb-3 pt-2 border-top">{% trans "Historical Timeline" %}</h6>
|
||||
<div class="timeline">
|
||||
|
||||
|
||||
{# Base Status: Application Submitted (Always required) #}
|
||||
<div class="timeline-item">
|
||||
<div class="timeline-icon timeline-bg-applied"><i class="fas fa-file-signature"></i></div>
|
||||
<div class="timeline-content">
|
||||
<p class="timeline-stage fw-bold mb-0 ms-2">{% trans "Application Submitted" %}</p>
|
||||
<small class="text-muted">
|
||||
<i class="far fa-calendar-alt me-1"></i> {{ candidate.created_at|date:"M d, Y" }}
|
||||
<span class="ms-2">|</span>
|
||||
<i class="far fa-clock ms-2 me-1"></i> {{ candidate.created_at|date:"h:i A" }}
|
||||
</small>
|
||||
</div>
|
||||
<div class="tab-content" id="parsedDataTabsContent">
|
||||
|
||||
{# 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>
|
||||
<div class="row g-3">
|
||||
{% for key, value in parsed.items %}
|
||||
<div class="col-md-6 parsed-data-item">
|
||||
<div class="p-3 border rounded h-100 bg-light">
|
||||
<h6 class="text-muted small text-uppercase mb-1">
|
||||
<i class="fas fa-tag me-1 text-primary"></i> {{ key|title }}
|
||||
</h6>
|
||||
<p class="mb-0 text-dark small data-value">
|
||||
{{ value|default:"N/A"|linebreaksbr }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{# Fallback if no history is explicitly logged #}
|
||||
{% if not candidate_stage_history %}
|
||||
<p class="text-muted mt-3 mb-0 ps-3">
|
||||
{% trans "Detailed stage history logs are currently unavailable." %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{# TAB 2: ACTIVITY (Placeholder) #}
|
||||
<div class="tab-pane fade" id="activity-pane" role="tabpanel" aria-labelledby="activity-tab">
|
||||
<p class="text-muted">
|
||||
{% trans "Activity feed (e.g., stage changes, notes, interview history) will appear here." %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,138 +1,197 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}Candidate Management - {{ job.title }} - University ATS{% endblock %}
|
||||
{% block title %}Candidate Tier Management - {{ job.title }} - ATS{% endblock %}
|
||||
|
||||
{% block customCSS %}
|
||||
<style>
|
||||
/* 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;
|
||||
}
|
||||
/* Minimal Tier Management Styles */
|
||||
.tier-controls {
|
||||
background-color: var(--kaauh-border); /* Light background for control sections */
|
||||
border-radius: 0.5rem;
|
||||
padding: 1.25rem;
|
||||
background-color: #f8f9fa;
|
||||
padding: 1rem;
|
||||
border-radius: 0.375rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
/* 2. Button Styling (from reference) */
|
||||
.btn-main-action {
|
||||
background-color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
.tier-controls .form-row {
|
||||
display: flex;
|
||||
align-items: end;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
.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;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.btn-main-action:hover {
|
||||
background-color: var(--kaauh-teal-dark);
|
||||
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);
|
||||
}
|
||||
|
||||
/* 3. Tab Styles (View Switcher) */
|
||||
.nav-pills .nav-link {
|
||||
color: var(--kaauh-teal-dark);
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-weight: 500;
|
||||
border-radius: 0.5rem;
|
||||
transition: background-color 0.2s;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
.nav-pills .nav-link.active {
|
||||
background-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
.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;
|
||||
color: #0056b3;
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.2rem 0.4rem;
|
||||
}
|
||||
|
||||
/* 4. Candidate Table Styling (Aligned with KAAT-S) */
|
||||
/* Tab Styles for Tiers */
|
||||
.nav-tabs {
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.nav-tabs .nav-link {
|
||||
border: none;
|
||||
color: #495057;
|
||||
font-weight: 500;
|
||||
padding: 0.5rem 1rem;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.nav-tabs .nav-link:hover {
|
||||
border: none;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.nav-tabs .nav-link.active {
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
border: none;
|
||||
border-bottom: 2px solid #007bff;
|
||||
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 */
|
||||
.candidate-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
background-color: white;
|
||||
border-radius: 0.5rem;
|
||||
border-radius: 0.375rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
.candidate-table thead {
|
||||
background-color: var(--kaauh-border);
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.candidate-table th {
|
||||
padding: 0.75rem;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
color: var(--kaauh-teal-dark);
|
||||
border-bottom: 2px solid var(--kaauh-teal);
|
||||
font-size: 0.875rem;
|
||||
color: #495057;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
.candidate-table td {
|
||||
padding: 0.75rem;
|
||||
border-bottom: 1px solid var(--kaauh-border);
|
||||
border-bottom: 1px solid #f1f3f4;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.candidate-table tbody tr:hover {
|
||||
background-color: #f1f3f4;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.candidate-table tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
.candidate-name {
|
||||
font-weight: 600;
|
||||
color: var(--kaauh-primary-text);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
.candidate-details {
|
||||
font-size: 0.8rem;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
/* 5. Badges (Status/Score) */
|
||||
.status-badge {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.3em 0.7em;
|
||||
border-radius: 0.35rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
.candidate-table-responsive {
|
||||
overflow-x: auto;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.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 {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 0.6rem;
|
||||
border-radius: 0.3rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.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 {
|
||||
padding: 0.125rem 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.7rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
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;
|
||||
padding: 0.125rem 0.25rem;
|
||||
}
|
||||
.tier-badge {
|
||||
font-size: 0.7rem;
|
||||
padding: 0.125rem 0.375rem;
|
||||
border-radius: 0.25rem;
|
||||
font-weight: 700;
|
||||
margin-left: 0.5rem;
|
||||
background-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
color: #495057;
|
||||
margin-left: 0.375rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
@ -141,12 +200,12 @@
|
||||
<div class="container py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-1" style="color: var(--kaauh-teal-dark); font-weight: 700;">
|
||||
<h1 class="h3 mb-1">
|
||||
<i class="fas fa-layer-group me-2"></i>
|
||||
{% trans "Applicant Screening for Job:" %} - {{ job.title }} <small class="text-muted fs-6">{{job.internal_job_id}}<small>
|
||||
{% trans "Candidate Tier Management" %} - {{ job.title }}
|
||||
</h1>
|
||||
<p class="text-muted mb-0">
|
||||
Total Applicants: <span class="fw-bold">{{ total_candidates }}</span>
|
||||
Total Candidates: {{ total_candidates }}
|
||||
</p>
|
||||
</div>
|
||||
<a href="{% url 'job_detail' job.slug %}" class="btn btn-outline-secondary">
|
||||
@ -154,25 +213,13 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="tier-controls kaauh-card shadow-sm">
|
||||
<h4 class="h5 mb-3" style="color: var(--kaauh-teal-dark);">{% trans "Filter Potential Candidates" %}</h4>
|
||||
<!-- Tier Controls -->
|
||||
<div class="tier-controls">
|
||||
<form method="post" class="mb-0">
|
||||
{% csrf_token %}
|
||||
<div class="row g-3 align-items-end">
|
||||
|
||||
<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>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="tier1_count">{% trans "Number of candidates in Tier 1 (Top N)" %}</label>
|
||||
<input type="number" name="tier1_count" id="tier1_count" class="form-control"
|
||||
value="{{ tier1_count }}" min="1" max="{{ total_candidates }}">
|
||||
</div>
|
||||
|
||||
@ -1,125 +0,0 @@
|
||||
{% 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,7 +4,8 @@
|
||||
{% block title %}Create Training Material - {{ block.super }}{% endblock %}
|
||||
|
||||
{% block customCSS %}
|
||||
|
||||
{# 💡 Required for Summernote if you added it, otherwise remove this line #}
|
||||
{{ form.media.css }}
|
||||
<style>
|
||||
/* ================================================= */
|
||||
/* THEME VARIABLES AND GLOBAL STYLES */
|
||||
@ -20,11 +21,9 @@
|
||||
/* Primary Color Overrides */
|
||||
.text-primary { color: var(--kaauh-teal) !important; }
|
||||
|
||||
|
||||
|
||||
/* Main Action Button Style */
|
||||
.btn-main-action{
|
||||
background-color: var(--kaauh-teal-dark); /* Changed to primary teal for main actions */
|
||||
.btn-main-action, .btn-primary {
|
||||
background-color: var(--kaauh-teal);
|
||||
border-color: var(--kaauh-teal);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
@ -35,7 +34,7 @@
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.btn-main-action:hover, .btn-primary:hover {
|
||||
background-color: var(--kaauh-teal-dark); /* Darker on 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);
|
||||
@ -130,14 +129,15 @@
|
||||
<form method="post" enctype="multipart/form-data" class="row">
|
||||
{% csrf_token %}
|
||||
|
||||
|
||||
{% crispy form %}
|
||||
|
||||
{# Add the main action button here for consistency #}
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{# 💡 Required for Summernote if you added it, otherwise remove this line #}
|
||||
{{ form.media.js }}
|
||||
{% endblock %}
|
||||
Loading…
x
Reference in New Issue
Block a user