Compare commits

..

No commits in common. "cb963d454f39a3732b54e7b1af62627c85e1c0a9" and "47807ace90d52a389399f9c926da61c49505615d" have entirely different histories.

14 changed files with 1515 additions and 1453 deletions

View File

@ -1634,7 +1634,7 @@ class CandidateEmailForm(forms.Form):
message_parts = [ message_parts = [
f"Than you, for your interest in the {self.job.title} role.", f"Than you, for your interest in the {self.job.title} role.",
f"We're pleased to inform you that you have cleared your exam!", f"We're pleased to inform you that you have cleared your exam!",
f"The next step is the mandatory interview.", f"The next step is the mandatory online assessment exam.",
f"Please complete the assessment by using the following link:", f"Please complete the assessment by using the following link:",
f"https://kaauh/hire/exam", f"https://kaauh/hire/exam",
f"We look forward to reviewing your results.", f"We look forward to reviewing your results.",
@ -1659,8 +1659,6 @@ class CandidateEmailForm(forms.Form):
f"If you have any questions before your start date, please contact [Onboarding Contact].", f"If you have any questions before your start date, please contact [Onboarding Contact].",
f"Best regards, The KAAUH Hiring team" f"Best regards, The KAAUH Hiring team"
] ]
elif candidate:
message_parts=""

View File

@ -1,19 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-23 09:22
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0003_jobposting_cv_zip_file_jobposting_zip_created'),
]
operations = [
migrations.AlterField(
model_name='interviewschedule',
name='template_location',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='schedule_templates', to='recruitment.interviewlocation', verbose_name='Location Template (Zoom/Onsite)'),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-23 09:41
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recruitment', '0004_alter_interviewschedule_template_location'),
]
operations = [
migrations.AlterField(
model_name='interviewschedule',
name='template_location',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='schedule_templates', to='recruitment.interviewlocation', verbose_name='Location Template (Zoom/Onsite)'),
),
]

View File

@ -997,18 +997,6 @@ class Application(Base):
else: else:
return False return False
@property
def is_active(self):
deadline=self.job.application_deadline
now=timezone.now().date()
if deadline>now:
return True
else:
return False
class TrainingMaterial(Base): class TrainingMaterial(Base):
@ -1174,9 +1162,6 @@ class OnsiteLocationDetails(InterviewLocation):
verbose_name_plural = _("Onsite Location Details") verbose_name_plural = _("Onsite Location Details")
# --- 2. Scheduling Models --- # --- 2. Scheduling Models ---
class InterviewSchedule(Base): class InterviewSchedule(Base):

View File

@ -761,7 +761,6 @@ from django.utils.html import strip_tags
def _task_send_individual_email(subject, body_message, recipient, attachments,sender,job): def _task_send_individual_email(subject, body_message, recipient, attachments,sender,job):
"""Internal helper to create and send a single email.""" """Internal helper to create and send a single email."""
from_email = getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@kaauh.edu.sa') from_email = getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@kaauh.edu.sa')
is_html = '<' in body_message and '>' in body_message is_html = '<' in body_message and '>' in body_message
@ -781,8 +780,7 @@ def _task_send_individual_email(subject, body_message, recipient, attachments,se
try: try:
result=email_obj.send(fail_silently=False) result=email_obj.send(fail_silently=False)
if result==1 and sender and job: # job is none when email sent after message creation if result==1:
try: try:
user=get_object_or_404(User,email=recipient) user=get_object_or_404(User,email=recipient)
new_message = Message.objects.create( new_message = Message.objects.create(
@ -800,7 +798,7 @@ def _task_send_individual_email(subject, body_message, recipient, attachments,se
else: else:
logger.error("failed to send email") logger.error("fialed to send email")
except Exception as e: except Exception as e:

View File

@ -4674,40 +4674,55 @@ def message_create(request):
message.sender = request.user message.sender = request.user
message.save() message.save()
# Send email if message_type is 'email' and recipient has email # Send email if message_type is 'email' and recipient has email
if message.message_type == 'email' and message.recipient and message.recipient.email:
if message.recipient and message.recipient.email:
try: try:
from .email_service import send_bulk_email
email_result = send_bulk_email(
email_result = async_task('recruitment.tasks._task_send_individual_email',
subject=message.subject, subject=message.subject,
body_message=message.content, message=message.content,
recipient=message.recipient.email, recipient_list=[message.recipient.email],
request=request,
attachments=None, attachments=None,
sender=False, async_task_=True,
job=False from_interview=False
) )
if email_result:
if email_result["success"]:
message.is_email_sent = True
message.email_address = message.recipient.email
message.save(update_fields=['is_email_sent', 'email_address'])
messages.success(request, "Message sent successfully via email!") messages.success(request, "Message sent successfully via email!")
else: else:
messages.warning(request, f"Message saved but email failed: {email_result.get('message', 'Unknown error')}")
messages.warning(request, f"email failed: {email_result.get('message', 'Unknown error')}")
except Exception as e: except Exception as e:
messages.warning(request, f"Message saved but email sending failed: {str(e)}") messages.warning(request, f"Message saved but email sending failed: {str(e)}")
else: else:
messages.success(request, "Message sent successfully!") messages.success(request, "Message sent successfully!")
["recipient", "job", "subject", "content", "message_type"]
recipient_email = form.cleaned_data['recipient'].email # Assuming recipient is a User or Model with an 'email' field
subject = form.cleaned_data['subject']
custom_message = form.cleaned_data['content']
job_id = form.cleaned_data['job'].id if 'job' in form.cleaned_data and form.cleaned_data['job'] else None
sender_user_id = request.user.id
task_id = async_task(
'recruitment.tasks.send_bulk_email_task',
subject,
custom_message, # Pass the custom message
[recipient_email], # Pass the specific recipient as a list of one
sender_user_id=sender_user_id,
job_id=job_id,
hook='recruitment.tasks.email_success_hook')
logger.info(f"{task_id} queued.")
return redirect("message_list") return redirect("message_list")
else: else:
messages.error(request, "Please correct the errors below.") messages.error(request, "Please correct the errors below.")
else: else:
form = MessageForm(request.user) form = MessageForm(request.user)
context = { context = {
@ -4744,21 +4759,27 @@ def message_reply(request, message_id):
message.save() message.save()
# Send email if message_type is 'email' and recipient has email # Send email if message_type is 'email' and recipient has email
if message.recipient and message.recipient.email: if message.message_type == 'email' and message.recipient and message.recipient.email:
try: try:
email_result = async_task('recruitment.tasks._task_send_individual_email', from .email_service import send_bulk_email
subject=message.subject,
body_message=message.content,
recipient=message.recipient.email,
attachments=None,
sender=False,
job=False
)
if email_result:
messages.success(request, "Message sent successfully via email!")
else:
messages.warning(request, f"email failed: {email_result.get('message', 'Unknown error')}") email_result = send_bulk_email(
subject=message.subject,
message=message.content,
recipient_list=[message.recipient.email],
request=request,
attachments=None,
async_task_=True,
from_interview=False
)
if email_result["success"]:
message.is_email_sent = True
message.email_address = message.recipient.email
message.save(update_fields=['is_email_sent', 'email_address'])
messages.success(request, "Reply sent successfully via email!")
else:
messages.warning(request, f"Reply saved but email failed: {email_result.get('message', 'Unknown error')}")
except Exception as e: except Exception as e:
messages.warning(request, f"Reply saved but email sending failed: {str(e)}") messages.warning(request, f"Reply saved but email sending failed: {str(e)}")
@ -5742,15 +5763,15 @@ def send_interview_email(request, slug):
return redirect("meeting_details", slug=meeting.slug) return redirect("meeting_details", slug=meeting.slug)
def schedule_interview_location_form(request,slug): # def schedule_interview_location_form(request,slug):
schedule=get_object_or_404(InterviewSchedule,slug=slug) # schedule=get_object_or_404(InterviewSchedule,slug=slug)
if request.method=='POST': # if request.method=='POST':
form=InterviewScheduleLocationForm(request.POST,instance=schedule) # form=InterviewScheduleLocationForm(request.POST,instance=schedule)
form.save() # form.save()
return redirect('list_meetings') # return redirect('list_meetings')
else: # else:
form=InterviewScheduleLocationForm(instance=schedule) # form=InterviewScheduleLocationForm(instance=schedule)
return render(request,'interviews/schedule_interview_location_form.html',{'form':form,'schedule':schedule}) # return render(request,'interviews/schedule_interview_location_form.html',{'form':form,'schedule':schedule})
class MeetingListView(ListView): class MeetingListView(ListView):
@ -5762,7 +5783,6 @@ class MeetingListView(ListView):
context_object_name = "meetings" context_object_name = "meetings"
paginate_by = 100 paginate_by = 100
def get_queryset(self): def get_queryset(self):
# Start with a base queryset, ensuring an InterviewLocation link exists. # Start with a base queryset, ensuring an InterviewLocation link exists.
queryset = super().get_queryset().filter(interview_location__isnull=False).select_related( queryset = super().get_queryset().filter(interview_location__isnull=False).select_related(
@ -5774,7 +5794,6 @@ class MeetingListView(ListView):
'interview_location__zoommeetingdetails', 'interview_location__zoommeetingdetails',
'interview_location__onsitelocationdetails', 'interview_location__onsitelocationdetails',
) )
# Note: Printing the queryset here can consume memory for large sets. # Note: Printing the queryset here can consume memory for large sets.
# Get filters from GET request # Get filters from GET request
@ -5788,10 +5807,11 @@ class MeetingListView(ListView):
if type_filter: if type_filter:
# Use .title() to handle case variations from URL (e.g., 'remote' -> 'Remote') # Use .title() to handle case variations from URL (e.g., 'remote' -> 'Remote')
normalized_type = type_filter.title() normalized_type = type_filter.title()
print(normalized_type)
# Assuming InterviewLocation.LocationType is accessible/defined # Assuming InterviewLocation.LocationType is accessible/defined
if normalized_type in ['Remote', 'Onsite']: if normalized_type in ['Remote', 'Onsite']:
queryset = queryset.filter(interview_location__location_type=normalized_type) queryset = queryset.filter(interview_location__location_type=normalized_type)
print(queryset)
# 3. Search by Topic (stored on InterviewLocation) # 3. Search by Topic (stored on InterviewLocation)
if search_query: if search_query:
@ -5866,28 +5886,6 @@ class MeetingListView(ListView):
return context return context
# class MeetingListView(ListView):
# """
# A unified view to list both Remote and Onsite Scheduled Interviews.
# """
# model = InterviewLocation
# template_name = "meetings/list_meetings.html"
# context_object_name = "meetings"
# def get_queryset(self):
# # Start with a base queryset, ensuring an InterviewLocation link exists.
# queryset = super().get_queryset().prefetch_related(
# 'zoommeetingdetails',
# 'onsitelocationdetails',
# )
# print(queryset)
# return queryset
def reschedule_onsite_meeting(request, slug, candidate_id, meeting_id): def reschedule_onsite_meeting(request, slug, candidate_id, meeting_id):
"""Handles the rescheduling of an Onsite Interview (updates OnsiteLocationDetails).""" """Handles the rescheduling of an Onsite Interview (updates OnsiteLocationDetails)."""
job = get_object_or_404(JobPosting, slug=slug) job = get_object_or_404(JobPosting, slug=slug)

View File

@ -295,18 +295,6 @@
</span> </span>
</a> </a>
</li> </li>
<li class="nav-item me-lg-4">
<a class="nav-link {% if request.resolver_match.url_name == 'kaauh_career' %}active{% endif %}" href="{% url 'kaauh_career' %}">
<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="M3.75 6A2.25 2.25 0 0 1 6 3.75h2.25A2.25 2.25 0 0 1 10.5 6v2.25a2.25 2.25 0 0 1-2.25 2.25H6a2.25 2.25 0 0 1-2.25-2.25V6ZM3.75 15.75A2.25 2.25 0 0 1 6 13.5h2.25a2.25 2.25 0 0 1 2.25 2.25V18a2.25 2.25 0 0 1-2.25 2.25H6A2.25 2.25 0 0 1 3.75 18v-2.25ZM13.5 6a2.25 2.25 0 0 1 2.25-2.25H18A2.25 2.25 0 0 1 20.25 6v2.25A2.25 2.25 0 0 1 18 10.5h-2.25a2.25 2.25 0 0 1-2.25-2.25V6ZM13.5 15.75a2.25 2.25 0 0 1 2.25-2.25H18a2.25 2.25 0 0 1 2.25 2.25V18A2.25 2.25 0 0 1 18 20.25h-2.25A2.25 2.25 0 0 1 13.5 18v-2.25Z" />
</svg>
{% trans "Career Page" %}
</span>
</a>
</li>
{% comment %} <li class="nav-item dropdown ms-lg-2"> {% comment %} <li class="nav-item dropdown ms-lg-2">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
data-bs-offset="0, 8" data-bs-auto-close="outside"> data-bs-offset="0, 8" data-bs-auto-close="outside">

View File

@ -326,15 +326,15 @@
<a href="{% url 'candidate_screening_view' job.slug %}" class="btn btn-main-action"> <a href="{% url 'candidate_screening_view' job.slug %}" class="btn btn-main-action">
<i class="fas fa-layer-group me-1"></i> {% trans "Manage Applicants" %} <i class="fas fa-layer-group me-1"></i> {% trans "Manage Applicants" %}
</a> </a>
{% if not job.zip_created%}
<a href="{% url 'request_cvs_download' job.slug %}" class="btn btn-main-action"> <a href="{% url 'request_cvs_download' job.slug %}" class="btn btn-main-action">
<i class="fa-solid fa-download me-1"></i> {% trans "Generate All CVs" %} <i class="fa-solid fa-download me-1"></i> {% trans "Download All CVs" %}
</a> </a>
{% else %}
<a href="{% url 'download_ready_cvs' job.slug %}" class="btn btn-outline-primary"> <a href="{% url 'download_ready_cvs' job.slug %}" class="btn btn-main-action">
<i class="fa-solid fa-eye me-1"></i> {% trans "View All CVs" %} <i class="fa-solid fa-eye me-1"></i> {% trans "View All CVs" %}
</a> </a>
{% endif %}
</div> </div>
</div> </div>

View File

@ -9,265 +9,285 @@
:root { :root {
--kaauh-teal: #00636e; --kaauh-teal: #00636e;
--kaauh-teal-dark: #004a53; --kaauh-teal-dark: #004a53;
--kaauh-border: #eaeff3; --kaauh-border: #e9ecef;
--kaauh-primary-text: #343a40; --kaauh-primary-text: #212529;
--kaauh-success: #28a745; --kaauh-success: #198754;
--kaauh-info: #17a2b8; --kaauh-info: #0dcaf0;
--kaauh-danger: #dc3545; --kaauh-danger: #dc3545;
--kaauh-warning: #ffc107; --kaauh-warning: #ffc107;
--kaauh-bg-light: #f8f9fa;
}
.text-primary-teal {
color: var(--kaauh-teal) !important;
} }
.kaauh-card { .kaauh-card {
border: 1px solid var(--kaauh-border); border: none;
border-radius: 0.75rem; border-radius: 0.75rem;
box-shadow: 0 4px 12px rgba(0,0,0,0.06); box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
background-color: white; background-color: white;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.kaauh-card:hover {
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
} }
.btn-main-action { .btn-main-action {
background-color: var(--kaauh-teal); background-color: var(--kaauh-teal);
border-color: var(--kaauh-teal); border-color: var(--kaauh-teal);
color: white; color: white;
font-weight: 600; font-weight: 500;
padding: 0.5rem 1.2rem;
transition: all 0.2s ease; transition: all 0.2s ease;
} }
.btn-main-action:hover { .btn-main-action:hover {
background-color: var(--kaauh-teal-dark); background-color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal-dark); border-color: var(--kaauh-teal-dark);
box-shadow: 0 4px 8px rgba(0,0,0,0.15); color: white;
transform: translateY(-1px);
}
.btn-white {
background-color: white;
border-color: var(--kaauh-border);
color: var(--kaauh-primary-text);
}
.btn-white:hover {
background-color: var(--kaauh-bg-light);
border-color: #dee2e6;
} }
.status-badge { .status-badge {
font-size: 0.75rem; font-size: 0.75rem;
padding: 0.3em 0.7em; font-weight: 600;
border-radius: 0.35rem; letter-spacing: 0.5px;
font-weight: 700; text-transform: uppercase;
}
.status-ACTIVE {
background-color: #d1e7dd;
color: #0f5132;
}
.status-EXPIRED {
background-color: #f8d7da;
color: #842029;
}
.status-COMPLETED {
background-color: #cff4fc;
color: #055160;
}
.status-CANCELLED {
background-color: #fff3cd;
color: #664d03;
}
.bg-soft-primary {
background-color: rgba(13, 110, 253, 0.1);
}
.bg-soft-info {
background-color: rgba(13, 202, 240, 0.1);
}
.bg-soft-success {
background-color: rgba(25, 135, 84, 0.1);
}
.avatar-circle {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
.w-20 {
width: 20px;
text-align: center;
} }
.status-ACTIVE { background-color: var(--kaauh-success); color: white; }
.status-EXPIRED { background-color: var(--kaauh-danger); color: white; }
.status-COMPLETED { background-color: var(--kaauh-info); color: white; }
.status-CANCELLED { background-color: var(--kaauh-warning); color: #856404; }
.progress-ring { .progress-ring {
width: 120px;
height: 120px;
position: relative;
}
.progress-ring-circle {
transition: stroke-dashoffset 0.35s;
transform: rotate(-90deg); transform: rotate(-90deg);
transform-origin: 50% 50%; transform-origin: 50% 50%;
} }
.progress-ring-text { .progress-ring-circle {
position: absolute; transition: stroke-dashoffset 0.5s ease-in-out;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 1.5rem;
font-weight: 700;
color: var(--kaauh-teal-dark);
}
.message-item {
border-left: 4px solid var(--kaauh-teal);
background-color: #f8f9fa;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 0 0.5rem 0.5rem 0;
}
.message-item.unread {
border-left-color: var(--kaauh-info);
background-color: #e7f3ff;
} }
</style> </style>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="container-fluid py-4"> <div class="container-fluid py-5 bg-light">
<!-- Header --> <!-- Header -->
<div class="d-flex justify-content-between align-items-center mb-4"> <div class="row mb-4">
<div class="col-12">
<div class="d-flex justify-content-between align-items-start">
<div> <div>
<h1 class="h3 mb-1" style="color: var(--kaauh-teal-dark); font-weight: 700;"> <nav aria-label="breadcrumb" class="mb-2">
<i class="fas fa-tasks me-2"></i> <ol class="breadcrumb mb-0 small">
{{ assignment.agency.name }} - {{ assignment.job.title }} <li class="breadcrumb-item"><a href="{% url 'agency_assignment_list' %}"
class="text-decoration-none text-muted">{% trans "Assignments" %}</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ assignment.job.title }}</li>
</ol>
</nav>
<h1 class="h2 fw-bold text-dark mb-2">
{{ assignment.job.title }}
</h1> </h1>
<p class="text-muted mb-0"> <div class="d-flex align-items-center text-muted">
{% trans "Assignment Details and Management" %} <span class="me-3"><i class="fas fa-building me-1"></i> {{ assignment.agency.name }}</span>
</p> <span class="badge status-{{ assignment.status }} rounded-pill px-3">{{
assignment.get_status_display }}</span>
</div> </div>
<div> </div>
<a href="{% url 'agency_assignment_list' %}" class="btn btn-outline-secondary me-2"> <div class="d-flex gap-2">
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Assignments" %} <a href="{% url 'agency_assignment_list' %}" class="btn btn-white border shadow-sm">
<i class="fas fa-arrow-left me-1"></i> {% trans "Back" %}
</a> </a>
<a href="{% url 'agency_assignment_update' assignment.slug %}" class="btn btn-main-action"> <a href="{% url 'agency_assignment_update' assignment.slug %}"
<i class="fas fa-edit me-1"></i> {% trans "Edit Assignment" %} class="btn btn-main-action shadow-sm">
<i class="fas fa-edit me-1"></i> {% trans "Edit" %}
</a> </a>
</div> </div>
</div> </div>
</div>
</div>
<div class="row"> <div class="row g-4">
<!-- Assignment Overview --> <!-- Left Column: Details & Candidates -->
<div class="col-lg-8"> <div class="col-lg-8 col-md-12">
<!-- Assignment Details Card --> <!-- Assignment Details Card -->
<div class="kaauh-card p-4 mb-4"> <div class="kaauh-card mb-4">
<h5 class="mb-4" style="color: var(--kaauh-teal-dark);"> <div class="card-header bg-transparent border-bottom py-3 px-4">
<i class="fas fa-info-circle me-2"></i> <h5 class="mb-0 fw-bold text-dark">
<i class="fas fa-info-circle me-2 text-primary-teal"></i>
{% trans "Assignment Details" %} {% trans "Assignment Details" %}
</h5> </h5>
</div>
<div class="row"> <div class="card-body p-4">
<div class="row g-4">
<div class="col-md-6"> <div class="col-md-6">
<div class="mb-3"> <div class="detail-group">
<label class="text-muted small">{% trans "Agency" %}</label> <label class="text-uppercase text-muted small fw-bold mb-1">{% trans "Agency" %}</label>
<div class="fw-bold">{{ assignment.agency.name }}</div> <div class="fs-6 fw-medium text-dark">{{ assignment.agency.name }}</div>
<div class="text-muted small">{{ assignment.agency.contact_person }}</div> <div class="text-muted small">{{ assignment.agency.contact_person }}</div>
</div> </div>
<div class="mb-3"> </div>
<label class="text-muted small">{% trans "Job" %}</label> <div class="col-md-6">
<div class="fw-bold">{{ assignment.job.title }}</div> <div class="detail-group">
<div class="text-muted small">{{ assignment.job.department }}</div> <label class="text-uppercase text-muted small fw-bold mb-1">{% trans "Department"
%}</label>
<div class="fs-6 fw-medium text-dark">{{ assignment.job.department }}</div>
</div> </div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="mb-3"> <div class="detail-group">
<label class="text-muted small">{% trans "Status" %}</label> <label class="text-uppercase text-muted small fw-bold mb-1">{% trans "Deadline"
<div> %}</label>
<span class="status-badge status-{{ assignment.status }}"> <div
{{ assignment.get_status_display }} class="fs-6 fw-medium {% if assignment.is_expired %}text-danger{% else %}text-dark{% endif %}">
</span> {{ assignment.deadline_date|date:"M d, Y - H:i" }}
</div>
</div>
<div class="mb-3">
<label class="text-muted small">{% trans "Deadline" %}</label>
<div class="{% if assignment.is_expired %}text-danger{% else %}text-muted{% endif %}">
<i class="fas fa-calendar-alt me-1"></i>
{{ assignment.deadline_date|date:"Y-m-d H:i" }}
</div> </div>
{% if assignment.is_expired %} {% if assignment.is_expired %}
<small class="text-danger"> <small class="text-danger fw-bold">
<i class="fas fa-exclamation-triangle me-1"></i>{% trans "Expired" %} <i class="fas fa-exclamation-triangle me-1"></i>{% trans "Expired" %}
</small> </small>
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div class="col-md-6">
<div class="detail-group">
<label class="text-uppercase text-muted small fw-bold mb-1">{% trans "Created At"
%}</label>
<div class="fs-6 fw-medium text-dark">{{ assignment.created_at|date:"M d, Y" }}</div>
</div>
</div>
</div> </div>
{% if assignment.admin_notes %} {% if assignment.admin_notes %}
<div class="mt-3 pt-3 border-top"> <div class="mt-4 pt-4 border-top">
<label class="text-muted small">{% trans "Admin Notes" %}</label> <label class="text-uppercase text-muted small fw-bold mb-2">{% trans "Admin Notes" %}</label>
<div class="text-muted">{{ assignment.admin_notes }}</div> <div class="p-3 bg-light rounded border-start border-4 border-info text-muted">
{{ assignment.admin_notes }}
</div>
</div> </div>
{% endif %} {% endif %}
</div>
{% comment %} <div class="kaauh-card shadow-sm mb-4">
<div class="card-body my-2">
<h5 class="card-title mb-3 mx-2">
<i class="fas fa-key me-2 text-warning"></i>
{% trans "Access Credentials" %}
</h5>
<div class="mb-3 mx-2">
<label class="form-label text-muted small">{% trans "Login URL" %}</label>
<div class="input-group">
<input type="text" readonly value="{{ request.scheme }}://{{ request.get_host }}{% url 'agency_portal_login' %}"
class="form-control font-monospace" id="loginUrl">
<button class="btn btn-outline-secondary" type="button" onclick="copyToClipboard('loginUrl')">
<i class="fas fa-copy"></i>
</button>
</div> </div>
</div> </div>
<div class="mb-3 mx-2">
<label class="form-label text-muted small">{% trans "Access Token" %}</label>
<div class="input-group">
<input type="text" readonly value="{{ access_link.unique_token }}"
class="form-control font-monospace" id="accessToken">
<button class="btn btn-outline-secondary" type="button" onclick="copyToClipboard('accessToken')">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="mb-3 mx-2">
<label class="form-label text-muted small">{% trans "Password" %}</label>
<div class="input-group">
<input type="text" readonly value="{{ access_link.access_password }}"
class="form-control font-monospace" id="accessPassword">
<button class="btn btn-outline-secondary" type="button" onclick="copyToClipboard('accessPassword')">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="alert alert-info mx-2">
<i class="fas fa-info-circle me-2"></i>
{% trans "Share these credentials securely with the agency. They can use this information to log in and submit candidates." %}
</div>
{% if access_link %}
<a href="{% url 'agency_access_link_detail' access_link.slug %}"
class="btn btn-outline-info btn-sm mx-2">
<i class="fas fa-eye me-1"></i> {% trans "View Access Links Details" %}
</a>
{% endif %}
</div>
</div> {% endcomment %}
<!-- Candidates Card --> <!-- Candidates Card -->
<div class="kaauh-card p-4"> <div class="kaauh-card">
<div class="d-flex justify-content-between align-items-center mb-4"> <div
<h5 class="mb-0" style="color: var(--kaauh-teal-dark);"> class="card-header bg-transparent border-bottom py-3 px-4 d-flex justify-content-between align-items-center">
<i class="fas fa-users me-2"></i> <h5 class="mb-0 fw-bold text-dark">
{% trans "Submitted Candidates" %} ({{ total_candidates }}) <i class="fas fa-users me-2 text-primary-teal"></i>
{% trans "Submitted Candidates" %}
<span class="badge bg-light text-dark border ms-2">{{ total_candidates }}</span>
</h5> </h5>
{% if access_link %} {% if access_link %}
<a href="{% url 'agency_portal_login' %}" target="_blank" class="btn btn-outline-info btn-sm"> <a href="{% url 'agency_portal_login' %}" target="_blank" class="btn btn-sm btn-outline-info">
<i class="fas fa-external-link-alt me-1"></i> {% trans "Preview Portal" %} <i class="fas fa-external-link-alt me-1"></i> {% trans "Portal Preview" %}
</a> </a>
{% endif %} {% endif %}
</div> </div>
<div class="card-body p-0">
{% if candidates %} {% if candidates %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-hover"> <table class="table table-hover align-middle mb-0">
<thead> <thead class="bg-light">
<tr> <tr>
<th>{% trans "Name" %}</th> <th class="px-4 py-3 text-uppercase small fw-bold text-muted">{% trans "Candidate"
<th>{% trans "Contact" %}</th> %}</th>
<th>{% trans "Stage" %}</th> <th class="px-4 py-3 text-uppercase small fw-bold text-muted">{% trans "Contact" %}
<th>{% trans "Submitted" %}</th> </th>
<th>{% trans "Actions" %}</th> <th class="px-4 py-3 text-uppercase small fw-bold text-muted">{% trans "Stage" %}
</th>
<th class="px-4 py-3 text-uppercase small fw-bold text-muted">{% trans "Submitted"
%}</th>
<th class="px-4 py-3 text-uppercase small fw-bold text-muted text-end">{% trans
"Actions" %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for candidate in candidates %} {% for candidate in candidates %}
<tr> <tr>
<td> <td class="px-4">
<div class="fw-bold">{{ candidate.name }}</div> <div class="d-flex align-items-center">
</td> <div class="avatar-circle me-3 bg-soft-primary text-primary fw-bold">
<td> {{ candidate.name|slice:":2"|upper }}
<div class="small"> </div>
<div><i class="fas fa-envelope me-1"></i> {{ candidate.email }}</div> <div>
<div><i class="fas fa-phone me-1"></i> {{ candidate.phone }}</div> <div class="fw-bold text-dark">{{ candidate.name }}</div>
</div>
</div> </div>
</td> </td>
<td> <td class="px-4">
<span class="badge bg-info">{{ candidate.get_stage_display }}</span>
</td>
<td>
<div class="small text-muted"> <div class="small text-muted">
{{ candidate.created_at|date:"Y-m-d H:i" }} <div class="mb-1"><i class="fas fa-envelope me-2 w-20"></i>{{
candidate.email }}</div>
<div><i class="fas fa-phone me-2 w-20"></i>{{ candidate.phone }}</div>
</div> </div>
</td> </td>
<td> <td class="px-4">
<span class="badge bg-soft-info text-info rounded-pill px-3">{{
candidate.get_stage_display }}</span>
</td>
<td class="px-4">
<span class="small text-muted">{{ candidate.created_at|date:"M d, Y" }}</span>
</td>
<td class="px-4 text-end">
<a href="{% url 'candidate_detail' candidate.slug %}" <a href="{% url 'candidate_detail' candidate.slug %}"
class="btn btn-sm btn-outline-primary" title="{% trans 'View Details' %}"> class="btn btn-sm btn-white border shadow-sm text-primary"
title="{% trans 'View Details' %}">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
</a> </a>
</td> </td>
@ -277,129 +297,102 @@
</table> </table>
</div> </div>
{% else %} {% else %}
<div class="text-center py-4"> <div class="text-center py-5">
<i class="fas fa-users fa-2x text-muted mb-3"></i> <div class="mb-3">
<h6 class="text-muted">{% trans "No candidates submitted yet" %}</h6> <div class="avatar-circle bg-light text-muted mx-auto"
<p class="text-muted small"> style="width: 64px; height: 64px; font-size: 24px;">
{% trans "Candidates will appear here once the agency submits them through their portal." %} <i class="fas fa-user-plus"></i>
</div>
</div>
<h6 class="fw-bold text-dark">{% trans "No candidates yet" %}</h6>
<p class="text-muted small mb-0">
{% trans "Candidates submitted by the agency will appear here." %}
</p> </p>
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div>
<!-- Sidebar --> <!-- Right Column: Sidebar -->
<div class="col-lg-4"> <div class="col-lg-4 col-md-12">
<!-- Progress Card --> <!-- Progress Card -->
<div class="kaauh-card p-4 mb-4"> <div class="kaauh-card mb-4">
<h5 class="mb-4 text-center" style="color: var(--kaauh-teal-dark);"> <div class="card-body p-4 text-center">
{% trans "Submission Progress" %} <h6 class="text-uppercase text-muted small fw-bold mb-4">{% trans "Submission Goal" %}</h6>
</h5>
<div class="text-center mb-3"> <div class="position-relative d-inline-block mb-3">
<div class="progress-ring"> <svg class="progress-ring" width="140" height="140">
<svg width="120" height="120"> <circle class="progress-ring-bg" stroke="#f1f3f5" stroke-width="10" fill="transparent"
<circle class="progress-ring-circle" r="60" cx="70" cy="70" />
stroke="#e9ecef" <circle class="progress-ring-circle" stroke="var(--kaauh-teal)" stroke-width="10"
stroke-width="8" fill="transparent" r="60" cx="70" cy="70"
fill="transparent" style="stroke-dasharray: 376.99; stroke-dashoffset: {{ stroke_dashoffset }};" />
r="52"
cx="60"
cy="60"/>
<circle class="progress-ring-circle"
stroke="var(--kaauh-teal)"
stroke-width="8"
fill="transparent"
r="52"
cx="60"
cy="60"
style="stroke-dasharray: 326.73; stroke-dashoffset: {{ stroke_dashoffset }};"/>
</svg> </svg>
<div class="progress-ring-text"> <div class="position-absolute top-50 start-50 translate-middle text-center">
{% widthratio total_candidates assignment.max_candidates 100 as progress %} <div class="h3 fw-bold mb-0 text-dark">{{ total_candidates }}</div>
{{ progress|floatformat:0 }}% <div class="small text-muted text-uppercase">{% trans "of" %} {{ assignment.max_candidates
</div> }}</div>
</div>
</div>
<div class="text-center">
<div class="h4 mb-1">{{ total_candidates }}</div>
<div class="text-muted">/ {{ assignment.max_candidates }} {% trans "candidates" %}</div>
</div>
<div class="progress mt-3" style="height: 8px;">
{% widthratio total_candidates assignment.max_candidates 100 as progress %}
<div class="progress-bar" style="width: {{ progress }}%"></div>
</div> </div>
</div> </div>
<p class="text-muted small mb-0">
{% trans "Candidates submitted" %}
</p>
</div>
</div>
<!-- Actions Card --> <!-- Actions Card -->
<div class="kaauh-card p-4"> <div class="kaauh-card mb-4">
<h5 class="mb-4" style="color: var(--kaauh-teal-dark);"> <div class="card-header bg-transparent border-bottom py-3 px-4">
<i class="fas fa-cog me-2"></i> <h6 class="mb-0 fw-bold text-dark">{% trans "Quick Actions" %}</h6>
{% trans "Actions" %} </div>
</h5> <div class="card-body p-4">
<div class="d-grid gap-3">
<div class="d-grid gap-2"> <a href="" class="btn btn-outline-primary">
<a href="" <i class="fas fa-envelope me-2"></i> {% trans "Send Message" %}
class="btn btn-outline-primary">
<i class="fas fa-envelope me-1"></i> {% trans "Send Message" %}
</a> </a>
{% if assignment.is_active and not assignment.is_expired %} {% if assignment.is_active and not assignment.is_expired %}
<button type="button" class="btn btn-outline-warning" <button type="button" class="btn btn-outline-warning" data-bs-toggle="modal"
data-bs-toggle="modal" data-bs-target="#extendDeadlineModal"> data-bs-target="#extendDeadlineModal">
<i class="fas fa-clock me-1"></i> {% trans "Extend Deadline" %} <i class="fas fa-clock me-2"></i> {% trans "Extend Deadline" %}
</button> </button>
{% endif %} {% endif %}
<a href="{% url 'agency_assignment_update' assignment.slug %}"
class="btn btn-outline-secondary">
<i class="fas fa-edit me-1"></i> {% trans "Edit Assignment" %}
</a>
</div>
</div> </div>
</div> </div>
</div> </div>
<!-- Messages Section --> <!-- Recent Messages -->
{% if messages_ %} {% if messages_ %}
<div class="kaauh-card p-4 mt-4"> <div class="kaauh-card">
<h5 class="mb-4" style="color: var(--kaauh-teal-dark);"> <div
<i class="fas fa-comments me-2"></i> class="card-header bg-transparent border-bottom py-3 px-4 d-flex justify-content-between align-items-center">
{% trans "Recent Messages" %} <h6 class="mb-0 fw-bold text-dark">{% trans "Recent Messages" %}</h6>
</h5> {% if messages_.count > 3 %}
<a href="#" class="small text-decoration-none">{% trans "View All" %}</a>
<div class="row">
{% for message in messages_|slice:":6" %}
<div class="col-lg-6 mb-3">
<div class="message-item {% if not message.is_read %}unread{% endif %}">
<div class="d-flex justify-content-between align-items-start mb-2">
<div class="fw-bold">{{ message.subject }}</div>
<small class="text-muted">{{ message.created_at|date:"Y-m-d H:i" }}</small>
</div>
<div class="small text-muted mb-2">
{% trans "From" %}: {{ message.sender.get_full_name }}
</div>
<div class="small">{{ message.message|truncatewords:30 }}</div>
{% if not message.is_read %}
<span class="badge bg-info mt-2">{% trans "New" %}</span>
{% endif %} {% endif %}
</div> </div>
<div class="card-body p-0">
<div class="list-group list-group-flush">
{% for message in messages_|slice:":3" %}
<div
class="list-group-item p-3 border-bottom-0 {% if not message.is_read %}bg-soft-info{% endif %}">
<div class="d-flex justify-content-between mb-1">
<span class="fw-bold text-dark small">{{ message.sender.get_full_name }}</span>
<small class="text-muted" style="font-size: 0.7rem;">{{ message.created_at|date:"M d"
}}</small>
</div>
<div class="fw-medium small text-dark mb-1">{{ message.subject }}</div>
<div class="text-muted small text-truncate">{{ message.message }}</div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
</div>
{% if messages_.count > 6 %}
<div class="text-center mt-3">
<a href="#" class="btn btn-outline-primary btn-sm">
{% trans "View All Messages" %}
</a>
</div> </div>
{% endif %} {% endif %}
</div> </div>
{% endif %} </div>
</div> </div>
<!-- Extend Deadline Modal --> <!-- Extend Deadline Modal -->
@ -420,8 +413,8 @@
<label for="new_deadline" class="form-label"> <label for="new_deadline" class="form-label">
{% trans "New Deadline" %} <span class="text-danger">*</span> {% trans "New Deadline" %} <span class="text-danger">*</span>
</label> </label>
<input type="datetime-local" class="form-control" id="new_deadline" <input type="datetime-local" class="form-control" id="new_deadline" name="new_deadline"
name="new_deadline" required> required>
<small class="form-text text-muted"> <small class="form-text text-muted">
{% trans "Current deadline:" %} {{ assignment.deadline_date|date:"Y-m-d H:i" }} {% trans "Current deadline:" %} {{ assignment.deadline_date|date:"Y-m-d H:i" }}
</small> </small>

View File

@ -165,7 +165,7 @@
<tr class="person-row"> <tr class="person-row">
<td> <td>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<div class="rounded-circle bg-primary-theme text-white d-flex align-items-center justify-content-center me-2" <div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center me-2"
style="width: 32px; height: 32px; font-size: 14px; font-weight: 600;"> style="width: 32px; height: 32px; font-size: 14px; font-weight: 600;">
{{ person.first_name|first|upper }}{{ person.last_name|first|upper }} {{ person.first_name|first|upper }}{{ person.last_name|first|upper }}
</div> </div>
@ -178,7 +178,7 @@
</div> </div>
</td> </td>
<td> <td>
<a href="mailto:{{ person.email }}" class="text-decoration-none text-dark"> <a href="mailto:{{ person.email }}" class="text-decoration-none">
{{ person.email }} {{ person.email }}
</a> </a>
</td> </td>

View File

@ -16,13 +16,15 @@
--kaauh-info: #17a2b8; --kaauh-info: #17a2b8;
--kaauh-danger: #dc3545; --kaauh-danger: #dc3545;
--kaauh-warning: #ffc107; --kaauh-warning: #ffc107;
--kaauh-secondary: #6c757d; /* Added secondary color for general use */ --kaauh-secondary: #6c757d;
/* Added secondary color for general use */
} }
/* Theme Utilities */ /* Theme Utilities */
.bg-primary-theme { .bg-primary-theme {
background-color: var(--kaauh-teal) !important; background-color: var(--kaauh-teal) !important;
} }
.text-primary-theme { .text-primary-theme {
color: var(--kaauh-teal) !important; color: var(--kaauh-teal) !important;
} }
@ -36,9 +38,22 @@
gap: 1.5rem; gap: 1.5rem;
/* Center the timeline content */ /* Center the timeline content */
justify-content: center; justify-content: center;
margin: 2rem 0 3rem; /* Extra spacing below timeline */ margin: 2rem 0 3rem;
/* Extra spacing below timeline */
padding: 0 1rem; padding: 0 1rem;
overflow-x: auto; /* Allow horizontal scroll for small screens */ overflow-x: auto;
/* Allow horizontal scroll for small screens */
-webkit-overflow-scrolling: touch;
/* Smooth scrolling on iOS */
padding-bottom: 1rem;
/* Space for scrollbar if needed */
}
@media (max-width: 768px) {
.application-progress {
justify-content: flex-start;
/* Align start to allow scrolling */
}
} }
.progress-step { .progress-step {
@ -90,7 +105,8 @@
font-weight: bold; font-weight: bold;
color: #6c757d; color: #6c757d;
position: relative; position: relative;
z-index: 2; /* Ensure icon covers the line */ z-index: 2;
/* Ensure icon covers the line */
} }
.progress-step.completed .progress-icon { .progress-step.completed .progress-icon {
@ -128,7 +144,8 @@
/* Card Header Consistency */ /* Card Header Consistency */
.card-header { .card-header {
padding: 1rem 1.5rem; /* Increased padding */ padding: 1rem 1.5rem;
/* Increased padding */
border-top-left-radius: 0.75rem; border-top-left-radius: 0.75rem;
border-top-right-radius: 0.75rem; border-top-right-radius: 0.75rem;
border-bottom: none; border-bottom: none;
@ -139,6 +156,7 @@
background-color: var(--kaauh-teal); background-color: var(--kaauh-teal);
border-color: var(--kaauh-teal); border-color: var(--kaauh-teal);
} }
.table .btn-primary:hover { .table .btn-primary:hover {
background-color: var(--kaauh-teal-dark); background-color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal-dark); border-color: var(--kaauh-teal-dark);
@ -151,6 +169,7 @@
font-weight: 600; font-weight: 600;
transition: all 0.2s ease; transition: all 0.2s ease;
} }
.btn-main-action:hover { .btn-main-action:hover {
background-color: var(--kaauh-teal-dark); background-color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal-dark); border-color: var(--kaauh-teal-dark);
@ -160,10 +179,12 @@
.action-card .card-body h6 { .action-card .card-body h6 {
font-size: 1rem; font-size: 1rem;
} }
.action-card .card-body p { .action-card .card-body p {
font-size: 0.75rem; font-size: 0.75rem;
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
} }
.action-card .card-body { .action-card .card-body {
padding: 1.5rem 1rem; padding: 1.5rem 1rem;
} }
@ -185,7 +206,8 @@
<a href="{% url 'candidate_portal_dashboard' %}" class=" text-decoration-none text-secondary">{% trans "Dashboard" %}</a> <a href="{% url 'candidate_portal_dashboard' %}" class=" text-decoration-none text-secondary">{% trans "Dashboard" %}</a>
</li> </li>
<li class="breadcrumb-item"> <li class="breadcrumb-item">
<a href="{% url 'candidate_portal_dashboard' %}#applications" class="text-secondary text-decoration-none">{% trans "My Applications" %}</a> <a href="{% url 'candidate_portal_dashboard' %}#applications"
class="text-secondary text-decoration-none">{% trans "My Applications" %}</a>
</li> </li>
<li class="breadcrumb-item active" aria-current="page" style=" <li class="breadcrumb-item active" aria-current="page" style="
color: #F43B5E; /* Rosy Accent Color */ color: #F43B5E; /* Rosy Accent Color */
@ -201,7 +223,7 @@
<div class="col-12"> <div class="col-12">
<div class="kaauh-card"> <div class="kaauh-card">
<div class="card-header bg-primary-theme text-white"> <div class="card-header bg-primary-theme text-white">
<div class="row align-items-center"> <div class="row align-items-center gy-2">
<div class="col-md-8"> <div class="col-md-8">
<h4 class="mb-1"> <h4 class="mb-1">
<i class="fas fa-briefcase me-2"></i> <i class="fas fa-briefcase me-2"></i>
@ -211,8 +233,9 @@
<small>{% trans "Application ID:" %} {{ application.slug }}</small> <small>{% trans "Application ID:" %} {{ application.slug }}</small>
</p> </p>
</div> </div>
<div class="col-md-4 text-end"> <div class="col-md-4 text-md-end text-start">
<div class="d-inline-block p-1 rounded-pill" style="background-color: rgba(255, 255, 255, 0.2);"> <div class="d-inline-block p-1 rounded-pill"
style="background-color: rgba(255, 255, 255, 0.2);">
<span class="status-badge status-{{ application.stage }}"> <span class="status-badge status-{{ application.stage }}">
{{ application.get_stage_display }} {{ application.get_stage_display }}
</span> </span>
@ -222,7 +245,8 @@
</div> </div>
<div class="card-body pt-5"> <div class="card-body pt-5">
<div class="application-progress"> <div class="application-progress">
<div class="progress-step {% if application.stage != 'Applied' and application.stage != 'Rejected' %}completed{% else %}active{% endif %}" style="flex: 0 0 auto;"> <div class="progress-step {% if application.stage != 'Applied' and application.stage != 'Rejected' %}completed{% else %}active{% endif %}"
style="flex: 0 0 auto;">
<div class="progress-icon"> <div class="progress-icon">
<i class="fas fa-paper-plane"></i> <i class="fas fa-paper-plane"></i>
</div> </div>
@ -230,7 +254,8 @@
</div> </div>
{% if application.stage in 'Exam,Interview,Document Review,Offer,Hired,Rejected' %} {% if application.stage in 'Exam,Interview,Document Review,Offer,Hired,Rejected' %}
<div class="progress-step {% if application.stage not in 'Applied,Exam' and application.stage != 'Rejected' %}completed{% elif application.stage == 'Exam' %}active{% endif %}" style="flex: 0 0 auto;"> <div class="progress-step {% if application.stage not in 'Applied,Exam' and application.stage != 'Rejected' %}completed{% elif application.stage == 'Exam' %}active{% endif %}"
style="flex: 0 0 auto;">
<div class="progress-icon"> <div class="progress-icon">
<i class="fas fa-clipboard-check"></i> <i class="fas fa-clipboard-check"></i>
</div> </div>
@ -239,7 +264,8 @@
{% endif %} {% endif %}
{% if application.stage in 'Interview,Document Review,Offer,Hired,Rejected' %} {% if application.stage in 'Interview,Document Review,Offer,Hired,Rejected' %}
<div class="progress-step {% if application.stage not in 'Applied,Exam,Interview' and application.stage != 'Rejected' %}completed{% elif application.stage == 'Interview' %}active{% endif %}" style="flex: 0 0 auto;"> <div class="progress-step {% if application.stage not in 'Applied,Exam,Interview' and application.stage != 'Rejected' %}completed{% elif application.stage == 'Interview' %}active{% endif %}"
style="flex: 0 0 auto;">
<div class="progress-icon"> <div class="progress-icon">
<i class="fas fa-video"></i> <i class="fas fa-video"></i>
</div> </div>
@ -248,7 +274,8 @@
{% endif %} {% endif %}
{% if application.stage in 'Document Review,Offer,Hired,Rejected' %} {% if application.stage in 'Document Review,Offer,Hired,Rejected' %}
<div class="progress-step {% if application.stage not in 'Applied,Exam,Interview,Document Review' and application.stage != 'Rejected' %}completed{% elif application.stage == 'Document Review' %}active{% endif %}" style="flex: 0 0 auto;"> <div class="progress-step {% if application.stage not in 'Applied,Exam,Interview,Document Review' and application.stage != 'Rejected' %}completed{% elif application.stage == 'Document Review' %}active{% endif %}"
style="flex: 0 0 auto;">
<div class="progress-icon"> <div class="progress-icon">
<i class="fas fa-file-alt"></i> <i class="fas fa-file-alt"></i>
</div> </div>
@ -257,7 +284,8 @@
{% endif %} {% endif %}
{% if application.stage in 'Offer,Hired,Rejected' %} {% if application.stage in 'Offer,Hired,Rejected' %}
<div class="progress-step {% if application.stage not in 'Applied,Exam,Interview,Document Review,Offer' and application.stage != 'Rejected' %}completed{% elif application.stage == 'Offer' %}active{% endif %}" style="flex: 0 0 auto;"> <div class="progress-step {% if application.stage not in 'Applied,Exam,Interview,Document Review,Offer' and application.stage != 'Rejected' %}completed{% elif application.stage == 'Offer' %}active{% endif %}"
style="flex: 0 0 auto;">
<div class="progress-icon"> <div class="progress-icon">
<i class="fas fa-handshake"></i> <i class="fas fa-handshake"></i>
</div> </div>
@ -266,40 +294,42 @@
{% endif %} {% endif %}
{% if application.stage in 'Hired,Rejected' %} {% if application.stage in 'Hired,Rejected' %}
<div class="progress-step {% if application.stage == 'Hired' %}completed{% elif application.stage == 'Rejected' %}active{% endif %}" style="flex: 0 0 auto;"> <div class="progress-step {% if application.stage == 'Hired' %}completed{% elif application.stage == 'Rejected' %}active{% endif %}"
style="flex: 0 0 auto;">
<div class="progress-icon"> <div class="progress-icon">
<i class="fas {% if application.stage == 'Hired' %}fa-trophy{% else %}fa-times-circle{% endif %}"></i> <i
class="fas {% if application.stage == 'Hired' %}fa-trophy{% else %}fa-times-circle{% endif %}"></i>
</div> </div>
<div class="progress-label">{% trans "Final Status" %}</div> <div class="progress-label">{% trans "Final Status" %}</div>
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="row mt-4 g-4"> <div class="row mt-4 g-3">
<div class="col-md-3"> <div class="col-6 col-md-3">
<div class="text-center p-3 bg-light rounded h-100 shadow-sm"> <div class="text-center p-3 bg-light rounded h-100 shadow-sm">
<i class="fas fa-calendar-alt text-primary-theme fa-2x mb-2"></i> <i class="fas fa-calendar-alt text-primary-theme fa-2x mb-2"></i>
<h6 class="text-muted small">{% trans "Applied Date" %}</h6> <h6 class="text-muted small">{% trans "Applied Date" %}</h6>
<p class="mb-0 fw-bold">{{ application.created_at|date:"M d, Y" }}</p> <p class="mb-0 fw-bold">{{ application.created_at|date:"M d, Y" }}</p>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-6 col-md-3">
<div class="text-center p-3 bg-light rounded h-100 shadow-sm"> <div class="text-center p-3 bg-light rounded h-100 shadow-sm">
<i class="fas fa-building text-primary-theme fa-2x mb-2"></i> <i class="fas fa-building text-info fa-2x mb-2"></i>
<h6 class="text-muted small">{% trans "Department" %}</h6> <h6 class="text-muted small">{% trans "Department" %}</h6>
<p class="mb-0 fw-bold">{{ application.job.department|default:"-" }}</p> <p class="mb-0 fw-bold">{{ application.job.department|default:"-" }}</p>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-6 col-md-3">
<div class="text-center p-3 bg-light rounded h-100 shadow-sm"> <div class="text-center p-3 bg-light rounded h-100 shadow-sm">
<i class="fas fa-briefcase text-primary-theme fa-2x mb-2"></i> <i class="fas fa-briefcase text-success fa-2x mb-2"></i>
<h6 class="text-muted small">{% trans "Job Type" %}</h6> <h6 class="text-muted small">{% trans "Job Type" %}</h6>
<p class="mb-0 fw-bold">{{ application.get_job_type_display }}</p> <p class="mb-0 fw-bold">{{ application.get_job_type_display }}</p>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-6 col-md-3">
<div class="text-center p-3 bg-light rounded h-100 shadow-sm"> <div class="text-center p-3 bg-light rounded h-100 shadow-sm">
<i class="fas fa-map-marker-alt text-primary-theme fa-2x mb-2"></i> <i class="fas fa-map-marker-alt text-warning fa-2x mb-2"></i>
<h6 class="text-muted small">{% trans "Location" %}</h6> <h6 class="text-muted small">{% trans "Location" %}</h6>
<p class="mb-0 fw-bold">{{ application.get_workplace_type_display }}</p> <p class="mb-0 fw-bold">{{ application.get_workplace_type_display }}</p>
</div> </div>
@ -310,10 +340,9 @@
</div> </div>
</div> </div>
<div class="row mb-5"> <div class="row mb-5 g-3">
<div class="col-md-6 col-6"> <div class="col-12 col-md-6">
<a href="{% url 'candidate_portal_dashboard' %}" class="text-decoration-none text-dark"> <div class="kaauh-card h-100 shadow-sm action-card">
<div class="kaauh-card h-50 shadow-sm action-card">
<div class="card-body text-center mb-4"> <div class="card-body text-center mb-4">
<i class="fas fa-arrow-left fa-2x text-primary-theme mb-3"></i> <i class="fas fa-arrow-left fa-2x text-primary-theme mb-3"></i>
<h6>{% trans "Go to Dashboard" %}</h6> <h6>{% trans "Go to Dashboard" %}</h6>
@ -323,33 +352,26 @@
</a> </a>
</div> </div>
</div> </div>
</a>
</div> </div>
{% if application.resume %} {% if application.resume %}
<div class="col-md-6 col-6"> <div class="col-12 col-md-6">
<a href="{{ application.resume.url }}" <div class="kaauh-card h-100 shadow-sm action-card">
target="_blank" class="text-decoration-none text-dark">
<div class="kaauh-card h-50 shadow-sm action-card">
<div class="card-body text-center mb-4"> <div class="card-body text-center mb-4">
<i class="fas fa-file-download fa-2x text-primary-theme mb-3"></i> <i class="fas fa-file-download fa-2x text-success mb-3"></i>
<h6>{% trans "Download Resume" %}</h6> <h6>{% trans "Download Resume" %}</h6>
<p class="text-muted small">{% trans "Get your submitted file" %}</p> <p class="text-muted small">{% trans "Get your submitted file" %}</p>
<a href="{{ application.resume.url }}" <a href="{{ application.resume.url }}" target="_blank" class="btn btn-main-action btn-sm w-100">
target="_blank"
class="btn btn-main-action btn-sm w-100">
<i class="fas fa-download me-2"></i> <i class="fas fa-download me-2"></i>
{% trans "Download" %} {% trans "Download" %}
</a> </a>
</div> </div>
</div> </div>
</a>
</div> </div>
{% endif %} {% endif %}
</div> </div>
{% if interviews %} {% if interviews %}
<div class="row mb-5"> <div class="row mb-5">
@ -400,8 +422,7 @@
</td> </td>
<td> <td>
{% if interview.zoom_meeting and interview.zoom_meeting.join_url %} {% if interview.zoom_meeting and interview.zoom_meeting.join_url %}
<a href="{{ interview.zoom_meeting.join_url }}" <a href="{{ interview.zoom_meeting.join_url }}" target="_blank"
target="_blank"
class="btn btn-sm btn-primary"> class="btn btn-sm btn-primary">
<i class="fas fa-video me-1"></i> <i class="fas fa-video me-1"></i>
{% trans "Join" %} {% trans "Join" %}
@ -412,7 +433,8 @@
</td> </td>
<td> <td>
{% if interview.zoom_meeting and interview.zoom_meeting.join_url %} {% if interview.zoom_meeting and interview.zoom_meeting.join_url %}
<button class="btn btn-sm btn-outline-primary" onclick="addToCalendar({{ interview.interview_date|date:'Y' }}, {{ interview.interview_date|date:'m' }}, {{ interview.interview_date|date:'d' }}, '{{ interview.interview_time|time:'H:i' }}', '{{ application.job.title }}')"> <button class="btn btn-sm btn-outline-primary"
onclick="addToCalendar({{ interview.interview_date|date:'Y' }}, {{ interview.interview_date|date:'m' }}, {{ interview.interview_date|date:'d' }}, '{{ interview.interview_time|time:'H:i' }}', '{{ application.job.title }}')">
<i class="fas fa-calendar-plus me-1"></i> <i class="fas fa-calendar-plus me-1"></i>
{% trans "Add to Calendar" %} {% trans "Add to Calendar" %}
</button> </button>
@ -448,7 +470,8 @@
</h5> </h5>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<button class="btn btn-outline-secondary text-white" data-bs-toggle="modal" data-bs-target="#uploadDocumentModal"> <button class="btn btn-sm btn-light" data-bs-toggle="modal"
data-bs-target="#uploadDocumentModal">
<i class="fas fa-plus me-1"></i> <i class="fas fa-plus me-1"></i>
{% trans "Upload Document" %} {% trans "Upload Document" %}
</button> </button>
@ -473,8 +496,7 @@
<tr> <tr>
<td> <td>
{% if document.file %} {% if document.file %}
<a href="{{ document.file.url }}" <a href="{{ document.file.url }}" target="_blank"
target="_blank"
class="text-decoration-none text-primary-theme"> class="text-decoration-none text-primary-theme">
<i class="fas fa-file-pdf text-danger me-2"></i> <i class="fas fa-file-pdf text-danger me-2"></i>
{{ document.get_document_type_display }} {{ document.get_document_type_display }}
@ -500,13 +522,13 @@
</td> </td>
<td> <td>
{% if document.file %} {% if document.file %}
<a href="{{ document.file.url }}" <a href="{{ document.file.url }}" class="btn btn-sm btn-outline-primary me-1"
class="btn btn-sm btn-outline-primary me-1"
target="_blank"> target="_blank">
<i class="fas fa-download"></i> <i class="fas fa-download"></i>
{% trans "Download" %} {% trans "Download" %}
</a> </a>
<button class="btn btn-sm btn-outline-danger" onclick="deleteDocument({{ document.id }})"> <button class="btn btn-sm btn-outline-danger"
onclick="deleteDocument({{ document.id }})">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
</button> </button>
{% endif %} {% endif %}
@ -520,7 +542,8 @@
<div class="text-center py-4"> <div class="text-center py-4">
<i class="fas fa-file-upload fa-3x text-muted mb-3"></i> <i class="fas fa-file-upload fa-3x text-muted mb-3"></i>
<p class="text-muted">{% trans "No documents uploaded." %}</p> <p class="text-muted">{% trans "No documents uploaded." %}</p>
<button class="btn btn-main-action" data-bs-toggle="modal" data-bs-target="#uploadDocumentModal"> <button class="btn btn-main-action" data-bs-toggle="modal"
data-bs-target="#uploadDocumentModal">
<i class="fas fa-plus me-2"></i> <i class="fas fa-plus me-2"></i>
{% trans "Upload Your First Document" %} {% trans "Upload Your First Document" %}
</button> </button>
@ -543,44 +566,51 @@
</div> </div>
<div class="card-body p-4"> <div class="card-body p-4">
{% if application.stage == 'Applied' %} {% if application.stage == 'Applied' %}
<div class="alert bg-primary-theme text-white"> <div class="alert alert-info">
<i class="fas fa-clock me-2"></i> <i class="fas fa-clock me-2"></i>
{% trans "Your application is being reviewed by our recruitment team. You will receive an update within 3-5 business days." %} {% trans "Your application is being reviewed by our recruitment team. You will receive an update
within 3-5 business days." %}
</div> </div>
{% elif application.stage == 'Screening' %} {% elif application.stage == 'Screening' %}
<div class="alert bg-primary-theme text-white"> <div class="alert alert-warning">
<i class="fas fa-search me-2"></i> <i class="fas fa-search me-2"></i>
{% trans "Your application is currently under screening. We are evaluating your qualifications against the job requirements." %} {% trans "Your application is currently under screening. We are evaluating your qualifications
against the job requirements." %}
</div> </div>
{% elif application.stage == 'Document Review' %} {% elif application.stage == 'Document Review' %}
<div class="alert bg-primary-theme text-white"> <div class="alert alert-purple">
<i class="fas fa-file-alt me-2"></i> <i class="fas fa-file-alt me-2"></i>
{% trans "Please upload the required documents for review. Our team will evaluate your submitted materials." %} {% trans "Please upload the required documents for review. Our team will evaluate your submitted
materials." %}
</div> </div>
{% elif application.stage == 'Exam' %} {% elif application.stage == 'Exam' %}
<div class="alert bg-primary-theme text-white"> <div class="alert alert-purple">
<i class="fas fa-clipboard-check me-2"></i> <i class="fas fa-clipboard-check me-2"></i>
{% trans "You have been shortlisted for an assessment. Please check your email for exam details and preparation materials." %} {% trans "You have been shortlisted for an assessment. Please check your email for exam details
and preparation materials." %}
</div> </div>
{% elif application.stage == 'Interview' %} {% elif application.stage == 'Interview' %}
<div class="alert bg-primary-theme text-white"> <div class="alert alert-success">
<i class="fas fa-video me-2"></i> <i class="fas fa-video me-2"></i>
{% trans "Congratulations! You have been selected for an interview. Please check the interview schedule above and prepare accordingly." %} {% trans "Congratulations! You have been selected for an interview. Please check the interview
schedule above and prepare accordingly." %}
</div> </div>
{% elif application.stage == 'Offer' %} {% elif application.stage == 'Offer' %}
<div class="alert bg-primary-theme text-white"> <div class="alert alert-warning">
<i class="fas fa-handshake me-2"></i> <i class="fas fa-handshake me-2"></i>
{% trans "You have received a job offer! Please check your email for the detailed offer letter and next steps." %} {% trans "You have received a job offer! Please check your email for the detailed offer letter
and next steps." %}
</div> </div>
{% elif application.stage == 'Hired' %} {% elif application.stage == 'Hired' %}
<div class="alert bg-primary-theme text-white"> <div class="alert alert-success">
<i class="fas fa-trophy me-2"></i> <i class="fas fa-trophy me-2"></i>
{% trans "Welcome to the team! You will receive onboarding information shortly." %} {% trans "Welcome to the team! You will receive onboarding information shortly." %}
</div> </div>
{% elif application.stage == 'Rejected' %} {% elif application.stage == 'Rejected' %}
<div class="alert bg-primary-theme text-white"> <div class="alert alert-danger">
<i class="fas fa-times-circle me-2"></i> <i class="fas fa-times-circle me-2"></i>
{% trans "Thank you for your interest. Unfortunately, your application was not selected at this time. We encourage you to apply for other positions." %} {% trans "Thank you for your interest. Unfortunately, your application was not selected at this
time. We encourage you to apply for other positions." %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
@ -617,13 +647,15 @@
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="documentFile" class="form-label">{% trans "Choose File" %}</label> <label for="documentFile" class="form-label">{% trans "Choose File" %}</label>
<input type="file" class="form-control" id="documentFile" name="file" accept=".pdf,.doc,.docx,.jpg,.png" required> <input type="file" class="form-control" id="documentFile" name="file"
accept=".pdf,.doc,.docx,.jpg,.png" required>
<div class="form-text">{% trans "Accepted formats: PDF, DOC, DOCX, JPG, PNG (Max 5MB)" %}</div> <div class="form-text">{% trans "Accepted formats: PDF, DOC, DOCX, JPG, PNG (Max 5MB)" %}</div>
</div> </div>
<input type="hidden" name="application_slug" value="{{ application.slug }}"> <input type="hidden" name="application_slug" value="{{ application.slug }}">
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-outline-secondary btn-lg" data-bs-dismiss="modal">{% trans "Cancel" %}</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel"
%}</button>
<button type="submit" class="btn btn-main-action"> <button type="submit" class="btn btn-main-action">
<i class="fas fa-upload me-2"></i> <i class="fas fa-upload me-2"></i>
{% trans "Upload" %} {% trans "Upload" %}

View File

@ -662,7 +662,6 @@
<i class="fas fa-eye me-1"></i> <i class="fas fa-eye me-1"></i>
{% trans "View Actual Resume" %} {% trans "View Actual Resume" %}
</a> {% endcomment %} </a> {% endcomment %}
<a href="{{ candidate.resume.url }}" download class="btn btn-outline-primary"> <a href="{{ candidate.resume.url }}" download class="btn btn-outline-primary">
<i class="fas fa-download me-1"></i> <i class="fas fa-download me-1"></i>
{% trans "Download Resume" %} {% trans "Download Resume" %}

View File

@ -395,13 +395,14 @@
{% endwith %} {% endwith %}
</td> </td>
<td class="text-center"> <td class="text-center">
<button type="button" class="btn btn-outline-secondary btn-sm" <button type="button"
class="btn btn-sm btn-main-action"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#documentModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}" hx-get="{% url 'candidate_application_detail' candidate.slug %}"
hx-target="#candidateviewModalBody" hx-target="#documentModalBody"
title="View Profile"> title="{% trans 'View Candidate Details' %}">
<i class="fas fa-eye ms-1"></i> <i class="fas fa-eye me-1"></i> {% trans "View Details" %}
</button> </button>
</td> </td>
</tr> </tr>
@ -418,45 +419,26 @@
</form> </form>
</div> </div>
<!-- Modal for viewing candidate details -->
</div> <div class="modal fade modal-xl" id="documentModal" tabindex="-1" aria-labelledby="documentModalLabel" aria-hidden="true">
<div class="modal fade modal-xl" id="candidateviewModal" tabindex="-1" aria-labelledby="candidateviewModalLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content kaauh-card"> <div class="modal-header" style="border-bottom: 1px solid var(--kaauh-border);">
<h5 class="modal-title" id="candidateviewModalLabel" style="color: var(--kaauh-teal-dark);">
{% trans "Candidate Details / Bulk Action Form" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div id="candidateviewModalBody" class="modal-body">
<div class="text-center py-5 text-muted">
<i class="fas fa-spinner fa-spin fa-2x"></i><br>
{% trans "Loading content..." %}
</div>
</div>
</div>
</div>
</div>
<!-- Email Modal -->
<div class="modal fade" id="emailModal" tabindex="-1" aria-labelledby="emailModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content kaauh-card"> <div class="modal-content kaauh-card">
<div class="modal-header" style="border-bottom: 1px solid var(--kaauh-border);"> <div class="modal-header" style="border-bottom: 1px solid var(--kaauh-border);">
<h5 class="modal-title" id="emailModalLabel" style="color: var(--kaauh-teal-dark);"> <h5 class="modal-title" id="documentModalLabel" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-envelope me-2"></i>{% trans "Compose Email" %} {% trans "Candidate Details" %}
</h5> </h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div id="emailModalBody" class="modal-body"> <div id="documentModalBody" class="modal-body">
<div class="text-center py-5 text-muted"> <div class="text-center py-5 text-muted">
<i class="fas fa-spinner fa-spin fa-2x"></i><br> <i class="fas fa-spinner fa-spin fa-2x"></i><br>
{% trans "Loading email form..." %} {% trans "Loading candidate details..." %}
</div>
</div>
<div class="modal-footer" style="border-top: 1px solid var(--kaauh-border);">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
{% trans "Close" %}
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -87,13 +87,40 @@
font-weight: 600; font-weight: 600;
} }
.status-applied { background: #e3f2fd; color: #1976d2; } .status-applied {
.status-screening { background: #fff3e0; color: #f57c00; } background: #e3f2fd;
.status-exam { background: #f3e5f5; color: #7b1fa2; } color: #1976d2;
.status-interview { background: #e8f5e8; color: #388e3c; } }
.status-offer { background: #fff8e1; color: #f9a825; }
.status-hired { background: #e8f5e8; color: #2e7d32; } .status-screening {
.status-rejected { background: #ffebee; color: #c62828; } background: #fff3e0;
color: #f57c00;
}
.status-exam {
background: #f3e5f5;
color: #7b1fa2;
}
.status-interview {
background: #e8f5e8;
color: #388e3c;
}
.status-offer {
background: #fff8e1;
color: #f9a825;
}
.status-hired {
background: #e8f5e8;
color: #2e7d32;
}
.status-rejected {
background: #ffebee;
color: #c62828;
}
/* Alert Purple - Using Theme Colors */ /* Alert Purple - Using Theme Colors */
.alert-purple { .alert-purple {
@ -109,6 +136,7 @@
font-size: 0.95rem; font-size: 0.95rem;
font-weight: 500; font-weight: 500;
} }
.profile-data-list li strong { .profile-data-list li strong {
font-weight: 700; font-weight: 700;
color: var(--kaauh-teal-dark); color: var(--kaauh-teal-dark);
@ -117,12 +145,18 @@
} }
/* Tabs styling */ /* Tabs styling */
{% comment %} .nav-tabs { {
% comment %
}
.nav-tabs {
border-bottom: 1px solid var(--kaauh-border); border-bottom: 1px solid var(--kaauh-border);
} }
.nav-tabs .nav-link.active { .nav-tabs .nav-link.active {
color: var(--kaauh-primary-text); color: var(--kaauh-primary-text);
} }
.nav-tabs .nav-link { .nav-tabs .nav-link {
color: var(--kaauh-teal); color: var(--kaauh-teal);
border: none; border: none;
@ -130,19 +164,26 @@
padding: 1rem 1.75rem; padding: 1rem 1.75rem;
font-weight: 600; font-weight: 600;
} }
.nav-tabs .nav-link:hover { .nav-tabs .nav-link:hover {
color: var(--kaauh-teal-dark); color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal-light); border-color: var(--kaauh-teal-light);
} }
.nav-tabs .nav-link.active { .nav-tabs .nav-link.active {
color: #000000; color: #000000;
border-color: var(--kaauh-teal); border-color: var(--kaauh-teal);
background-color: transparent; background-color: transparent;
font-weight: 700; font-weight: 700;
} }
.nav-tabs .nav-link i { .nav-tabs .nav-link i {
color: var(--kaauh-teal) !important; color: var(--kaauh-teal) !important;
} {% endcomment %} }
{
% endcomment %
}
/* Tabs Theming - Applies to the right column */ /* Tabs Theming - Applies to the right column */
.nav-tabs { .nav-tabs {
@ -159,7 +200,10 @@
padding: 0.75rem 1rem; padding: 0.75rem 1rem;
margin-right: 0.5rem; margin-right: 0.5rem;
transition: all 0.2s; transition: all 0.2s;
white-space: nowrap;
/* Ensure text doesn't wrap in tabs */
} }
/* Active Link */ /* Active Link */
.nav-tabs .nav-link.active { .nav-tabs .nav-link.active {
color: var(--kaauh-teal-dark) !important; color: var(--kaauh-teal-dark) !important;
@ -175,9 +219,45 @@
overflow-x: auto; overflow-x: auto;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
white-space: nowrap; white-space: nowrap;
/* Hide scrollbar for cleaner look but keep functionality */
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE 10+ */
position: relative;
}
.nav-scroll::-webkit-scrollbar {
display: none;
/* Chrome/Safari */
}
.nav-scroll .nav-tabs {
flex-wrap: nowrap;
border-bottom: none;
padding-bottom: 5px;
/* Space for active border */
}
.nav-scroll .nav-tabs .nav-item {
flex-shrink: 0;
}
/* Add a subtle fade effect to indicate more content */
.nav-scroll-container {
position: relative;
}
.nav-scroll-container::after {
content: '';
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 30px;
background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
pointer-events: none;
} }
.nav-scroll .nav-tabs { flex-wrap: nowrap; border-bottom: none; }
.nav-scroll .nav-tabs .nav-item { flex-shrink: 0; }
/* Application table styling */ /* Application table styling */
.application-table thead th { .application-table thead th {
@ -187,12 +267,15 @@
border-bottom: 1px solid var(--kaauh-border); border-bottom: 1px solid var(--kaauh-border);
padding: 1rem 1.5rem; padding: 1rem 1.5rem;
} }
.application-table tbody tr { .application-table tbody tr {
transition: background-color 0.2s ease; transition: background-color 0.2s ease;
} }
.application-table tbody tr:hover { .application-table tbody tr:hover {
background-color: var(--kaauh-teal-light); background-color: var(--kaauh-teal-light);
} }
.badge-stage { .badge-stage {
font-weight: 600; font-weight: 600;
padding: 0.4em 0.8em; padding: 0.4em 0.8em;
@ -201,19 +284,24 @@
/* Responsive table for mobile */ /* Responsive table for mobile */
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
.application-table thead { display: none; } .application-table thead {
display: none;
}
.application-table tr { .application-table tr {
margin-bottom: 1rem; margin-bottom: 1rem;
border: 1px solid var(--kaauh-border); border: 1px solid var(--kaauh-border);
border-radius: 8px; border-radius: 8px;
box-shadow: var(--kaauh-shadow-sm); box-shadow: var(--kaauh-shadow-sm);
} }
.application-table td { .application-table td {
text-align: right !important; text-align: right !important;
padding: 0.75rem 1rem; padding: 0.75rem 1rem;
padding-left: 50%; padding-left: 50%;
position: relative; position: relative;
} }
.application-table td::before { .application-table td::before {
content: attr(data-label); content: attr(data-label);
position: absolute; position: absolute;
@ -222,6 +310,34 @@
font-weight: 700; font-weight: 700;
color: var(--gray-text); color: var(--gray-text);
} }
/* Profile Data List Mobile Optimization */
.profile-data-list li {
flex-direction: column;
align-items: flex-start !important;
}
.profile-data-list li>div {
margin-bottom: 0.25rem;
color: var(--kaauh-secondary);
}
.profile-data-list li>span {
width: 100%;
text-align: left !important;
word-break: break-word;
/* Handle long emails/addresses */
}
/* Adjust padding for mobile */
.tab-content {
padding: 1.5rem !important;
}
.nav-tabs .nav-link {
padding: 0.75rem 1rem;
font-size: 0.9rem;
}
} }
/* Document management list */ /* Document management list */
@ -231,6 +347,7 @@
border: 1px solid var(--kaauh-border); border: 1px solid var(--kaauh-border);
transition: all 0.2s ease; transition: all 0.2s ease;
} }
.list-group-item:hover { .list-group-item:hover {
background-color: var(--kaauh-teal-light); background-color: var(--kaauh-teal-light);
border-color: var(--kaauh-teal-accent); border-color: var(--kaauh-teal-accent);
@ -245,12 +362,14 @@
transition: all 0.3s ease; transition: all 0.3s ease;
box-shadow: var(--kaauh-shadow-sm); box-shadow: var(--kaauh-shadow-sm);
} }
.btn-action-tile:hover { .btn-action-tile:hover {
background-color: var(--kaauh-teal-light); background-color: var(--kaauh-teal-light);
border-color: var(--kaauh-teal-accent); border-color: var(--kaauh-teal-accent);
transform: translateY(-2px); transform: translateY(-2px);
box-shadow: var(--kaauh-shadow-lg); box-shadow: var(--kaauh-shadow-lg);
} }
.action-tile-icon { .action-tile-icon {
font-size: 2rem; font-size: 2rem;
color: var(--kaauh-teal-accent); color: var(--kaauh-teal-accent);
@ -261,6 +380,7 @@
.hover-lift { .hover-lift {
transition: all 0.3s ease; transition: all 0.3s ease;
} }
.hover-lift:hover { .hover-lift:hover {
transform: translateY(-4px); transform: translateY(-4px);
box-shadow: var(--kaauh-shadow-lg); box-shadow: var(--kaauh-shadow-lg);
@ -270,6 +390,7 @@
.application-card .card-title a { .application-card .card-title a {
transition: color 0.2s ease; transition: color 0.2s ease;
} }
.application-card .card-title a:hover { .application-card .card-title a:hover {
color: var(--kaauh-teal-dark) !important; color: var(--kaauh-teal-dark) !important;
} }
@ -279,6 +400,7 @@
.application-card .card-body { .application-card .card-body {
padding: 1.25rem; padding: 1.25rem;
} }
.application-card .card-title { .application-card .card-title {
font-size: 1.1rem; font-size: 1.1rem;
} }
@ -290,21 +412,22 @@
<div class="container-fluid"> <div class="container-fluid">
{# Header: Larger, more dynamic on large screens. Stacks cleanly on mobile. #} {# Header: Larger, more dynamic on large screens. Stacks cleanly on mobile. #}
<div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-5"> <div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-4 mb-md-5">
<h1 class="display-6 display-md-5 fw-extrabold mb-3 mb-md-0" style="color: var(--kaauh-teal-dark);"> <h1 class="display-6 display-md-5 fw-extrabold mb-3 mb-md-0 text-center text-md-start"
style="color: var(--kaauh-teal-dark);">
{% trans "Your Candidate Dashboard" %} {% trans "Your Candidate Dashboard" %}
</h1> </h1>
{% comment %} <a href="#profile-details" data-bs-toggle="tab" class="btn btn-main-action btn-sm btn-md-lg px-4 py-2 rounded-pill shadow-sm shadow-md-lg"> {% comment %} <a href="#profile-details" data-bs-toggle="tab"
class="btn btn-main-action btn-sm btn-md-lg px-4 py-2 rounded-pill shadow-sm shadow-md-lg">
<i class="fas fa-edit me-2"></i> {% trans "Update Profile" %} <i class="fas fa-edit me-2"></i> {% trans "Update Profile" %}
</a> {% endcomment %} </a> {% endcomment %}
</div> </div>
{# Candidate Quick Overview Card: Use a softer background color #} {# Candidate Quick Overview Card: Use a softer background color #}
<div class="card kaauh-card mb-5 p-4 bg-white"> <div class="card kaauh-card mb-4 mb-md-5 p-3 p-md-4 bg-white">
<div class="d-flex align-items-center flex-column flex-sm-row text-center text-sm-start"> <div class="d-flex align-items-center flex-column flex-sm-row text-center text-sm-start">
<img src="{% if candidate.user.profile_image %}{{ candidate.user.profile_image.url }}{% else %}{% static 'image/default_avatar.png' %}{% endif %}" <img src="{% if candidate.user.profile_image %}{{ candidate.user.profile_image.url }}{% else %}{% static 'image/default_avatar.png' %}{% endif %}"
alt="{% trans 'Profile Picture' %}" alt="{% trans 'Profile Picture' %}" class="rounded-circle me-sm-4 mb-3 mb-sm-0 shadow-lg"
class="rounded-circle me-sm-4 mb-3 mb-sm-0 shadow-lg"
style="width: 80px; height: 80px; object-fit: cover; border: 4px solid var(--kaauh-teal-accent);"> style="width: 80px; height: 80px; object-fit: cover; border: 4px solid var(--kaauh-teal-accent);">
<div> <div>
<h3 class="card-title mb-1 fw-bold text-dark">{{ candidate.full_name|default:"Candidate Name" }}</h3> <h3 class="card-title mb-1 fw-bold text-dark">{{ candidate.full_name|default:"Candidate Name" }}</h3>
@ -319,33 +442,36 @@
<div class="card kaauh-card p-0 bg-white"> <div class="card kaauh-card p-0 bg-white">
{# Tab Navigation: Used nav-scroll for responsiveness #} {# Tab Navigation: Used nav-scroll for responsiveness #}
<div class="nav-scroll px-4 pt-3"> <div class="nav-scroll-container px-3 px-md-4 pt-3">
<div class="nav-scroll">
<ul class="nav nav-tabs" id="candidateTabs" role="tablist"> <ul class="nav nav-tabs" id="candidateTabs" role="tablist">
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link active" id="profile-tab" data-bs-toggle="tab" data-bs-target="#profile-details" type="button" role="tab" aria-controls="profile-details" aria-selected="true"> <button class="nav-link active" id="profile-tab" data-bs-toggle="tab"
data-bs-target="#profile-details" type="button" role="tab" aria-controls="profile-details"
aria-selected="true">
<i class="fas fa-user-circle me-2"></i> {% trans "Profile Details" %} <i class="fas fa-user-circle me-2"></i> {% trans "Profile Details" %}
</button> </button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link" id="applications-tab" data-bs-toggle="tab" data-bs-target="#applications-history" type="button" role="tab" aria-controls="applications-history" aria-selected="false"> <button class="nav-link" id="applications-tab" data-bs-toggle="tab"
data-bs-target="#applications-history" type="button" role="tab"
aria-controls="applications-history" aria-selected="false">
<i class="fas fa-list-alt me-2"></i> {% trans "My Applications" %} <i class="fas fa-list-alt me-2"></i> {% trans "My Applications" %}
</button> </button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link" id="documents-tab" data-bs-toggle="tab" data-bs-target="#document-management" type="button" role="tab" aria-controls="document-management" aria-selected="false"> <button class="nav-link" id="documents-tab" data-bs-toggle="tab"
data-bs-target="#document-management" type="button" role="tab"
aria-controls="document-management" aria-selected="false">
<i class="fas fa-file-upload me-2"></i> {% trans "Documents" %} <i class="fas fa-file-upload me-2"></i> {% trans "Documents" %}
</button> </button>
</li> </li>
{% comment %} <li class="nav-item" role="presentation">
<button class="nav-link" id="settings-tab" data-bs-toggle="tab" data-bs-target="#account-settings" type="button" role="tab" aria-controls="account-settings" aria-selected="false">
<i class="fas fa-cogs me-2"></i> {% trans "Settings" %}
</button>
</li> {% endcomment %}
</ul> </ul>
</div> </div>
</div>
{# Tab Content #} {# Tab Content #}
<div class="tab-content p-4 p-md-5" id="candidateTabsContent"> <div class="tab-content p-3 p-md-5" id="candidateTabsContent">
<div class="tab-pane fade show active" id="profile-details" role="tabpanel" aria-labelledby="profile-tab"> <div class="tab-pane fade show active" id="profile-details" role="tabpanel" aria-labelledby="profile-tab">
<!-- Basic Information Section --> <!-- Basic Information Section -->
@ -354,23 +480,27 @@
<i class="fas fa-user me-2 text-primary-theme"></i>{% trans "Basic Information" %} <i class="fas fa-user me-2 text-primary-theme"></i>{% trans "Basic Information" %}
</h4> </h4>
<ul class="list-unstyled profile-data-list p-0"> <ul class="list-unstyled profile-data-list p-0">
<li class="d-flex justify-content-between align-items-center"> <li
class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
<div><i class="fas fa-id-card me-2 text-primary-theme"></i> <strong>{% trans "First Name" %}</strong></div> <div><i class="fas fa-id-card me-2 text-primary-theme"></i> <strong>{% trans "First Name" %}</strong></div>
<span class="text-end">{{ candidate.first_name|default:"" }}</span> <span class="text-start text-sm-end">{{ candidate.first_name|default:"" }}</span>
</li> </li>
<li class="d-flex justify-content-between align-items-center"> <li
class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
<div><i class="fas fa-id-card me-2 text-primary-theme"></i> <strong>{% trans "Last Name" %}</strong></div> <div><i class="fas fa-id-card me-2 text-primary-theme"></i> <strong>{% trans "Last Name" %}</strong></div>
<span class="text-end">{{ candidate.last_name|default:"" }}</span> <span class="text-start text-sm-end">{{ candidate.last_name|default:"" }}</span>
</li> </li>
{% if candidate.middle_name %} {% if candidate.middle_name %}
<li class="d-flex justify-content-between align-items-center"> <li
class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
<div><i class="fas fa-id-card me-2 text-primary-theme"></i> <strong>{% trans "Middle Name" %}</strong></div> <div><i class="fas fa-id-card me-2 text-primary-theme"></i> <strong>{% trans "Middle Name" %}</strong></div>
<span class="text-end">{{ candidate.middle_name }}</span> <span class="text-start text-sm-end">{{ candidate.middle_name }}</span>
</li> </li>
{% endif %} {% endif %}
<li class="d-flex justify-content-between align-items-center"> <li
class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
<div><i class="fas fa-envelope me-2 text-primary-theme"></i> <strong>{% trans "Email" %}</strong></div> <div><i class="fas fa-envelope me-2 text-primary-theme"></i> <strong>{% trans "Email" %}</strong></div>
<span class="text-end">{{ candidate.email|default:"" }}</span> <span class="text-start text-sm-end text-break">{{ candidate.email|default:"" }}</span>
</li> </li>
</ul> </ul>
</div> </div>
@ -381,21 +511,24 @@
<i class="fas fa-address-book me-2 text-primary-theme"></i>{% trans "Contact Information" %} <i class="fas fa-address-book me-2 text-primary-theme"></i>{% trans "Contact Information" %}
</h4> </h4>
<ul class="list-unstyled profile-data-list p-0"> <ul class="list-unstyled profile-data-list p-0">
<li class="d-flex justify-content-between align-items-center"> <li
class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
<div><i class="fas fa-phone-alt me-2 text-primary-theme"></i> <strong>{% trans "Phone" %}</strong></div> <div><i class="fas fa-phone-alt me-2 text-primary-theme"></i> <strong>{% trans "Phone" %}</strong></div>
<span class="text-end">{{ candidate.phone|default:"" }}</span> <span class="text-start text-sm-end">{{ candidate.phone|default:"" }}</span>
</li> </li>
{% if candidate.address %} {% if candidate.address %}
<li class="d-flex align-items-start"> <li class="d-flex flex-column flex-sm-row align-items-start">
<div class="mb-1"><i class="fas fa-map-marker-alt me-2 text-primary-theme"></i> <strong>{%trans "Address" %}</strong></div> <div class="mb-1"><i class="fas fa-map-marker-alt me-2 text-primary-theme"></i> <strong>{%trans "Address" %}</strong></div>
<span class="text-end text-break">{{ candidate.address|linebreaksbr }}</span> <span class="text-start text-sm-end text-break">{{ candidate.address|linebreaksbr }}</span>
</li> </li>
{% endif %} {% endif %}
{% if candidate.linkedin_profile %} {% if candidate.linkedin_profile %}
<li class="d-flex justify-content-between align-items-center"> <li
class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
<div><i class="fab fa-linkedin me-2 text-primary-theme"></i> <strong>{% trans "LinkedIn Profile" %}</strong></div> <div><i class="fab fa-linkedin me-2 text-primary-theme"></i> <strong>{% trans "LinkedIn Profile" %}</strong></div>
<span class="text-end"> <span class="text-start text-sm-end">
<a href="{{ candidate.linkedin_profile }}" target="_blank" class="text-primary-theme text-decoration-none"> <a href="{{ candidate.linkedin_profile }}" target="_blank"
class="text-primary-theme text-decoration-none">
{% trans "View Profile" %} <i class="fas fa-external-link-alt ms-1"></i> {% trans "View Profile" %} <i class="fas fa-external-link-alt ms-1"></i>
</a> </a>
</span> </span>
@ -410,17 +543,20 @@
<i class="fas fa-user-circle me-2 text-primary-theme"></i>{% trans "Personal Details" %} <i class="fas fa-user-circle me-2 text-primary-theme"></i>{% trans "Personal Details" %}
</h4> </h4>
<ul class="list-unstyled profile-data-list p-0"> <ul class="list-unstyled profile-data-list p-0">
<li class="d-flex justify-content-between align-items-center"> <li
class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
<div><i class="fas fa-calendar-alt me-2 text-primary-theme"></i> <strong>{% trans "Date of Birth" %}</strong></div> <div><i class="fas fa-calendar-alt me-2 text-primary-theme"></i> <strong>{% trans "Date of Birth" %}</strong></div>
<span class="text-end">{{ candidate.date_of_birth|date:"M d, Y"|default:"" }}</span> <span class="text-start text-sm-end">{{ candidate.date_of_birth|date:"M d, Y"|default:"" }}</span>
</li> </li>
<li class="d-flex justify-content-between align-items-center"> <li
class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
<div><i class="fas fa-venus-mars me-2 text-primary-theme"></i> <strong>{% trans "Gender" %}</strong></div> <div><i class="fas fa-venus-mars me-2 text-primary-theme"></i> <strong>{% trans "Gender" %}</strong></div>
<span class="text-end">{{ candidate.get_gender_display|default:"" }}</span> <span class="text-start text-sm-end">{{ candidate.get_gender_display|default:"" }}</span>
</li> </li>
<li class="d-flex justify-content-between align-items-center"> <li
class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
<div><i class="fas fa-globe me-2 text-primary-theme"></i> <strong>{% trans "Nationality" %}</strong></div> <div><i class="fas fa-globe me-2 text-primary-theme"></i> <strong>{% trans "Nationality" %}</strong></div>
<span class="text-end">{{ candidate.get_nationality_display|default:"" }}</span> <span class="text-start text-sm-end">{{ candidate.get_nationality_display|default:"" }}</span>
</li> </li>
</ul> </ul>
</div> </div>
@ -432,51 +568,22 @@
</h4> </h4>
<ul class="list-unstyled profile-data-list p-0"> <ul class="list-unstyled profile-data-list p-0">
{% if candidate.user.designation %} {% if candidate.user.designation %}
<li class="d-flex justify-content-between align-items-center"> <li
<div><i class="fas fa-user-tie me-2 text-primary-theme"></i> <strong>{% trans "Designation" %}</strong></div> class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
<span class="text-end">{{ candidate.user.designation }}</span> <div><i class="fas fa-user-tie me-2 text-primary-theme"></i> <strong>{% trans "Designation"
%}</strong></div>
<span class="text-start text-sm-end">{{ candidate.user.designation }}</span>
</li> </li>
{% endif %} {% endif %}
{% if candidate.gpa %} {% if candidate.gpa %}
<li class="d-flex justify-content-between align-items-center"> <li
class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
<div><i class="fas fa-graduation-cap me-2 text-primary-theme"></i> <strong>{% trans "GPA" %}</strong></div> <div><i class="fas fa-graduation-cap me-2 text-primary-theme"></i> <strong>{% trans "GPA" %}</strong></div>
<span class="text-end">{{ candidate.gpa }}</span> <span class="text-start text-sm-end">{{ candidate.gpa }}</span>
</li> </li>
{% endif %} {% endif %}
</ul> </ul>
</div> </div>
{% comment %} <div class="alert alert-info mt-4">
<i class="fas fa-info-circle me-2"></i>
<small>{% trans "Use the 'Update Profile' button above to edit these details." %}</small>
</div> {% endcomment %}
{% comment %} <hr class="my-5"> {% endcomment %}
{% comment %} <h4 class="mb-4 fw-bold text-gray-subtle">{% trans "Quick Actions" %}</h4>
<div class="row g-3 g-md-4">
<div class="col-6 col-sm-4 col-md-4">
<a href="#applications-history" data-bs-toggle="tab" class="btn btn-action-tile w-100 d-grid text-center text-dark text-decoration-none">
<span class="action-tile-icon mb-2"><i class="fas fa-list-check"></i></span>
<span class="fw-bold">{% trans "Track Jobs" %}</span>
<span class="small text-muted d-none d-sm-block">{% trans "View stages" %}</span>
</a>
</div>
<div class="col-6 col-sm-4 col-md-4">
<a href="#document-management" data-bs-toggle="tab" class="btn btn-action-tile w-100 d-grid text-center text-dark text-decoration-none">
<span class="action-tile-icon mb-2"><i class="fas fa-cloud-upload-alt"></i></span>
<span class="fw-bold">{% trans "Manage Documents" %}</span>
<span class="small text-muted d-none d-sm-block">{% trans "Upload/View files" %}</span>
</a>
</div>
<div class="col-12 col-sm-4 col-md-4">
<a href="{% url 'kaauh_career' %}" class="btn btn-action-tile w-100 d-grid text-center text-dark text-decoration-none">
<span class="action-tile-icon mb-2"><i class="fas fa-search"></i></span>
<span class="fw-bold">{% trans "Find New Careers" %}</span>
<span class="small text-muted d-none d-sm-block">{% trans "Explore open roles" %}</span>
</a>
</div>
</div> {% endcomment %}
</div> </div>
<div class="tab-pane fade" id="applications-history" role="tabpanel" aria-labelledby="applications-tab"> <div class="tab-pane fade" id="applications-history" role="tabpanel" aria-labelledby="applications-tab">
@ -499,7 +606,7 @@
</h5> </h5>
<p class="text-muted small mb-0"> <p class="text-muted small mb-0">
<i class="fas fa-calendar-alt me-1"></i> <i class="fas fa-calendar-alt me-1"></i>
{% trans "Applied" %}: {{ application.created_at|date:"d M Y" }} {% trans "Applied" %}: {{ application.applied_date|date:"d M Y" }}
</p> </p>
</div> </div>
</div> </div>
@ -508,16 +615,16 @@
<div class="mb-3"> <div class="mb-3">
<div class="d-flex justify-content-between align-items-center mb-2"> <div class="d-flex justify-content-between align-items-center mb-2">
<span class="text-muted small fw-medium">{% trans "Current Stage" %}</span> <span class="text-muted small fw-medium">{% trans "Current Stage" %}</span>
<span class="badge badge-stage bg-primary-theme text-white"> <span class="badge badge-stage bg-info text-white">
{{ application.stage }} {{ application.stage }}
</span> </span>
</div> </div>
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
<span class="text-muted small fw-medium">{% trans "Status" %}</span> <span class="text-muted small fw-medium">{% trans "Status" %}</span>
{% if application.is_active %} {% if application.is_active %}
<span class="badge badge-stage bg-primary-theme">{% trans "Active" %}</span> <span class="badge badge-stage bg-success">{% trans "Active" %}</span>
{% else %} {% else %}
<span class="badge badge-stage bg-danger text-dark">{% trans "Closed" %}</span> <span class="badge badge-stage bg-warning text-dark">{% trans "Closed" %}</span>
{% endif %} {% endif %}
</div> </div>
</div> </div>
@ -536,7 +643,8 @@
</div> </div>
{% else %} {% else %}
<div class="alert alert-info text-center p-5 rounded-3" style="border: 1px dashed var(--kaauh-border); background-color: var(--kaauh-teal-light);"> <div class="alert alert-info text-center p-5 rounded-3"
style="border: 1px dashed var(--kaauh-border); background-color: var(--kaauh-teal-light);">
<i class="fas fa-info-circle fa-2x mb-3 text-primary-theme"></i> <i class="fas fa-info-circle fa-2x mb-3 text-primary-theme"></i>
<h5 class="mb-3 fw-bold text-primary-theme">{% trans "You haven't submitted any applications yet." %}</h5> <h5 class="mb-3 fw-bold text-primary-theme">{% trans "You haven't submitted any applications yet." %}</h5>
<a href="{% url 'kaauh_career' %}" class="ms-3 btn btn-main-action mt-2 rounded-pill px-4"> <a href="{% url 'kaauh_career' %}" class="ms-3 btn btn-main-action mt-2 rounded-pill px-4">
@ -551,7 +659,9 @@
<p class="text-gray-subtle">{% trans "You can upload and manage your resume, certificates, and professional documents here. These documents will be attached to your applications." %}</p> <p class="text-gray-subtle">{% trans "You can upload and manage your resume, certificates, and professional documents here. These documents will be attached to your applications." %}</p>
<button type="button" class="btn btn-main-action rounded-pill px-4 me-3 d-block d-sm-inline-block w-100 w-sm-auto mb-4" data-bs-toggle="modal" data-bs-target="#documentUploadModal"> <button type="button"
class="btn btn-main-action rounded-pill px-4 me-3 d-block d-sm-inline-block w-100 w-sm-auto mb-4"
data-bs-toggle="modal" data-bs-target="#documentUploadModal">
<i class="fas fa-cloud-upload-alt me-2"></i> {% trans "Upload New Document" %} <i class="fas fa-cloud-upload-alt me-2"></i> {% trans "Upload New Document" %}
</button> </button>
@ -560,15 +670,18 @@
{# Document List #} {# Document List #}
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
{% for document in documents %} {% for document in documents %}
<li class="list-group-item d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center bg-white p-3"> <li
class="list-group-item d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center bg-white p-3">
<div class="mb-2 mb-sm-0 fw-medium"> <div class="mb-2 mb-sm-0 fw-medium">
<i class="fas fa-file-pdf me-2 text-primary-theme"></i> <strong>{{document.document_type|title }}</strong> <i class="fas fa-file-pdf me-2 text-primary-theme"></i> <strong>{{document.document_type|title }}</strong>
<span class="text-muted small">({{ document.file.name|split:"/"|last }})</span> <span class="text-muted small">({{ document.file.name|split:"/"|last }})</span>
</div> </div>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center mt-2 mt-sm-0">
<span class="text-muted small me-3">{% trans "Uploaded:" %} {{ document.uploaded_at|date:"d M Y" }}</span> <span class="text-muted small me-3 d-none d-sm-inline">{% trans "Uploaded:" %} {{document.uploaded_at|date:"d M Y" }}</span>
<a href="{{ document.file.url }}" target="_blank" class="btn btn-sm btn-outline-secondary me-2"><i class="fas fa-eye"></i></a> <a href="{{ document.file.url }}" target="_blank"
<a href="{% url 'candidate_document_delete' document.id %}" class="btn btn-sm btn-outline-danger" onclick="return confirm('{% trans "Are you sure you want to delete this document?" %}')"><i class="fas fa-trash-alt"></i></a> class="btn btn-sm btn-outline-secondary me-2"><i class="fas fa-eye"></i></a>
<a href="{% url 'candidate_document_delete' document.id %}"
class="btn btn-sm btn-outline-danger" onclick="return confirm('{% trans " Are you sure you want to delete this document?" %}')"><i class="fas fa-trash-alt"></i></a>
</div> </div>
</li> </li>
{% empty %} {% empty %}
@ -581,32 +694,41 @@
</div> </div>
{% comment %} <div class="tab-pane fade" id="account-settings" role="tabpanel" aria-labelledby="settings-tab"> {% comment %} <div class="tab-pane fade" id="account-settings" role="tabpanel"
aria-labelledby="settings-tab">
<h4 class="mb-4 fw-bold text-gray-subtle">{% trans "Security & Preferences" %}</h4> <h4 class="mb-4 fw-bold text-gray-subtle">{% trans "Security & Preferences" %}</h4>
<div class="row g-4"> <div class="row g-4">
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<div class="card kaauh-card p-4 h-100 bg-white"> <div class="card kaauh-card p-4 h-100 bg-white">
<h5 class="fw-bold"><i class="fas fa-key me-2 text-primary-theme"></i> {% trans "Password Security" %}</h5> <h5 class="fw-bold"><i class="fas fa-key me-2 text-primary-theme"></i> {% trans "Password
<p class="text-muted small">{% trans "Update your password regularly to keep your account secure." %}</p> Security" %}</h5>
<button type="button" class="btn btn-outline-secondary mt-auto w-100 py-2 fw-medium" data-bs-toggle="modal" data-bs-target="#passwordModal"> <p class="text-muted small">{% trans "Update your password regularly to keep your account
secure." %}</p>
<button type="button" class="btn btn-outline-secondary mt-auto w-100 py-2 fw-medium"
data-bs-toggle="modal" data-bs-target="#passwordModal">
{% trans "Change Password" %} {% trans "Change Password" %}
</button> </button>
</div> </div>
</div> </div>
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<div class="card kaauh-card p-4 h-100 bg-white"> <div class="card kaauh-card p-4 h-100 bg-white">
<h5 class="fw-bold"><i class="fas fa-image me-2 text-primary-theme"></i> {% trans "Profile Image" %}</h5> <h5 class="fw-bold"><i class="fas fa-image me-2 text-primary-theme"></i> {% trans "Profile
<p class="text-muted small">{% trans "Update your profile picture to personalize your account." %}</p> Image" %}</h5>
<button type="button" class="btn btn-outline-secondary mt-auto w-100 py-2 fw-medium" data-bs-toggle="modal" data-bs-target="#profileImageModal"> <p class="text-muted small">{% trans "Update your profile picture to personalize your
account." %}</p>
<button type="button" class="btn btn-outline-secondary mt-auto w-100 py-2 fw-medium"
data-bs-toggle="modal" data-bs-target="#profileImageModal">
{% trans "Change Image" %} {% trans "Change Image" %}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<div class="alert mt-5 py-3" style="background-color: var(--danger-subtle); color: #842029; border: 1px solid #f5c2c7; border-radius: 8px;"> <div class="alert mt-5 py-3"
<i class="fas fa-exclamation-triangle me-2"></i> {% trans "To delete your profile, please contact HR support." %} style="background-color: var(--danger-subtle); color: #842029; border: 1px solid #f5c2c7; border-radius: 8px;">
<i class="fas fa-exclamation-triangle me-2"></i> {% trans "To delete your profile, please contact HR
support." %}
</div> </div>
</div> {% endcomment %} </div> {% endcomment %}
@ -637,7 +759,8 @@
</div> </div>
<!-- Profile Image Modal (Reused from portal_profile.html) --> <!-- Profile Image Modal (Reused from portal_profile.html) -->
<div class="modal fade mt-4" id="profileImageModal" tabindex="-1" aria-labelledby="profileImageModalLabel" aria-hidden="true"> <div class="modal fade mt-4" id="profileImageModal" tabindex="-1" aria-labelledby="profileImageModalLabel"
aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -645,7 +768,8 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form method="post" action="{% url 'user_profile_image_update' candidate.pk %}" enctype="multipart/form-data" > <form method="post" action="{% url 'user_profile_image_update' candidate.pk %}"
enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
@ -658,7 +782,8 @@
<small class="text-muted d-block">{% trans "Current Image:" %}</small> <small class="text-muted d-block">{% trans "Current Image:" %}</small>
{# Display Link to View Current Image #} {# Display Link to View Current Image #}
<a href="{{ profile_form.instance.profile_image.url }}" target="_blank" class="d-inline-block me-3 text-info fw-bold"> <a href="{{ profile_form.instance.profile_image.url }}" target="_blank"
class="d-inline-block me-3 text-info fw-bold">
{% trans "View/Download" %} ({{ profile_form.instance.profile_image.name }}) {% trans "View/Download" %} ({{ profile_form.instance.profile_image.name }})
</a> </a>
@ -672,7 +797,7 @@
{# 2. Explicitly render the 'Clear' checkbox and the Change input #} {# 2. Explicitly render the 'Clear' checkbox and the Change input #}
<div class="form-check mt-3"> <div class="form-check mt-3">
{# The ClearableFileInput widget renders itself here. It provides the "Clear" checkbox and the "Change" input field. #}
{{ profile_form.profile_image }} {{ profile_form.profile_image }}
</div> </div>
@ -701,7 +826,8 @@
</div> </div>
<!-- Document Upload Modal --> <!-- Document Upload Modal -->
<div class="modal fade mt-4" id="documentUploadModal" tabindex="-1" aria-labelledby="documentUploadModalLabel" aria-hidden="true"> <div class="modal fade mt-4" id="documentUploadModal" tabindex="-1" aria-labelledby="documentUploadModalLabel"
aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -709,7 +835,8 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form method="post" action="{% url 'document_upload' candidate.id %}" enctype="multipart/form-data" id="documentUploadForm"> <form method="post" action="{% url 'document_upload' candidate.id %}" enctype="multipart/form-data"
id="documentUploadForm">
<input type="hidden" name="upload_target" value="person"> <input type="hidden" name="upload_target" value="person">
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">