This commit is contained in:
Faheed 2025-10-08 14:10:19 +03:00
parent ef952ab596
commit f02d859c7a
15 changed files with 3620 additions and 646 deletions

View File

@ -66,6 +66,7 @@ MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', 'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',

View File

@ -1,24 +1,9 @@
"""
URL configuration for NorahUniversity project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin from django.contrib import admin
from django.urls import path, include from django.urls import path, include
from django.conf.urls.static import static from django.conf.urls.static import static
from django.conf import settings from django.conf import settings
from django.conf.urls.i18n import i18n_patterns from django.conf.urls.i18n import i18n_patterns # Import i18n_patterns
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from recruitment import views from recruitment import views
@ -26,11 +11,19 @@ router = DefaultRouter()
router.register(r'jobs', views.JobPostingViewSet) router.register(r'jobs', views.JobPostingViewSet)
router.register(r'candidates', views.CandidateViewSet) router.register(r'candidates', views.CandidateViewSet)
# 1. URLs that DO NOT have a language prefix (admin, API, static files)
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('api/', include(router.urls)), path('api/', include(router.urls)),
path('accounts/', include('allauth.urls')), path('accounts/', include('allauth.urls')),
path('', include('recruitment.urls')), path('i18n/', include('django.conf.urls.i18n')),
] ]
# 2. URLs that DO have a language prefix (user-facing views)
# This includes the root path (''), which is handled by 'recruitment.urls'
urlpatterns += i18n_patterns(
path('', include('recruitment.urls')),
)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@
--kaauh-border: #eaeff3; --kaauh-border: #eaeff3;
} }
/* === Top Bar === */ /* === Top Bar === */
.top-bar { .top-bar {
background-color: white; background-color: white;
@ -260,8 +261,7 @@
<nav class="navbar navbar-expand-lg navbar-dark sticky-top"> <nav class="navbar navbar-expand-lg navbar-dark sticky-top">
<div class="container"> <div class="container">
<a class="navbar-brand text-white" href="{% url 'dashboard' %}"> <a class="navbar-brand text-white" href="{% url 'dashboard' %}">
<i class="fas fa-hospital"></i> <img src="{% static 'image/kaauh.jpeg' %}" alt="{% trans 'Saudi Vision 2030' %}" style="width: 60px; height: 60px;">
<span class="d-lg-none ms-1">KAAUH ATS</span>
</a> </a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
@ -271,14 +271,14 @@
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0"> <ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item"> {% comment %} <li class="nav-item">
<a class="nav-link {% if request.resolver_match.url_name == 'dashboard' %}active{% endif %}" href="{% url 'dashboard' %}"> <a class="nav-link {% if request.resolver_match.url_name == 'dashboard' %}active{% endif %}" href="{% url 'dashboard' %}">
<span class="d-flex align-items-center gap-2"> <span class="d-flex align-items-center gap-2">
{% include "icons/dashboard.html" %} {% include "icons/dashboard.html" %}
{% trans "Dashboard" %} {% trans "Dashboard" %}
</span> </span>
</a> </a>
</li> </li> {% endcomment %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if request.resolver_match.url_name == 'job_list' %}active{% endif %}" href="{% url 'job_list' %}"> <a class="nav-link {% if request.resolver_match.url_name == 'job_list' %}active{% endif %}" href="{% url 'job_list' %}">
<span class="d-flex align-items-center gap-2"> <span class="d-flex align-items-center gap-2">
@ -345,19 +345,6 @@
</li> </li>
</ul> </ul>
{% if not request.session.linkedin_authenticated %}
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="{% url 'linkedin_login' %}">
<i class="fab fa-linkedin me-1"></i> {% trans "Connect LinkedIn" %}
</a>
</li>
</ul>
{% else %}
<span class="text-success d-none d-lg-inline ms-auto me-3">
<i class="fab fa-linkedin me-1"></i> {% trans "LinkedIn Connected" %}
</span>
{% endif %}
<ul class="navbar-nav me-2"> <ul class="navbar-nav me-2">
<li class="nav-item dropdown"> <li class="nav-item dropdown">
@ -367,16 +354,20 @@
<span class="d-none d-lg-inline">{{ LANGUAGE_CODE|upper }}</span> <span class="d-none d-lg-inline">{{ LANGUAGE_CODE|upper }}</span>
</a> </a>
<ul class="dropdown-menu dropdown-menu-end" data-bs-popper="static"> <ul class="dropdown-menu dropdown-menu-end" data-bs-popper="static">
{% get_current_language as LANGUAGE_CODE %}
<li> <li>
<form action="" method="post" class="d-inline">{% csrf_token %} <form action="{% url 'set_language' %}" method="post" class="d-inline">{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path }}"> <input name="next" type="hidden" value="{{ request.get_full_path }}">
<button name="language" value="en" class="dropdown-item {% if LANGUAGE_CODE == 'en' %}active bg-light-subtle{% endif %}" type="submit"> <button name="language" value="en" class="dropdown-item {% if LANGUAGE_CODE == 'en' %}active bg-light-subtle{% endif %}" type="submit">
<span class="me-2">🇺🇸</span> English <span class="me-2">🇺🇸</span> English
</button> </button>
</form> </form>
</li> </li>
<li> <li>
<form action="" method="post" class="d-inline">{% csrf_token %} <form action="{% url 'set_language' %}" method="post" class="d-inline">{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path }}"> <input name="next" type="hidden" value="{{ request.get_full_path }}">
<button name="language" value="ar" class="dropdown-item {% if LANGUAGE_CODE == 'ar' %}active bg-light-subtle{% endif %}" type="submit"> <button name="language" value="ar" class="dropdown-item {% if LANGUAGE_CODE == 'ar' %}active bg-light-subtle{% endif %}" type="submit">
<span class="me-2">🇸🇦</span> العربية (Arabic) <span class="me-2">🇸🇦</span> العربية (Arabic)
@ -387,7 +378,6 @@
</li> </li>
</ul> </ul>
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<button <button
@ -426,6 +416,23 @@
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-cog me-3 text-primary fs-5"></i> <span>{% trans "Settings" %}</span></a></li> <li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-cog me-3 text-primary fs-5"></i> <span>{% trans "Settings" %}</span></a></li>
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-history me-3 text-primary fs-5"></i> <span>{% trans "Activity Log" %}</span></a></li> <li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-history me-3 text-primary fs-5"></i> <span>{% trans "Activity Log" %}</span></a></li>
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-question-circle me-3 text-primary fs-5"></i> <span>{% trans "Help & Support" %}</span></a></li> <li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#"><i class="fas fa-question-circle me-3 text-primary fs-5"></i> <span>{% trans "Help & Support" %}</span></a></li>
<li><a class="dropdown-item py-2 px-4 d-flex align-items-center text-decoration-none" href="#">
{% if not request.session.linkedin_authenticated %}
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="{% url 'linkedin_login' %}">
<i class="fab fa-linkedin me-1"></i> {% trans "Connect LinkedIn" %}
</a>
</li>
</ul>
{% else %}
<i class="fab fa-linkedin text-primary me-1"></i>
<span class="text-primary d-none d-lg-inline ms-auto me-3">
{% trans "LinkedIn Connected" %}
</span>
{% endif %}
</a></li>
<li><hr class="dropdown-divider my-1"></li> <li><hr class="dropdown-divider my-1"></li>
<li> <li>
<form method="post" action="" class="d-inline"> <form method="post" action="" class="d-inline">

View File

@ -1,10 +1,10 @@
<!-- templates/form_wizard.html --> {% load static i18n %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Application Form</title> <title>{% translate "Application Form" %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style> <style>
@ -31,14 +31,27 @@
} }
body { body {
/* Remove centering/flex properties to allow for normal document flow and scrolling */
padding-top: 56px; /* Space for the sticky navbar */
/* Dark gradient background to match the theme */ /* Dark gradient background to match the theme */
background: linear-gradient(135deg, var(--kaauh-teal-dark) 0%, #1e3a47 100%); background: linear-gradient(135deg, var(--kaauh-teal-dark) 0%, #1e3a47 100%);
background-image: url("{% static 'image/vision.svg' %}");
background-repeat: no-repeat;
background-position: 60px;
background-size: 320px auto;
min-height: 100vh; min-height: 100vh;
padding: 0; /* Remove padding from body */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
/* Wrapper to center the wizard content below the navbar */
.page-content-wrapper {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
padding: 20px; padding: 20px; /* Re-apply padding here for the content area */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; min-height: calc(100vh - 56px); /* Adjust height to account for navbar */
} }
.wizard-container { .wizard-container {
@ -50,7 +63,9 @@
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2); box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 90vh; /* Allow height to be determined by content, constrained by max-height */
height: auto;
max-height: 90vh;
} }
/* Progress Bar */ /* Progress Bar */
@ -389,6 +404,7 @@
height: 100vh; height: 100vh;
border-radius: 0; border-radius: 0;
max-width: 100%; max-width: 100%;
max-height: 100vh;
} }
.stage-title { .stage-title {
@ -407,9 +423,67 @@
padding: 0 20px 20px; padding: 0 20px 20px;
} }
} }
</style>
/* === FIX FOR SMALL-SCREEN HAMBURGER MENU === */
@media (max-width: 991.98px) {
/* Add vertical spacing to the navigation items when the navbar is collapsed */
#navbarNav .nav-item {
margin-top: 5px;
margin-bottom: 5px;
padding: 5px 0;
border-bottom: 1px solid #f0f0f0;
}
#navbarNav .nav-item:last-child {
border-bottom: none;
}
#navbarNav .nav-link {
padding: 8px 15px;
display: block;
}
/* Adjust the total margin of the top navbar container when collapsed */
#topNavbar.mb-3 {
margin-bottom: 0 !important;
}
}
#bottomNavbar {
/* Position the dark navbar 72px from the top of the viewport */
top: 72px;
/* The z-index is already 1030 in the inline style, which is correct */
}
</style>
</head> </head>
<body> <body>
<nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
<div class="container-fluid">
<a class="navbar-brand text-white fw-bold" href="/">
<img src="{% static 'image/kaauh.jpeg' %}" alt="{% translate 'KAAUH IMAGE' %}" style="height: 50px; margin-right: 10px;">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link text-secondary" href="/applications/">{% translate "Applications" %}</a>
</li>
<li class="nav-item">
<a class="nav-link text-secondary" href="/profile/">{% translate "Profile" %}</a>
</li>
</ul>
</div>
</div>
</nav>
<nav id="bottomNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: var(--kaauh-teal); z-index: 1030;">
</nav>
<div class="page-content-wrapper">
<div class="wizard-container"> <div class="wizard-container">
<div class="progress-container"> <div class="progress-container">
<div class="progress-bar" id="progressBar"></div> <div class="progress-bar" id="progressBar"></div>
@ -418,7 +492,7 @@
<div class="wizard-header"> <div class="wizard-header">
<div class="logo"> <div class="logo">
<i class="fas fa-file-alt"></i> <i class="fas fa-file-alt"></i>
<span id="formTitle">Application Form</span> <span id="formTitle">{% translate "Application Form" %}</span>
</div> </div>
<div class="progress-text" id="progressText">1 of 1</div> <div class="progress-text" id="progressText">1 of 1</div>
</div> </div>
@ -428,26 +502,42 @@
</div> </div>
<div class="preview-container" id="previewContainer" style="display: none;"> <div class="preview-container" id="previewContainer" style="display: none;">
<h3 class="mb-4">Review Your Application</h3> <h3 class="mb-4">{% translate "Review Your Application" %}</h3>
<div id="previewContent"></div> <div id="previewContent"></div>
</div> </div>
</div> </div>
<div class="wizard-footer"> <div class="wizard-footer">
<button id="backBtn" class="nav-btn btn-back" style="display: none;"> <button id="backBtn" class="nav-btn btn-back" style="display: none;">
<i class="fas fa-arrow-left"></i> Back <i class="fas fa-arrow-left"></i> {% translate "Back" %}
</button> </button>
<button id="nextBtn" class="nav-btn btn-next"> <button id="nextBtn" class="nav-btn btn-next">
Next <i class="fas fa-arrow-right"></i> {% translate "Next" %} <i class="fas fa-arrow-right"></i>
</button> </button>
<button id="submitBtn" class="nav-btn btn-submit" style="display: none;"> <button id="submitBtn" class="nav-btn btn-submit" style="display: none;">
Submit Application <i class="fas fa-paper-plane"></i> {% translate "Submit Application" %} <i class="fas fa-paper-plane"></i>
</button> </button>
</div> </div>
</div> </div>
</div> <script>
// Placeholder for the complete JavaScript logic (omitted for brevity, but required for functionality)
// This script block should contain the Application State, DOM Elements, Validation, API, Rendering, and Event Handlers
console.log("JavaScript logic for form wizard needs to be included here.");
// --- COMPLETE JAVASCRIPT LOGIC GOES HERE ---
// (The logic provided in the previous turn, including the completed createFieldElement and renderPreview functions)
// Example structure for reference:
// function validateEmail(email) { ... }
// function loadFormTemplate() { ... }
// function renderCurrentStage() { ... }
// function createFieldElement(field) { ... }
// function renderPreview() { ... }
// document.addEventListener('DOMContentLoaded', loadFormTemplate);
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script> <script>
// Application State // Application State
const csrfToken = '{{ csrf_token }}'; const csrfToken = '{{ csrf_token }}';

View File

@ -1,18 +1,30 @@
{% extends "base.html" %} {% load static i18n %}
<!DOCTYPE html>
{% block title %}{{ job.title }} - University ATS{% endblock %} <html lang="en">
{% block customCSS %} <head>
<meta charset="UTF-8">
<style> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% translate "Application Form" %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* THEME STYLES (Keep from previous response) */ /* THEME & UTILITY VARIABLES */
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
:root { :root {
--kaauh-teal: #00636e; --kaauh-teal: #00636e;
--kaauh-teal-dark: #004a53; --kaauh-teal-dark: #004a53;
--success: #198754; --success: #198754;
/* Define a subtle background for mobile sticky bar */
--light-bg: #f8f9fa; --light-bg: #f8f9fa;
/* CALCULATED STICKY HEIGHTS */
/* Standard Bootstrap Navbar Height (approx 56px) */
--navbar-height: 56px;
/* Bootstrap mb-3 spacing (1rem or 16px) */
--navbar-gap: 16px;
/* Combined height of the two navbars when collapsed on desktop (56 + 16 + 56 = 128px) */
--sticky-navbar-total-height: 128px;
} }
.btn-main-action { .btn-main-action {
@ -34,12 +46,65 @@
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* MOBILE RESPONSIVE STYLES */ /* LAYOUT & STICKY POSITIONING FIXES (Desktop/Tablet) */
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* 1. Mobile Fixed Footer Bar for Application */ /* 1. Position the dark navbar below the white navbar + gap */
#bottomNavbar {
/* 56px (white nav) + 16px (mb-3) = 72px */
top: calc(var(--navbar-height) + var(--navbar-gap));
z-index: 1030;
}
/* 2. Pushes the main content down so it's not hidden under the navbars */
.main-content-area {
/* Total Sticky Height (128px) + Extra Margin (12px) = 140px */
margin-top: calc(var(--sticky-navbar-total-height) + 12px);
}
/* 3. Positions the sticky sidebar correctly */
.card.sticky-top {
/* Start scrolling the sidebar just below the two navbars + a small gap */
top: calc(var(--sticky-navbar-total-height) + 15px);
}
/* ---------------------------------------------------------------------- */
/* MOBILE RESPONSIVE STYLES (Below 992px) */
/* ---------------------------------------------------------------------- */
@media (max-width: 991.98px) { @media (max-width: 991.98px) {
/* Fix the "Apply" button bar to the bottom on mobile/tablet */
/* --- FIX: Spacing for Collapsed Hamburger Menu --- */
#navbarNav .nav-item {
margin-top: 5px;
margin-bottom: 5px;
padding: 5px 0;
border-bottom: 1px solid #f0f0f0;
}
#navbarNav .nav-item:last-child {
border-bottom: none;
}
#navbarNav .nav-link {
padding: 8px 15px;
display: block;
}
/* --- END FIX --- */
/* On mobile, the top navbar is generally only 56px tall when collapsed.
The bottom navbar position remains correct (72px down). */
#bottomNavbar {
top: calc(var(--navbar-height) + var(--navbar-gap));
}
/* Main content area needs less margin on mobile since the sidebar isn't active
and the navs are collapsed by default. */
.main-content-area {
/* Reduced margin-top for smaller screens */
margin-top: calc(var(--sticky-navbar-total-height) / 2);
}
/* Mobile Fixed Footer Bar for Application */
.mobile-fixed-apply-bar { .mobile-fixed-apply-bar {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
@ -47,9 +112,9 @@
right: 0; right: 0;
width: 100%; width: 100%;
padding: 15px; padding: 15px;
background-color: var(--light-bg); /* Use a light background */ background-color: var(--light-bg);
border-top: 1px solid #ddd; border-top: 1px solid #ddd;
z-index: 1000; /* Ensure it stays above everything */ z-index: 1000;
box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.08); box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.08);
} }
@ -58,29 +123,50 @@
padding-bottom: 90px; padding-bottom: 90px;
} }
/* Adjust header font size for small screens */ /* Fix job overview grid responsiveness (ensures 1 column) */
.card-header h2 {
font-size: 1.25rem !important;
}
/* Change job overview grid to single column on small phones */
.row-cols-md-2 {
--bs-gutter-x: 1.5rem;
--bs-gutter-y: 1rem;
}
.row-cols-md-2 > .col { .row-cols-md-2 > .col {
flex: 0 0 100%; /* force to 1 column */ flex: 0 0 100%;
max-width: 100%; max-width: 100%;
} }
} }
</style> </style>
{% endblock %} </head>
<body>
{% block content %} <nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
<div class="row mb-5"> <div class="container-fluid">
<a class="navbar-brand text-white fw-bold" href="/">
<img src="{% static 'image/kaauh.jpeg' %}" alt="{% translate 'KAAUH IMAGE' %}" style="height: 50px; margin-right: 10px;">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link text-secondary" href="/applications/">{% translate "Applications" %}</a>
</li>
<li class="nav-item">
<a class="nav-link text-secondary" href="/profile/">{% translate "Profile" %}</a>
</li>
</ul>
</div>
</div>
</nav>
<nav id="bottomNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: var(--kaauh-teal); z-index: 1030;">
<div class="container-fluid">
<span class="navbar-text text-white fw-bold">{% translate "Job Overview" %}</span>
</div>
</nav>
<div class="container">
<div class="row mb-5 mt-3 main-content-area">
<div class="col-lg-4 order-lg-2 order-1 d-none d-lg-block"> <div class="col-lg-4 order-lg-2 order-1 d-none d-lg-block">
<div class="card shadow-sm sticky-top" style="top: 90px;"> <div class="card shadow-sm sticky-top" style="top: var(--sticky-navbar-total-height);">
<div class="card-header bg-kaauh-teal-dark text-white"> <div class="card-header bg-kaauh-teal-dark text-white">
<h5 class="mb-0"><i class="fas fa-file-signature me-2"></i>Ready to Apply?</h5> <h5 class="mb-0"><i class="fas fa-file-signature me-2"></i>Ready to Apply?</h5>
</div> </div>
@ -92,10 +178,6 @@
<i class="fas fa-paper-plane me-2"></i> Apply for this Position <i class="fas fa-paper-plane me-2"></i> Apply for this Position
</a> </a>
{% endif %} {% endif %}
{% comment %} <p class="text-muted mt-3 mb-0">
<small>Application ID: **{{ job.pk }}**</small>
</p> {% endcomment %}
</div> </div>
</div> </div>
</div> </div>
@ -105,7 +187,7 @@
<div class="card-header bg-kaauh-teal-dark text-white d-flex justify-content-between align-items-center"> <div class="card-header bg-kaauh-teal-dark text-white d-flex justify-content-between align-items-center">
<h2 class="h3 mb-0 fw-bold">{{ job.title }}</h2> <h2 class="h3 mb-0 fw-bold">{{ job.title }}</h2>
{% with status_class=job.status|lower %} {% comment %} {% with status_class=job.status|lower %}
<span class="badge <span class="badge
{% if status_class == 'open' %}bg-success {% if status_class == 'open' %}bg-success
{% elif status_class == 'closed' %}bg-danger {% elif status_class == 'closed' %}bg-danger
@ -115,14 +197,13 @@
status-badge fw-bold p-2"> status-badge fw-bold p-2">
{{ job.get_status_display }} {{ job.get_status_display }}
</span> </span>
{% endwith %} {% endwith %} {% endcomment %}
</div> </div>
<div class="card-body"> <div class="card-body">
<h4 class="mb-3" style="color: var(--kaauh-teal-dark);">Job Overview</h4> <h4 class="mb-3" style="color: var(--kaauh-teal-dark);">Job Overview</h4>
<div class="row row-cols-1 row-cols-md-2 g-3 mb-4"> <div class="row row-cols-1 row-cols-md-2 g-3 mb-4">
{% if job.salary_range %} {% if job.salary_range %}
<div class="col"> <div class="col">
<i class="fas fa-money-bill-wave text-success me-2"></i> <i class="fas fa-money-bill-wave text-success me-2"></i>
@ -144,87 +225,31 @@
{% endif %} {% endif %}
</div> </div>
<div class="col"> <div class="col"> <i class="fas fa-briefcase text-muted me-2"></i> <strong>Job Type:</strong> {{ job.get_job_type_display }} </div>
<i class="fas fa-briefcase text-muted me-2"></i> <div class="col"> <i class="fas fa-map-marker-alt text-muted me-2"></i> <strong>Location:</strong> {{ job.get_location_display }} </div>
<strong>Job Type:</strong> {{ job.get_job_type_display }} <div class="col"> <i class="fas fa-building text-muted me-2"></i> <strong>Department:</strong> {{ job.department|default:"Not specified" }} </div>
<div class="col"> <i class="fas fa-hashtag text-muted me-2"></i> <strong>JOB ID:</strong> {{ job.internal_job_id|default:"N/A" }} </div>
<div class="col"> <i class="fas fa-desktop text-muted me-2"></i> <strong>Workplace:</strong> {{ job.get_workplace_type_display }} </div>
{% comment %} <div class="col"> <i class="fas fa-user-tie text-muted me-2"></i> <strong>Created By:</strong> {{ job.created_by|default:"N/A" }} </div> {% endcomment %}
</div> </div>
<div class="col"> {% if job.description %}<hr class="my-4"><div class="mb-4"><h5 class="fw-bold" style="color: var(--kaauh-teal-dark);"><i class="fas fa-info-circle me-2"></i>Job Description</h5><div class="text-secondary">{{ job.description|linebreaks }}</div></div>{% endif %}
<i class="fas fa-map-marker-alt text-muted me-2"></i> {% if job.qualifications %}<hr class="my-4"><div class="mb-4"><h5 class="fw-bold" style="color: var(--kaauh-teal-dark);"><i class="fas fa-graduation-cap me-2"></i>Qualifications</h5><div class="text-secondary">{{ job.qualifications|linebreaks }}</div></div>{% endif %}
<strong>Location:</strong> {{ job.get_location_display }} {% if job.benefits %}<hr class="my-4"><div class="mb-4"><h5 class="fw-bold" style="color: var(--kaauh-teal-dark);"><i class="fas fa-hand-holding-usd me-2"></i>Benefits</h5><div class="text-secondary">{{ job.benefits|linebreaks }}</div></div>{% endif %}
</div> {% if job.application_instructions %}<hr class="my-4"><div class="mb-4"><h5 class="fw-bold" style="color: var(--kaauh-teal-dark);"><i class="fas fa-file-alt me-2"></i>Application Instructions</h5><div class="text-secondary">{{ job.application_instructions|linebreaks }}</div></div>{% endif %}
<div class="col">
<i class="fas fa-building text-muted me-2"></i>
<strong>Department:</strong> {{ job.department|default:"Not specified" }}
</div>
<div class="col">
<i class="fas fa-hashtag text-muted me-2"></i>
<strong>JOB ID:</strong> {{ job.internal_job_id|default:"N/A" }}
</div>
<div class="col">
<i class="fas fa-desktop text-muted me-2"></i>
<strong>Workplace:</strong> {{ job.get_workplace_type_display }}
</div>
<div class="col">
<i class="fas fa-user-tie text-muted me-2"></i>
<strong>Created By:</strong> {{ job.created_by|default:"N/A" }}
</div>
</div>
{% if job.description %}
<hr class="my-4">
<div class="mb-4">
<h5 class="fw-bold" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-info-circle me-2"></i>Job Description
</h5>
<div class="text-secondary">{{ job.description|linebreaks }}</div>
</div>
{% endif %}
{% if job.qualifications %}
<hr class="my-4">
<div class="mb-4">
<h5 class="fw-bold" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-graduation-cap me-2"></i>Qualifications
</h5>
<div class="text-secondary">{{ job.qualifications|linebreaks }}</div>
</div>
{% endif %}
{% if job.benefits %}
<hr class="my-4">
<div class="mb-4">
<h5 class="fw-bold" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-hand-holding-usd me-2"></i>Benefits
</h5>
<div class="text-secondary">{{ job.benefits|linebreaks }}</div>
</div>
{% endif %}
{% if job.application_instructions %}
<hr class="my-4">
<div class="mb-4">
<h5 class="fw-bold" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-file-alt me-2"></i>Application Instructions
</h5>
<div class="text-secondary">{{ job.application_instructions|linebreaks }}</div>
</div>
{% endif %}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> <div class="mobile-fixed-apply-bar d-lg-none">
<div class="mobile-fixed-apply-bar d-lg-none">
{% if job.form_template %} {% if job.form_template %}
<a href="{% url 'form_wizard' job.form_template.pk %}" class="btn btn-main-action btn-lg w-100"> <a href="{% url 'form_wizard' job.form_template.pk %}" class="btn btn-main-action btn-lg w-100">
<i class="fas fa-paper-plane me-2"></i> Apply for this Position <i class="fas fa-paper-plane me-2"></i> Apply for this Position
</a> </a>
{% endif %} {% endif %}
</div> </div>
{% endblock %}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -1,8 +1,7 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load static %} {% load static i18n %}
{% block title %}Recruitment Dashboard - {{ block.super }}{% endblock %} {% block title %}{% trans "Recruitment Dashboard" %} - {{ block.super }}{% endblock %}
{% block customCSS %} {% block customCSS %}
<style> <style>
@ -88,56 +87,56 @@
{% block content %} {% block content %}
<div class="container-fluid py-4"> <div class="container-fluid py-4">
<h1 class="mb-4" style="color: var(--kaauh-teal-dark); font-weight: 700;">Recruitment Overview 🚀</h1> <h1 class="mb-4" style="color: var(--kaauh-teal-dark); font-weight: 700;">{% trans "Recruitment Overview" %} 🚀</h1>
<div class="stats"> <div class="stats">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h3><i class="fas fa-briefcase stat-icon"></i> Total Jobs</h3> <h3><i class="fas fa-briefcase stat-icon"></i> {% trans "Total Jobs" %}</h3>
</div> </div>
<div class="stat-value">{{ total_jobs }}</div> <div class="stat-value">{{ total_jobs }}</div>
<div class="stat-caption">Active & Drafted Positions</div> <div class="stat-caption">{% trans "Active & Drafted Positions" %}</div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h3><i class="fas fa-users stat-icon"></i> Total Candidates</h3> <h3><i class="fas fa-users stat-icon"></i> {% trans "Total Candidates" %}</h3>
</div> </div>
<div class="stat-value">{{ total_candidates }}</div> <div class="stat-value">{{ total_candidates }}</div>
<div class="stat-caption">All Profiles in ATS</div> <div class="stat-caption">{% trans "All Profiles in ATS" %}</div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h3><i class="fas fa-chart-line stat-icon"></i> Avg. Apps per Job</h3> <h3><i class="fas fa-chart-line stat-icon"></i> {% trans "Avg. Apps per Job" %}</h3>
</div> </div>
<div class="stat-value">{{ average_applications|floatformat:1 }}</div> <div class="stat-value">{{ average_applications|floatformat:1 }}</div>
<div class="stat-caption">Key Efficiency Metric</div> <div class="stat-caption">{% trans "Key Efficiency Metric" %}</div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h3><i class="fas fa-arrow-alt-circle-up stat-icon" style="color: var(--color-success);"></i> Active Listings</h3> <h3><i class="fas fa-arrow-alt-circle-up stat-icon" style="color: var(--color-success);"></i> {% trans "Active Listings" %}</h3>
</div> </div>
<div class="stat-value">22</div> <div class="stat-value">22</div>
<div class="stat-caption">Jobs currently open for application</div> <div class="stat-caption">{% trans "Jobs currently open for application" %}</div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h3><i class="fas fa-clock stat-icon" style="color: var(--color-info);"></i> Time to Hire</h3> <h3><i class="fas fa-clock stat-icon" style="color: var(--color-info);"></i> {% trans "Time to Hire" %}</h3>
</div> </div>
<div class="stat-value">35d</div> <div class="stat-value">35d</div>
<div class="stat-caption">Average days from apply to offer</div> <div class="stat-caption">{% trans "Average days from apply to offer" %}</div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h3><i class="fas fa-handshake stat-icon" style="color: var(--kaauh-teal-light);"></i> Offer Acceptance</h3> <h3><i class="fas fa-handshake stat-icon" style="color: var(--kaauh-teal-light);"></i> {% trans "Offer Acceptance" %}</h3>
</div> </div>
<div class="stat-value">85%</div> <div class="stat-value">85%</div>
<div class="stat-caption">Successful offers vs. Total offers</div> <div class="stat-caption">{% trans "Successful offers vs. Total offers" %}</div>
</div> </div>
</div> </div>
@ -145,7 +144,7 @@
<div class="card-header"> <div class="card-header">
<h2 class="d-flex align-items-center mb-0"> <h2 class="d-flex align-items-center mb-0">
<i class="fas fa-chart-bar stat-icon"></i> <i class="fas fa-chart-bar stat-icon"></i>
Applications Volume by Job {% trans "Applications Volume by Job" %}
</h2> </h2>
</div> </div>
<div class="chart-container"> <div class="chart-container">
@ -156,13 +155,17 @@
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script> <script>
// if the strings are visible to the user. 'Applications' is used for Chart.js here.
const ctx = document.getElementById('applicationsChart').getContext('2d'); const ctx = document.getElementById('applicationsChart').getContext('2d');
const chart = new Chart(ctx, { const chart = new Chart(ctx, {
type: 'bar', type: 'bar',
data: { data: {
labels: {{ job_titles|safe }}, labels: {{ job_titles|safe }},
datasets: [{ datasets: [{
label: 'Applications',
// For simplicity, we are leaving it as-is for now, assuming the context provides the translated labels.
label: '{% trans "Applications" %}',
data: {{ job_app_counts|safe }}, data: {{ job_app_counts|safe }},
backgroundColor: ' #00636e', // Green theme backgroundColor: ' #00636e', // Green theme
borderColor: ' #004a53', borderColor: ' #004a53',