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.
@ -464,4 +464,12 @@ class InterviewScheduleForm(forms.ModelForm):
|
||||
def clean_working_days(self):
|
||||
working_days = self.cleaned_data.get('working_days')
|
||||
# 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>/', views.job_detail, name='job_detail'),
|
||||
path('jobs/<slug:slug>/candidate/', views.job_detail_candidate, name='job_detail_candidate'),
|
||||
path('jobs/<slug:slug>/candidate/application/success', views.application_sucess, name='application_success'),
|
||||
path('jobs/<slug:slug>/candidate/application/success', views.application_success, name='application_success'),
|
||||
|
||||
|
||||
# LinkedIn Integration URLs
|
||||
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.conf import settings
|
||||
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 django.contrib import messages
|
||||
from django.core.paginator import Paginator
|
||||
@ -225,6 +225,7 @@ def edit_job(request,slug):
|
||||
def job_detail(request, slug):
|
||||
"""View details of a specific job"""
|
||||
job = get_object_or_404(JobPosting, slug=slug)
|
||||
|
||||
|
||||
# Get all candidates for this job, ordered by most recent
|
||||
candidates = job.candidates.all().order_by('-created_at')
|
||||
@ -235,6 +236,27 @@ def job_detail(request, slug):
|
||||
interview_count = candidates.filter(stage='Interview').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 = {
|
||||
'job': job,
|
||||
'candidates': candidates,
|
||||
@ -242,6 +264,7 @@ def job_detail(request, slug):
|
||||
'applied_count': applied_count,
|
||||
'interview_count': interview_count,
|
||||
'offer_count': offer_count,
|
||||
'status_form':status_form
|
||||
}
|
||||
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')
|
||||
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
|
||||
# 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 . import models
|
||||
from django.utils.translation import get_language
|
||||
@ -188,10 +189,13 @@ class CandidateDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
|
||||
slug_url_kwarg = 'slug'
|
||||
|
||||
|
||||
def job_detail(request, slug):
|
||||
job = get_object_or_404(models.JobPosting, slug=slug, status='Published')
|
||||
form = forms.CandidateForm()
|
||||
return render(request, 'jobs/job_detail.html', {'job': job, 'form': form})
|
||||
# def job_detail(request, slug):
|
||||
# job = get_object_or_404(models.JobPosting, slug=slug, status='Published')
|
||||
# form = forms.CandidateForm()
|
||||
|
||||
# return render(request, 'jobs/job_detail.html', {'job': job, 'form': form})
|
||||
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
|
||||
@ -460,9 +460,9 @@
|
||||
|
||||
<nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
|
||||
<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;">
|
||||
</a>
|
||||
</span>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<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;">
|
||||
<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;">
|
||||
</a>
|
||||
</span>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
@ -152,7 +152,7 @@
|
||||
</nav>
|
||||
|
||||
<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="card shadow-lg thank-you-card">
|
||||
@ -168,7 +168,7 @@
|
||||
<h1 class="text-success-header">{% translate "Thank You!" %}</h1>
|
||||
<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">
|
||||
<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>
|
||||
@ -176,14 +176,14 @@
|
||||
{% if job.application_deadline %}
|
||||
<p><strong>{% translate "Application Deadline" %}:</strong> {{ job.application_deadline|date:"F j, Y" }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div> {% endcomment %}
|
||||
|
||||
<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." %}
|
||||
</p>
|
||||
|
||||
<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" %}
|
||||
</a>
|
||||
{# You can add a link to view the saved application here if applicable #}
|
||||
|
||||
@ -36,6 +36,8 @@
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.7px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Mapped color classes for status badges */
|
||||
@ -109,7 +111,6 @@
|
||||
/* ==================================== */
|
||||
|
||||
.right-column-tabs {
|
||||
/* Use the .card wrapper for the main structure */
|
||||
padding: 0;
|
||||
margin-bottom: 0;
|
||||
border-bottom: 1px solid var(--kaauh-border);
|
||||
@ -119,41 +120,38 @@
|
||||
margin-bottom: 0;
|
||||
border-bottom: none;
|
||||
background-color: transparent;
|
||||
display: flex; /* Ensure the nav-items take up equal space */
|
||||
display: flex;
|
||||
}
|
||||
.right-column-tabs .nav-item {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
.right-column-tabs .nav-link {
|
||||
/* Base style for all right column tabs */
|
||||
padding: 0.9rem 1rem; /* Slightly larger padding for better spacing */
|
||||
padding: 0.9rem 1rem;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--kaauh-primary-text);
|
||||
border-radius: 0;
|
||||
border-right: 1px solid var(--kaauh-border);
|
||||
border-bottom: 1px solid var(--kaauh-border); /* Separator line */
|
||||
background-color: #f8f9fa; /* Subtle background for non-active tabs */
|
||||
border-bottom: 1px solid var(--kaauh-border);
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.right-column-tabs .nav-item:last-child .nav-link {
|
||||
border-right: none;
|
||||
}
|
||||
/* Active Tab */
|
||||
.right-column-tabs .nav-link.active {
|
||||
background-color: white; /* Lift the active tab */
|
||||
background-color: white;
|
||||
color: var(--kaauh-teal-dark);
|
||||
border-bottom: 3px solid var(--kaauh-teal); /* Strong accent */
|
||||
border-right-color: transparent; /* Clean up border next to it */
|
||||
margin-bottom: -1px; /* Overlap the border for a cleaner look */
|
||||
border-bottom: 3px solid var(--kaauh-teal);
|
||||
border-right-color: transparent;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
/* Hover state for non-active tabs */
|
||||
.right-column-tabs .nav-link:not(.active):hover {
|
||||
background-color: #f0f4f7; /* Darken slightly on hover */
|
||||
background-color: #f0f4f7;
|
||||
color: var(--kaauh-teal);
|
||||
}
|
||||
.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;
|
||||
}
|
||||
|
||||
@ -229,13 +227,11 @@
|
||||
|
||||
/* Table styling for the Applicant preview */
|
||||
.table-applicants tbody tr:hover {
|
||||
background-color: #f3f9f9; /* Light teal hover for rows */
|
||||
background-color: #f3f9f9;
|
||||
}
|
||||
.table-applicants td {
|
||||
border-top: 1px solid var(--kaauh-border);
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
@ -249,10 +245,19 @@
|
||||
|
||||
{# HEADER SECTION #}
|
||||
<div class="job-header-card d-flex justify-content-between align-items-center flex-wrap">
|
||||
<h2>{{job}}</h2>
|
||||
<span class="badge bg-{{ job.status|lower|striptags|yesno:'success,warning,secondary,danger' }} status-badge">
|
||||
{{ job.get_status_display }}
|
||||
</span>
|
||||
<div>
|
||||
<h2 class="mb-1">{{ job.title }}</h2>
|
||||
<small class="text-light">{{ job.internal_job_id }}</small>
|
||||
</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>
|
||||
|
||||
{# LEFT TABS NAVIGATION #}
|
||||
@ -566,4 +571,37 @@
|
||||
</div>
|
||||
|
||||
{% 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 %}
|
||||
@ -135,9 +135,9 @@
|
||||
|
||||
<nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
|
||||
<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;">
|
||||
</a>
|
||||
</span>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<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