diff --git a/.env b/.env index 8d7fbd5..b9e2bf0 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ -DB_NAME=haikal_db -DB_USER=faheed -DB_PASSWORD=Faheed@215 \ No newline at end of file +DB_NAME=norahuniversity +DB_USER=norahuniversity +DB_PASSWORD=norahuniversity \ No newline at end of file diff --git a/recruitment/urls.py b/recruitment/urls.py index 91e9b6d..46e8ad8 100644 --- a/recruitment/urls.py +++ b/recruitment/urls.py @@ -17,6 +17,7 @@ urlpatterns = [ # Job CRUD Operations path("jobs/", views.JobListView.as_view(), name="job_list"), path("jobs/create/", views.create_job, name="job_create"), + path("jobs/bank/", views.job_bank_view, name="job_bank"), path("jobs//", views.job_detail, name="job_detail"), path("jobs//update/", views.edit_job, name="job_update"), path("jobs//upload-image/", views.job_image_upload, name="job_image_upload"), @@ -25,7 +26,6 @@ urlpatterns = [ path("jobs//applicants/", views.job_applicants_view, name="job_applicants"), path("jobs//applications/", views.JobApplicationListView.as_view(), name="job_applications_list"), path("jobs//calendar/", views.interview_calendar_view, name="interview_calendar"), - path("jobs/bank/", views.job_bank_view, name="job_bank"), # Job Actions & Integrations path("jobs//post-to-linkedin/", views.post_to_linkedin, name="post_to_linkedin"), diff --git a/recruitment/views.py b/recruitment/views.py index 5fce1f0..42b1d93 100644 --- a/recruitment/views.py +++ b/recruitment/views.py @@ -2230,60 +2230,60 @@ def reschedule_meeting_for_application(request, slug): def interview_calendar_view(request, slug): job = get_object_or_404(JobPosting, slug=slug) - # # Get all scheduled interviews for this job - # scheduled_interviews = ScheduledInterview.objects.filter(job=job).select_related( - # "applicaton", "zoom_meeting" - # ) + # Get all scheduled interviews for this job + scheduled_interviews = ScheduledInterview.objects.filter(job=job).select_related( + "interview","application" + ) - # # Convert interviews to calendar events - # events = [] - # for interview in scheduled_interviews: - # # Create start datetime - # start_datetime = datetime.combine( - # interview.interview_date, interview.interview_time - # ) + # Convert interviews to calendar events + events = [] + for interview in scheduled_interviews: + # Create start datetime + start_datetime = datetime.combine( + interview.interview_date, interview.interview_time + ) - # # Calculate end datetime based on interview duration - # duration = interview.zoom_meeting.duration if interview.zoom_meeting else 60 - # end_datetime = start_datetime + timedelta(minutes=duration) + # Calculate end datetime based on interview duration + duration = interview.interview.duration if interview.interview else 60 + end_datetime = start_datetime + timedelta(minutes=duration) - # # Determine event color based on status - # color = "#00636e" # Default color - # if interview.status == "confirmed": - # color = "#00a86b" # Green for confirmed - # elif interview.status == "cancelled": - # color = "#e74c3c" # Red for cancelled - # elif interview.status == "completed": - # color = "#95a5a6" # Gray for completed + # Determine event color based on status + color = "#00636e" # Default color + if interview.status == "confirmed": + color = "#00a86b" # Green for confirmed + elif interview.status == "cancelled": + color = "#e74c3c" # Red for cancelled + elif interview.status == "completed": + color = "#95a5a6" # Gray for completed - # events.append( - # { - # "title": f"Interview: {interview.candidate.name}", - # "start": start_datetime.isoformat(), - # "end": end_datetime.isoformat(), - # "url": f"{request.path}interview/{interview.id}/", - # "color": color, - # "extendedProps": { - # "candidate": interview.candidate.name, - # "email": interview.candidate.email, - # "status": interview.status, - # "meeting_id": interview.zoom_meeting.meeting_id - # if interview.zoom_meeting - # else None, - # "join_url": interview.zoom_meeting.join_url - # if interview.zoom_meeting - # else None, - # }, - # } - # ) + events.append( + { + "title": f"Interview: {interview.application.person.full_name}", + "start": start_datetime.isoformat(), + "end": end_datetime.isoformat(), + "url": f"{request.path}interview/{interview.id}/", + "color": color, + "extendedProps": { + "candidate": interview.application.person.full_name, + "email": interview.application.person.email, + "status": interview.interview.status, + "meeting_id": interview.interview.meeting_id + if interview.interview + else None, + "join_url": interview.interview.join_url + if interview.interview + else None, + }, + } + ) - # context = { - # "job": job, - # "events": events, - # "calendar_color": "#00636e", - # } + context = { + "job": job, + "events": events, + "calendar_color": "#00636e", + } - # return render(request, "recruitment/interview_calendar.html", context) + return render(request, "recruitment/interview_calendar.html", context) def user_profile_image_update(request, pk): @@ -4476,7 +4476,7 @@ def source_list(request): """List all sources with search and pagination""" search_query = request.GET.get("q", "") sources = Source.objects.all() - + if search_query: sources = sources.filter( Q(name__icontains=search_query) diff --git a/templates/applicant/application_submit_form.html b/templates/applicant/application_submit_form.html index 5242007..cbb8b5c 100644 --- a/templates/applicant/application_submit_form.html +++ b/templates/applicant/application_submit_form.html @@ -877,33 +877,39 @@ } function renderCurrentStage() { - if (state.isPreview) { - renderPreview(); - return; - } + // Always show stage container and hide preview container initially + elements.stageContainer.style.display = 'block'; + elements.previewContainer.style.display = 'none'; - const currentStage = state.stages[state.currentStage]; - elements.stageContainer.innerHTML = ''; - elements.previewContainer.style.display = 'none'; + if (state.isPreview) { + renderPreview(); + return; + } - const stageTitle = document.createElement('h2'); - stageTitle.className = 'stage-title'; - stageTitle.textContent = currentStage.name; - elements.stageContainer.appendChild(stageTitle); + const currentStage = state.stages[state.currentStage]; + elements.stageContainer.innerHTML = ''; - currentStage.fields.forEach(field => { - const fieldElement = createFieldElement(field); - elements.stageContainer.appendChild(fieldElement); - }); + const stageTitle = document.createElement('h2'); + stageTitle.className = 'stage-title'; + stageTitle.textContent = currentStage.name; + elements.stageContainer.appendChild(stageTitle); + + currentStage.fields.forEach(field => { + const fieldElement = createFieldElement(field); + elements.stageContainer.appendChild(fieldElement); + }); + + // Update navigation buttons + elements.backBtn.style.display = state.currentStage > 0 ? 'flex' : 'none'; + elements.submitBtn.style.display = 'none'; + elements.nextBtn.style.display = 'flex'; + + // Fix: Update the Next button text correctly + elements.nextBtn.innerHTML = state.currentStage === state.stages.length - 1 ? + 'Preview ' : + 'Next '; +} - // Update navigation buttons - elements.backBtn.style.display = state.currentStage > 0 ? 'flex' : 'none'; - elements.submitBtn.style.display = 'none'; - elements.nextBtn.style.display = 'flex'; - elements.nextBtn.textContent = state.currentStage === state.stages.length - 1 ? - 'Preview' : - 'Next' - } function createFieldElement(field) { const fieldDiv = document.createElement('div'); @@ -1158,103 +1164,106 @@ } function renderPreview() { - elements.stageContainer.style.display = 'none'; - elements.previewContainer.style.display = 'block'; - elements.previewContent.innerHTML = ''; + elements.stageContainer.style.display = 'none'; + elements.previewContainer.style.display = 'block'; + elements.previewContent.innerHTML = ''; - // Add applicant info if available - if (state.formData.applicant_name || state.formData.applicant_email) { - const applicantDiv = document.createElement('div'); - applicantDiv.className = 'preview-item'; - applicantDiv.innerHTML = ` -
Applicant Information
-
- ${state.formData.applicant_name ? `Name: ${state.formData.applicant_name}
` : ''} - ${state.formData.applicant_email ? `Email: ${state.formData.applicant_email}` : ''} -
- `; - elements.previewContent.appendChild(applicantDiv); - } + // Add applicant info if available + if (state.formData.applicant_name || state.formData.applicant_email) { + const applicantDiv = document.createElement('div'); + applicantDiv.className = 'preview-item'; + applicantDiv.innerHTML = ` +
Applicant Information
+
+ ${state.formData.applicant_name ? `Name: ${state.formData.applicant_name}
` : ''} + ${state.formData.applicant_email ? `Email: ${state.formData.applicant_email}` : ''} +
+ `; + elements.previewContent.appendChild(applicantDiv); + } - // Add stage data - state.stages.forEach(stage => { - const stageDiv = document.createElement('div'); - stageDiv.className = 'preview-item'; + // Add stage data + state.stages.forEach(stage => { + const stageDiv = document.createElement('div'); + stageDiv.className = 'preview-item'; - const stageTitle = document.createElement('div'); - stageTitle.className = 'preview-label'; - stageTitle.textContent = stage.name; - stageDiv.appendChild(stageTitle); + const stageTitle = document.createElement('div'); + stageTitle.className = 'preview-label'; + stageTitle.textContent = stage.name; + stageDiv.appendChild(stageTitle); - const stageContent = document.createElement('div'); - stageContent.className = 'preview-value'; + const stageContent = document.createElement('div'); + stageContent.className = 'preview-value'; - stage.fields.forEach(field => { - let value = state.formData[field.id]; - if (value === undefined || value === null || value === '') { - value = 'Not provided'; - } else if (field.type === 'file' && value instanceof File) { - value = value.name; - } else if (field.type === 'checkbox' && Array.isArray(value)) { - value = value.join(', '); - } + stage.fields.forEach(field => { + let value = state.formData[field.id]; + if (value === undefined || value === null || value === '') { + value = 'Not provided'; + } else if (field.type === 'file' && value instanceof File) { + value = value.name; + } else if (field.type === 'checkbox' && Array.isArray(value)) { + value = value.join(', '); + } - const fieldDiv = document.createElement('div'); - fieldDiv.innerHTML = `${field.label}: ${value}`; - stageContent.appendChild(fieldDiv); - }); + const fieldDiv = document.createElement('div'); + fieldDiv.innerHTML = `${field.label}: ${value}`; + stageContent.appendChild(fieldDiv); + }); - stageDiv.appendChild(stageContent); - elements.previewContent.appendChild(stageDiv); - }); + stageDiv.appendChild(stageContent); + elements.previewContent.appendChild(stageDiv); + }); - // Update navigation buttons - elements.backBtn.style.display = 'flex'; - elements.nextBtn.style.display = 'none'; - elements.submitBtn.style.display = 'flex'; - } + // Update navigation buttons + elements.backBtn.style.display = 'flex'; + elements.nextBtn.style.display = 'none'; + elements.submitBtn.style.display = 'flex'; +} // Navigation Functions function nextStage() { - if (state.isPreview) { - submitForm(); - return; - } + if (state.isPreview) { + submitForm(); + return; + } - if (!validateCurrentStage()) { - // Scroll to first error - const firstError = document.querySelector('.error-message.show'); - if (firstError) { - firstError.scrollIntoView({ behavior: 'smooth', block: 'center' }); - } - return; - } + if (!validateCurrentStage()) { + // Scroll to first error + const firstError = document.querySelector('.error-message.show'); + if (firstError) { + firstError.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } + return; + } - if (state.currentStage === state.stages.length - 1) { - // Go to preview - state.isPreview = true; - renderCurrentStage(); - updateProgress(); - } else { - // Go to next stage - state.currentStage++; - renderCurrentStage(); - updateProgress(); - } - } + if (state.currentStage === state.stages.length - 1) { + // Go to preview + state.isPreview = true; + renderCurrentStage(); + updateProgress(); + } else { + // Go to next stage + state.currentStage++; + renderCurrentStage(); + updateProgress(); + } +} - function prevStage() { - if (state.isPreview) { - // Go back to last stage - state.isPreview = false; - renderCurrentStage(); - updateProgress(); - } else if (state.currentStage > 0) { - state.currentStage--; - renderCurrentStage(); - updateProgress(); - } - } + function prevStage() { + if (state.isPreview) { + // Go back to last stage from preview + state.isPreview = false; + // Set to the last form stage + state.currentStage = state.stages.length - 1; + renderCurrentStage(); + updateProgress(); + } else if (state.currentStage > 0) { + // Go to previous stage + state.currentStage--; + renderCurrentStage(); + updateProgress(); + } +} // Initialize Application function init() { diff --git a/templates/base.html b/templates/base.html index a2bbb1e..b3d5d34 100644 --- a/templates/base.html +++ b/templates/base.html @@ -234,11 +234,7 @@ {% endif %} - -
  • - -
  • {% csrf_token %} diff --git a/templates/jobs/job_detail.html b/templates/jobs/job_detail.html index 6b0c0e8..30a0cf4 100644 --- a/templates/jobs/job_detail.html +++ b/templates/jobs/job_detail.html @@ -147,6 +147,30 @@ {% block content %}
    + +
    {% endblock %} \ No newline at end of file