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

@ -20,6 +20,7 @@
--kaauh-light-bg: #f9fbfd; --kaauh-light-bg: #f9fbfd;
--kaauh-border: #eaeff3; --kaauh-border: #eaeff3;
} }
/* === Top Bar === */ /* === Top Bar === */
.top-bar { .top-bar {
@ -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,48 +345,38 @@
</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">
<a class="language-toggle-btn dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" <a class="language-toggle-btn dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
data-bs-offset="0, 8" aria-expanded="false" aria-label="{% trans 'Toggle language menu' %}"> data-bs-offset="0, 8" aria-expanded="false" aria-label="{% trans 'Toggle language menu' %}">
<i class="fas fa-globe"></i> <i class="fas fa-globe"></i>
<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)
</button> </button>
</form> </form>
</li> </li>
</ul> </ul>
</li> </li>
</ul> </ul>
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item dropdown"> <li class="nav-item dropdown">
@ -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,454 +1,544 @@
<!-- 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>
/* KAAT-S Theme Variables */ /* KAAT-S Theme Variables */
:root { :root {
--kaauh-teal: #00636e; /* Main Primary Color */ --kaauh-teal: #00636e; /* Main Primary Color */
--kaauh-teal-dark: #004a53; /* Dark Primary Color */ --kaauh-teal-dark: #004a53; /* Dark Primary Color */
/* Mapping wizard defaults to theme colors */ /* Mapping wizard defaults to theme colors */
--primary: var(--kaauh-teal); --primary: var(--kaauh-teal);
--primary-light: #007c89; /* Slightly lighter shade for subtle hover/border */ --primary-light: #007c89; /* Slightly lighter shade for subtle hover/border */
--secondary: var(--kaauh-teal-dark); --secondary: var(--kaauh-teal-dark);
--success: #198754; /* Keeping a standard success green for Submit */ --success: #198754; /* Keeping a standard success green for Submit */
--error: #dc3545; /* Standard danger red */ --error: #dc3545; /* Standard danger red */
--light: #f8f9fa; --light: #f8f9fa;
--dark: #212529; --dark: #212529;
--gray: #6c757d; --gray: #6c757d;
--light-gray: #e9ecef; --light-gray: #e9ecef;
--border: #dee2e6; --border: #dee2e6;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1); --shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--radius: 16px; /* Increased radius for a softer look */ --radius: 16px; /* Increased radius for a softer look */
--transition: all 0.3s ease; --transition: all 0.3s ease;
} }
body { body {
/* Dark gradient background to match the theme */ /* Remove centering/flex properties to allow for normal document flow and scrolling */
background: linear-gradient(135deg, var(--kaauh-teal-dark) 0%, #1e3a47 100%); padding-top: 56px; /* Space for the sticky navbar */
min-height: 100vh;
display: flex; /* Dark gradient background to match the theme */
justify-content: center; background: linear-gradient(135deg, var(--kaauh-teal-dark) 0%, #1e3a47 100%);
align-items: center; background-image: url("{% static 'image/vision.svg' %}");
padding: 20px; background-repeat: no-repeat;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; background-position: 60px;
} background-size: 320px auto;
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;
justify-content: center;
align-items: center;
padding: 20px; /* Re-apply padding here for the content area */
min-height: calc(100vh - 56px); /* Adjust height to account for navbar */
}
.wizard-container {
width: 100%;
max-width: 800px; /* Increased max-width slightly for content */
background: white;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
/* Allow height to be determined by content, constrained by max-height */
height: auto;
max-height: 90vh;
}
/* Progress Bar */
.progress-container {
height: 8px; /* Slightly thicker bar */
background: var(--light-gray);
position: relative;
overflow: hidden;
}
.progress-bar {
height: 100%;
background: var(--primary); /* Teal color */
transition: width 0.4s ease;
width: 0%;
}
/* Header */
.wizard-header {
padding: 25px 30px 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 1.4rem;
font-weight: 700;
color: var(--secondary); /* Dark teal for logo */
display: flex;
align-items: center;
gap: 10px;
}
.progress-text {
font-size: 0.9rem;
color: var(--gray);
font-weight: 500;
}
/* Main Content */
.wizard-content {
flex: 1;
padding: 0 30px 30px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.stage-container {
flex: 1;
display: flex;
flex-direction: column;
overflow-y: auto;
padding-right: 15px; /* Space for scrollbar */
}
.stage-title {
font-size: 1.8rem;
font-weight: 700;
margin-bottom: 25px;
color: var(--dark);
line-height: 1.3;
}
.field-container {
margin-bottom: 25px;
}
.field-label {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 8px;
color: var(--dark);
}
.required-indicator {
color: var(--error);
font-weight: bold;
}
/* Input Styles */
.form-input {
width: 100%;
padding: 14px 16px;
border: 2px solid var(--border);
border-radius: 12px;
font-size: 1rem;
transition: var(--transition);
}
.form-input:focus {
outline: none;
border-color: var(--primary); /* Teal focus border */
box-shadow: 0 0 0 4px rgba(0, 99, 110, 0.2); /* Teal shadow */
}
.form-input.error {
border-color: var(--error);
box-shadow: 0 0 0 4px rgba(220, 53, 69, 0.2);
}
.error-message {
color: var(--error);
font-size: 0.85rem;
margin-top: 5px;
display: none;
}
.error-message.show {
display: block;
}
.form-textarea {
min-height: 120px;
resize: vertical;
}
/* File Upload Styles */
.file-upload-area {
border: 2px dashed var(--border);
border-radius: 12px;
padding: 25px;
text-align: center;
background: var(--light);
transition: var(--transition);
cursor: pointer;
}
.file-upload-area:hover {
border-color: var(--primary); /* Teal hover border */
background: rgba(0, 99, 110, 0.05); /* Light teal background */
}
.file-upload-area.error {
border-color: var(--error);
background: rgba(220, 53, 69, 0.05);
}
.file-upload-icon {
font-size: 2.5rem;
color: var(--primary); /* Teal icon */
margin-bottom: 15px;
}
.file-upload-text {
font-size: 1.1rem;
margin-bottom: 10px;
}
.file-upload-text strong {
color: var(--primary); /* Teal text */
}
.file-upload-info {
font-size: 0.9rem;
color: var(--gray);
}
.uploaded-file {
display: flex;
align-items: center;
justify-content: space-between;
background: white;
border: 1px solid var(--border);
border-radius: 12px;
padding: 12px 16px;
margin-top: 15px;
}
.file-info {
display: flex;
align-items: center;
gap: 12px;
}
.file-icon {
color: var(--primary); /* Teal icon */
font-size: 1.2rem;
}
.file-name {
font-weight: 600;
}
.file-size {
font-size: 0.85rem;
color: var(--gray);
}
.remove-file-btn {
background: none;
border: none;
color: var(--error);
cursor: pointer;
font-size: 1.2rem;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: var(--transition);
}
.remove-file-btn:hover {
background: rgba(220, 53, 69, 0.1);
}
/* Radio/Checkbox Styles */
.option-item {
display: flex;
align-items: center;
margin-bottom: 12px;
padding: 12px;
border: 2px solid var(--border);
border-radius: 12px;
transition: var(--transition);
cursor: pointer;
}
.option-item:hover {
border-color: var(--primary-light);
}
.option-item.selected {
border-color: var(--primary); /* Teal border */
background: rgba(0, 99, 110, 0.05); /* Light teal background */
}
.option-item.error {
border-color: var(--error);
background: rgba(220, 53, 69, 0.05);
}
/* Ensures radio/checkbox controls themselves use the primary color */
.option-item input[type="radio"]:checked,
.option-item input[type="checkbox"]:checked {
accent-color: var(--primary);
}
.option-item input {
margin-right: 12px;
width: 20px;
height: 20px;
}
/* Preview Styles */
.preview-container {
background: var(--light);
border-radius: 12px;
padding: 20px;
margin-bottom: 25px;
}
.preview-item {
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 1px solid var(--border);
}
.preview-item:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.preview-label {
font-weight: 600;
margin-bottom: 5px;
color: var(--dark);
}
.preview-value {
color: var(--gray);
}
/* Navigation */
.wizard-footer {
padding: 0 30px 30px;
display: flex;
justify-content: space-between;
align-items: center;
}
.nav-btn {
padding: 14px 28px;
border-radius: 12px;
border: none;
font-weight: 600;
font-size: 1rem;
cursor: pointer;
transition: var(--transition);
display: flex;
align-items: center;
gap: 10px;
}
.btn-back {
background: var(--light-gray); /* Match theme's light gray */
color: var(--gray);
}
.btn-back:hover {
background: #d8dadc;
}
.btn-next {
background: var(--primary); /* Teal color */
color: white;
box-shadow: 0 4px 12px rgba(0, 99, 110, 0.3); /* Teal shadow */
}
.btn-next:hover {
background: var(--secondary); /* Darker teal on hover */
transform: translateY(-2px);
}
.btn-submit {
background: var(--success); /* Green for submit */
color: white;
box-shadow: 0 4px 12px rgba(25, 135, 84, 0.3);
}
.btn-submit:hover {
background: #157347;
transform: translateY(-2px);
}
/* Responsive */
@media (max-width: 600px) {
.wizard-container { .wizard-container {
width: 100%; height: 100vh;
max-width: 800px; /* Increased max-width slightly for content */ border-radius: 0;
background: white; max-width: 100%;
border-radius: 20px; max-height: 100vh;
overflow: hidden;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
height: 90vh;
}
/* Progress Bar */
.progress-container {
height: 8px; /* Slightly thicker bar */
background: var(--light-gray);
position: relative;
overflow: hidden;
}
.progress-bar {
height: 100%;
background: var(--primary); /* Teal color */
transition: width 0.4s ease;
width: 0%;
}
/* Header */
.wizard-header {
padding: 25px 30px 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 1.4rem;
font-weight: 700;
color: var(--secondary); /* Dark teal for logo */
display: flex;
align-items: center;
gap: 10px;
}
.progress-text {
font-size: 0.9rem;
color: var(--gray);
font-weight: 500;
}
/* Main Content */
.wizard-content {
flex: 1;
padding: 0 30px 30px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.stage-container {
flex: 1;
display: flex;
flex-direction: column;
overflow-y: auto;
padding-right: 15px; /* Space for scrollbar */
} }
.stage-title { .stage-title {
font-size: 1.8rem; font-size: 1.5rem;
font-weight: 700;
margin-bottom: 25px;
color: var(--dark);
line-height: 1.3;
} }
.field-container { .wizard-header {
margin-bottom: 25px; padding: 20px;
} }
.field-label { .wizard-content {
font-size: 1.1rem; padding: 0 20px 20px;
font-weight: 600;
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 8px;
color: var(--dark);
} }
.required-indicator { .wizard-footer {
color: var(--error); padding: 0 20px 20px;
font-weight: bold;
} }
}
/* Input Styles */
.form-input { /* === FIX FOR SMALL-SCREEN HAMBURGER MENU === */
width: 100%; @media (max-width: 991.98px) {
padding: 14px 16px; /* Add vertical spacing to the navigation items when the navbar is collapsed */
border: 2px solid var(--border); #navbarNav .nav-item {
border-radius: 12px;
font-size: 1rem;
transition: var(--transition);
}
.form-input:focus {
outline: none;
border-color: var(--primary); /* Teal focus border */
box-shadow: 0 0 0 4px rgba(0, 99, 110, 0.2); /* Teal shadow */
}
.form-input.error {
border-color: var(--error);
box-shadow: 0 0 0 4px rgba(220, 53, 69, 0.2);
}
.error-message {
color: var(--error);
font-size: 0.85rem;
margin-top: 5px; margin-top: 5px;
display: none; margin-bottom: 5px;
padding: 5px 0;
border-bottom: 1px solid #f0f0f0;
} }
.error-message.show { #navbarNav .nav-item:last-child {
border-bottom: none;
}
#navbarNav .nav-link {
padding: 8px 15px;
display: block; display: block;
} }
.form-textarea { /* Adjust the total margin of the top navbar container when collapsed */
min-height: 120px; #topNavbar.mb-3 {
resize: vertical; margin-bottom: 0 !important;
} }
}
/* File Upload Styles */ #bottomNavbar {
.file-upload-area { /* Position the dark navbar 72px from the top of the viewport */
border: 2px dashed var(--border); top: 72px;
border-radius: 12px; /* The z-index is already 1030 in the inline style, which is correct */
padding: 25px; }
text-align: center; </style>
background: var(--light);
transition: var(--transition);
cursor: pointer;
}
.file-upload-area:hover {
border-color: var(--primary); /* Teal hover border */
background: rgba(0, 99, 110, 0.05); /* Light teal background */
}
.file-upload-area.error {
border-color: var(--error);
background: rgba(220, 53, 69, 0.05);
}
.file-upload-icon {
font-size: 2.5rem;
color: var(--primary); /* Teal icon */
margin-bottom: 15px;
}
.file-upload-text {
font-size: 1.1rem;
margin-bottom: 10px;
}
.file-upload-text strong {
color: var(--primary); /* Teal text */
}
.file-upload-info {
font-size: 0.9rem;
color: var(--gray);
}
.uploaded-file {
display: flex;
align-items: center;
justify-content: space-between;
background: white;
border: 1px solid var(--border);
border-radius: 12px;
padding: 12px 16px;
margin-top: 15px;
}
.file-info {
display: flex;
align-items: center;
gap: 12px;
}
.file-icon {
color: var(--primary); /* Teal icon */
font-size: 1.2rem;
}
.file-name {
font-weight: 600;
}
.file-size {
font-size: 0.85rem;
color: var(--gray);
}
.remove-file-btn {
background: none;
border: none;
color: var(--error);
cursor: pointer;
font-size: 1.2rem;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: var(--transition);
}
.remove-file-btn:hover {
background: rgba(220, 53, 69, 0.1);
}
/* Radio/Checkbox Styles */
.option-item {
display: flex;
align-items: center;
margin-bottom: 12px;
padding: 12px;
border: 2px solid var(--border);
border-radius: 12px;
transition: var(--transition);
cursor: pointer;
}
.option-item:hover {
border-color: var(--primary-light);
}
.option-item.selected {
border-color: var(--primary); /* Teal border */
background: rgba(0, 99, 110, 0.05); /* Light teal background */
}
.option-item.error {
border-color: var(--error);
background: rgba(220, 53, 69, 0.05);
}
/* Ensures radio/checkbox controls themselves use the primary color */
.option-item input[type="radio"]:checked,
.option-item input[type="checkbox"]:checked {
accent-color: var(--primary);
}
.option-item input {
margin-right: 12px;
width: 20px;
height: 20px;
}
/* Preview Styles */
.preview-container {
background: var(--light);
border-radius: 12px;
padding: 20px;
margin-bottom: 25px;
}
.preview-item {
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 1px solid var(--border);
}
.preview-item:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.preview-label {
font-weight: 600;
margin-bottom: 5px;
color: var(--dark);
}
.preview-value {
color: var(--gray);
}
/* Navigation */
.wizard-footer {
padding: 0 30px 30px;
display: flex;
justify-content: space-between;
align-items: center;
}
.nav-btn {
padding: 14px 28px;
border-radius: 12px;
border: none;
font-weight: 600;
font-size: 1rem;
cursor: pointer;
transition: var(--transition);
display: flex;
align-items: center;
gap: 10px;
}
.btn-back {
background: var(--light-gray); /* Match theme's light gray */
color: var(--gray);
}
.btn-back:hover {
background: #d8dadc;
}
.btn-next {
background: var(--primary); /* Teal color */
color: white;
box-shadow: 0 4px 12px rgba(0, 99, 110, 0.3); /* Teal shadow */
}
.btn-next:hover {
background: var(--secondary); /* Darker teal on hover */
transform: translateY(-2px);
}
.btn-submit {
background: var(--success); /* Green for submit */
color: white;
box-shadow: 0 4px 12px rgba(25, 135, 84, 0.3);
}
.btn-submit:hover {
background: #157347;
transform: translateY(-2px);
}
/* Responsive */
@media (max-width: 600px) {
.wizard-container {
height: 100vh;
border-radius: 0;
max-width: 100%;
}
.stage-title {
font-size: 1.5rem;
}
.wizard-header {
padding: 20px;
}
.wizard-content {
padding: 0 20px 20px;
}
.wizard-footer {
padding: 0 20px 20px;
}
}
</style>
</head> </head>
<body> <body>
<div class="wizard-container">
<div class="progress-container"> <nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
<div class="progress-bar" id="progressBar"></div> <div class="container-fluid">
</div> <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;">
<div class="wizard-header"> </a>
<div class="logo"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
<i class="fas fa-file-alt"></i> aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span id="formTitle">Application Form</span> <span class="navbar-toggler-icon"></span>
</div> </button>
<div class="progress-text" id="progressText">1 of 1</div> <div class="collapse navbar-collapse" id="navbarNav">
</div> <ul class="navbar-nav ms-auto">
<div class="wizard-content"> <li class="nav-item">
<div class="stage-container" id="stageContainer"> <a class="nav-link text-secondary" href="/applications/">{% translate "Applications" %}</a>
</div> </li>
<li class="nav-item">
<div class="preview-container" id="previewContainer" style="display: none;"> <a class="nav-link text-secondary" href="/profile/">{% translate "Profile" %}</a>
<h3 class="mb-4">Review Your Application</h3> </li>
<div id="previewContent"></div> </ul>
</div>
</div>
<div class="wizard-footer">
<button id="backBtn" class="nav-btn btn-back" style="display: none;">
<i class="fas fa-arrow-left"></i> Back
</button>
<button id="nextBtn" class="nav-btn btn-next">
Next <i class="fas fa-arrow-right"></i>
</button>
<button id="submitBtn" class="nav-btn btn-submit" style="display: none;">
Submit Application <i class="fas fa-paper-plane"></i>
</button>
</div> </div>
</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="progress-container">
<div class="progress-bar" id="progressBar"></div>
</div>
<script> <div class="wizard-header">
<div class="logo">
<i class="fas fa-file-alt"></i>
<span id="formTitle">{% translate "Application Form" %}</span>
</div>
<div class="progress-text" id="progressText">1 of 1</div>
</div>
<div class="wizard-content">
<div class="stage-container" id="stageContainer">
</div>
<div class="preview-container" id="previewContainer" style="display: none;">
<h3 class="mb-4">{% translate "Review Your Application" %}</h3>
<div id="previewContent"></div>
</div>
</div>
<div class="wizard-footer">
<button id="backBtn" class="nav-btn btn-back" style="display: none;">
<i class="fas fa-arrow-left"></i> {% translate "Back" %}
</button>
<button id="nextBtn" class="nav-btn btn-next">
{% translate "Next" %} <i class="fas fa-arrow-right"></i>
</button>
<button id="submitBtn" class="nav-btn btn-submit" style="display: none;">
{% translate "Submit Application" %} <i class="fas fa-paper-plane"></i>
</button>
</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>
// Application State // Application State
const csrfToken = '{{ csrf_token }}'; const csrfToken = '{{ csrf_token }}';
const state = { const state = {
@ -1154,4 +1244,4 @@
document.addEventListener('DOMContentLoaded', init); document.addEventListener('DOMContentLoaded', init);
</script> </script>
</body> </body>
</html> </html>

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 {
@ -32,14 +44,67 @@
.bg-kaauh-teal-dark { .bg-kaauh-teal-dark {
background-color: var(--kaauh-teal-dark) !important; background-color: var(--kaauh-teal-dark) !important;
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* 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,173 +123,133 @@
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 %}
<div class="row mb-5"> <nav id="topNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: white; z-index: 1030;">
<div class="container-fluid">
<div class="col-lg-4 order-lg-2 order-1 d-none d-lg-block"> <a class="navbar-brand text-white fw-bold" href="/">
<div class="card shadow-sm sticky-top" style="top: 90px;"> <img src="{% static 'image/kaauh.jpeg' %}" alt="{% translate 'KAAUH IMAGE' %}" style="height: 50px; margin-right: 10px;">
<div class="card-header bg-kaauh-teal-dark text-white"> </a>
<h5 class="mb-0"><i class="fas fa-file-signature me-2"></i>Ready to Apply?</h5> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
</div> aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<div class="card-body text-center"> <span class="navbar-toggler-icon"></span>
<p class="text-muted">Review the job details, then apply below.</p> </button>
<div class="collapse navbar-collapse" id="navbarNav">
{% if job.form_template %} <ul class="navbar-nav ms-auto">
<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 <li class="nav-item">
</a> <a class="nav-link text-secondary" href="/applications/">{% translate "Applications" %}</a>
{% endif %} </li>
<li class="nav-item">
{% comment %} <p class="text-muted mt-3 mb-0"> <a class="nav-link text-secondary" href="/profile/">{% translate "Profile" %}</a>
<small>Application ID: **{{ job.pk }}**</small> </li>
</p> {% endcomment %} </ul>
</div>
</div> </div>
</div> </div>
</nav>
<div class="col-lg-8 order-lg-1 order-2">
<div class="card shadow-sm"> <nav id="bottomNavbar" class="navbar navbar-expand-lg sticky-top" style="background-color: var(--kaauh-teal); z-index: 1030;">
<div class="card-header bg-kaauh-teal-dark text-white d-flex justify-content-between align-items-center"> <div class="container-fluid">
<h2 class="h3 mb-0 fw-bold">{{ job.title }}</h2> <span class="navbar-text text-white fw-bold">{% translate "Job Overview" %}</span>
</div>
{% with status_class=job.status|lower %} </nav>
<span class="badge
{% if status_class == 'open' %}bg-success <div class="container">
{% elif status_class == 'closed' %}bg-danger <div class="row mb-5 mt-3 main-content-area">
{% elif status_class == 'draft' %}bg-secondary
{% else %}bg-primary <div class="col-lg-4 order-lg-2 order-1 d-none d-lg-block">
{% endif %} <div class="card shadow-sm sticky-top" style="top: var(--sticky-navbar-total-height);">
status-badge fw-bold p-2"> <div class="card-header bg-kaauh-teal-dark text-white">
{{ job.get_status_display }} <h5 class="mb-0"><i class="fas fa-file-signature me-2"></i>Ready to Apply?</h5>
</span>
{% endwith %}
</div>
<div class="card-body">
<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">
{% if job.salary_range %}
<div class="col">
<i class="fas fa-money-bill-wave text-success me-2"></i>
<strong>Salary:</strong>
<span class="fw-bold text-success">{{ job.salary_range }}</span>
</div> </div>
{% endif %} <div class="card-body text-center">
<p class="text-muted">Review the job details, then apply below.</p>
<div class="col">
<i class="fas fa-calendar-alt text-muted me-2"></i> {% if job.form_template %}
<strong>Deadline:</strong> <a href="{% url 'form_wizard' job.form_template.pk %}" class="btn btn-main-action btn-lg w-100">
{% if job.application_deadline %} <i class="fas fa-paper-plane me-2"></i> Apply for this Position
{{ job.application_deadline|date:"M d, Y" }} </a>
{% if job.is_expired %}
<span class="badge bg-danger ms-2">EXPIRED</span>
{% endif %}
{% else %}
<span class="text-muted">Not specified</span>
{% endif %} {% endif %}
</div> </div>
</div>
<div class="col"> </div>
<i class="fas fa-briefcase text-muted me-2"></i>
<strong>Job Type:</strong> {{ job.get_job_type_display }} <div class="col-lg-8 order-lg-1 order-2">
<div class="card shadow-sm">
<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>
{% comment %} {% with status_class=job.status|lower %}
<span class="badge
{% if status_class == 'open' %}bg-success
{% elif status_class == 'closed' %}bg-danger
{% elif status_class == 'draft' %}bg-secondary
{% else %}bg-primary
{% endif %}
status-badge fw-bold p-2">
{{ job.get_status_display }}
</span>
{% endwith %} {% endcomment %}
</div> </div>
<div class="col"> <div class="card-body">
<i class="fas fa-map-marker-alt text-muted me-2"></i>
<strong>Location:</strong> {{ job.get_location_display }} <h4 class="mb-3" style="color: var(--kaauh-teal-dark);">Job Overview</h4>
</div> <div class="row row-cols-1 row-cols-md-2 g-3 mb-4">
{% if job.salary_range %}
<div class="col"> <div class="col">
<i class="fas fa-building text-muted me-2"></i> <i class="fas fa-money-bill-wave text-success me-2"></i>
<strong>Department:</strong> {{ job.department|default:"Not specified" }} <strong>Salary:</strong>
</div> <span class="fw-bold text-success">{{ job.salary_range }}</span>
</div>
<div class="col"> {% endif %}
<i class="fas fa-hashtag text-muted me-2"></i>
<strong>JOB ID:</strong> {{ job.internal_job_id|default:"N/A" }} <div class="col">
</div> <i class="fas fa-calendar-alt text-muted me-2"></i>
<strong>Deadline:</strong>
<div class="col"> {% if job.application_deadline %}
<i class="fas fa-desktop text-muted me-2"></i> {{ job.application_deadline|date:"M d, Y" }}
<strong>Workplace:</strong> {{ job.get_workplace_type_display }} {% if job.is_expired %}
</div> <span class="badge bg-danger ms-2">EXPIRED</span>
{% endif %}
<div class="col"> {% else %}
<i class="fas fa-user-tie text-muted me-2"></i> <span class="text-muted">Not specified</span>
<strong>Created By:</strong> {{ job.created_by|default:"N/A" }} {% endif %}
</div>
<div class="col"> <i class="fas fa-briefcase text-muted me-2"></i> <strong>Job Type:</strong> {{ job.get_job_type_display }} </div>
<div class="col"> <i class="fas fa-map-marker-alt text-muted me-2"></i> <strong>Location:</strong> {{ job.get_location_display }} </div>
<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>
{% 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>
{% 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 class="mobile-fixed-apply-bar d-lg-none">
{% if job.form_template %}
<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
</a>
{% endif %}
</div> </div>
</div>
<div class="mobile-fixed-apply-bar d-lg-none"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
{% if job.form_template %} </body>
<a href="{% url 'form_wizard' job.form_template.pk %}" class="btn btn-main-action btn-lg w-100"> </html>
<i class="fas fa-paper-plane me-2"></i> Apply for this Position
</a>
{% endif %}
</div>
{% endblock %}

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',