first refactoring in the ai_overview branch for the candidate to application for views and urls name

This commit is contained in:
Faheed 2025-11-26 12:59:59 +03:00
parent 473dc8e00f
commit 1ad85b82e1
57 changed files with 394 additions and 393 deletions

View File

@ -26,7 +26,7 @@ urlpatterns = [
path('application/<slug:template_slug>/', views.application_submit_form, name='application_submit_form'), path('application/<slug:template_slug>/', views.application_submit_form, name='application_submit_form'),
path('application/<slug:template_slug>/submit/', views.application_submit, name='application_submit'), path('application/<slug:template_slug>/submit/', views.application_submit, name='application_submit'),
path('application/<slug:slug>/apply/', views.application_detail, name='application_detail'), path('application/<slug:slug>/apply/', views.application_detail, name='application_detail'),
path('application/<slug:slug>/signup/', views.candidate_signup, name='candidate_signup'), path('application/<slug:slug>/signup/', views.application_signup, name='application_signup'),
path('application/<slug:slug>/success/', views.application_success, name='application_success'), path('application/<slug:slug>/success/', views.application_success, name='application_success'),
# path('application/applicant/profile', views.applicant_profile, name='applicant_profile'), # path('application/applicant/profile', views.applicant_profile, name='applicant_profile'),

View File

@ -79,10 +79,10 @@ def debug_url_routing():
print(f"Error with document_upload URL: {e}") print(f"Error with document_upload URL: {e}")
try: try:
url2 = reverse('candidate_document_upload', kwargs={'slug': application.slug}) url2 = reverse('pplication_document_upload', kwargs={'slug': application.slug})
print(f"URL pattern 2 (candidate_document_upload): {url2}") print(f"URL pattern 2 (pplication_document_upload): {url2}")
except Exception as e: except Exception as e:
print(f"Error with candidate_document_upload URL: {e}") print(f"Error with pplication_document_upload URL: {e}")
# Test GET request to see if the URL is accessible # Test GET request to see if the URL is accessible
try: try:

View File

@ -24,7 +24,7 @@ class CustomAuthenticationBackend(AuthenticationBackend):
elif user.user_type == 'agency': elif user.user_type == 'agency':
redirect_url = reverse('agency_portal_dashboard') redirect_url = reverse('agency_portal_dashboard')
elif user.user_type == 'candidate': elif user.user_type == 'candidate':
redirect_url = reverse('candidate_portal_dashboard') redirect_url = reverse('applicant_portal_dashboard')
else: else:
# Fallback to default redirect URL if user type is unknown # Fallback to default redirect URL if user type is unknown
redirect_url = '/' redirect_url = '/'

View File

@ -55,7 +55,7 @@ def user_type_required(allowed_types=None, login_url=None):
if user.user_type == 'agency': if user.user_type == 'agency':
return redirect('agency_portal_dashboard') return redirect('agency_portal_dashboard')
elif user.user_type == 'candidate': elif user.user_type == 'candidate':
return redirect('candidate_portal_dashboard') return redirect('applicant_portal_dashboard')
else: else:
return redirect('dashboard') return redirect('dashboard')
@ -92,7 +92,7 @@ class UserTypeRequiredMixin(AccessMixin):
if request.user.user_type == 'agency': if request.user.user_type == 'agency':
return redirect('agency_portal_dashboard') return redirect('agency_portal_dashboard')
elif request.user.user_type == 'candidate': elif request.user.user_type == 'candidate':
return redirect('candidate_portal_dashboard') return redirect('applicant_portal_dashboard')
else: else:
return redirect('dashboard') return redirect('dashboard')

View File

@ -2344,7 +2344,7 @@ class MessageForm(forms.ModelForm):
) )
class CandidateSignupForm(forms.ModelForm): class ApplicantSignupForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control'})) password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control'}))
confirm_password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control'})) confirm_password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control'}))

View File

@ -19,8 +19,8 @@ from .forms import (
CandidateStageForm, InterviewScheduleForm, CandidateSignupForm CandidateStageForm, InterviewScheduleForm, CandidateSignupForm
) )
from .views import ( from .views import (
ZoomMeetingListView, ZoomMeetingCreateView, job_detail, candidate_screening_view, ZoomMeetingListView, ZoomMeetingCreateView, job_detail, applications_screening_view,
candidate_exam_view, candidate_interview_view, api_schedule_candidate_meeting applications_exam_view, applications_interview_view, api_schedule_application_meeting
) )
from .views_frontend import CandidateListView, JobListView from .views_frontend import CandidateListView, JobListView
from .utils import create_zoom_meeting, get_candidates_from_request from .utils import create_zoom_meeting, get_candidates_from_request
@ -189,32 +189,32 @@ class ViewTests(BaseTestCase):
def test_candidate_screening_view(self): def test_candidate_screening_view(self):
"""Test candidate_screening_view""" """Test candidate_screening_view"""
response = self.client.get(reverse('candidate_screening_view', kwargs={'slug': self.job.slug})) response = self.client.get(reverse('applications_screening_view', kwargs={'slug': self.job.slug}))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertContains(response, 'John Doe') self.assertContains(response, 'John Doe')
def test_candidate_screening_view_filters(self): def test_candidate_screening_view_filters(self):
"""Test candidate_screening_view with filters""" """Test candidate_screening_view with filters"""
response = self.client.get( response = self.client.get(
reverse('candidate_screening_view', kwargs={'slug': self.job.slug}), reverse('applications_screening_view', kwargs={'slug': self.job.slug}),
{'min_ai_score': '50', 'tier1_count': '5'} {'min_ai_score': '50', 'tier1_count': '5'}
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_candidate_exam_view(self): def test_candidate_exam_view(self):
"""Test candidate_exam_view""" """Test candidate_exam_view"""
response = self.client.get(reverse('candidate_exam_view', kwargs={'slug': self.job.slug})) response = self.client.get(reverse('applications_exam_view', kwargs={'slug': self.job.slug}))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertContains(response, 'John Doe') self.assertContains(response, 'John Doe')
def test_candidate_interview_view(self): def test_candidate_interview_view(self):
"""Test candidate_interview_view""" """Test applications_interview_view"""
response = self.client.get(reverse('candidate_interview_view', kwargs={'slug': self.job.slug})) response = self.client.get(reverse('applications_interview_view', kwargs={'slug': self.job.slug}))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@patch('recruitment.views.create_zoom_meeting') @patch('recruitment.views.create_zoom_meeting')
def test_schedule_candidate_meeting(self, mock_create_zoom): def test_schedule_candidate_meeting(self, mock_create_zoom):
"""Test api_schedule_candidate_meeting view""" """Test api_schedule_application_meeting view"""
mock_create_zoom.return_value = { mock_create_zoom.return_value = {
'status': 'success', 'status': 'success',
'meeting_details': { 'meeting_details': {
@ -231,7 +231,7 @@ class ViewTests(BaseTestCase):
'duration': 60 'duration': 60
} }
response = self.client.post( response = self.client.post(
reverse('api_schedule_candidate_meeting', reverse('api_schedule_application_meeting',
kwargs={'job_slug': self.job.slug, 'candidate_pk': self.candidate.pk}), kwargs={'job_slug': self.job.slug, 'candidate_pk': self.candidate.pk}),
data data
) )
@ -478,7 +478,7 @@ class PerformanceTests(BaseTestCase):
) )
# Test pagination # Test pagination
response = self.client.get(reverse('candidate_list')) response = self.client.get(reverse('application_list'))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Candidate') self.assertContains(response, 'Candidate')

View File

@ -33,8 +33,8 @@ from .forms import (
ApplicationStageForm, InterviewScheduleForm, BreakTimeFormSet ApplicationStageForm, InterviewScheduleForm, BreakTimeFormSet
) )
from .views import ( from .views import (
ZoomMeetingListView, ZoomMeetingCreateView, job_detail, candidate_screening_view, ZoomMeetingListView, ZoomMeetingCreateView, job_detail, applications_screening_view,
candidate_exam_view, candidate_interview_view, api_schedule_candidate_meeting, applications_exam_view, applications_interview_view, api_schedule_application_meeting,
schedule_interviews_view, confirm_schedule_interviews_view, _handle_preview_submission, schedule_interviews_view, confirm_schedule_interviews_view, _handle_preview_submission,
_handle_confirm_schedule, _handle_get_request _handle_confirm_schedule, _handle_get_request
) )
@ -421,27 +421,27 @@ class AdvancedViewTests(TestCase):
) )
# Test search by name # Test search by name
response = self.client.get(reverse('candidate_list'), { response = self.client.get(reverse('application_list'), {
'search': 'Jane' 'search': 'Jane'
}) })
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Jane Smith') self.assertContains(response, 'Jane Smith')
# Test search by email # Test search by email
response = self.client.get(reverse('candidate_list'), { response = self.client.get(reverse('application_list'), {
'search': 'bob@example.com' 'search': 'bob@example.com'
}) })
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Bob Johnson') self.assertContains(response, 'Bob Johnson')
# Test filter by job # Test filter by job
response = self.client.get(reverse('candidate_list'), { response = self.client.get(reverse('application_list'), {
'job': self.job.slug 'job': self.job.slug
}) })
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
# Test filter by stage # Test filter by stage
response = self.client.get(reverse('candidate_list'), { response = self.client.get(reverse('application_list'), {
'stage': 'Exam' 'stage': 'Exam'
}) })
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@ -521,7 +521,7 @@ class AdvancedViewTests(TestCase):
"""Test HTMX responses for partial updates""" """Test HTMX responses for partial updates"""
# Test HTMX request for candidate screening # Test HTMX request for candidate screening
response = self.client.get( response = self.client.get(
reverse('candidate_screening_view', kwargs={'slug': self.job.slug}), reverse('applications_screening_view', kwargs={'slug': self.job.slug}),
HTTP_HX_REQUEST='true' HTTP_HX_REQUEST='true'
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@ -557,7 +557,7 @@ class AdvancedViewTests(TestCase):
# This would be tested via a form submission # This would be tested via a form submission
# For now, we test the view logic directly # For now, we test the view logic directly
request = self.client.post( request = self.client.post(
reverse('candidate_update_status', kwargs={'slug': self.job.slug}), reverse('application_update_status', kwargs={'slug': self.job.slug}),
data={'candidate_ids': application_ids, 'mark_as': 'Exam'} data={'candidate_ids': application_ids, 'mark_as': 'Exam'}
) )
# Should redirect back to the view # Should redirect back to the view
@ -954,7 +954,7 @@ class AdvancedIntegrationTests(TransactionTestCase):
) )
response = self.client.post( response = self.client.post(
reverse('api_schedule_candidate_meeting', reverse('api_schedule_application_meeting',
kwargs={'job_slug': job.slug, 'candidate_pk': application.pk}), kwargs={'job_slug': job.slug, 'candidate_pk': application.pk}),
data={ data={
'start_time': (timezone.now() + timedelta(hours=1)).isoformat(), 'start_time': (timezone.now() + timedelta(hours=1)).isoformat(),

View File

@ -41,52 +41,52 @@ urlpatterns = [
# Candidate URLs # Candidate URLs
path( path(
"candidates/", views_frontend.ApplicationListView.as_view(), name="candidate_list" "applications/", views_frontend.ApplicationListView.as_view(), name="application_list"
), ),
path( path(
"candidates/create/", "application/create/",
views_frontend.ApplicationCreateView.as_view(), views_frontend.ApplicationCreateView.as_view(),
name="candidate_create", name="application_create",
), ),
path( path(
"candidates/create/<slug:slug>/", "application/create/<slug:slug>/",
views_frontend.ApplicationCreateView.as_view(), views_frontend.ApplicationCreateView.as_view(),
name="candidate_create_for_job", name="application_create_for_job",
), ),
path( path(
"jobs/<slug:slug>/candidates/", "jobs/<slug:slug>/application/",
views_frontend.JobApplicationListView.as_view(), views_frontend.JobApplicationListView.as_view(),
name="job_candidates_list", name="job_applications_list",
), ),
path( path(
"candidates/<slug:slug>/update/", "applications/<slug:slug>/update/",
views_frontend.ApplicationUpdateView.as_view(), views_frontend.ApplicationUpdateView.as_view(),
name="candidate_update", name="application_update",
), ),
path( path(
"candidates/<slug:slug>/delete/", "application/<slug:slug>/delete/",
views_frontend.ApplicationDeleteView.as_view(), views_frontend.ApplicationDeleteView.as_view(),
name="candidate_delete", name="application_delete",
), ),
path( path(
"candidate/<slug:slug>/view/", "application/<slug:slug>/view/",
views_frontend.candidate_detail, views_frontend.application_detail,
name="candidate_detail", name="application_detail",
), ),
path( path(
"candidate/<slug:slug>/resume-template/", "application/<slug:slug>/resume-template/",
views_frontend.candidate_resume_template_view, views_frontend.application_resume_template_view,
name="candidate_resume_template", name="application_resume_template",
), ),
path( path(
"candidate/<slug:slug>/update-stage/", "application/<slug:slug>/update-stage/",
views_frontend.candidate_update_stage, views_frontend.application_update_stage,
name="candidate_update_stage", name="application_update_stage",
), ),
path( path(
"candidate/<slug:slug>/retry-scoring/", "application/<slug:slug>/retry-scoring/",
views_frontend.retry_scoring_view, views_frontend.retry_scoring_view,
name="candidate_retry_scoring", name="application_retry_scoring",
), ),
# Training URLs # Training URLs
path("training/", views_frontend.TrainingListView.as_view(), name="training_list"), path("training/", views_frontend.TrainingListView.as_view(), name="training_list"),
@ -155,50 +155,50 @@ urlpatterns = [
name="edit_linkedin_post_content", name="edit_linkedin_post_content",
), ),
path( path(
"jobs/<slug:slug>/candidate_screening_view/", "jobs/<slug:slug>/applications_screening_view/",
views.candidate_screening_view, views.applications_screening_view,
name="candidate_screening_view", name="applications_screening_view",
), ),
path( path(
"jobs/<slug:slug>/candidate_exam_view/", "jobs/<slug:slug>/applications_exam_view/",
views.candidate_exam_view, views.applications_exam_view,
name="candidate_exam_view", name="applications_exam_view",
), ),
path( path(
"jobs/<slug:slug>/candidate_interview_view/", "jobs/<slug:slug>/applications_interview_view/",
views.candidate_interview_view, views.applications_interview_view,
name="candidate_interview_view", name="applications_interview_view",
), ),
path( path(
"jobs/<slug:slug>/candidate_document_review_view/", "jobs/<slug:slug>/applications_document_review_view/",
views.candidate_document_review_view, views.applications_document_review_view,
name="candidate_document_review_view", name="applications_document_review_view",
), ),
path( path(
"jobs/<slug:slug>/candidate_offer_view/", "jobs/<slug:slug>/applications_offer_view/",
views_frontend.candidate_offer_view, views_frontend.applications_offer_view,
name="candidate_offer_view", name="applications_offer_view",
), ),
path( path(
"jobs/<slug:slug>/candidate_hired_view/", "jobs/<slug:slug>/applications_hired_view/",
views_frontend.candidate_hired_view, views_frontend.applications_hired_view,
name="candidate_hired_view", name="applications_hired_view",
), ),
path( path(
"jobs/<slug:job_slug>/export/<str:stage>/csv/", "jobs/<slug:job_slug>/export/<str:stage>/csv/",
views_frontend.export_candidates_csv, views_frontend.export_applications_csv,
name="export_candidates_csv", name="export_applications_csv",
), ),
path( path(
"jobs/<slug:job_slug>/candidates/<slug:candidate_slug>/update_status/<str:stage_type>/<str:status>/", "jobs/<slug:job_slug>/application/<slug:application_slug>/update_status/<str:stage_type>/<str:status>/",
views_frontend.update_candidate_status, views_frontend.update_application_status,
name="update_candidate_status", name="update_application_status",
), ),
# Sync URLs # Sync URLs
path( path(
"jobs/<slug:job_slug>/sync-hired-candidates/", "jobs/<slug:job_slug>/sync-hired-applications/",
views_frontend.sync_hired_candidates, views_frontend.sync_hired_applications,
name="sync_hired_candidates", name="sync_hired_applications",
), ),
path( path(
"sources/<int:source_id>/test-connection/", "sources/<int:source_id>/test-connection/",
@ -206,34 +206,34 @@ urlpatterns = [
name="test_source_connection", name="test_source_connection",
), ),
path( path(
"jobs/<slug:slug>/<int:candidate_id>/reschedule_meeting_for_candidate/<int:meeting_id>/", "jobs/<slug:slug>/<int:application_id>/reschedule_meeting_for_application/<int:meeting_id>/",
views.reschedule_meeting_for_candidate, views.reschedule_meeting_for_application,
name="reschedule_meeting_for_candidate", name="reschedule_meeting_for_application",
), ),
path( path(
"jobs/<slug:slug>/update_candidate_exam_status/", "jobs/<slug:slug>/update_application_exam_status/",
views.update_candidate_exam_status, views.update_application_exam_status,
name="update_candidate_exam_status", name="update_application_exam_status",
), ),
path( path(
"jobs/<slug:slug>/bulk_update_candidate_exam_status/", "jobs/<slug:slug>/bulk_update_application_exam_status/",
views.bulk_update_candidate_exam_status, views.bulk_update_application_exam_status,
name="bulk_update_candidate_exam_status", name="bulk_update_application_exam_status",
), ),
path( path(
"htmx/<int:pk>/candidate_criteria_view/", "htmx/<int:pk>/application_criteria_view/",
views.candidate_criteria_view_htmx, views.application_criteria_view_htmx,
name="candidate_criteria_view_htmx", name="application_criteria_view_htmx",
), ),
path( path(
"htmx/<slug:slug>/candidate_set_exam_date/", "htmx/<slug:slug>/application_set_exam_date/",
views.candidate_set_exam_date, views.application_set_exam_date,
name="candidate_set_exam_date", name="application_set_exam_date",
), ),
path( path(
"htmx/<slug:slug>/candidate_update_status/", "htmx/<slug:slug>/application_update_status/",
views.candidate_update_status, views.application_update_status,
name="candidate_update_status", name="application_update_status",
), ),
# path('forms/form/<slug:template_slug>/submit/', views.submit_form, name='submit_form'), # path('forms/form/<slug:template_slug>/submit/', views.submit_form, name='submit_form'),
# path('forms/form/<slug:template_slug>/', views.form_wizard_view, name='form_wizard'), # path('forms/form/<slug:template_slug>/', views.form_wizard_view, name='form_wizard'),
@ -347,9 +347,9 @@ urlpatterns = [
name="delete_meeting_comment", name="delete_meeting_comment",
), ),
path( path(
"meetings/<slug:slug>/set_meeting_candidate/", "meetings/<slug:slug>/set_meeting_application/",
views.set_meeting_candidate, views.set_meeting_application,
name="set_meeting_candidate", name="set_meeting_application",
), ),
# Hiring Agency URLs # Hiring Agency URLs
path("agencies/", views.agency_list, name="agency_list"), path("agencies/", views.agency_list, name="agency_list"),
@ -358,9 +358,9 @@ urlpatterns = [
path("agencies/<slug:slug>/update/", views.agency_update, name="agency_update"), path("agencies/<slug:slug>/update/", views.agency_update, name="agency_update"),
path("agencies/<slug:slug>/delete/", views.agency_delete, name="agency_delete"), path("agencies/<slug:slug>/delete/", views.agency_delete, name="agency_delete"),
path( path(
"agencies/<slug:slug>/candidates/", "agencies/<slug:slug>/applications/",
views.agency_candidates, views.agency_applications,
name="agency_candidates", name="agency_applications",
), ),
# path('agencies/<slug:slug>/send-message/', views.agency_detail_send_message, name='agency_detail_send_message'), # path('agencies/<slug:slug>/send-message/', views.agency_detail_send_message, name='agency_detail_send_message'),
# Agency Assignment Management URLs # Agency Assignment Management URLs
@ -433,19 +433,19 @@ urlpatterns = [
# Unified Portal URLs # Unified Portal URLs
path("login/", views.portal_login, name="portal_login"), path("login/", views.portal_login, name="portal_login"),
path( path(
"candidate/dashboard/", "applicant/dashboard/",
views.candidate_portal_dashboard, views.applicant_portal_dashboard,
name="candidate_portal_dashboard", name="applicant_portal_dashboard",
), ),
path( path(
"candidate/applications/<slug:slug>/", "applications/applications/<slug:slug>/",
views.candidate_application_detail, views.applicant_application_detail,
name="candidate_application_detail", name="applicant_application_detail",
), ),
# path( # path(
# "candidate/<slug:application_slug>/applications/<slug:person_slug>/detail/<slug:agency_slug>/", # "candidate/<slug:application_slug>/applications/<slug:person_slug>/detail/<slug:agency_slug>/",
# views.candidate_application_detail, # views.applicant_application_detail,
# name="candidate_application_detail", # name="applicant_application_detail",
# ), # ),
path( path(
"portal/dashboard/", "portal/dashboard/",
@ -463,35 +463,35 @@ urlpatterns = [
name="agency_portal_assignment_detail", name="agency_portal_assignment_detail",
), ),
path( path(
"portal/assignment/<slug:slug>/submit-candidate/", "portal/assignment/<slug:slug>/submit-application/",
views.agency_portal_submit_candidate_page, views.agency_portal_submit_application_page,
name="agency_portal_submit_candidate_page", name="agency_portal_submit_application_page",
), ),
path( path(
"portal/submit-candidate/", "portal/submit-application/",
views.agency_portal_submit_candidate, views.agency_portal_submit_application,
name="agency_portal_submit_candidate", name="agency_portal_submit_application",
), ),
path("portal/logout/", views.portal_logout, name="portal_logout"), path("portal/logout/", views.portal_logout, name="portal_logout"),
# Agency Portal Candidate Management URLs # Agency Portal Candidate Management URLs
path( path(
"portal/candidates/<int:candidate_id>/edit/", "portal/applications/<int:application_id>/edit/",
views.agency_portal_edit_candidate, views.agency_portal_edit_application,
name="agency_portal_edit_candidate", name="agency_portal_edit_application",
), ),
path( path(
"portal/candidates/<int:candidate_id>/delete/", "portal/applications/<int:application_id>/delete/",
views.agency_portal_delete_candidate, views.agency_portal_delete_application,
name="agency_portal_delete_candidate", name="agency_portal_delete_application",
), ),
# API URLs for messaging (removed) # API URLs for messaging (removed)
# path('api/agency/messages/<int:message_id>/', views.api_agency_message_detail, name='api_agency_message_detail'), # path('api/agency/messages/<int:message_id>/', views.api_agency_message_detail, name='api_agency_message_detail'),
# path('api/agency/messages/<int:message_id>/mark-read/', views.api_agency_mark_message_read, name='api_agency_mark_message_read'), # path('api/agency/messages/<int:message_id>/mark-read/', views.api_agency_mark_message_read, name='api_agency_mark_message_read'),
# API URLs for candidate management # API URLs for candidate management
path( path(
"api/candidate/<int:candidate_id>/", "api/application/<int:application_id>/",
views.api_candidate_detail, views.api_application_detail,
name="api_candidate_detail", name="api_application_detail",
), ),
# # Admin Notification API # # Admin Notification API
# path('api/admin/notification-count/', views.api_notification_count, name='admin_notification_count'), # path('api/admin/notification-count/', views.api_notification_count, name='admin_notification_count'),
@ -535,10 +535,11 @@ urlpatterns = [
), ),
# Email composition URLs # Email composition URLs
path( path(
"jobs/<slug:job_slug>/candidates/compose-email/", "jobs/<slug:job_slug>/applications/compose-email/",
views.compose_candidate_email, views.compose_application_email,
name="compose_candidate_email", name="compose_application_email",
), ),
# Message URLs # Message URLs
path("messages/", views.message_list, name="message_list"), path("messages/", views.message_list, name="message_list"),
path("messages/create/", views.message_create, name="message_create"), path("messages/create/", views.message_create, name="message_create"),
@ -555,15 +556,15 @@ urlpatterns = [
path("documents/<int:document_id>/delete/", views.document_delete, name="document_delete"), path("documents/<int:document_id>/delete/", views.document_delete, name="document_delete"),
path("documents/<int:document_id>/download/", views.document_download, name="document_download"), path("documents/<int:document_id>/download/", views.document_download, name="document_download"),
# Candidate Document Management URLs # Candidate Document Management URLs
path("candidate/documents/upload/<slug:slug>/", views.document_upload, name="candidate_document_upload"), path("application/documents/upload/<slug:slug>/", views.document_upload, name="application_document_upload"),
path("candidate/documents/<int:document_id>/delete/", views.document_delete, name="candidate_document_delete"), path("application/documents/<int:document_id>/delete/", views.document_delete, name="application_document_delete"),
path("candidate/documents/<int:document_id>/download/", views.document_download, name="candidate_document_download"), path("application/documents/<int:document_id>/download/", views.document_download, name="application_document_download"),
path('jobs/<slug:job_slug>/candidates/compose_email/', views.compose_candidate_email, name='compose_candidate_email'), path('jobs/<slug:job_slug>/applications/compose_email/', views.compose_application_email, name='compose_application_email'),
path('interview/partcipants/<slug:slug>/',views.create_interview_participants,name='create_interview_participants'), path('interview/partcipants/<slug:slug>/',views.create_interview_participants,name='create_interview_participants'),
path('interview/email/<slug:slug>/',views.send_interview_email,name='send_interview_email'), path('interview/email/<slug:slug>/',views.send_interview_email,name='send_interview_email'),
# Candidate Signup # Candidate Signup
path('candidate/signup/<slug:template_slug>/', views.candidate_signup, name='candidate_signup'), path('application/signup/<slug:template_slug>/', views.application_signup, name='application_signup'),
# Password Reset # Password Reset
path('user/<int:pk>/password-reset/', views.portal_password_reset, name='portal_password_reset'), path('user/<int:pk>/password-reset/', views.portal_password_reset, name='portal_password_reset'),
@ -607,43 +608,43 @@ urlpatterns = [
), ),
# Candidate Meeting Scheduling/Rescheduling URLs # Candidate Meeting Scheduling/Rescheduling URLs
path( path(
"jobs/<slug:job_slug>/candidates/<int:candidate_pk>/schedule-meeting/", "jobs/<slug:job_slug>/applications/<int:application_pk>/schedule-meeting/",
views.schedule_candidate_meeting, views.schedule_application_meeting,
name="schedule_candidate_meeting", name="schedule_application_meeting",
), ),
path( path(
"api/jobs/<slug:job_slug>/candidates/<int:candidate_pk>/schedule-meeting/", "api/jobs/<slug:job_slug>/applications/<int:application_pk>/schedule-meeting/",
views.api_schedule_candidate_meeting, views.api_schedule_application_meeting,
name="api_schedule_candidate_meeting", name="api_schedule_application_meeting",
), ),
path( path(
"jobs/<slug:job_slug>/candidates/<int:candidate_pk>/reschedule-meeting/<int:interview_pk>/", "jobs/<slug:job_slug>/applications/<int:application_pk>/reschedule-meeting/<int:interview_pk>/",
views.reschedule_candidate_meeting, views.reschedule_application_meeting,
name="reschedule_candidate_meeting", name="reschedule_application_meeting",
), ),
path( path(
"api/jobs/<slug:job_slug>/candidates/<int:candidate_pk>/reschedule-meeting/<int:interview_pk>/", "api/jobs/<slug:job_slug>/applications/<int:application_pk>/reschedule-meeting/<int:interview_pk>/",
views.api_reschedule_candidate_meeting, views.api_reschedule_application_meeting,
name="api_reschedule_candidate_meeting", name="api_reschedule_application_meeting",
), ),
# New URL for simple page-based meeting scheduling # New URL for simple page-based meeting scheduling
path( path(
"jobs/<slug:slug>/candidates/<int:candidate_pk>/schedule-meeting-page/", "jobs/<slug:slug>/applications/<int:application_pk>/schedule-meeting-page/",
views.schedule_meeting_for_candidate, views.schedule_meeting_for_application,
name="schedule_meeting_for_candidate", name="schedule_meeting_for_application",
),
path(
"jobs/<slug:slug>/candidates/<int:candidate_pk>/delete_meeting_for_candidate/<int:meeting_id>/",
views.delete_meeting_for_candidate,
name="delete_meeting_for_candidate",
), ),
# path(
# "jobs/<slug:slug>/applications/<int:application_pk>/delete_meeting_for_application/<int:meeting_id>/",
# views.delete_meeting_for_candidate,
# name="delete_meeting_for_candidate",
# ),
path("interviews/meetings/", views.MeetingListView.as_view(), name="list_meetings"), path("interviews/meetings/", views.MeetingListView.as_view(), name="list_meetings"),
# 1. Onsite Reschedule URL # 1. Onsite Reschedule URL
path( path(
'<slug:slug>/candidate/<int:candidate_id>/onsite/reschedule/<int:meeting_id>/', '<slug:slug>/application/<int:application_id>/onsite/reschedule/<int:meeting_id>/',
views.reschedule_onsite_meeting, views.reschedule_onsite_meeting,
name='reschedule_onsite_meeting' name='reschedule_onsite_meeting'
), ),
@ -651,15 +652,15 @@ urlpatterns = [
# 2. Onsite Delete URL # 2. Onsite Delete URL
path( path(
'job/<slug:slug>/candidates/<int:candidate_pk>/delete-onsite-meeting/<int:meeting_id>/', 'job/<slug:slug>/applications/<int:application_pk>/delete-onsite-meeting/<int:meeting_id>/',
views.delete_onsite_meeting_for_candidate, views.delete_onsite_meeting_for_application,
name='delete_onsite_meeting_for_candidate' name='delete_onsite_meeting_for_application'
), ),
path( path(
'job/<slug:slug>/candidate/<int:candidate_pk>/schedule/onsite/', 'job/<slug:slug>/application/<int:application_pk>/schedule/onsite/',
views.schedule_onsite_meeting_for_candidate, views.schedule_onsite_meeting_for_application,
name='schedule_onsite_meeting_for_candidate' # This is the name used in the button name='schedule_onsite_meeting_for_application' # This is the name used in the button
), ),
@ -667,7 +668,7 @@ urlpatterns = [
path("interviews/meetings/<slug:slug>/", views.meeting_details, name="meeting_details"), path("interviews/meetings/<slug:slug>/", views.meeting_details, name="meeting_details"),
# Email invitation URLs # Email invitation URLs
path("interviews/meetings/<slug:slug>/send-candidate-invitation/", views.send_candidate_invitation, name="send_candidate_invitation"), path("interviews/meetings/<slug:slug>/send-application-invitation/", views.send_application_invitation, name="send_application_invitation"),
path("interviews/meetings/<slug:slug>/send-participants-invitation/", views.send_participants_invitation, name="send_participants_invitation"), path("interviews/meetings/<slug:slug>/send-participants-invitation/", views.send_participants_invitation, name="send_participants_invitation"),
] ]

View File

@ -201,7 +201,7 @@ class PersonCreateView(CreateView):
instance.save() instance.save()
return redirect("agency_portal_persons_list") return redirect("agency_portal_persons_list")
if view == "job": if view == "job":
return redirect("candidate_create") return redirect("application_create")
return super().form_valid(form) return super().form_valid(form)
@ -1199,7 +1199,7 @@ def delete_form_template(request, template_id):
def application_submit_form(request, template_slug): def application_submit_form(request, template_slug):
"""Display the form as a step-by-step wizard""" """Display the form as a step-by-step wizard"""
if not request.user.is_authenticated: if not request.user.is_authenticated:
return redirect("candidate_signup",slug=template_slug) return redirect("application_signup",slug=template_slug)
template = get_object_or_404(FormTemplate, slug=template_slug, is_active=True) template = get_object_or_404(FormTemplate, slug=template_slug, is_active=True)
stage = template.stages.filter(name="Contact Information") stage = template.stages.filter(name="Contact Information")
@ -1329,7 +1329,7 @@ def application_submit(request, template_slug):
# return redirect('application_success',slug=job.slug) # return redirect('application_success',slug=job.slug)
except Exception as e: except Exception as e:
logger.error(f"Candidate creation failed,{e}") logger.error(f"Application creation failed,{e}")
pass pass
return JsonResponse( return JsonResponse(
{ {
@ -1760,7 +1760,7 @@ def confirm_schedule_interviews_view(request, slug):
@staff_user_required @staff_user_required
def candidate_screening_view(request, slug): def applications_screening_view(request, slug):
""" """
Manage candidate tiers and stage transitions Manage candidate tiers and stage transitions
""" """
@ -1842,7 +1842,7 @@ def candidate_screening_view(request, slug):
@staff_user_required @staff_user_required
def candidate_exam_view(request, slug): def applications_exam_view(request, slug):
""" """
Manage candidate tiers and stage transitions Manage candidate tiers and stage transitions
""" """
@ -1852,13 +1852,13 @@ def candidate_exam_view(request, slug):
@staff_user_required @staff_user_required
def update_candidate_exam_status(request, slug): def update_application_exam_status(request, slug):
candidate = get_object_or_404(Application, slug=slug) candidate = get_object_or_404(Application, slug=slug)
if request.method == "POST": if request.method == "POST":
form = CandidateExamDateForm(request.POST, instance=candidate) form = CandidateExamDateForm(request.POST, instance=candidate)
if form.is_valid(): if form.is_valid():
form.save() form.save()
return redirect("candidate_exam_view", slug=candidate.job.slug) return redirect("applications_exam_view", slug=candidate.job.slug)
else: else:
form = CandidateExamDateForm(request.POST, instance=candidate) form = CandidateExamDateForm(request.POST, instance=candidate)
return render( return render(
@ -1869,7 +1869,7 @@ def update_candidate_exam_status(request, slug):
@staff_user_required @staff_user_required
def bulk_update_candidate_exam_status(request, slug): def bulk_update_application_exam_status(request, slug):
job = get_object_or_404(JobPosting, slug=slug) job = get_object_or_404(JobPosting, slug=slug)
status = request.headers.get("status") status = request.headers.get("status")
if status: if status:
@ -1884,10 +1884,10 @@ def bulk_update_candidate_exam_status(request, slug):
except Exception as e: except Exception as e:
print(e) print(e)
messages.success(request, f"Updated exam status selected candidates") messages.success(request, f"Updated exam status selected candidates")
return redirect("candidate_exam_view", slug=job.slug) return redirect("applications_exam_view", slug=job.slug)
def candidate_criteria_view_htmx(request, pk): def application_criteria_view_htmx(request, pk):
candidate = get_object_or_404(Application, pk=pk) candidate = get_object_or_404(Application, pk=pk)
return render( return render(
request, "includes/candidate_modal_body.html", {"candidate": candidate} request, "includes/candidate_modal_body.html", {"candidate": candidate}
@ -1895,18 +1895,18 @@ def candidate_criteria_view_htmx(request, pk):
@staff_user_required @staff_user_required
def candidate_set_exam_date(request, slug): def application_set_exam_date(request, slug):
candidate = get_object_or_404(Application, slug=slug) candidate = get_object_or_404(Application, slug=slug)
candidate.exam_date = timezone.now() candidate.exam_date = timezone.now()
candidate.save() candidate.save()
messages.success( messages.success(
request, f"Set exam date for {candidate.name} to {candidate.exam_date}" request, f"Set exam date for {candidate.name} to {candidate.exam_date}"
) )
return redirect("candidate_screening_view", slug=candidate.job.slug) return redirect("applications_screening_view", slug=candidate.job.slug)
@staff_user_required @staff_user_required
def candidate_update_status(request, slug): def application_update_status(request, slug):
job = get_object_or_404(JobPosting, slug=slug) job = get_object_or_404(JobPosting, slug=slug)
mark_as = request.POST.get("mark_as") mark_as = request.POST.get("mark_as")
if mark_as != "----------": if mark_as != "----------":
@ -1979,13 +1979,13 @@ def candidate_update_status(request, slug):
) )
messages.success(request, f"Candidates Updated") messages.success(request, f"Candidates Updated")
response = HttpResponse(redirect("candidate_screening_view", slug=job.slug)) response = HttpResponse(redirect("applications_screening_view", slug=job.slug))
response.headers["HX-Refresh"] = "true" response.headers["HX-Refresh"] = "true"
return response return response
@staff_user_required @staff_user_required
def candidate_interview_view(request, slug): def applications_interview_view(request, slug):
job = get_object_or_404(JobPosting, slug=slug) job = get_object_or_404(JobPosting, slug=slug)
context = { context = {
"job": job, "job": job,
@ -1997,7 +1997,7 @@ def candidate_interview_view(request, slug):
@staff_user_required @staff_user_required
def candidate_document_review_view(request, slug): def applications_document_review_view(request, slug):
""" """
Document review view for candidates after interview stage and before offer stage Document review view for candidates after interview stage and before offer stage
""" """
@ -2025,7 +2025,7 @@ def candidate_document_review_view(request, slug):
@staff_user_required @staff_user_required
def reschedule_meeting_for_candidate(request, slug, candidate_id, meeting_id): def reschedule_meeting_for_application(request, slug, candidate_id, meeting_id):
job = get_object_or_404(JobPosting, slug=slug) job = get_object_or_404(JobPosting, slug=slug)
candidate = get_object_or_404(Application, pk=candidate_id) candidate = get_object_or_404(Application, pk=candidate_id)
meeting = get_object_or_404(ZoomMeetingDetails, pk=meeting_id) meeting = get_object_or_404(ZoomMeetingDetails, pk=meeting_id)
@ -2043,7 +2043,7 @@ def reschedule_meeting_for_candidate(request, slug, candidate_id, meeting_id):
if instance.start_time < timezone.now(): if instance.start_time < timezone.now():
messages.error(request, "Start time must be in the future.") messages.error(request, "Start time must be in the future.")
return redirect( return redirect(
"reschedule_meeting_for_candidate", "reschedule_meeting_for_application",
slug=job.slug, slug=job.slug,
candidate_id=candidate_id, candidate_id=candidate_id,
meeting_id=meeting_id, meeting_id=meeting_id,
@ -2056,7 +2056,7 @@ def reschedule_meeting_for_candidate(request, slug, candidate_id, meeting_id):
else: else:
messages.error(request, result["message"]) messages.error(request, result["message"])
return redirect( return redirect(
reverse("candidate_interview_view", kwargs={"slug": job.slug}) reverse("applications_interview_view", kwargs={"slug": job.slug})
) )
context = {"job": job, "candidate": candidate, "meeting": meeting, "form": form} context = {"job": job, "candidate": candidate, "meeting": meeting, "form": form}
@ -2064,7 +2064,7 @@ def reschedule_meeting_for_candidate(request, slug, candidate_id, meeting_id):
@staff_user_required @staff_user_required
def delete_meeting_for_candidate(request, slug, candidate_pk, meeting_id): def schedule_meeting_for_application(request, slug, candidate_pk, meeting_id):
job = get_object_or_404(JobPosting, slug=slug) job = get_object_or_404(JobPosting, slug=slug)
candidate = get_object_or_404(Application, pk=candidate_pk) candidate = get_object_or_404(Application, pk=candidate_pk)
meeting = get_object_or_404(ZoomMeetingDetails, pk=meeting_id) meeting = get_object_or_404(ZoomMeetingDetails, pk=meeting_id)
@ -2078,14 +2078,14 @@ def delete_meeting_for_candidate(request, slug, candidate_pk, meeting_id):
messages.success(request, "Meeting deleted successfully") messages.success(request, "Meeting deleted successfully")
else: else:
messages.error(request, result["message"]) messages.error(request, result["message"])
return redirect(reverse("candidate_interview_view", kwargs={"slug": job.slug})) return redirect(reverse("applications_interview_view", kwargs={"slug": job.slug}))
context = { context = {
"job": job, "job": job,
"candidate": candidate, "candidate": candidate,
"meeting": meeting, "meeting": meeting,
"delete_url": reverse( "delete_url": reverse(
"delete_meeting_for_candidate", "schedule_meeting_for_application",
kwargs={ kwargs={
"slug": job.slug, "slug": job.slug,
"candidate_pk": candidate_pk, "candidate_pk": candidate_pk,
@ -2125,7 +2125,7 @@ def delete_zoom_meeting_for_candidate(request, slug, candidate_pk, meeting_id):
else: else:
messages.error(request, result["message"]) messages.error(request, result["message"])
return redirect(reverse("candidate_interview_view", kwargs={"slug": job.slug})) return redirect(reverse("applications_interview_view", kwargs={"slug": job.slug}))
context = { context = {
"job": job, "job": job,
@ -2218,7 +2218,7 @@ def interview_detail_view(request, slug, interview_id):
# Candidate Meeting Scheduling/Rescheduling Views # Candidate Meeting Scheduling/Rescheduling Views
@require_POST @require_POST
def api_schedule_candidate_meeting(request, job_slug, candidate_pk): def api_schedule_application_meeting(request, job_slug, candidate_pk):
""" """
Handle POST request to schedule a Zoom meeting for a candidate via HTMX. Handle POST request to schedule a Zoom meeting for a candidate via HTMX.
Returns JSON response for modal update. Returns JSON response for modal update.
@ -2298,23 +2298,23 @@ def api_schedule_candidate_meeting(request, job_slug, candidate_pk):
return JsonResponse({"success": False, "error": result["message"]}, status=400) return JsonResponse({"success": False, "error": result["message"]}, status=400)
def schedule_candidate_meeting(request, job_slug, candidate_pk): def schedule_application_meeting(request, job_slug, candidate_pk):
""" """
GET: Render modal form to schedule a meeting. (For HTMX) GET: Render modal form to schedule a meeting. (For HTMX)
POST: Handled by api_schedule_candidate_meeting. POST: Handled by api_schedule_application_meeting.
""" """
job = get_object_or_404(JobPosting, slug=job_slug) job = get_object_or_404(JobPosting, slug=job_slug)
candidate = get_object_or_404(Application, pk=candidate_pk, job=job) candidate = get_object_or_404(Application, pk=candidate_pk, job=job)
if request.method == "POST": if request.method == "POST":
return api_schedule_candidate_meeting(request, job_slug, candidate_pk) return api_schedule_application_meeting(request, job_slug, candidate_pk)
# GET request - render the form snippet for HTMX # GET request - render the form snippet for HTMX
context = { context = {
"job": job, "job": job,
"candidate": candidate, "candidate": candidate,
"action_url": reverse( "action_url": reverse(
"api_schedule_candidate_meeting", "api_schedule_application_meeting",
kwargs={"job_slug": job_slug, "candidate_pk": candidate_pk}, kwargs={"job_slug": job_slug, "candidate_pk": candidate_pk},
), ),
"scheduled_interview": None, # Explicitly None for schedule "scheduled_interview": None, # Explicitly None for schedule
@ -2324,7 +2324,7 @@ def schedule_candidate_meeting(request, job_slug, candidate_pk):
@require_http_methods(["GET", "POST"]) @require_http_methods(["GET", "POST"])
def api_schedule_candidate_meeting(request, job_slug, candidate_pk): def api_schedule_application_meeting(request, job_slug, candidate_pk):
""" """
Handles GET to render form and POST to process scheduling. Handles GET to render form and POST to process scheduling.
""" """
@ -2337,7 +2337,7 @@ def api_schedule_candidate_meeting(request, job_slug, candidate_pk):
"job": job, "job": job,
"candidate": candidate, "candidate": candidate,
"action_url": reverse( "action_url": reverse(
"api_schedule_candidate_meeting", "api_schedule_application_meeting",
kwargs={"job_slug": job_slug, "candidate_pk": candidate_pk}, kwargs={"job_slug": job_slug, "candidate_pk": candidate_pk},
), ),
"scheduled_interview": None, "scheduled_interview": None,
@ -2408,7 +2408,7 @@ def api_schedule_candidate_meeting(request, job_slug, candidate_pk):
@require_http_methods(["GET", "POST"]) @require_http_methods(["GET", "POST"])
def api_reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk): def api_reschedule_application_meeting(request, job_slug, candidate_pk, interview_pk):
""" """
Handles GET to render form and POST to process rescheduling. Handles GET to render form and POST to process rescheduling.
""" """
@ -2434,7 +2434,7 @@ def api_reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_
"scheduled_interview": scheduled_interview, # Pass for conditional logic in template "scheduled_interview": scheduled_interview, # Pass for conditional logic in template
"initial_data": initial_data, "initial_data": initial_data,
"action_url": reverse( "action_url": reverse(
"api_reschedule_candidate_meeting", "api_reschedule_application_meeting",
kwargs={ kwargs={
"job_slug": job_slug, "job_slug": job_slug,
"candidate_pk": candidate_pk, "candidate_pk": candidate_pk,
@ -2530,14 +2530,14 @@ def api_reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_
return JsonResponse({"success": False, "error": result["message"]}, status=400) return JsonResponse({"success": False, "error": result["message"]}, status=400)
# The original schedule_candidate_meeting and reschedule_candidate_meeting (without api_ prefix) # The original schedule_application_meeting and reschedule_application_meeting (without api_ prefix)
# can be removed if their only purpose was to be called by the JS onclicks. # can be removed if their only purpose was to be called by the JS onclicks.
# If they were intended for other direct URL access, they can be kept as simple redirects # If they were intended for other direct URL access, they can be kept as simple redirects
# or wrappers to the api_ versions. # or wrappers to the api_ versions.
# For now, let's assume the api_ versions are the primary ones for HTMX. # For now, let's assume the api_ versions are the primary ones for HTMX.
def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk): def reschedule_application_meeting(request, job_slug, candidate_pk, interview_pk):
""" """
Handles GET to display a form for rescheduling a meeting. Handles GET to display a form for rescheduling a meeting.
Handles POST to process the rescheduling of a meeting. Handles POST to process the rescheduling of a meeting.
@ -2592,7 +2592,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
else "", else "",
"initial_duration": new_duration, "initial_duration": new_duration,
"action_url": reverse( "action_url": reverse(
"reschedule_candidate_meeting", "reschedule_application_meeting",
kwargs={ kwargs={
"job_slug": job_slug, "job_slug": job_slug,
"candidate_pk": candidate_pk, "candidate_pk": candidate_pk,
@ -2672,7 +2672,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
f"Meeting for {application.name} rescheduled. (Note: Could not refresh all details from Zoom.)", f"Meeting for {application.name} rescheduled. (Note: Could not refresh all details from Zoom.)",
) )
return redirect("candidate_interview_view", slug=job.slug) return redirect("applications_interview_view", slug=job.slug)
else: else:
messages.error( messages.error(
request, request,
@ -2693,7 +2693,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
else "", else "",
"initial_duration": new_duration, "initial_duration": new_duration,
"action_url": reverse( "action_url": reverse(
"reschedule_candidate_meeting", "reschedule_application_meeting",
kwargs={ kwargs={
"job_slug": job_slug, "job_slug": job_slug,
"candidate_pk": candidate_pk, "candidate_pk": candidate_pk,
@ -2722,7 +2722,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
), ),
"initial_duration": request.POST.get("duration", new_duration), "initial_duration": request.POST.get("duration", new_duration),
"action_url": reverse( "action_url": reverse(
"reschedule_candidate_meeting", "reschedule_application_meeting",
kwargs={ kwargs={
"job_slug": job_slug, "job_slug": job_slug,
"candidate_pk": candidate_pk, "candidate_pk": candidate_pk,
@ -2749,7 +2749,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
"application": application, "application": application,
"scheduled_interview": scheduled_interview, # Pass to template for title/differentiation "scheduled_interview": scheduled_interview, # Pass to template for title/differentiation
"action_url": reverse( "action_url": reverse(
"reschedule_candidate_meeting", "reschedule_application_meeting",
kwargs={ kwargs={
"job_slug": job_slug, "job_slug": job_slug,
"candidate_pk": candidate_pk, "candidate_pk": candidate_pk,
@ -2761,7 +2761,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
) )
def schedule_meeting_for_candidate(request, slug, candidate_pk): def schedule_meeting_for_application(request, slug, candidate_pk):
""" """
Handles GET to display a simple form for scheduling a meeting for a candidate. Handles GET to display a simple form for scheduling a meeting for a candidate.
Handles POST to process the form, create a meeting, and redirect back. Handles POST to process the form, create a meeting, and redirect back.
@ -2784,7 +2784,7 @@ def schedule_meeting_for_candidate(request, slug, candidate_pk):
if start_time_val <= timezone.now(): if start_time_val <= timezone.now():
messages.error(request, "Start time must be in the future.") messages.error(request, "Start time must be in the future.")
# Re-render form with error and initial data # Re-render form with error and initial data
return redirect("candidate_interview_view", slug=job.slug) return redirect("applications_interview_view", slug=job.slug)
# return render(request, "recruitment/schedule_meeting_form.html", { # return render(request, "recruitment/schedule_meeting_form.html", {
# 'form': form, # 'form': form,
# 'job': job, # 'job': job,
@ -2829,7 +2829,7 @@ def schedule_meeting_for_candidate(request, slug, candidate_pk):
status="scheduled", status="scheduled",
) )
messages.success(request, f"Meeting scheduled with {candidate.name}.") messages.success(request, f"Meeting scheduled with {candidate.name}.")
return redirect("candidate_interview_view", slug=job.slug) return redirect("applications_interview_view", slug=job.slug)
else: else:
messages.error( messages.error(
request, request,
@ -3232,7 +3232,7 @@ def delete_meeting_comment(request, slug, comment_id):
@staff_user_required @staff_user_required
def set_meeting_candidate(request, slug): def set_meeting_application(request, slug):
meeting = get_object_or_404(ZoomMeetingDetails, slug=slug) meeting = get_object_or_404(ZoomMeetingDetails, slug=slug)
if request.method == "POST" and "HX-Request" not in request.headers: if request.method == "POST" and "HX-Request" not in request.headers:
form = InterviewForm(request.POST) form = InterviewForm(request.POST)
@ -3254,7 +3254,7 @@ def set_meeting_candidate(request, slug):
form.fields["candidate"].queryset = Application.objects.none() form.fields["candidate"].queryset = Application.objects.none()
form.fields["job"].widget.attrs.update( form.fields["job"].widget.attrs.update(
{ {
"hx-get": reverse("set_meeting_candidate", kwargs={"slug": slug}), "hx-get": reverse("set_meeting_application", kwargs={"slug": slug}),
"hx-target": "#div_id_candidate", "hx-target": "#div_id_candidate",
"hx-select": "#div_id_candidate", "hx-select": "#div_id_candidate",
"hx-swap": "outerHTML", "hx-swap": "outerHTML",
@ -3708,7 +3708,7 @@ def agency_delete(request, slug):
@staff_user_required @staff_user_required
def agency_candidates(request, slug): def agency_applications(request, slug):
"""View all candidates from a specific agency""" """View all candidates from a specific agency"""
agency = get_object_or_404(HiringAgency, slug=slug) agency = get_object_or_404(HiringAgency, slug=slug)
candidates = Application.objects.filter(hiring_agency=agency).order_by( candidates = Application.objects.filter(hiring_agency=agency).order_by(
@ -4011,7 +4011,7 @@ def portal_login(request):
return redirect("agency_portal_dashboard") return redirect("agency_portal_dashboard")
if request.user.user_type == "candidate": if request.user.user_type == "candidate":
print(request.user) print(request.user)
return redirect("candidate_portal_dashboard") return redirect("applicant_portal_dashboard")
if request.method == "POST": if request.method == "POST":
form = PortalLoginForm(request.POST) form = PortalLoginForm(request.POST)
@ -4052,7 +4052,7 @@ def portal_login(request):
# request, # request,
# f"Welcome, {user.candidate_profile.first_name}!", # f"Welcome, {user.candidate_profile.first_name}!",
# ) # )
# return redirect("candidate_portal_dashboard") # return redirect("applicant_portal_dashboard")
# else: # else:
# messages.error( # messages.error(
# request, "No candidate profile found for this user." # request, "No candidate profile found for this user."
@ -4075,7 +4075,7 @@ def portal_login(request):
@login_required @login_required
@candidate_user_required @candidate_user_required
def candidate_portal_dashboard(request): def applicant_portal_dashboard(request):
"""Candidate portal dashboard""" """Candidate portal dashboard"""
if not request.user.is_authenticated: if not request.user.is_authenticated:
return redirect("account_login") return redirect("account_login")
@ -4113,7 +4113,7 @@ def candidate_portal_dashboard(request):
@login_required @login_required
def candidate_application_detail(request, slug): def applicant_application_detail(request, slug):
"""View detailed information about a specific application""" """View detailed information about a specific application"""
if not request.user.is_authenticated: if not request.user.is_authenticated:
return redirect("account_login") return redirect("account_login")
@ -4278,7 +4278,7 @@ def agency_portal_dashboard(request):
@agency_user_required @agency_user_required
def agency_portal_submit_candidate_page(request, slug): def agency_portal_submit_application_page(request, slug):
"""Dedicated page for submitting a candidate""" """Dedicated page for submitting a candidate"""
# assignment_id = request.session.get("agency_assignment_id") # assignment_id = request.session.get("agency_assignment_id")
# if not assignment_id: # if not assignment_id:
@ -4345,7 +4345,7 @@ def agency_portal_submit_candidate_page(request, slug):
@agency_user_required @agency_user_required
def agency_portal_submit_candidate(request): def agency_portal_submit_application(request):
"""Handle candidate submission via AJAX (for embedded form)""" """Handle candidate submission via AJAX (for embedded form)"""
assignment_id = request.session.get("agency_assignment_id") assignment_id = request.session.get("agency_assignment_id")
if not assignment_id: if not assignment_id:
@ -4517,7 +4517,7 @@ def agency_assignment_detail_admin(request, slug):
@agency_user_required @agency_user_required
def agency_portal_edit_candidate(request, candidate_id): def agency_portal_edit_application(request, candidate_id):
"""Edit a candidate for agency portal""" """Edit a candidate for agency portal"""
assignment_id = request.session.get("agency_assignment_id") assignment_id = request.session.get("agency_assignment_id")
if not assignment_id: if not assignment_id:
@ -4578,7 +4578,7 @@ def agency_portal_edit_candidate(request, candidate_id):
@agency_user_required @agency_user_required
def agency_portal_delete_candidate(request, candidate_id): def agency_portal_delete_application(request, candidate_id):
"""Delete a candidate for agency portal""" """Delete a candidate for agency portal"""
assignment_id = request.session.get("agency_assignment_id") assignment_id = request.session.get("agency_assignment_id")
if not assignment_id: if not assignment_id:
@ -4986,7 +4986,7 @@ def document_upload(request, slug):
} }
}) })
return redirect("candidate_portal_dashboard") return redirect("applicant_portal_dashboard")
else: else:
# Create document for Application (existing logic) # Create document for Application (existing logic)
document = Document.objects.create( document = Document.objects.create(
@ -5016,15 +5016,15 @@ def document_upload(request, slug):
} }
}) })
if upload_target == 'person': if upload_target == 'person':
return redirect("candidate_portal_dashboard") return redirect("applicant_portal_dashboard")
else: else:
return redirect("candidate_application_detail", application_slug=application.slug) return redirect("applicant_application_detail", application_slug=application.slug)
# Handle GET request for AJAX # Handle GET request for AJAX
if request.headers.get("X-Requested-With") == "XMLHttpRequest": if request.headers.get("X-Requested-With") == "XMLHttpRequest":
return JsonResponse({"success": False, "error": "Method not allowed"}) return JsonResponse({"success": False, "error": "Method not allowed"})
return redirect("candidate_detail", slug=application.job.slug) return redirect("application_detail", slug=application.job.slug)
@login_required @login_required
def document_delete(request, document_id): def document_delete(request, document_id):
@ -5043,7 +5043,7 @@ def document_delete(request, document_id):
) )
return JsonResponse({"success": False, "error": "Permission denied"}) return JsonResponse({"success": False, "error": "Permission denied"})
job_slug = document.content_object.job.slug job_slug = document.content_object.job.slug
redirect_url = "candidate_portal_dashboard" if request.user.user_type == "candidate" else "job_detail" redirect_url = "applicant_portal_dashboard" if request.user.user_type == "candidate" else "job_detail"
elif hasattr(document.content_object, "person"): elif hasattr(document.content_object, "person"):
# Person document # Person document
if request.user.user_type == "candidate": if request.user.user_type == "candidate":
@ -5053,7 +5053,7 @@ def document_delete(request, document_id):
request, "You can only delete your own documents." request, "You can only delete your own documents."
) )
return JsonResponse({"success": False, "error": "Permission denied"}) return JsonResponse({"success": False, "error": "Permission denied"})
redirect_url = "candidate_portal_dashboard" redirect_url = "applicant_portal_dashboard"
else: else:
# Handle other content object types # Handle other content object types
messages.error(request, "You don't have permission to delete this document.") messages.error(request, "You don't have permission to delete this document.")
@ -5070,7 +5070,7 @@ def document_delete(request, document_id):
{"success": True, "message": "Document deleted successfully!"} {"success": True, "message": "Document deleted successfully!"}
) )
else: else:
return redirect("candidate_detail", slug=job_slug) return redirect("application_detail", slug=job_slug)
return JsonResponse({"success": False, "error": "Method not allowed"}) return JsonResponse({"success": False, "error": "Method not allowed"})
@ -5091,7 +5091,7 @@ def document_download(request, document_id):
) )
return JsonResponse({"success": False, "error": "Permission denied"}) return JsonResponse({"success": False, "error": "Permission denied"})
job_slug = document.content_object.job.slug job_slug = document.content_object.job.slug
redirect_url = "candidate_detail" if request.user.user_type == "candidate" else "job_detail" redirect_url = "application_detail" if request.user.user_type == "candidate" else "job_detail"
elif hasattr(document.content_object, "person"): elif hasattr(document.content_object, "person"):
# Person document # Person document
if request.user.user_type == "candidate": if request.user.user_type == "candidate":
@ -5101,7 +5101,7 @@ def document_download(request, document_id):
request, "You can only download your own documents." request, "You can only download your own documents."
) )
return JsonResponse({"success": False, "error": "Permission denied"}) return JsonResponse({"success": False, "error": "Permission denied"})
redirect_url = "candidate_portal_dashboard" redirect_url = "applicant_portal_dashboard"
else: else:
# Handle other content object types # Handle other content object types
messages.error(request, "You don't have permission to download this document.") messages.error(request, "You don't have permission to download this document.")
@ -5210,7 +5210,7 @@ def agency_access_link_reactivate(request, slug):
@agency_user_required @agency_user_required
def api_candidate_detail(request, candidate_id): def api_application_detail(request, candidate_id):
"""API endpoint to get candidate details for agency portal""" """API endpoint to get candidate details for agency portal"""
try: try:
# Get candidate from session-based agency access # Get candidate from session-based agency access
@ -5248,7 +5248,7 @@ def api_candidate_detail(request, candidate_id):
@staff_user_required @staff_user_required
def compose_candidate_email(request, job_slug): def compose_application_email(request, job_slug):
"""Compose email to participants about a candidate""" """Compose email to participants about a candidate"""
from .email_service import send_bulk_email from .email_service import send_bulk_email
@ -5326,7 +5326,7 @@ def compose_candidate_email(request, job_slug):
response = HttpResponse(status=200) response = HttpResponse(status=200)
response.headers["HX-Refresh"] = "true" response.headers["HX-Refresh"] = "true"
return response return response
# return redirect("candidate_interview_view", slug=job.slug) # return redirect("applications_interview_view", slug=job.slug)
else: else:
messages.error( messages.error(
request, request,
@ -5556,14 +5556,14 @@ def source_toggle_status(request, slug):
return JsonResponse({"success": False, "error": "Method not allowed"}) return JsonResponse({"success": False, "error": "Method not allowed"})
def candidate_signup(request, slug): def application_signup(request, slug):
from .forms import CandidateSignupForm from .forms import ApplicantSignupForm
form_template = get_object_or_404(FormTemplate, slug=slug) form_template = get_object_or_404(FormTemplate, slug=slug)
job = form_template.job job = form_template.job
if request.method == "POST": if request.method == "POST":
form = CandidateSignupForm(request.POST) form = ApplicantSignupForm(request.POST)
if form.is_valid(): if form.is_valid():
try: try:
first_name = form.cleaned_data["first_name"] first_name = form.cleaned_data["first_name"]
@ -5599,13 +5599,13 @@ def candidate_signup(request, slug):
messages.error(request, f"Error creating application: {str(e)}") messages.error(request, f"Error creating application: {str(e)}")
return render( return render(
request, request,
"recruitment/candidate_signup.html", "recruitment/applicant_signup.html",
{"form": form, "job": job}, {"form": form, "job": job},
) )
form = CandidateSignupForm() form = ApplicantSignupForm()
return render( return render(
request, "recruitment/candidate_signup.html", {"form": form, "job": job} request, "recruitment/applicant_signup.html", {"form": form, "job": job}
) )
@ -5959,7 +5959,7 @@ def reschedule_onsite_meeting(request, slug, candidate_id, meeting_id):
instance.save() instance.save()
messages.success(request, "Onsite meeting successfully rescheduled! ✅") messages.success(request, "Onsite meeting successfully rescheduled! ✅")
return redirect(reverse("candidate_interview_view", kwargs={'slug': job.slug})) return redirect(reverse("applications_interview_view", kwargs={'slug': job.slug}))
else: else:
form = OnsiteReshuduleForm(instance=onsite_meeting) form = OnsiteReshuduleForm(instance=onsite_meeting)
@ -5976,7 +5976,7 @@ def reschedule_onsite_meeting(request, slug, candidate_id, meeting_id):
# recruitment/views.py # recruitment/views.py
@staff_user_required @staff_user_required
def delete_onsite_meeting_for_candidate(request, slug, candidate_pk, meeting_id): def delete_onsite_meeting_for_application(request, slug, candidate_pk, meeting_id):
""" """
Deletes a specific Onsite Location Details instance. Deletes a specific Onsite Location Details instance.
This does not require an external API call. This does not require an external API call.
@ -5993,7 +5993,7 @@ def delete_onsite_meeting_for_candidate(request, slug, candidate_pk, meeting_id)
meeting.delete() meeting.delete()
messages.success(request, f"Onsite meeting for {candidate.name} deleted successfully.") messages.success(request, f"Onsite meeting for {candidate.name} deleted successfully.")
return redirect(reverse("candidate_interview_view", kwargs={"slug": job.slug})) return redirect(reverse("applications_interview_view", kwargs={"slug": job.slug}))
context = { context = {
"job": job, "job": job,
@ -6001,7 +6001,7 @@ def delete_onsite_meeting_for_candidate(request, slug, candidate_pk, meeting_id)
"meeting": meeting, "meeting": meeting,
"location_type": "Onsite", "location_type": "Onsite",
"delete_url": reverse( "delete_url": reverse(
"delete_onsite_meeting_for_candidate", # Use the specific new URL name "delete_onsite_meeting_for_application", # Use the specific new URL name
kwargs={ kwargs={
"slug": job.slug, "slug": job.slug,
"candidate_pk": candidate_pk, "candidate_pk": candidate_pk,
@ -6013,14 +6013,14 @@ def delete_onsite_meeting_for_candidate(request, slug, candidate_pk, meeting_id)
def schedule_onsite_meeting_for_candidate(request, slug, candidate_pk): def schedule_onsite_meeting_for_application(request, slug, candidate_pk):
""" """
Handles scheduling a NEW Onsite Interview for a candidate using OnsiteScheduleForm. Handles scheduling a NEW Onsite Interview for a candidate using OnsiteScheduleForm.
""" """
job = get_object_or_404(JobPosting, slug=slug) job = get_object_or_404(JobPosting, slug=slug)
candidate = get_object_or_404(Application, pk=candidate_pk) candidate = get_object_or_404(Application, pk=candidate_pk)
action_url = reverse('schedule_onsite_meeting_for_candidate', action_url = reverse('schedule_onsite_meeting_for_application',
kwargs={'slug': job.slug, 'candidate_pk': candidate.pk}) kwargs={'slug': job.slug, 'candidate_pk': candidate.pk})
if request.method == 'POST': if request.method == 'POST':
@ -6058,7 +6058,7 @@ def schedule_onsite_meeting_for_candidate(request, slug, candidate_pk):
) )
messages.success(request, "Onsite interview scheduled successfully. ✅") messages.success(request, "Onsite interview scheduled successfully. ✅")
return redirect(reverse("candidate_interview_view", kwargs={'slug': job.slug})) return redirect(reverse("applications_interview_view", kwargs={'slug': job.slug}))
else: else:
# GET Request: Initialize the hidden fields with the correct objects # GET Request: Initialize the hidden fields with the correct objects
@ -6139,7 +6139,7 @@ def meeting_details(request, slug):
@login_required @login_required
def send_candidate_invitation(request, slug): def send_application_invitation(request, slug):
"""Send invitation email to the candidate""" """Send invitation email to the candidate"""
meeting = get_object_or_404(InterviewLocation, slug=slug) meeting = get_object_or_404(InterviewLocation, slug=slug)

View File

@ -187,7 +187,7 @@ class ApplicationCreateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessa
model = models.Application model = models.Application
form_class = forms.ApplicationForm form_class = forms.ApplicationForm
template_name = 'recruitment/candidate_create.html' template_name = 'recruitment/candidate_create.html'
success_url = reverse_lazy('candidate_list') success_url = reverse_lazy('application_list')
success_message = 'Candidate created successfully.' success_message = 'Candidate created successfully.'
def get_initial(self): def get_initial(self):
@ -216,7 +216,7 @@ class ApplicationUpdateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessa
model = models.Application model = models.Application
form_class = forms.ApplicationForm form_class = forms.ApplicationForm
template_name = 'recruitment/candidate_update.html' template_name = 'recruitment/candidate_update.html'
success_url = reverse_lazy('candidate_list') success_url = reverse_lazy('application_list')
success_message = 'Candidate updated successfully.' success_message = 'Candidate updated successfully.'
slug_url_kwarg = 'slug' slug_url_kwarg = 'slug'
@ -224,7 +224,7 @@ class ApplicationUpdateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessa
class ApplicationDeleteView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, DeleteView): class ApplicationDeleteView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, DeleteView):
model = models.Application model = models.Application
template_name = 'recruitment/candidate_delete.html' template_name = 'recruitment/candidate_delete.html'
success_url = reverse_lazy('candidate_list') success_url = reverse_lazy('application_list')
success_message = 'Candidate deleted successfully.' success_message = 'Candidate deleted successfully.'
slug_url_kwarg = 'slug' slug_url_kwarg = 'slug'
@ -240,7 +240,7 @@ def retry_scoring_view(request,slug):
hook='recruitment.hooks.callback_ai_parsing', hook='recruitment.hooks.callback_ai_parsing',
sync=True, sync=True,
) )
return redirect('candidate_detail', slug=application.slug) return redirect('application_detail', slug=application.slug)
@ -253,7 +253,7 @@ def training_list(request):
@login_required @login_required
@staff_user_required @staff_user_required
def candidate_detail(request, slug): def application_detail(request, slug):
from rich.json import JSON from rich.json import JSON
candidate = get_object_or_404(models.Application, slug=slug) candidate = get_object_or_404(models.Application, slug=slug)
try: try:
@ -270,7 +270,7 @@ def candidate_detail(request, slug):
# parsed = JSON(json.dumps(parsed), indent=2, highlight=True, skip_keys=False, ensure_ascii=False, check_circular=True, allow_nan=True, default=None, sort_keys=False) # parsed = JSON(json.dumps(parsed), indent=2, highlight=True, skip_keys=False, ensure_ascii=False, check_circular=True, allow_nan=True, default=None, sort_keys=False)
# parsed = json_to_markdown_table([parsed]) # parsed = json_to_markdown_table([parsed])
return render(request, 'recruitment/candidate_detail.html', { return render(request, 'recruitment/application_detail.html', {
'candidate': candidate, 'candidate': candidate,
'parsed': parsed, 'parsed': parsed,
'stage_form': stage_form, 'stage_form': stage_form,
@ -279,13 +279,13 @@ def candidate_detail(request, slug):
@login_required @login_required
@staff_user_required @staff_user_required
def candidate_resume_template_view(request, slug): def application_resume_template_view(request, slug):
"""Display formatted resume template for a candidate""" """Display formatted resume template for a candidate"""
application = get_object_or_404(models.Application, slug=slug) application = get_object_or_404(models.Application, slug=slug)
if not request.user.is_staff: if not request.user.is_staff:
messages.error(request, _("You don't have permission to view this page.")) messages.error(request, _("You don't have permission to view this page."))
return redirect('candidate_list') return redirect('application_list')
return render(request, 'recruitment/candidate_resume_template.html', { return render(request, 'recruitment/candidate_resume_template.html', {
'application': application 'application': application
@ -293,7 +293,7 @@ def candidate_resume_template_view(request, slug):
@login_required @login_required
@staff_user_required @staff_user_required
def candidate_update_stage(request, slug): def application_update_stage(request, slug):
"""Handle HTMX stage update requests""" """Handle HTMX stage update requests"""
application = get_object_or_404(models.Application, slug=slug) application = get_object_or_404(models.Application, slug=slug)
form = forms.ApplicationStageForm(request.POST, instance=application) form = forms.ApplicationStageForm(request.POST, instance=application)
@ -302,7 +302,7 @@ def candidate_update_stage(request, slug):
application.stage = stage_value application.stage = stage_value
application.save(update_fields=['stage']) application.save(update_fields=['stage'])
messages.success(request,"application Stage Updated") messages.success(request,"application Stage Updated")
return redirect("candidate_detail",slug=application.slug) return redirect("application_detail",slug=application.slug)
class TrainingListView(LoginRequiredMixin, StaffRequiredMixin, ListView): class TrainingListView(LoginRequiredMixin, StaffRequiredMixin, ListView):
model = models.TrainingMaterial model = models.TrainingMaterial
@ -637,7 +637,7 @@ def dashboard_view(request):
@login_required @login_required
@staff_user_required @staff_user_required
def candidate_offer_view(request, slug): def applications_offer_view(request, slug):
"""View for candidates in the Offer stage""" """View for candidates in the Offer stage"""
job = get_object_or_404(models.JobPosting, slug=slug) job = get_object_or_404(models.JobPosting, slug=slug)
@ -667,7 +667,7 @@ def candidate_offer_view(request, slug):
@login_required @login_required
@staff_user_required @staff_user_required
def candidate_hired_view(request, slug): def applications_hired_view(request, slug):
"""View for hired candidates""" """View for hired candidates"""
job = get_object_or_404(models.JobPosting, slug=slug) job = get_object_or_404(models.JobPosting, slug=slug)
@ -697,7 +697,7 @@ def candidate_hired_view(request, slug):
@login_required @login_required
@staff_user_required @staff_user_required
def update_candidate_status(request, job_slug, candidate_slug, stage_type, status): def update_application_status(request, job_slug, candidate_slug, stage_type, status):
"""Handle exam/interview/offer status updates""" """Handle exam/interview/offer status updates"""
from django.utils import timezone from django.utils import timezone
@ -723,7 +723,7 @@ def update_candidate_status(request, job_slug, candidate_slug, stage_type, statu
candidate.offer_date = timezone.now() candidate.offer_date = timezone.now()
candidate.save(update_fields=['offer_status', 'offer_date']) candidate.save(update_fields=['offer_status', 'offer_date'])
return render(request,'recruitment/partials/offer-results.html',{'candidate':candidate,'job':job}) return render(request,'recruitment/partials/offer-results.html',{'candidate':candidate,'job':job})
return redirect('candidate_detail', candidate.slug) return redirect('application_detail', candidate.slug)
else: else:
if stage_type == 'exam': if stage_type == 'exam':
return render(request,"includes/candidate_update_exam_form.html",{'candidate':candidate,'job':job}) return render(request,"includes/candidate_update_exam_form.html",{'candidate':candidate,'job':job})
@ -765,7 +765,7 @@ STAGE_CONFIG = {
@login_required @login_required
@staff_user_required @staff_user_required
def export_candidates_csv(request, job_slug, stage): def export_applications_csv(request, job_slug, stage):
"""Export candidates for a specific stage as CSV""" """Export candidates for a specific stage as CSV"""
job = get_object_or_404(models.JobPosting, slug=job_slug) job = get_object_or_404(models.JobPosting, slug=job_slug)
@ -905,7 +905,7 @@ def export_candidates_csv(request, job_slug, stage):
@login_required @login_required
@staff_user_required @staff_user_required
def sync_hired_candidates(request, job_slug): def sync_hired_applications(request, job_slug):
"""Sync hired candidates to external sources using Django-Q""" """Sync hired candidates to external sources using Django-Q"""
from django_q.tasks import async_task from django_q.tasks import async_task
from .tasks import sync_hired_candidates_task from .tasks import sync_hired_candidates_task

View File

@ -323,7 +323,7 @@
<a class="nav-link text-secondary" href="{% url 'applicant_profile' %}">{% translate "Applications" %}</a> <a class="nav-link text-secondary" href="{% url 'applicant_profile' %}">{% translate "Applications" %}</a>
</li> {% endcomment %} </li> {% endcomment %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-secondary" href="{% url 'candidate_portal_dashboard' %}">{% translate "Profile" %}</a> <a class="nav-link text-secondary" href="{% url 'applicant_portal_dashboard' %}">{% translate "Profile" %}</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-secondary" href="{% url 'kaauh_career' %}">{% translate "Careers" %}</a> <a class="nav-link text-secondary" href="{% url 'kaauh_career' %}">{% translate "Careers" %}</a>

View File

@ -253,7 +253,7 @@
</a> </a>
</li> </li>
<li class="nav-item me-lg-4"> <li class="nav-item me-lg-4">
<a class="nav-link {% if request.resolver_match.url_name == 'candidate_list' %}active{% endif %}" href="{% url 'candidate_list' %}"> <a class="nav-link {% if request.resolver_match.url_name == 'application_list' %}active{% endif %}" href="{% url 'application_list' %}">
<span class="d-flex align-items-center gap-2"> <span class="d-flex align-items-center gap-2">
<i class="fas fa-user-tie me-2"></i> <i class="fas fa-user-tie me-2"></i>
{% trans "Applications" %} {% trans "Applications" %}

View File

@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
{% url 'update_candidate_exam_status' slug=candidate.slug as url %} {% url 'update_application_exam_status' slug=candidate.slug as url %}
<form data-on-submit="@post('{{url}}', {contentType: 'form', headers: {'X-CSRFToken': '{{ csrf_token }}'}})"> <form data-on-submit="@post('{{url}}', {contentType: 'form', headers: {'X-CSRFToken': '{{ csrf_token }}'}})">
{% csrf_token %} {% csrf_token %}
{{ form.as_p }} {{ form.as_p }}

View File

@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
<form id="exam-update-form" hx-post="{% url 'update_candidate_status' job.slug candidate.slug 'exam' 'Failed' %}" hx-swap='outerHTML' hx-target="#status-result-{{ candidate.pk }}" <form id="exam-update-form" hx-post="{% url 'update_application_status' job.slug candidate.slug 'exam' 'Failed' %}" hx-swap='outerHTML' hx-target="#status-result-{{ candidate.pk }}"
hx-on::after-request="const modal = bootstrap.Modal.getInstance(document.getElementById('candidateviewModal')); if (modal) { modal.hide(); }"> hx-on::after-request="const modal = bootstrap.Modal.getInstance(document.getElementById('candidateviewModal')); if (modal) { modal.hide(); }">
<div class="d-flex justify-content-center align-items-center gap-2"> <div class="d-flex justify-content-center align-items-center gap-2">
<div class="form-check d-flex align-items-center gap-2"> <div class="form-check d-flex align-items-center gap-2">

View File

@ -1,10 +1,10 @@
{% load i18n %} {% load i18n %}
<div class="d-flex justify-content-center align-items-center gap-2" hx-swap='outerHTML' hx-target="#interview-result-{{ candidate.pk }}" <div class="d-flex justify-content-center align-items-center gap-2" hx-swap='outerHTML' hx-target="#interview-result-{{ candidate.pk }}"
hx-on::after-request="const modal = bootstrap.Modal.getInstance(document.getElementById('candidateviewModal')); if (modal) { modal.hide(); }"> hx-on::after-request="const modal = bootstrap.Modal.getInstance(document.getElementById('candidateviewModal')); if (modal) { modal.hide(); }">
<a hx-post="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'Passed' %}" class="btn btn-outline-secondary"> <a hx-post="{% url 'update_application_status' job.slug candidate.slug 'interview' 'Passed' %}" class="btn btn-outline-secondary">
<i class="fas fa-check me-1"></i> {% trans "Passed" %} <i class="fas fa-check me-1"></i> {% trans "Passed" %}
</a> </a>
<a hx-post="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'Failed' %}" class="btn btn-danger"> <a hx-post="{% url 'update_application_status' job.slug candidate.slug 'interview' 'Failed' %}" class="btn btn-danger">
<i class="fas fa-times me-1"></i> {% trans "Failed" %} <i class="fas fa-times me-1"></i> {% trans "Failed" %}
</a> </a>
</div> </div>

View File

@ -1,10 +1,10 @@
{% load i18n %} {% load i18n %}
<div class="d-flex justify-content-center align-items-center gap-2" hx-swap='outerHTML' hx-target="#status-result-{{ candidate.pk }}" <div class="d-flex justify-content-center align-items-center gap-2" hx-swap='outerHTML' hx-target="#status-result-{{ candidate.pk }}"
hx-on::after-request="const modal = bootstrap.Modal.getInstance(document.getElementById('candidateviewModal')); if (modal) { modal.hide(); }"> hx-on::after-request="const modal = bootstrap.Modal.getInstance(document.getElementById('candidateviewModal')); if (modal) { modal.hide(); }">
<a hx-post="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'Accepted' %}" class="btn btn-outline-secondary"> <a hx-post="{% url 'update_application_status' job.slug candidate.slug 'offer' 'Accepted' %}" class="btn btn-outline-secondary">
<i class="fas fa-check me-1"></i> {% trans "Accepted" %} <i class="fas fa-check me-1"></i> {% trans "Accepted" %}
</a> </a>
<a hx-post="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'Rejected' %}" class="btn btn-danger"> <a hx-post="{% url 'update_application_status' job.slug candidate.slug 'offer' 'Rejected' %}" class="btn btn-danger">
<i class="fas fa-times me-1"></i> {% trans "Rejected" %} <i class="fas fa-times me-1"></i> {% trans "Rejected" %}
</a> </a>
</div> </div>

View File

@ -17,7 +17,7 @@
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<form hx-boost="true" method="post" id="email-compose-form" action="{% url 'compose_candidate_email' job.slug %}" <form hx-boost="true" method="post" id="email-compose-form" action="{% url 'compose_application_email' job.slug %}"
hx-include="#candidate-form" hx-include="#candidate-form"
hx-target="#messageContent" hx-target="#messageContent"
hx-select="#messageContent" hx-select="#messageContent"

View File

@ -91,7 +91,7 @@
<div class="card-body d-flex flex-column"> <div class="card-body d-flex flex-column">
<div class="d-flex justify-content-between align-items-start mb-2"> <div class="d-flex justify-content-between align-items-start mb-2">
<h5 class="card-title flex-grow-1 me-3"> <h5 class="card-title flex-grow-1 me-3">
<a href="{% url 'candidate_detail' interview.candidate.slug %}" class="text-decoration-none text-primary-theme">{{ interview.candidate.name }}</a> <a href="{% url 'application_detail' interview.candidate.slug %}" class="text-decoration-none text-primary-theme">{{ interview.candidate.name }}</a>
</h5> </h5>
<span class="status-badge bg-{{ interview.status }}"> <span class="status-badge bg-{{ interview.status }}">
{{ interview.status|title }} {{ interview.status|title }}
@ -169,7 +169,7 @@
<tr> <tr>
<td> <td>
<strong class="text-primary-theme"> <strong class="text-primary-theme">
<a href="{% url 'candidate_detail' interview.candidate.slug %}" class="text-decoration-none text-primary-theme">{{ interview.candidate.name }}</a> <a href="{% url 'application_detail' interview.candidate.slug %}" class="text-decoration-none text-primary-theme">{{ interview.candidate.name }}</a>
</strong> </strong>
</td> </td>
<td> <td>

View File

@ -127,7 +127,7 @@
</nav> </nav>
</div> </div>
<div> <div>
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action"> <a href="{% url 'application_create_for_job' job.slug %}" class="btn btn-main-action">
<i class="fas fa-user-plus"></i> {% trans "Add New Applicant" %} <i class="fas fa-user-plus"></i> {% trans "Add New Applicant" %}
</a> </a>
</div> </div>
@ -186,7 +186,7 @@
</button> </button>
</div> </div>
<div class="col-md-3 d-flex align-items-end"> <div class="col-md-3 d-flex align-items-end">
<a href="{% url 'job_candidates_list' job.slug %}" class="btn btn-outline-secondary w-100"> <a href="{% url 'job_applications_list' job.slug %}" class="btn btn-outline-secondary w-100">
<i class="fas fa-times"></i> {% trans "Clear Filters" %} <i class="fas fa-times"></i> {% trans "Clear Filters" %}
</a> </a>
</div> </div>
@ -250,16 +250,16 @@
<td class="text-secondary small">{{ candidate.created_at|date:"M d, Y" }}</td> <td class="text-secondary small">{{ candidate.created_at|date:"M d, Y" }}</td>
<td class="text-center pe-3"> <td class="text-center pe-3">
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'View' %}"> <a href="{% url 'application_detail' candidate.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'View' %}">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
</a> </a>
{% if user.is_staff %} {% if user.is_staff %}
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Edit' %}"> <a href="{% url 'application_update' candidate.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
</a> </a>
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}" <button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal" data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'candidate_delete' candidate.slug %}" data-delete-url="{% url 'application_delete' candidate.slug %}"
data-item-name="{{ candidate.first_name }} {{ candidate.last_name }}"> data-item-name="{{ candidate.first_name }} {{ candidate.last_name }}">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
</button> </button>
@ -345,17 +345,17 @@
</div> </div>
<div class="card-footer"> <div class="card-footer">
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-secondary w-100"> <a href="{% url 'application_detail' candidate.slug %}" class="btn btn-outline-secondary w-100">
<i class="fas fa-eye"></i> {% trans "View Profile" %} <i class="fas fa-eye"></i> {% trans "View Profile" %}
</a> </a>
{% if user.is_staff %} {% if user.is_staff %}
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary" title="{% trans 'Edit' %}"> <a href="{% url 'application_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
</a> </a>
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}" <button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal" data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'candidate_delete' candidate.slug %}" data-delete-url="{% url 'application_delete' candidate.slug %}"
data-item-name="{{ candidate.first_name }} {{ candidate.last_name }}"> data-item-name="{{ candidate.first_name }} {{ candidate.last_name }}">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
</button> </button>
@ -375,7 +375,7 @@
<i class="fas fa-user-slash fa-3x text-muted mb-3"></i> <i class="fas fa-user-slash fa-3x text-muted mb-3"></i>
<h4 class="text-muted">{% trans "No applicants found" %}</h4> <h4 class="text-muted">{% trans "No applicants found" %}</h4>
<p class="text-secondary">{% trans "There are no candidates who have applied for this position yet." %}</p> <p class="text-secondary">{% trans "There are no candidates who have applied for this position yet." %}</p>
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action mt-3"> <a href="{% url 'application_create_for_job' job.slug %}" class="btn btn-main-action mt-3">
<i class="fas fa-user-plus"></i> {% trans "Add First Applicant" %} <i class="fas fa-user-plus"></i> {% trans "Add First Applicant" %}
</a> </a>
</div> </div>

View File

@ -325,10 +325,10 @@
<h5 class="mb-3">{% trans "Total Applicants" %} (<span id="total_candidates">{{ total_applicants }}</span>)</h5> <h5 class="mb-3">{% trans "Total Applicants" %} (<span id="total_candidates">{{ total_applicants }}</span>)</h5>
<div class="d-grid gap-3"> <div class="d-grid gap-3">
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action"> <a href="{% url 'application_create_for_job' job.slug %}" class="btn btn-main-action">
<i class="fas fa-user-plus me-1"></i> {% trans "Create Applicant" %} <i class="fas fa-user-plus me-1"></i> {% trans "Create Applicant" %}
</a> </a>
<a href="{% url 'candidate_screening_view' job.slug %}" class="btn btn-main-action"> <a href="{% url 'applications_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>

View File

@ -330,12 +330,12 @@
</td> </td>
{# CANDIDATE MANAGEMENT DATA #} {# CANDIDATE MANAGEMENT DATA #}
<td class="candidate-data-cell text-primary-theme"><a href="{% url 'candidate_screening_view' job.slug %}" class="text-primary-theme">{% if job.all_candidates.count %}{{ job.all_candidates.count }}{% else %}-{% endif %}</a></td> <td class="candidate-data-cell text-primary-theme"><a href="{% url 'applications_screening_view' job.slug %}" class="text-primary-theme">{% if job.all_candidates.count %}{{ job.all_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-info"><a href="{% url 'candidate_screening_view' job.slug %}" class="text-info">{% if job.screening_candidates.count %}{{ job.screening_candidates.count }}{% else %}-{% endif %}</a></td> <td class="candidate-data-cell text-info"><a href="{% url 'applications_screening_view' job.slug %}" class="text-info">{% if job.screening_candidates.count %}{{ job.screening_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_exam_view' job.slug %}" class="text-success">{% if job.exam_candidates.count %}{{ job.exam_candidates.count }}{% else %}-{% endif %}</a></td> <td class="candidate-data-cell text-success"><a href="{% url 'applications_exam_view' job.slug %}" class="text-success">{% if job.exam_candidates.count %}{{ job.exam_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_interview_view' job.slug %}" class="text-success">{% if job.interview_candidates.count %}{{ job.interview_candidates.count }}{% else %}-{% endif %}</a></td> <td class="candidate-data-cell text-success"><a href="{% url 'applications_interview_view' job.slug %}" class="text-success">{% if job.interview_candidates.count %}{{ job.interview_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_document_review_view' job.slug %}" class="text-success">{% if job.document_review_candidates.count %}{{ job.document_review_candidates.count }}{% else %}-{% endif %}</a></td> <td class="candidate-data-cell text-success"><a href="{% url 'applications_document_review_view' job.slug %}" class="text-success">{% if job.document_review_candidates.count %}{{ job.document_review_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_offer_view' job.slug %}" class="text-success">{% if job.offer_candidates.count %}{{ job.offer_candidates.count }}{% else %}-{% endif %}</a></td> <td class="candidate-data-cell text-success"><a href="{% url 'applications_offer_view' job.slug %}" class="text-success">{% if job.offer_candidates.count %}{{ job.offer_candidates.count }}{% else %}-{% endif %}</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@ -102,7 +102,7 @@
<div class="progress-stages"> <div class="progress-stages">
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
{% comment %} STAGE 1: Applied {% endcomment %} {% comment %} STAGE 1: Applied {% endcomment %}
<a href="{% url 'candidate_screening_view' job.slug %}" <a href="{% url 'applications_screening_view' job.slug %}"
class="stage-item {% if current_stage == 'Applied' %}active{% endif %}" class="stage-item {% if current_stage == 'Applied' %}active{% endif %}"
data-stage="Applied"> data-stage="Applied">
<div class="stage-icon"> <div class="stage-icon">
@ -116,7 +116,7 @@
<div class="stage-connector {% if current_stage == 'Exam' or current_stage == 'Interview' or current_stage == 'Document Review' or current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div> <div class="stage-connector {% if current_stage == 'Exam' or current_stage == 'Interview' or current_stage == 'Document Review' or current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div>
{% comment %} STAGE 2: Exam {% endcomment %} {% comment %} STAGE 2: Exam {% endcomment %}
<a href="{% url 'candidate_exam_view' job.slug %}" <a href="{% url 'applications_exam_view' job.slug %}"
class="stage-item {% if current_stage == 'Exam' %}active{% endif %}" class="stage-item {% if current_stage == 'Exam' %}active{% endif %}"
data-stage="Exam"> data-stage="Exam">
<div class="stage-icon"> <div class="stage-icon">
@ -130,7 +130,7 @@
<div class="stage-connector {% if current_stage == 'Interview' or current_stage == 'Document Review' or current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div> <div class="stage-connector {% if current_stage == 'Interview' or current_stage == 'Document Review' or current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div>
{% comment %} STAGE 3: Interview {% endcomment %} {% comment %} STAGE 3: Interview {% endcomment %}
<a href="{% url 'candidate_interview_view' job.slug %}" <a href="{% url 'applications_interview_view' job.slug %}"
class="stage-item {% if current_stage == 'Interview' %}active{% endif %}" class="stage-item {% if current_stage == 'Interview' %}active{% endif %}"
data-stage="Interview"> data-stage="Interview">
<div class="stage-icon"> <div class="stage-icon">
@ -144,7 +144,7 @@
<div class="stage-connector {% if current_stage == 'Document Review' or current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div> <div class="stage-connector {% if current_stage == 'Document Review' or current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div>
{% comment %} STAGE 4: Document Review {% endcomment %} {% comment %} STAGE 4: Document Review {% endcomment %}
<a href="{% url 'candidate_document_review_view' job.slug %}" <a href="{% url 'applications_document_review_view' job.slug %}"
class="stage-item {% if current_stage == 'Document Review' %}active{% endif %} {% if current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}" class="stage-item {% if current_stage == 'Document Review' %}active{% endif %} {% if current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"
data-stage="Document Review"> data-stage="Document Review">
<div class="stage-icon"> <div class="stage-icon">
@ -158,7 +158,7 @@
<div class="stage-connector {% if current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div> <div class="stage-connector {% if current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div>
{% comment %} STAGE 5: Offer {% endcomment %} {% comment %} STAGE 5: Offer {% endcomment %}
<a href="{% url 'candidate_offer_view' job.slug %}" <a href="{% url 'applications_offer_view' job.slug %}"
class="stage-item {% if current_stage == 'Offer' %}active{% endif %} {% if current_stage == 'Hired' %}completed{% endif %}" class="stage-item {% if current_stage == 'Offer' %}active{% endif %} {% if current_stage == 'Hired' %}completed{% endif %}"
data-stage="Offer"> data-stage="Offer">
<div class="stage-icon"> <div class="stage-icon">
@ -172,7 +172,7 @@
<div class="stage-connector {% if current_stage == 'Hired' %}completed{% endif %}"></div> <div class="stage-connector {% if current_stage == 'Hired' %}completed{% endif %}"></div>
{% comment %} STAGE 6: Hired {% endcomment %} {% comment %} STAGE 6: Hired {% endcomment %}
<a href="{% url 'candidate_hired_view' job.slug %}" <a href="{% url 'applications_hired_view' job.slug %}"
class="stage-item {% if current_stage == 'Hired' %}active{% endif %}" class="stage-item {% if current_stage == 'Hired' %}active{% endif %}"
data-stage="Hired"> data-stage="Hired">
<div class="stage-icon"> <div class="stage-icon">

View File

@ -290,7 +290,7 @@
<span class="status-badge bg-primary-theme text-white">{{ meeting.type|title }}</span> <span class="status-badge bg-primary-theme text-white">{{ meeting.type|title }}</span>
</td> </td>
<td> <td>
<a class="text-primary text-decoration-none" href="{% url 'candidate_detail' meeting.interview.application.person.slug %}">{{ meeting.interview.application.person.full_name }} <i class="fas fa-link"></i></a> <a class="text-primary text-decoration-none" href="{% url 'application_detail' meeting.interview.application.person.slug %}">{{ meeting.interview.application.person.full_name }} <i class="fas fa-link"></i></a>
</td> </td>
<td> <td>
<a class="text-primary text-decoration-none" href="{% url 'job_detail' meeting.interview.job.slug %}">{{ meeting.interview.job.title }} <i class="fas fa-link"></i></a> <a class="text-primary text-decoration-none" href="{% url 'job_detail' meeting.interview.job.slug %}">{{ meeting.interview.job.title }} <i class="fas fa-link"></i></a>

View File

@ -218,7 +218,7 @@ body {
</a> </a>
{# Send Candidate Invitation Button #} {# Send Candidate Invitation Button #}
<form method="post" action="{% url 'send_candidate_invitation' meeting.slug %}" style="display: inline;"> <form method="post" action="{% url 'send_application_invitation' meeting.slug %}" style="display: inline;">
{% csrf_token %} {% csrf_token %}
<button type="submit" class="btn btn-outline-info btn-sm" onclick="return confirm('{% trans "Send invitation email to the candidate?" %}')"> <button type="submit" class="btn btn-outline-info btn-sm" onclick="return confirm('{% trans "Send invitation email to the candidate?" %}')">
<i class="fas fa-envelope me-1"></i> {% trans "Send Candidate Invitation" %} <i class="fas fa-envelope me-1"></i> {% trans "Send Candidate Invitation" %}

View File

@ -19,7 +19,7 @@
</div> </div>
<div> <div>
<form method="post" id="updateMeeting" action="{% url 'reschedule_meeting_for_candidate' job.slug candidate.pk meeting.pk %}"> <form method="post" id="updateMeeting" action="{% url 'reschedule_meeting_for_application' job.slug candidate.pk meeting.pk %}">
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">

View File

@ -20,7 +20,7 @@
</div> </div>
<div> <div>
<form method="post" action="{% url 'schedule_meeting_for_candidate' job.slug candidate.pk %}"> <form method="post" action="{% url 'schedule_meeting_for_application' job.slug candidate.pk %}">
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
<label for="{{ form.topic.id_for_label }}" class="form-label small"> <label for="{{ form.topic.id_for_label }}" class="form-label small">

View File

@ -1,5 +1,5 @@
{% load i18n crispy_forms_tags %} {% load i18n crispy_forms_tags %}
<form action="{% url 'set_meeting_candidate' meeting.slug %}" method="post" class="d-flex flex-column gap-2 py-2 px-4"> <form action="{% url 'set_meeting_application' meeting.slug %}" method="post" class="d-flex flex-column gap-2 py-2 px-4">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
<button type="submit" class="btn bg-primary-theme text-white">{% trans "Save" %}</button> <button type="submit" class="btn bg-primary-theme text-white">{% trans "Save" %}</button>

View File

@ -412,7 +412,7 @@
<div class="d-flex justify-content-between align-items-start"> <div class="d-flex justify-content-between align-items-start">
<div> <div>
<h6 class="mb-1"> <h6 class="mb-1">
<a href="{% url 'candidate_detail' application.slug %}" <a href="{% url 'application_detail' application.slug %}"
class="text-decoration-none text-secondary"> class="text-decoration-none text-secondary">
{{ application.job.title }} {{ application.job.title }}
</a> </a>

View File

@ -55,7 +55,7 @@
<nav class="navbar navbar-expand-lg navbar-dark sticky-top"> <nav class="navbar navbar-expand-lg navbar-dark sticky-top">
<div class="container-fluid" style="max-width: 1600px;"> <div class="container-fluid" style="max-width: 1600px;">
{% if request.user.user_type == 'candidate' %} {% if request.user.user_type == 'candidate' %}
<a class="navbar-brand text-white" href="{% url 'candidate_portal_dashboard' %}" aria-label="Applicant Dashboard"> <a class="navbar-brand text-white" href="{% url 'applicant_portal_dashboard' %}" aria-label="Applicant Dashboard">
<img src="{% static 'image/kaauh_green1.png' %}" alt="{% trans 'kaauh logo green bg' %}" style="width: 40px; height: 40px;"> <img src="{% static 'image/kaauh_green1.png' %}" alt="{% trans 'kaauh logo green bg' %}" style="width: 40px; height: 40px;">
<span class="ms-3 d-none d-md-inline fw-semibold">{% trans "Applicant Portal" %}</span> <span class="ms-3 d-none d-md-inline fw-semibold">{% trans "Applicant Portal" %}</span>
</a> </a>
@ -106,7 +106,7 @@
</li> </li>
{% elif request.user.user_type == 'candidate' %} {% elif request.user.user_type == 'candidate' %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-white" href="{% url 'candidate_portal_dashboard' %}"> <a class="nav-link text-white" href="{% url 'applicant_portal_dashboard' %}">
<i class="fas fa-tachometer-alt me-1"></i> {% trans "Dashboard" %} <i class="fas fa-tachometer-alt me-1"></i> {% trans "Dashboard" %}
</a> </a>
</li> </li>

View File

@ -277,7 +277,7 @@
<span class="small text-muted">{{ candidate.created_at|date:"M d, Y" }}</span> <span class="small text-muted">{{ candidate.created_at|date:"M d, Y" }}</span>
</td> </td>
<td class="px-4 text-end"> <td class="px-4 text-end">
<a href="{% url 'candidate_detail' candidate.slug %}" <a href="{% url 'application_detail' candidate.slug %}"
class="btn btn-sm btn-outline-primary" title="{% trans 'View Details' %}"> class="btn btn-sm btn-outline-primary" title="{% trans 'View Details' %}">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
</a> </a>

View File

@ -114,7 +114,7 @@
<a href="{% url 'agency_portal_dashboard' %}" class="btn btn-outline-secondary btn-sm me-2"> <a href="{% url 'agency_portal_dashboard' %}" class="btn btn-outline-secondary btn-sm me-2">
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Dashboard" %} <i class="fas fa-arrow-left me-1"></i> {% trans "Back to Dashboard" %}
</a> </a>
<a href="{% url 'agency_portal_submit_candidate_page' assignment.slug %}" class="btn btn-sm btn-main-action {% if assignment.is_full %}disabled{% endif %}" > <a href="{% url 'agency_portal_submit_application_page' assignment.slug %}" class="btn btn-sm btn-main-action {% if assignment.is_full %}disabled{% endif %}" >
<i class="fas fa-user-plus me-1"></i> {% trans "Submit New Candidate" %} <i class="fas fa-user-plus me-1"></i> {% trans "Submit New Candidate" %}
</a> </a>
{% comment %} <a href="#" class="btn btn-outline-info"> {% comment %} <a href="#" class="btn btn-outline-info">
@ -194,7 +194,7 @@
<div class="d-grid gap-2"> <div class="d-grid gap-2">
{% if assignment.can_submit %} {% if assignment.can_submit %}
<a href="{% url 'agency_portal_submit_candidate_page' assignment.slug %}" class="btn btn-main-action"> <a href="{% url 'agency_portal_submit_application_page' assignment.slug %}" class="btn btn-main-action">
<i class="fas fa-user-plus me-1"></i> {% trans "Submit New Candidate" %} <i class="fas fa-user-plus me-1"></i> {% trans "Submit New Candidate" %}
</a> </a>
{% else %} {% else %}
@ -264,7 +264,7 @@
</div> </div>
</td> </td>
<td> <td>
<a href="{% url 'candidate_application_detail' candidate.slug %}" class="btn btn-sm btn-outline-primary" title="{% trans 'View Profile' %}"> <a href="{% url 'applicant_application_detail' candidate.slug %}" class="btn btn-sm btn-outline-primary" title="{% trans 'View Profile' %}">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
</a> </a>
</td> </td>
@ -523,7 +523,7 @@
</h5> </h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button> <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div> </div>
<form id="editCandidateForm" method="post" action="{% url 'agency_portal_edit_candidate' 0 %}"> <form id="editCandidateForm" method="post" action="{% url 'agency_portal_edit_application' 0 %}">
{% csrf_token %} {% csrf_token %}
<input type="hidden" id="edit_candidate_id" name="candidate_id"> <input type="hidden" id="edit_candidate_id" name="candidate_id">
<div class="modal-body"> <div class="modal-body">
@ -588,7 +588,7 @@
</h5> </h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button> <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div> </div>
<form id="deleteCandidateForm" method="post" action="{% url 'agency_portal_delete_candidate' 0 %}"> <form id="deleteCandidateForm" method="post" action="{% url 'agency_portal_delete_application' 0 %}">
{% csrf_token %} {% csrf_token %}
<input type="hidden" id="delete_candidate_id" name="candidate_id"> <input type="hidden" id="delete_candidate_id" name="candidate_id">
<div class="modal-body"> <div class="modal-body">

View File

@ -49,7 +49,7 @@
</p> </p>
</div> </div>
<div> <div>
{% comment %} <a href="{% url 'agency_portal_submit_candidate' %}" class="btn btn-main-action me-2"> {% comment %} <a href="{% url 'agency_portal_submit_application' %}" class="btn btn-main-action me-2">
<i class="fas fa-user-plus me-1"></i> {% trans "Submit Candidate" %} <i class="fas fa-user-plus me-1"></i> {% trans "Submit Candidate" %}
</a> </a>
<a href="#" class="btn btn-outline-secondary position-relative"> <a href="#" class="btn btn-outline-secondary position-relative">
@ -192,7 +192,7 @@
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
<div> <div>
{% if stats.can_submit %} {% if stats.can_submit %}
<a href="{% url 'agency_portal_submit_candidate_page' stats.assignment.slug %}" <a href="{% url 'agency_portal_submit_application_page' stats.assignment.slug %}"
class="btn btn-sm btn-main-action"> class="btn btn-sm btn-main-action">
<i class="fas fa-user-plus me-1"></i> {% trans "Submit Candidate" %} <i class="fas fa-user-plus me-1"></i> {% trans "Submit Candidate" %}
</a> </a>

View File

@ -235,7 +235,7 @@
{% endif %} {% endif %}
</p> </p>
{% if not search_query and not stage_filter and agency.assignments.exists %} {% if not search_query and not stage_filter and agency.assignments.exists %}
<a href="{% url 'agency_portal_submit_candidate_page' agency.assignments.first.slug %}" <a href="{% url 'agency_portal_submit_application_page' agency.assignments.first.slug %}"
class="btn btn-main-action"> class="btn btn-main-action">
<i class="fas fa-user-plus me-1"></i> {% trans "Add First Person" %} <i class="fas fa-user-plus me-1"></i> {% trans "Add First Person" %}
</a> </a>

View File

@ -175,7 +175,7 @@
</h5> </h5>
<form method="post" enctype="multipart/form-data" id="candidateForm" <form method="post" enctype="multipart/form-data" id="candidateForm"
action="{% url 'agency_portal_submit_candidate_page' assignment.slug %}"> action="{% url 'agency_portal_submit_application_page' assignment.slug %}">
{% csrf_token %} {% csrf_token %}
{{form|crispy}} {{form|crispy}}
<button type="submit" class="btn btn-main-action"> <button type="submit" class="btn btn-main-action">

View File

@ -184,10 +184,10 @@
<nav aria-label="breadcrumb" class="mb-4"> <nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li class="breadcrumb-item"> <li class="breadcrumb-item">
<a href="{% url 'candidate_portal_dashboard' %}" class=" text-decoration-none text-secondary">{% trans "Dashboard" %}</a> <a href="{% url 'applicant_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 'applicant_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 */
@ -315,13 +315,13 @@
<div class="row mb-5"> <div class="row mb-5">
<div class="col-md-6 col-6"> <div class="col-md-6 col-6">
<a href="{% url 'candidate_portal_dashboard' %}" class="text-decoration-none text-dark"> <a href="{% url 'applicant_portal_dashboard' %}" class="text-decoration-none text-dark">
<div class="kaauh-card h-50 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>
<p class="text-muted small">{% trans "View all applications" %}</p> <p class="text-muted small">{% trans "View all applications" %}</p>
<a href="{% url 'candidate_portal_dashboard' %}" class="btn btn-main-action btn-sm w-100"> <a href="{% url 'applicant_portal_dashboard' %}" class="btn btn-main-action btn-sm w-100">
{% trans "Dashboard" %} {% trans "Dashboard" %}
</a> </a>
</div> </div>

View File

@ -100,7 +100,7 @@
<i class="fas fa-user-plus me-1"></i> <i class="fas fa-user-plus me-1"></i>
<span class="d-none d-sm-inline">{% trans "Create New Person" %}</span> <span class="d-none d-sm-inline">{% trans "Create New Person" %}</span>
</button> </button>
<a href="{% url 'candidate_list' %}" class="btn btn-outline-light btn-sm" title="{% trans 'Back to List' %}"> <a href="{% url 'application_list' %}" class="btn btn-outline-light btn-sm" title="{% trans 'Back to List' %}">
<i class="fas fa-arrow-left"></i> <i class="fas fa-arrow-left"></i>
<span class="d-none d-sm-inline">{% trans "Back to List" %}</span> <span class="d-none d-sm-inline">{% trans "Back to List" %}</span>
</a> </a>

View File

@ -648,13 +648,13 @@
<div class="card shadow-sm mb-2 p-2"> <div class="card shadow-sm mb-2 p-2">
<h5 class="text-muted mb-3"><i class="fas fa-cog me-2"></i>{% trans "Management Actions" %}</h5> <h5 class="text-muted mb-3"><i class="fas fa-cog me-2"></i>{% trans "Management Actions" %}</h5>
<div class="d-grid gap-2"> <div class="d-grid gap-2">
{% comment %} <a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-primary"> {% comment %} <a href="{% url 'application_update' candidate.slug %}" class="btn btn-outline-primary">
<i class="fas fa-edit"></i> {% trans "Edit Details" %} <i class="fas fa-edit"></i> {% trans "Edit Details" %}
</a> {% endcomment %} </a> {% endcomment %}
{% comment %} <a href="{% url 'candidate_delete' candidate.slug %}" class="btn btn-outline-danger" onclick="return confirm('{% trans "Are you sure you want to delete this candidate?" %}')"> {% comment %} <a href="{% url 'application_delete' candidate.slug %}" class="btn btn-outline-danger" onclick="return confirm('{% trans "Are you sure you want to delete this candidate?" %}')">
<i class="fas fa-trash-alt"></i> {% trans "Delete Candidate" %} <i class="fas fa-trash-alt"></i> {% trans "Delete Candidate" %}
</a> {% endcomment %} </a> {% endcomment %}
<a href="{% url 'candidate_list' %}" class="btn btn-outline-secondary"> <a href="{% url 'application_list' %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left"></i> {% trans "Back to List" %} <i class="fas fa-arrow-left"></i> {% trans "Back to List" %}
</a> </a>
{% if candidate.resume %} {% if candidate.resume %}
@ -669,7 +669,7 @@
{% trans "Download Resume" %} {% trans "Download Resume" %}
</a> </a>
{% comment %} <a href="{% url 'candidate_resume_template' candidate.slug %}" class="btn btn-outline-info"> {% comment %} <a href="{% url 'application_resume_template' candidate.slug %}" class="btn btn-outline-info">
<i class="fas fa-file-alt me-1"></i> <i class="fas fa-file-alt me-1"></i>
{% trans "View Resume AI Overview" %} {% trans "View Resume AI Overview" %}
</a> {% endcomment %} </a> {% endcomment %}
@ -711,7 +711,7 @@
</div> </div>
{% else %} {% else %}
<div style="display: flex; justify-content: center; align-items: center; height: 100%;"> <div style="display: flex; justify-content: center; align-items: center; height: 100%;">
<button type="submit" class="btn btn-sm btn-main-action" hx-get="{% url 'candidate_retry_scoring' candidate.slug %}" hx-select=".resume-parsed-section" hx-target=".resume-parsed-section" hx-swap="outerHTML" hx-on:click="this.disabled=true;this.innerHTML=`Scoring Resume , Please Wait.. <i class='fa-solid fa-spinner fa-spin'></i>`"> <button type="submit" class="btn btn-sm btn-main-action" hx-get="{% url 'application_retry_scoring' candidate.slug %}" hx-select=".resume-parsed-section" hx-target=".resume-parsed-section" hx-swap="outerHTML" hx-on:click="this.disabled=true;this.innerHTML=`Scoring Resume , Please Wait.. <i class='fa-solid fa-spinner fa-spin'></i>`">
<i class="fas fa-redo-alt me-1"></i> <i class="fas fa-redo-alt me-1"></i>
{% trans "Unable to Parse Resume , click to retry" %} {% trans "Unable to Parse Resume , click to retry" %}
</button> </button>

View File

@ -71,7 +71,7 @@
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium"> <td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<div class="flex space-x-2"> <div class="flex space-x-2">
{% if document.file %} {% if document.file %}
<a href="{% url 'candidate_document_download' document.id %}" <a href="{% url 'application_document_download' document.id %}"
class="text-green-600 hover:text-green-800 mr-3" class="text-green-600 hover:text-green-800 mr-3"
title="Download document"> title="Download document">
<i class="fas fa-download"></i> <i class="fas fa-download"></i>

View File

@ -211,7 +211,7 @@
</h2> </h2>
</div> </div>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
{% comment %} <a href="{% url 'export_candidates_csv' job.slug 'document_review' %}" {% comment %} <a href="{% url 'export_applications_csv' job.slug 'document_review' %}"
class="btn btn-outline-secondary" class="btn btn-outline-secondary"
title="{% trans 'Export document review candidates to CSV' %}"> title="{% trans 'Export document review candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %} <i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -262,7 +262,7 @@
<div class="d-flex align-items-end gap-3"> <div class="d-flex align-items-end gap-3">
{# Form 1: Status Update #} {# Form 1: Status Update #}
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group"> <form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group">
{% csrf_token %} {% csrf_token %}
{# Select Input Group - No label needed for this one, so we just flex the select and button #} {# Select Input Group - No label needed for this one, so we just flex the select and button #}
@ -290,7 +290,7 @@
data-bs-toggle="modal" data-bs-toggle="modal"
hx-boost='true' hx-boost='true'
data-bs-target="#emailModal" data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}" hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody" hx-target="#emailModalBody"
hx-include="#candidate-form" hx-include="#candidate-form"
title="Email Participants"> title="Email Participants">
@ -300,7 +300,7 @@
</div> </div>
<div class="table-responsive"> <div class="table-responsive">
<form id="candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="get"> <form id="candidate-form" action="{% url 'application_update_status' job.slug %}" method="get">
<table class="table candidate-table align-middle"> <table class="table candidate-table align-middle">
<thead> <thead>
<tr> <tr>
@ -398,7 +398,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm" <button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}" hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="View Profile"> title="View Profile">
<i class="fas fa-eye ms-1"></i> <i class="fas fa-eye ms-1"></i>

View File

@ -178,7 +178,7 @@
</h2> </h2>
</div> </div>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<a href="{% url 'export_candidates_csv' job.slug 'exam' %}" <a href="{% url 'export_applications_csv' job.slug 'exam' %}"
class="btn btn-outline-secondary" class="btn btn-outline-secondary"
title="{% trans 'Export exam candidates to CSV' %}"> title="{% trans 'Export exam candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %} <i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -202,7 +202,7 @@
<div class="kaauh-card shadow-sm p-3"> <div class="kaauh-card shadow-sm p-3">
{% if candidates %} {% if candidates %}
<div class="bulk-action-bar p-3 bg-light border-bottom"> <div class="bulk-action-bar p-3 bg-light border-bottom">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="action-group"> <form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="action-group">
{% csrf_token %} {% csrf_token %}
{# Using d-flex for horizontal alignment and align-items-end to align items to the bottom baseline #} {# Using d-flex for horizontal alignment and align-items-end to align items to the bottom baseline #}
@ -233,7 +233,7 @@
data-bs-toggle="modal" data-bs-toggle="modal"
hx-boost='true' hx-boost='true'
data-bs-target="#emailModal" data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}" hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody" hx-target="#emailModalBody"
hx-include="#candidate-form" hx-include="#candidate-form"
title="Email Participants"> title="Email Participants">
@ -304,7 +304,7 @@
<button type="button" class="btn btn-warning btn-sm" <button type="button" class="btn btn-warning btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'exam' 'passed' %}" hx-get="{% url 'update_application_status' job.slug candidate.slug 'exam' 'passed' %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Pass Exam"> title="Pass Exam">
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
@ -314,7 +314,7 @@
<button type="button" class="btn btn-{% if candidate.exam_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm" <button type="button" class="btn btn-{% if candidate.exam_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'exam' 'passed' %}" hx-get="{% url 'update_application_status' job.slug candidate.slug 'exam' 'passed' %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Pass Exam"> title="Pass Exam">
{{ candidate.exam_status }} {{ candidate.exam_status }}
@ -329,7 +329,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm" <button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}" hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="View Profile"> title="View Profile">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>

View File

@ -202,7 +202,7 @@
title="{% trans 'Sync hired candidates to external sources' %}"> title="{% trans 'Sync hired candidates to external sources' %}">
<i class="fas fa-sync me-1"></i> {% trans "Sync to Sources" %} <i class="fas fa-sync me-1"></i> {% trans "Sync to Sources" %}
</button> </button>
<a href="{% url 'export_candidates_csv' job.slug 'hired' %}" <a href="{% url 'export_applications_csv' job.slug 'hired' %}"
class="btn btn-outline-secondary" class="btn btn-outline-secondary"
title="{% trans 'Export hired candidates to CSV' %}"> title="{% trans 'Export hired candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %} <i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -227,7 +227,7 @@
<div class="kaauh-card shadow-sm p-3"> <div class="kaauh-card shadow-sm p-3">
{% if candidates %} {% if candidates %}
<div class="bulk-action-bar p-3 bg-light border-bottom"> <div class="bulk-action-bar p-3 bg-light border-bottom">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="action-group"> <form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="action-group">
{% csrf_token %} {% csrf_token %}
{# MODIFIED: Using d-flex for horizontal alignment and align-items-end to align everything based on the baseline of the button/select #} {# MODIFIED: Using d-flex for horizontal alignment and align-items-end to align everything based on the baseline of the button/select #}
@ -256,7 +256,7 @@
data-bs-toggle="modal" data-bs-toggle="modal"
hx-boost='true' hx-boost='true'
data-bs-target="#emailModal" data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}" hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody" hx-target="#emailModalBody"
hx-include="#candidate-form" hx-include="#candidate-form"
title="Email Participants"> title="Email Participants">
@ -269,7 +269,7 @@
{% endif %} {% endif %}
<div class="table-responsive"> <div class="table-responsive">
<form id="candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="get"> <form id="candidate-form" action="{% url 'application_update_status' job.slug %}" method="get">
{% csrf_token %} {% csrf_token %}
<table class="table candidate-table align-middle"> <table class="table candidate-table align-middle">
<thead> <thead>
@ -337,12 +337,12 @@
<button type="button" class="btn btn-outline-secondary btn-sm" <button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}" hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="View Profile"> title="View Profile">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
</button> </button>
<a href="{% url 'candidate_resume_template' candidate.slug %}" <a href="{% url 'application_resume_template' candidate.slug %}"
class="btn btn-outline-primary btn-sm" class="btn btn-outline-primary btn-sm"
title="View Resume Template"> title="View Resume Template">
<i class="fas fa-file-alt"></i> <i class="fas fa-file-alt"></i>
@ -503,7 +503,7 @@
syncButton.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i> {% trans "Syncing..." %}'; syncButton.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i> {% trans "Syncing..." %}';
// Perform sync request // Perform sync request
fetch(`{% url 'sync_hired_candidates' job.slug %}`, { fetch(`{% url 'sync_hired_applications' job.slug %}`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View File

@ -181,7 +181,7 @@
</h2> </h2>
</div> </div>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<a href="{% url 'export_candidates_csv' job.slug 'interview' %}" <a href="{% url 'export_applications_csv' job.slug 'interview' %}"
class="btn btn-outline-secondary" class="btn btn-outline-secondary"
title="{% trans 'Export interview candidates to CSV' %}"> title="{% trans 'Export interview candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %} <i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -202,7 +202,7 @@
<div class="d-flex align-items-end gap-3"> <div class="d-flex align-items-end gap-3">
{# Form 1: Status Update #} {# Form 1: Status Update #}
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group"> <form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group">
{% csrf_token %} {% csrf_token %}
{# Select Input Group - No label needed for this one, so we just flex the select and button #} {# Select Input Group - No label needed for this one, so we just flex the select and button #}
@ -239,7 +239,7 @@
data-bs-toggle="modal" data-bs-toggle="modal"
hx-boost='true' hx-boost='true'
data-bs-target="#emailModal" data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}" hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody" hx-target="#emailModalBody"
hx-include="#candidate-form" hx-include="#candidate-form"
title="Email Participants"> title="Email Participants">
@ -251,7 +251,7 @@
</div> </div>
<div class="table-responsive"> <div class="table-responsive">
<form id="candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="get"> <form id="candidate-form" action="{% url 'application_update_status' job.slug %}" method="get">
{% csrf_token %} {% csrf_token %}
<table class="table candidate-table align-middle"> <table class="table candidate-table align-middle">
<thead> <thead>
@ -288,7 +288,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm" <button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}" hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="View Profile"> title="View Profile">
{{ candidate.name }} {{ candidate.name }}
@ -357,7 +357,7 @@
<button type="button" class="btn btn-warning btn-sm" <button type="button" class="btn btn-warning btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'passed' %}" hx-get="{% url 'update_application_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Pass Exam"> title="Pass Exam">
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
@ -367,7 +367,7 @@
<button type="button" class="btn btn-{% if candidate.interview_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm" <button type="button" class="btn btn-{% if candidate.interview_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'passed' %}" hx-get="{% url 'update_application_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Pass Exam"> title="Pass Exam">
{{ candidate.interview_status }} {{ candidate.interview_status }}
@ -385,7 +385,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm" <button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'reschedule_meeting_for_candidate' job.slug candidate.pk candidate.get_latest_meeting.pk %}" hx-get="{% url 'reschedule_meeting_for_application' job.slug candidate.pk candidate.get_latest_meeting.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Reschedule"> title="Reschedule">
<i class="fas fa-redo-alt"></i> <i class="fas fa-redo-alt"></i>
@ -394,7 +394,7 @@
<button type="button" class="btn btn-outline-danger btn-sm" <button type="button" class="btn btn-outline-danger btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'delete_meeting_for_candidate' job.slug candidate.pk candidate.get_latest_meeting.pk %}" hx-get="{% url 'schedule_meeting_for_application' job.slug candidate.pk candidate.get_latest_meeting.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Delete Meeting"> title="Delete Meeting">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
@ -413,7 +413,7 @@
<button type="button" class="btn btn-outline-danger btn-sm" <button type="button" class="btn btn-outline-danger btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'delete_onsite_meeting_for_candidate' job.slug candidate.pk candidate.get_latest_meeting.pk %}" hx-get="{% url 'delete_onsite_meeting_for_application' job.slug candidate.pk candidate.get_latest_meeting.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Delete Meeting"> title="Delete Meeting">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
@ -425,7 +425,7 @@
<button type="button" class="btn btn-main-action btn-sm" <button type="button" class="btn btn-main-action btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'schedule_meeting_for_candidate' job.slug candidate.pk %}" hx-get="{% url 'schedule_meeting_for_application' job.slug candidate.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
data-modal-title="{% trans 'Schedule Interview' %}" data-modal-title="{% trans 'Schedule Interview' %}"
title="Schedule Interview"> title="Schedule Interview">
@ -435,7 +435,7 @@
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
{# UPDATED: Points to the specific Onsite scheduling URL #} {# UPDATED: Points to the specific Onsite scheduling URL #}
hx-get="{% url 'schedule_onsite_meeting_for_candidate' job.slug candidate.pk %}" hx-get="{% url 'schedule_onsite_meeting_for_application' job.slug candidate.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
data-modal-title="{% trans 'Schedule Onsite Interview' %}" data-modal-title="{% trans 'Schedule Onsite Interview' %}"
title="Schedule Onsite Interview"> title="Schedule Onsite Interview">

View File

@ -193,7 +193,7 @@
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;"> <h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
<i class="fas fa-users me-2"></i> {% trans "Applications List" %} <i class="fas fa-users me-2"></i> {% trans "Applications List" %}
</h1> </h1>
<a href="{% url 'candidate_create' %}" class="btn btn-main-action"> <a href="{% url 'application_create' %}" class="btn btn-main-action">
<i class="fas fa-plus me-1"></i> {% trans "Add New Application" %} <i class="fas fa-plus me-1"></i> {% trans "Add New Application" %}
</a> </a>
</div> </div>
@ -211,7 +211,7 @@
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
{% url 'candidate_list' as candidate_list_url %} {% url 'application_list' as candidate_list_url %}
<form method="GET" class="row g-3 align-items-end h-100"> <form method="GET" class="row g-3 align-items-end h-100">
{% if search_query %}<input type="hidden" name="q" value="{{ search_query }}">{% endif %} {% if search_query %}<input type="hidden" name="q" value="{{ search_query }}">{% endif %}
@ -250,7 +250,7 @@
<i class="fas fa-filter me-1"></i> {% trans "Apply Filters" %} <i class="fas fa-filter me-1"></i> {% trans "Apply Filters" %}
</button> </button>
{% if job_filter or stage_filter or search_query %} {% if job_filter or stage_filter or search_query %}
<a href="{% url 'candidate_list' %}" class="btn btn-outline-secondary btn-sm"> <a href="{% url 'application_list' %}" class="btn btn-outline-secondary btn-sm">
<i class="fas fa-times me-1"></i> {% trans "Clear" %} <i class="fas fa-times me-1"></i> {% trans "Clear" %}
</a> </a>
{% endif %} {% endif %}
@ -286,7 +286,7 @@
<tbody> <tbody>
{% for candidate in applications %} {% for candidate in applications %}
<tr> <tr>
<td class="fw-medium"><a href="{% url 'candidate_detail' candidate.slug %}" class="text-decoration-none link-secondary">{{ candidate.name }}<a></td> <td class="fw-medium"><a href="{% url 'application_detail' candidate.slug %}" class="text-decoration-none link-secondary">{{ candidate.name }}<a></td>
<td>{{ candidate.email }}</td> <td>{{ candidate.email }}</td>
<td> <span class="badge bg-primary"><a href="{% url 'job_detail' candidate.job.slug %}" class="text-decoration-none text-white">{{ candidate.job.title }}</a></span></td> <td> <span class="badge bg-primary"><a href="{% url 'job_detail' candidate.job.slug %}" class="text-decoration-none text-white">{{ candidate.job.title }}</a></span></td>
<td> <td>
@ -297,7 +297,7 @@
</span> </span>
{% endif %} {% endif %}
{% else %} {% else %}
<a href="{% url 'candidate_list' %}" class="text-decoration-none d-flex align-items-center gap-2"> <a href="{% url 'application_list' %}" class="text-decoration-none d-flex align-items-center gap-2">
<svg class="kaats-spinner" viewBox="0 0 50 50" style="width: 25px; height: 25px;"> <svg class="kaats-spinner" viewBox="0 0 50 50" style="width: 25px; height: 25px;">
<circle cx="25" cy="25" r="20"></circle> <circle cx="25" cy="25" r="20"></circle>
<circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5" <circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"
@ -325,16 +325,16 @@
<td>{{ candidate.created_at|date:"d-m-Y" }}</td> <td>{{ candidate.created_at|date:"d-m-Y" }}</td>
<td class="text-end"> <td class="text-end">
<div class="btn-group btn-group-sm" role="group"> <div class="btn-group btn-group-sm" role="group">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-secondary" title="{% trans 'View' %}"> <a href="{% url 'application_detail' candidate.slug %}" class="btn btn-outline-secondary" title="{% trans 'View' %}">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
</a> </a>
{% if user.is_staff %} {% if user.is_staff %}
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}"> <a href="{% url 'application_update' candidate.slug %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
</a> </a>
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}" <button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal" data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'candidate_delete' candidate.slug %}" data-delete-url="{% url 'application_delete' candidate.slug %}"
data-item-name="{{ candidate.name }}"> data-item-name="{{ candidate.name }}">
<i class="fas fa-trash-alt"></i> <i class="fas fa-trash-alt"></i>
</button> </button>
@ -356,7 +356,7 @@
<div class="card-body d-flex flex-column"> <div class="card-body d-flex flex-column">
<div class="d-flex justify-content-between align-items-start mb-3"> <div class="d-flex justify-content-between align-items-start mb-3">
<h5 class="card-title flex-grow-1 me-3"> <h5 class="card-title flex-grow-1 me-3">
<a href="{% url 'candidate_detail' candidate.slug %}" class="text-decoration-none text-primary-theme ">{{ candidate.name }}</a> <a href="{% url 'application_detail' candidate.slug %}" class="text-decoration-none text-primary-theme ">{{ candidate.name }}</a>
</h5> </h5>
<span class="badge bg-primary">{{ candidate.stage }}</span> <span class="badge bg-primary">{{ candidate.stage }}</span>
</div> </div>
@ -379,16 +379,16 @@
<div class="mt-auto pt-3 border-top"> <div class="mt-auto pt-3 border-top">
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-sm btn-main-action"> <a href="{% url 'application_detail' candidate.slug %}" class="btn btn-sm btn-main-action">
<i class="fas fa-eye"></i> {% trans "View" %} <i class="fas fa-eye"></i> {% trans "View" %}
</a> </a>
{% if user.is_staff %} {% if user.is_staff %}
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary"> <a href="{% url 'application_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-edit"></i> {% trans "Edit" %} <i class="fas fa-edit"></i> {% trans "Edit" %}
</a> </a>
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}" <button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal" data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'candidate_delete' candidate.slug %}" data-delete-url="{% url 'application_delete' candidate.slug %}"
data-item-name="{{ candidate.name }}"> data-item-name="{{ candidate.name }}">
<i class="fas fa-trash-alt"></i> <i class="fas fa-trash-alt"></i>
</button> </button>
@ -411,7 +411,7 @@
<h3>{% trans "No application found" %}</h3> <h3>{% trans "No application found" %}</h3>
<p class="text-muted">{% trans "Create your first application." %}</p> <p class="text-muted">{% trans "Create your first application." %}</p>
{% if user.is_staff %} {% if user.is_staff %}
<a href="{% url 'candidate_create' %}" class="btn btn-main-action mt-3"> <a href="{% url 'application_create' %}" class="btn btn-main-action mt-3">
<i class="fas fa-plus me-1"></i> {% trans "Add Application" %} <i class="fas fa-plus me-1"></i> {% trans "Add Application" %}
</a> </a>
{% endif %} {% endif %}

View File

@ -180,7 +180,7 @@
</h2> </h2>
</div> </div>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<a href="{% url 'export_candidates_csv' job.slug 'offer' %}" <a href="{% url 'export_applications_csv' job.slug 'offer' %}"
class="btn btn-outline-secondary" class="btn btn-outline-secondary"
title="{% trans 'Export offer candidates to CSV' %}"> title="{% trans 'Export offer candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %} <i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -201,7 +201,7 @@
<div class="d-flex align-items-end gap-3"> <div class="d-flex align-items-end gap-3">
{# Form: Hired/Rejected Status Update #} {# Form: Hired/Rejected Status Update #}
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group"> <form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group">
{% csrf_token %} {% csrf_token %}
{# Select element #} {# Select element #}
@ -236,7 +236,7 @@
data-bs-toggle="modal" data-bs-toggle="modal"
hx-boost='true' hx-boost='true'
data-bs-target="#emailModal" data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}" hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody" hx-target="#emailModalBody"
hx-include="#candidate-form" hx-include="#candidate-form"
title="Email Participants"> title="Email Participants">
@ -247,7 +247,7 @@
</div> </div>
{% endif %} {% endif %}
<div class="table-responsive"> <div class="table-responsive">
<form id="candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="get"> <form id="candidate-form" action="{% url 'application_update_status' job.slug %}" method="get">
{% csrf_token %} {% csrf_token %}
<table class="table candidate-table align-middle"> <table class="table candidate-table align-middle">
<thead> <thead>
@ -293,7 +293,7 @@
<button type="button" class="btn btn-warning btn-sm" <button type="button" class="btn btn-warning btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'passed' %}" hx-get="{% url 'update_application_status' job.slug candidate.slug 'offer' 'passed' %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Pass Exam"> title="Pass Exam">
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
@ -303,7 +303,7 @@
<button type="button" class="btn btn-{% if candidate.offer_status == 'Accepted' %}success{% else %}danger{% endif %} btn-sm" <button type="button" class="btn btn-{% if candidate.offer_status == 'Accepted' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'passed' %}" hx-get="{% url 'update_application_status' job.slug candidate.slug 'offer' 'passed' %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Pass Exam"> title="Pass Exam">
{{ candidate.offer_status }} {{ candidate.offer_status }}
@ -361,7 +361,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm" <button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}" hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="View Profile"> title="View Profile">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>

View File

@ -184,7 +184,7 @@
{% endif %} {% endif %}
</td> </td>
<td> <td>
<a href="{% url 'candidate_application_detail' application.slug %}" <a href="{% url 'applicant_application_detail' application.slug %}"
class="btn btn-sm btn-outline-primary"> class="btn btn-sm btn-outline-primary">
<i class="fas fa-eye me-1"></i> <i class="fas fa-eye me-1"></i>
{% trans "View Details" %} {% trans "View Details" %}

View File

@ -492,7 +492,7 @@
<div class="d-flex align-items-start mb-3"> <div class="d-flex align-items-start mb-3">
<div class="flex-grow-1"> <div class="flex-grow-1">
<h5 class="card-title fw-bold mb-1"> <h5 class="card-title fw-bold mb-1">
<a href="{% url 'candidate_application_detail' application.slug %}" <a href="{% url 'applicant_application_detail' application.slug %}"
class="text-decoration-none text-primary-theme hover:text-primary-theme-dark"> class="text-decoration-none text-primary-theme hover:text-primary-theme-dark">
{{ application.job.title }} {{ application.job.title }}
</a> </a>
@ -524,7 +524,7 @@
<!-- Action Button --> <!-- Action Button -->
<div class="mt-auto"> <div class="mt-auto">
<a href="{% url 'candidate_application_detail' application.slug %}" <a href="{% url 'applicant_application_detail' application.slug %}"
class="btn btn-main-action w-100 rounded-pill"> class="btn btn-main-action w-100 rounded-pill">
<i class="fas fa-eye me-2"></i> {% trans "View Details" %} <i class="fas fa-eye me-2"></i> {% trans "View Details" %}
</a> </a>
@ -568,7 +568,7 @@
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="text-muted small me-3">{% trans "Uploaded:" %} {{ document.uploaded_at|date:"d M Y" }}</span> <span class="text-muted small me-3">{% 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" 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> <a href="{% url 'application_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 %}

View File

@ -224,7 +224,7 @@
</h2> </h2>
</div> </div>
<div class="d-flex gap-2"> <div class="d-flex gap-2">
<a href="{% url 'export_candidates_csv' job.slug 'screening' %}" <a href="{% url 'export_applications_csv' job.slug 'screening' %}"
class="btn btn-outline-secondary" class="btn btn-outline-secondary"
title="{% trans 'Export screening candidates to CSV' %}"> title="{% trans 'Export screening candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %} <i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -319,7 +319,7 @@
<div class="kaauh-card p-3"> <div class="kaauh-card p-3">
{% if candidates %} {% if candidates %}
<div class="bulk-action-bar p-3 bg-light border-bottom"> <div class="bulk-action-bar p-3 bg-light border-bottom">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="action-group"> <form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="action-group">
{% csrf_token %} {% csrf_token %}
{# MODIFIED: Using d-flex for horizontal alignment and align-items-end to align everything based on the baseline of the button/select #} {# MODIFIED: Using d-flex for horizontal alignment and align-items-end to align everything based on the baseline of the button/select #}
@ -348,7 +348,7 @@
data-bs-toggle="modal" data-bs-toggle="modal"
hx-boost='true' hx-boost='true'
data-bs-target="#emailModal" data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}" hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody" hx-target="#emailModalBody"
hx-include="#candidate-form" hx-include="#candidate-form"
title="Email Participants"> title="Email Participants">
@ -361,7 +361,7 @@
{% endif %} {% endif %}
<div class="table-responsive"> <div class="table-responsive">
<form id="candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post"> <form id="candidate-form" action="{% url 'application_update_status' job.slug %}" method="post">
{% csrf_token %} {% csrf_token %}
<table class="table candidate-table align-middle"> <table class="table candidate-table align-middle">
<thead> <thead>
@ -471,7 +471,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm" <button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}" hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="View Candidate Profile and Criteria"> title="View Candidate Profile and Criteria">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>

View File

@ -94,12 +94,12 @@
<p class="text-white opacity-75 mb-0">{% trans "Edit candidate information and details" %}</p> <p class="text-white opacity-75 mb-0">{% trans "Edit candidate information and details" %}</p>
</div> </div>
<div class="d-flex gap-2 mt-1"> <div class="d-flex gap-2 mt-1">
<a href="{% url 'candidate_list' %}" class="btn btn-outline-light btn-sm" title="{% trans 'Back to List' %}"> <a href="{% url 'application_list' %}" class="btn btn-outline-light btn-sm" title="{% trans 'Back to List' %}">
<i class="fas fa-arrow-left"></i> <i class="fas fa-arrow-left"></i>
<span class="d-none d-sm-inline">{% trans "Back to List" %}</span> <span class="d-none d-sm-inline">{% trans "Back to List" %}</span>
</a> </a>
{% if object.slug %} {% if object.slug %}
<a href="{% url 'candidate_detail' object.slug %}" class="btn btn-outline-light btn-sm" title="{% trans 'View Candidate' %}"> <a href="{% url 'application_detail' object.slug %}" class="btn btn-outline-light btn-sm" title="{% trans 'View Candidate' %}">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
<span class="d-none d-sm-inline">{% trans "View" %}</span> <span class="d-none d-sm-inline">{% trans "View" %}</span>
</a> </a>

View File

@ -59,7 +59,7 @@
<button type="button" class="btn btn-main-action" <button type="button" class="btn btn-main-action"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}" hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="{% trans 'View Details and Score Breakdown' %}"> title="{% trans 'View Details and Score Breakdown' %}">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>

View File

@ -60,7 +60,7 @@
</li> </li>
<li style="display: flex; align-items: center;"> <li style="display: flex; align-items: center;">
<a <a
href="{% url 'candidate_list' %}" href="{% url 'application_list' %}"
style=" style="
color: #6c757d; /* text-secondary/gray */ color: #6c757d; /* text-secondary/gray */
text-decoration: none; text-decoration: none;
@ -82,7 +82,7 @@
</li> </li>
<li style="display: flex; align-items: center;"> <li style="display: flex; align-items: center;">
<a <a
href="{% url 'candidate_detail' candidate.slug %}" href="{% url 'application_detail' candidate.slug %}"
style=" style="
color: #6c757d; /* text-secondary/gray */ color: #6c757d; /* text-secondary/gray */
text-decoration: none; text-decoration: none;

View File

@ -3,7 +3,7 @@
<button type="button" class="btn btn-{% if candidate.exam_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm" <button type="button" class="btn btn-{% if candidate.exam_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'exam' 'passed' %}" hx-get="{% url 'update_application_status' job.slug candidate.slug 'exam' 'passed' %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Pass Exam"> title="Pass Exam">
{{ candidate.exam_status }} {{ candidate.exam_status }}

View File

@ -3,7 +3,7 @@
<button type="button" class="btn btn-warning btn-sm" <button type="button" class="btn btn-warning btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'passed' %}" hx-get="{% url 'update_application_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Pass Exam"> title="Pass Exam">
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
@ -13,7 +13,7 @@
<button type="button" class="btn btn-{% if candidate.interview_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm" <button type="button" class="btn btn-{% if candidate.interview_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'passed' %}" hx-get="{% url 'update_application_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Pass Exam"> title="Pass Exam">
{{ candidate.interview_status }} {{ candidate.interview_status }}

View File

@ -3,7 +3,7 @@
<button type="button" class="btn btn-warning btn-sm" <button type="button" class="btn btn-warning btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'Accepted' %}" hx-get="{% url 'update_application_status' job.slug candidate.slug 'offer' 'Accepted' %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Pass Exam"> title="Pass Exam">
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
@ -13,7 +13,7 @@
<button type="button" class="btn btn-{% if candidate.offer_status == 'Accepted' %}success{% else %}danger{% endif %} btn-sm" <button type="button" class="btn btn-{% if candidate.offer_status == 'Accepted' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#candidateviewModal" data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'Rejected' %}" hx-get="{% url 'update_application_status' job.slug candidate.slug 'offer' 'Rejected' %}"
hx-target="#candidateviewModalBody" hx-target="#candidateviewModalBody"
title="Pass Exam"> title="Pass Exam">
{{ candidate.offer_status }} {{ candidate.offer_status }}

View File

@ -1,5 +1,5 @@
<!-- Stage Update Form with Errors --> <!-- Stage Update Form with Errors -->
<form id="stageUpdateForm" hx-post="{% url 'candidate_update_stage' candidate.slug %}"> <form id="stageUpdateForm" hx-post="{% url 'application_update_stage' candidate.slug %}">
{% csrf_token %} {% csrf_token %}
<!-- Stage Selection --> <!-- Stage Selection -->

View File

@ -23,12 +23,12 @@
<!-- Form Container --> <!-- Form Container -->
<div id="stageUpdateFormContainer"> <div id="stageUpdateFormContainer">
<form id="stageUpdateForm" action="{% url 'candidate_update_stage' candidate.slug %}" method="post"> <form id="stageUpdateForm" action="{% url 'application_update_stage' candidate.slug %}" method="post">
{% csrf_token %} {% csrf_token %}
<!-- Stage Selection --> <!-- Stage Selection -->
<div class="mb-3"> <div class="mb-3">
<label for="id_stage" class="form-label"> <label for="id_stage" class="form-label">
<i class="fas fa-arrow-right me-1"></i>Move to Stage <i class="fas fa-arrow-right me-1"></i>{% trans "Move to Stage" %}
</label> </label>
<select id="id_stage" name="stage" class="form-select"> <select id="id_stage" name="stage" class="form-select">
@ -42,19 +42,19 @@
<div class="alert alert-light border" id="availableStagesInfo"> <div class="alert alert-light border" id="availableStagesInfo">
<small class="text-muted"> <small class="text-muted">
<i class="fas fa-lightbulb me-1"></i> <i class="fas fa-lightbulb me-1"></i>
<span id="availableStagesText">Select a stage above to see transition information.</span> <span id="availableStagesText">{% trans "Select a stage above to see transition information." %}</span>
</small> </small>
</div> </div>
<!-- Form Actions --> <!-- Form Actions -->
<div class="d-flex justify-content-between mt-4"> <div class="d-flex justify-content-between mt-4">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal"> <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
<i class="fas fa-times me-1"></i>Cancel <i class="fas fa-times me-1"></i>{% trans "Cancel" %}
</button> </button>
<button type="submit" class="btn btn-main-action" id="stageUpdateSubmit"> <button type="submit" class="btn btn-main-action" id="stageUpdateSubmit">
<i class="fas fa-save me-1"></i> <i class="fas fa-save me-1"></i>
<span class="ms-2">Update</span> <span class="ms-2">{% trans "Update" %}</span>
</button> </button>
</div> </div>
</form> </form>

View File

@ -23,7 +23,7 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
<a href="{% url 'candidate_interview_view' job.slug %}" class="btn btn-outline-secondary"> <a href="{% url 'applications_interview_view' job.slug %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Candidates" %} <i class="fas fa-arrow-left me-1"></i> {% trans "Back to Candidates" %}
</a> </a>
</div> </div>
@ -85,7 +85,7 @@
<button type="submit" class="btn btn-primary"> <button type="submit" class="btn btn-primary">
<i class="fas fa-save me-1"></i> {% trans "Schedule Meeting" %} <i class="fas fa-save me-1"></i> {% trans "Schedule Meeting" %}
</button> </button>
<a href="{% url 'candidate_interview_view' job.slug %}" class="btn btn-secondary"> <a href="{% url 'applications_interview_view' job.slug %}" class="btn btn-secondary">
<i class="fas fa-times me-1"></i> {% trans "Cancel" %} <i class="fas fa-times me-1"></i> {% trans "Cancel" %}
</a> </a>
</div> </div>