modal for job status update
This commit is contained in:
parent
cc540517a9
commit
e0b88f8b22
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -465,3 +465,11 @@ class InterviewScheduleForm(forms.ModelForm):
|
|||||||
working_days = self.cleaned_data.get('working_days')
|
working_days = self.cleaned_data.get('working_days')
|
||||||
# Convert string values to integers
|
# Convert string values to integers
|
||||||
return [int(day) for day in working_days]
|
return [int(day) for day in working_days]
|
||||||
|
|
||||||
|
class JobStatusUpdateForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model=JobPosting
|
||||||
|
|
||||||
|
fields=[
|
||||||
|
'status'
|
||||||
|
]
|
||||||
@ -13,7 +13,8 @@ urlpatterns = [
|
|||||||
# path('jobs/<slug:slug>/delete/', views., name='job_delete'),
|
# path('jobs/<slug:slug>/delete/', views., name='job_delete'),
|
||||||
path('jobs/<slug:slug>/', views.job_detail, name='job_detail'),
|
path('jobs/<slug:slug>/', views.job_detail, name='job_detail'),
|
||||||
path('jobs/<slug:slug>/candidate/', views.job_detail_candidate, name='job_detail_candidate'),
|
path('jobs/<slug:slug>/candidate/', views.job_detail_candidate, name='job_detail_candidate'),
|
||||||
path('jobs/<slug:slug>/candidate/application/success', views.application_sucess, name='application_success'),
|
path('jobs/<slug:slug>/candidate/application/success', views.application_success, name='application_success'),
|
||||||
|
|
||||||
|
|
||||||
# LinkedIn Integration URLs
|
# LinkedIn Integration URLs
|
||||||
path('jobs/<slug:slug>/post-to-linkedin/', views.post_to_linkedin, name='post_to_linkedin'),
|
path('jobs/<slug:slug>/post-to-linkedin/', views.post_to_linkedin, name='post_to_linkedin'),
|
||||||
|
|||||||
@ -10,7 +10,7 @@ from django.db.models import Q
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from .forms import ZoomMeetingForm,JobPostingForm,FormTemplateForm,InterviewScheduleForm
|
from .forms import ZoomMeetingForm,JobPostingForm,FormTemplateForm,InterviewScheduleForm,JobStatusUpdateForm
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
@ -226,6 +226,7 @@ def job_detail(request, slug):
|
|||||||
"""View details of a specific job"""
|
"""View details of a specific job"""
|
||||||
job = get_object_or_404(JobPosting, slug=slug)
|
job = get_object_or_404(JobPosting, slug=slug)
|
||||||
|
|
||||||
|
|
||||||
# Get all candidates for this job, ordered by most recent
|
# Get all candidates for this job, ordered by most recent
|
||||||
candidates = job.candidates.all().order_by('-created_at')
|
candidates = job.candidates.all().order_by('-created_at')
|
||||||
|
|
||||||
@ -235,6 +236,27 @@ def job_detail(request, slug):
|
|||||||
interview_count = candidates.filter(stage='Interview').count()
|
interview_count = candidates.filter(stage='Interview').count()
|
||||||
offer_count = candidates.filter(stage='Offer').count()
|
offer_count = candidates.filter(stage='Offer').count()
|
||||||
|
|
||||||
|
status_form = JobStatusUpdateForm(instance=job)
|
||||||
|
|
||||||
|
# 2. Check for POST request (Status Update Submission)
|
||||||
|
if request.method == 'POST':
|
||||||
|
|
||||||
|
status_form = JobStatusUpdateForm(request.POST, instance=job)
|
||||||
|
|
||||||
|
if status_form.is_valid():
|
||||||
|
status_form.save()
|
||||||
|
|
||||||
|
# Add a success message
|
||||||
|
messages.success(request, f"Status for '{job.title}' updated to '{job.get_status_display()}' successfully!")
|
||||||
|
|
||||||
|
|
||||||
|
return redirect('job_detail', slug=slug)
|
||||||
|
else:
|
||||||
|
|
||||||
|
messages.error(request, "Failed to update status due to validation errors.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'job': job,
|
'job': job,
|
||||||
'candidates': candidates,
|
'candidates': candidates,
|
||||||
@ -242,6 +264,7 @@ def job_detail(request, slug):
|
|||||||
'applied_count': applied_count,
|
'applied_count': applied_count,
|
||||||
'interview_count': interview_count,
|
'interview_count': interview_count,
|
||||||
'offer_count': offer_count,
|
'offer_count': offer_count,
|
||||||
|
'status_form':status_form
|
||||||
}
|
}
|
||||||
return render(request, 'jobs/job_detail.html', context)
|
return render(request, 'jobs/job_detail.html', context)
|
||||||
|
|
||||||
@ -345,6 +368,13 @@ def applicant_job_detail(request,slug):
|
|||||||
job=get_object_or_404(JobPosting,slug=slug,status='ACTIVE')
|
job=get_object_or_404(JobPosting,slug=slug,status='ACTIVE')
|
||||||
return render(request,'jobs/applicant_job_detail.html',{'job':job})
|
return render(request,'jobs/applicant_job_detail.html',{'job':job})
|
||||||
|
|
||||||
|
def application_success(request,slug):
|
||||||
|
job=get_object_or_404(JobPosting,slug=slug)
|
||||||
|
return render(request,'jobs/application_success.html',{'job':job})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Form Preview Views
|
# Form Preview Views
|
||||||
# from django.http import JsonResponse
|
# from django.http import JsonResponse
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404,redirect
|
||||||
|
from django.contrib import messages
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from . import models
|
from . import models
|
||||||
from django.utils.translation import get_language
|
from django.utils.translation import get_language
|
||||||
@ -188,10 +189,13 @@ class CandidateDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
|
|||||||
slug_url_kwarg = 'slug'
|
slug_url_kwarg = 'slug'
|
||||||
|
|
||||||
|
|
||||||
def job_detail(request, slug):
|
# def job_detail(request, slug):
|
||||||
job = get_object_or_404(models.JobPosting, slug=slug, status='Published')
|
# job = get_object_or_404(models.JobPosting, slug=slug, status='Published')
|
||||||
form = forms.CandidateForm()
|
# form = forms.CandidateForm()
|
||||||
return render(request, 'jobs/job_detail.html', {'job': job, 'form': form})
|
|
||||||
|
# return render(request, 'jobs/job_detail.html', {'job': job, 'form': form})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
@ -460,9 +460,9 @@
|
|||||||
|
|
||||||
<nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
|
<nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand text-white fw-bold" href="/">
|
<span class="navbar-brand text-white fw-bold">
|
||||||
<img src="{% static 'image/kaauh.jpeg' %}" alt="{% translate 'KAAUH IMAGE' %}" style="height: 50px; margin-right: 10px;">
|
<img src="{% static 'image/kaauh.jpeg' %}" alt="{% translate 'KAAUH IMAGE' %}" style="height: 50px; margin-right: 10px;">
|
||||||
</a>
|
</span>
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
|||||||
@ -122,9 +122,9 @@
|
|||||||
|
|
||||||
<nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
|
<nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand text-white fw-bold" href="/">
|
<span class="navbar-brand text-white fw-bold">
|
||||||
<img src="{% static 'image/kaauh.jpeg' %}" alt="{% translate 'KAAUH IMAGE' %}" style="height: 50px; margin-right: 10px;">
|
<img src="{% static 'image/kaauh.jpeg' %}" alt="{% translate 'KAAUH IMAGE' %}" style="height: 50px; margin-right: 10px;">
|
||||||
</a>
|
</span>
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
@ -152,7 +152,7 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-5 mt-3 main-content-area">
|
<div class="row mb-5 mt-5 main-content-area">
|
||||||
|
|
||||||
<div class="col-12 thank-you-card-wrapper">
|
<div class="col-12 thank-you-card-wrapper">
|
||||||
<div class="card shadow-lg thank-you-card">
|
<div class="card shadow-lg thank-you-card">
|
||||||
@ -168,7 +168,7 @@
|
|||||||
<h1 class="text-success-header">{% translate "Thank You!" %}</h1>
|
<h1 class="text-success-header">{% translate "Thank You!" %}</h1>
|
||||||
<h2 class="h4" style="color: #333;">{% translate "Your application has been submitted successfully" %}</h2>
|
<h2 class="h4" style="color: #333;">{% translate "Your application has been submitted successfully" %}</h2>
|
||||||
|
|
||||||
{# JOB INFO BLOCK #}
|
{% comment %} {# JOB INFO BLOCK #}
|
||||||
<div class="job-info-block">
|
<div class="job-info-block">
|
||||||
<p class="mb-2"><strong>{% translate "Position" %}:</strong> <span class="fw-bold">{{ job.title }}</span></p>
|
<p class="mb-2"><strong>{% translate "Position" %}:</strong> <span class="fw-bold">{{ job.title }}</span></p>
|
||||||
<p class="mb-2"><strong>{% translate "Job ID" %}:</strong> {{ job.internal_job_id }}</p>
|
<p class="mb-2"><strong>{% translate "Job ID" %}:</strong> {{ job.internal_job_id }}</p>
|
||||||
@ -176,14 +176,14 @@
|
|||||||
{% if job.application_deadline %}
|
{% if job.application_deadline %}
|
||||||
<p><strong>{% translate "Application Deadline" %}:</strong> {{ job.application_deadline|date:"F j, Y" }}</p>
|
<p><strong>{% translate "Application Deadline" %}:</strong> {{ job.application_deadline|date:"F j, Y" }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div> {% endcomment %}
|
||||||
|
|
||||||
<p style="font-size: 1rem; line-height: 1.6; color: #555;">
|
<p style="font-size: 1rem; line-height: 1.6; color: #555;">
|
||||||
{% translate "We appreciate your interest in joining our team. Our hiring team will review your application and contact you if there's a potential match for this position." %}
|
{% translate "We appreciate your interest in joining our team. Our hiring team will review your application and contact you if there's a potential match for this position." %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div style="margin-top: 30px;">
|
<div style="margin-top: 30px;">
|
||||||
<a href="{% url 'job_list' %}" class="btn btn-main-action btn-lg">
|
<a href="https://kaauh.edu.sa/career" class="btn btn-main-action btn-lg">
|
||||||
<i class="fas fa-arrow-left me-2"></i> {% translate "Return to Job Listings" %}
|
<i class="fas fa-arrow-left me-2"></i> {% translate "Return to Job Listings" %}
|
||||||
</a>
|
</a>
|
||||||
{# You can add a link to view the saved application here if applicable #}
|
{# You can add a link to view the saved application here if applicable #}
|
||||||
|
|||||||
@ -36,6 +36,8 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.7px;
|
letter-spacing: 0.7px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mapped color classes for status badges */
|
/* Mapped color classes for status badges */
|
||||||
@ -109,7 +111,6 @@
|
|||||||
/* ==================================== */
|
/* ==================================== */
|
||||||
|
|
||||||
.right-column-tabs {
|
.right-column-tabs {
|
||||||
/* Use the .card wrapper for the main structure */
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
border-bottom: 1px solid var(--kaauh-border);
|
border-bottom: 1px solid var(--kaauh-border);
|
||||||
@ -119,41 +120,38 @@
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
display: flex; /* Ensure the nav-items take up equal space */
|
display: flex;
|
||||||
}
|
}
|
||||||
.right-column-tabs .nav-item {
|
.right-column-tabs .nav-item {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.right-column-tabs .nav-link {
|
.right-column-tabs .nav-link {
|
||||||
/* Base style for all right column tabs */
|
padding: 0.9rem 1rem;
|
||||||
padding: 0.9rem 1rem; /* Slightly larger padding for better spacing */
|
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--kaauh-primary-text);
|
color: var(--kaauh-primary-text);
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
border-right: 1px solid var(--kaauh-border);
|
border-right: 1px solid var(--kaauh-border);
|
||||||
border-bottom: 1px solid var(--kaauh-border); /* Separator line */
|
border-bottom: 1px solid var(--kaauh-border);
|
||||||
background-color: #f8f9fa; /* Subtle background for non-active tabs */
|
background-color: #f8f9fa;
|
||||||
}
|
}
|
||||||
.right-column-tabs .nav-item:last-child .nav-link {
|
.right-column-tabs .nav-item:last-child .nav-link {
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
/* Active Tab */
|
|
||||||
.right-column-tabs .nav-link.active {
|
.right-column-tabs .nav-link.active {
|
||||||
background-color: white; /* Lift the active tab */
|
background-color: white;
|
||||||
color: var(--kaauh-teal-dark);
|
color: var(--kaauh-teal-dark);
|
||||||
border-bottom: 3px solid var(--kaauh-teal); /* Strong accent */
|
border-bottom: 3px solid var(--kaauh-teal);
|
||||||
border-right-color: transparent; /* Clean up border next to it */
|
border-right-color: transparent;
|
||||||
margin-bottom: -1px; /* Overlap the border for a cleaner look */
|
margin-bottom: -1px;
|
||||||
}
|
}
|
||||||
/* Hover state for non-active tabs */
|
|
||||||
.right-column-tabs .nav-link:not(.active):hover {
|
.right-column-tabs .nav-link:not(.active):hover {
|
||||||
background-color: #f0f4f7; /* Darken slightly on hover */
|
background-color: #f0f4f7;
|
||||||
color: var(--kaauh-teal);
|
color: var(--kaauh-teal);
|
||||||
}
|
}
|
||||||
.right-column-tabs .tab-content {
|
.right-column-tabs .tab-content {
|
||||||
padding: 1.5rem 1.25rem; /* Increased padding inside the content for breathing room */
|
padding: 1.5rem 1.25rem;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,13 +227,11 @@
|
|||||||
|
|
||||||
/* Table styling for the Applicant preview */
|
/* Table styling for the Applicant preview */
|
||||||
.table-applicants tbody tr:hover {
|
.table-applicants tbody tr:hover {
|
||||||
background-color: #f3f9f9; /* Light teal hover for rows */
|
background-color: #f3f9f9;
|
||||||
}
|
}
|
||||||
.table-applicants td {
|
.table-applicants td {
|
||||||
border-top: 1px solid var(--kaauh-border);
|
border-top: 1px solid var(--kaauh-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@ -249,10 +245,19 @@
|
|||||||
|
|
||||||
{# HEADER SECTION #}
|
{# HEADER SECTION #}
|
||||||
<div class="job-header-card d-flex justify-content-between align-items-center flex-wrap">
|
<div class="job-header-card d-flex justify-content-between align-items-center flex-wrap">
|
||||||
<h2>{{job}}</h2>
|
<div>
|
||||||
<span class="badge bg-{{ job.status|lower|striptags|yesno:'success,warning,secondary,danger' }} status-badge">
|
<h2 class="mb-1">{{ job.title }}</h2>
|
||||||
{{ job.get_status_display }}
|
<small class="text-light">{{ job.internal_job_id }}</small>
|
||||||
</span>
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center gap-2">
|
||||||
|
<span class="badge bg-success status-badge">
|
||||||
|
{{ job.get_status_display }}
|
||||||
|
<button type="button" class="btn btn-outline-light btn-sm ms-2" data-bs-toggle="modal" data-bs-target="#editStatusModal">
|
||||||
|
<i class="fas fa-edit text-primary"></i>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# LEFT TABS NAVIGATION #}
|
{# LEFT TABS NAVIGATION #}
|
||||||
@ -566,4 +571,37 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% include "jobs/partials/image_upload.html" %}
|
{% include "jobs/partials/image_upload.html" %}
|
||||||
|
|
||||||
|
<!-- JOB STATUS MODAL-->
|
||||||
|
<div class="modal fade" id="editStatusModal" tabindex="-1" aria-labelledby="editStatusModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<form method="post" action="{% url 'job_detail' slug=job.slug %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="editStatusModalLabel">{% trans "Edit Job Status" %}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans 'Close' %}"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
{% if status_form %}
|
||||||
|
<label for="{{ status_form.status.id_for_label }}" class="form-label">{% trans "Select New Status" %}</label>
|
||||||
|
{{ status_form.status }}
|
||||||
|
{% if status_form.status.errors %}
|
||||||
|
<div class="text-danger small mt-1">{{ status_form.status.errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<div class="text-danger">{% trans "Status form not available. Please check your view." %}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||||
|
<button type="submit" class="btn btn-main-action">{% trans "Save Changes" %}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -135,9 +135,9 @@
|
|||||||
|
|
||||||
<nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
|
<nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand text-white fw-bold" href="/">
|
<span class="navbar-brand text-white fw-bold">
|
||||||
<img src="{% static 'image/kaauh.jpeg' %}" alt="{% translate 'KAAUH IMAGE' %}" style="height: 50px; margin-right: 10px;">
|
<img src="{% static 'image/kaauh.jpeg' %}" alt="{% translate 'KAAUH IMAGE' %}" style="height: 50px; margin-right: 10px;">
|
||||||
</a>
|
</span>
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
|||||||
0
templates/jobs/partials/job_status_form.html
Normal file
0
templates/jobs/partials/job_status_form.html
Normal file
Loading…
x
Reference in New Issue
Block a user