Merge pull request 'ui fixes' (#39) from frontend into main

Reviewed-on: #39
This commit is contained in:
ismail 2025-11-24 13:15:20 +03:00
commit a8fae9011c
12 changed files with 82 additions and 7895 deletions

6
.env
View File

@ -1,3 +1,3 @@
DB_NAME=norahuniversity
DB_USER=norahuniversity
DB_PASSWORD=norahuniversity
DB_NAME=haikal_db
DB_USER=faheed
DB_PASSWORD=Faheed@215

2
.gitignore vendored
View File

@ -92,6 +92,8 @@ coverage.xml
# Translations
*.mo
locale/
# Django stuff:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -287,7 +287,10 @@ class JobPosting(Base):
next_num = 1
self.internal_job_id = f"{prefix}-{year}-{next_num:06d}"
if self.department:
self.department = self.department.title()
super().save(*args, **kwargs)
def get_location_display(self):

View File

@ -806,11 +806,11 @@ def kaauh_career(request):
selected_job_type = request.GET.get("employment_type", "")
job_type_keys = active_jobs.order_by("job_type").distinct("job_type").values_list("job_type", flat=True)
print(job_type_keys)
workplace_type_keys = active_jobs.order_by("workplace_type").distinct("workplace_type").values_list(
"workplace_type", flat=True
).distinct()
print(workplace_type_keys)
if selected_job_type and selected_job_type in job_type_keys:
active_jobs = active_jobs.filter(job_type=selected_job_type)
if selected_workplace_type and selected_workplace_type in workplace_type_keys:
@ -4053,7 +4053,8 @@ def portal_login(request):
return render(request, "recruitment/portal_login.html", context)
@login_required
@candidate_user_required
def candidate_portal_dashboard(request):
"""Candidate portal dashboard"""
if not request.user.is_authenticated:

View File

@ -35,6 +35,9 @@
#1e3a47 100%
);
background-image: url("{% static 'image/vision.svg' %}");
@media (max-width: 768px) {
background-image: none;
}
background-repeat: no-repeat;
background-position: 60px;
background-size: 320px auto;
@ -58,11 +61,11 @@
.wizard-container {
width: 100%;
max-width: 800px; /* Increased max-width slightly for content */
max-width: 900px; /* 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 */
@ -473,7 +476,7 @@
class="navbar navbar-expand-lg sticky-top"
style="background-color: var(--kaauh-teal); z-index: 1030"
>
<span class="ms-2 text-white">JOB ID:&nbsp;&nbsp;{{job_id}}</span>
<span class="ms-2 text-white">{% trans "JOB ID" %}:&nbsp;&nbsp;{{job_id}}</span>
</nav>
<div class="page-content-wrapper">
@ -486,7 +489,7 @@
<div class="logo">
<i class="fas fa-file-alt"></i>
<span id="formTitle"
>{% translate "Application Form" %}</span
>{% trans "Application Form" %}</span
>
</div>
<div class="progress-text" id="progressText">1 of 1</div>
@ -501,7 +504,7 @@
style="display: none"
>
<h3 class="mb-4">
{% translate "Review Your Application" %}
{% trans "Review Your Application" %}
</h3>
<div id="previewContent"></div>
</div>
@ -513,11 +516,11 @@
class="nav-btn btn-back"
style="display: none"
>
<i class="fas fa-arrow-left"></i> {% translate "Back" %}
<i class="fas fa-arrow-left"></i> {% trans "Back" %}
</button>
<button id="nextBtn" class="nav-btn btn-next">
{% translate "Next" %}
{% trans "Next" %}
<i class="fas fa-arrow-right"></i>
</button>
@ -526,7 +529,7 @@
class="nav-btn btn-submit"
style="display: none"
>
{% translate "Submit Application" %}
{% trans "Submit Application" %}
<i class="fas fa-paper-plane"></i>
</button>
</div>

View File

@ -73,13 +73,7 @@
{% for key in job_type_keys %}
<option value="{{ key }}" {% if key == selected_job_type %}selected{% endif %}>
<!-- Hard-coded mapping using IF statements -->
{% if key == 'FULL_TIME' %}{% trans "Full-time" %}{% endif %}
{% if key == 'PART_TIME' %}{% trans "Part-time" %}{% endif %}
{% if key == 'CONTRACT' %}{% trans "Contract" %}{% endif %}
{% if key == 'INTERNSHIP' %}{% trans "Internship" %}{% endif %}
{% if key == 'FACULTY' %}{% trans "Faculty" %}{% endif %}
{% if key == 'TEMPORARY' %}{% trans "Temporary" %}{% endif %}
{{key}}
</option>
{% endfor %}
</select>
@ -89,10 +83,7 @@
{% for key in workplace_type_keys %}
<option value="{{ key }}" {% if key == selected_workplace_type %}selected{% endif %}>
<!-- Hard-coded mapping using IF statements -->
{% if key == 'ON_SITE' %}{% trans "On-site" %}{% endif %}
{% if key == 'REMOTE' %}{% trans "Remote" %}{% endif %}
{% if key == 'HYBRID' %}{% trans "Hybrid" %}{% endif %}
{{key}}
</option>
{% endfor %}
@ -246,7 +237,7 @@
</div>
</a>
{% empty %}
<div class="alert alert-info border-0 shadow-sm mt-5" role="alert">
<div class="alert text-primary-theme border-0 shadow-sm mt-5" role="alert">
<h5 class="alert-heading">{% trans "No Matching Opportunities" %}</h5>
<p>{% trans "We currently have no open roles that match your search and filters. Please modify your criteria or check back soon!" %}</p>
</div>

View File

@ -281,6 +281,15 @@
{% trans "Meetings" %}
</span>
</a>
</li>
<li class="nav-item me-lg-4">
<a class="nav-link {% if request.resolver_match.url_name == 'kaauh_career' %}active{% endif %}" href="{% url 'kaauh_career' %}">
<span class="d-flex align-items-center gap-2">
<i class="fas fa-globe me-2"></i>
{% trans "Career Page" %}
</span>
</a>
</li>
{% comment %} <li class="nav-item me-lg-4">
<a class="nav-link {% if request.resolver_match.url_name == 'interview_list' %}active{% endif %}" href="{% url 'interview_list' %}">
@ -303,17 +312,7 @@
</a>
</li>
<li class="nav-item me-lg-4">
<a class="nav-link {% if request.resolver_match.url_name == 'kaauh_career' %}active{% endif %}" href="{% url 'kaauh_career' %}">
<span class="d-flex align-items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6A2.25 2.25 0 0 1 6 3.75h2.25A2.25 2.25 0 0 1 10.5 6v2.25a2.25 2.25 0 0 1-2.25 2.25H6a2.25 2.25 0 0 1-2.25-2.25V6ZM3.75 15.75A2.25 2.25 0 0 1 6 13.5h2.25a2.25 2.25 0 0 1 2.25 2.25V18a2.25 2.25 0 0 1-2.25 2.25H6A2.25 2.25 0 0 1 3.75 18v-2.25ZM13.5 6a2.25 2.25 0 0 1 2.25-2.25H18A2.25 2.25 0 0 1 20.25 6v2.25A2.25 2.25 0 0 1 18 10.5h-2.25a2.25 2.25 0 0 1-2.25-2.25V6ZM13.5 15.75a2.25 2.25 0 0 1 2.25-2.25H18a2.25 2.25 0 0 1 2.25 2.25V18A2.25 2.25 0 0 1 18 20.25h-2.25A2.25 2.25 0 0 1 13.5 18v-2.25Z" />
</svg>
{% trans "Career Page" %}
</span>
</a>
</li>
{% comment %} <li class="nav-item dropdown ms-lg-2">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
data-bs-offset="0, 8" data-bs-auto-close="outside">

View File

@ -112,22 +112,13 @@
</li>
<li class="nav-item">
<a class="nav-link text-white" href="{% url 'kaauh_career' %}">
<i class="fas fa-hand me-1"></i> {% trans "KAAUH Careers" %}
<i class="fas fa-globe me-1"></i> {% trans "KAAUH Careers" %}
</a>
</li>
{% endif %}
{% if request.user.is_authenticated %}
<li class="nav-item">
<a class="nav-link text-white" href="{% url 'user_detail' request.user.pk %}">
<i class="fas fa-user-circle me-1"></i> <span>{% trans "My Profile" %}</span></a></li>
{% endif %}
<li class="nav-item me-2">
<a class="nav-link text-white" href="{% url 'message_list' %}">
<i class="fas fa-envelope"></i> <span>{% trans "Messages" %}</span>
</a>
</li>
{% comment %} <li class="nav-item dropdown">
@ -155,6 +146,7 @@
</li>
</ul>
</li>
{% endcomment %}
{% if request.user.is_authenticated %}
<li class="nav-item">
<a class="nav-link text-white" href="{% url 'user_detail' request.user.pk %}">

View File

@ -502,7 +502,7 @@
<div class="info-label">{% trans "Generated Password" %}</div>
<div class="password-container">
<div class="password-value" id="password-value">{{ generated_password }}</div>
<button type="button" class="btn btn-sm btn-outline-secondary ms-2" onclick="copyPassword()">
<button type="button" class="btn btn-sm btn-outline-secondary ms-2" onclick="copyPassword(this)">
<i class="fas fa-copy me-1"></i>
{% trans "Copy" %}
</button>
@ -711,25 +711,46 @@
</div>
<script>
function copyPassword() {
const passwordText = document.getElementById('password-value').textContent;
navigator.clipboard.writeText(passwordText).then(function() {
// Show success feedback
const button = event.target;
const originalText = button.innerHTML;
button.innerHTML = '<i class="fas fa-check me-1"></i> {% trans "Copied!" %}';
button.classList.remove('btn-outline-secondary');
button.classList.add('btn-success');
// Reset after 2 seconds
function copyPassword(button) {
const passwordTextEl = document.getElementById('password-value');
if (!passwordTextEl) return;
const passwordText = passwordTextEl.textContent;
// Try Clipboard API first
const doFeedback = (btn) => {
const originalHTML = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-check me-1"></i> {% trans "Copied!" %}';
btn.classList.remove('btn-outline-secondary');
btn.classList.add('btn-success');
setTimeout(function() {
button.innerHTML = originalText;
button.classList.remove('btn-success');
button.classList.add('btn-outline-secondary');
btn.innerHTML = originalHTML;
btn.classList.remove('btn-success');
btn.classList.add('btn-outline-secondary');
}, 2000);
}).catch(function(err) {
console.error('Failed to copy password: ', err);
});
};
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(passwordText).then(function() {
doFeedback(button);
}).catch(function(err) {
console.error('Failed to copy password via Clipboard API: ', err);
// fallback
const ta = document.createElement('textarea');
ta.value = passwordText;
document.body.appendChild(ta);
ta.select();
try { document.execCommand('copy'); doFeedback(button); } catch (e) { console.error('execCommand fallback failed', e); }
document.body.removeChild(ta);
});
} else {
// fallback for older browsers
const ta = document.createElement('textarea');
ta.value = passwordText;
document.body.appendChild(ta);
ta.select();
try { document.execCommand('copy'); doFeedback(button); } catch (e) { console.error('execCommand fallback failed', e); }
document.body.removeChild(ta);
}
}
</script>

View File

@ -290,7 +290,7 @@
<div class="text-center p-3 bg-light rounded h-100 shadow-sm">
<i class="fas fa-building text-primary-theme fa-2x mb-2"></i>
<h6 class="text-muted small">{% trans "Department" %}</h6>
<p class="mb-0 fw-bold">{{ application.job.department|default:"-" }}</p>
<p class="mb-0 fw-bold">{{ application.job.department|default:"" }}</p>
</div>
</div>
<div class="col-md-3">
@ -535,45 +535,7 @@
</div>
{% endif %}
<div class="row mb-4">
<div class="col-md-3 mb-3">
<div class="kaauh-card h-100">
<div class="card-body text-center">
<i class="fas fa-arrow-left fa-2x text-primary-theme mb-3"></i>
<h6>{% trans "Back to Dashboard" %}</h6>
<p class="text-muted small">{% trans "View all your applications" %}</p>
{% if application.hiring_agency %}
<a href="{% url 'agency_portal_dashboard' %}" class="btn btn-main-action w-100">
{% trans "Go Back" %}
</a>
{% else %}
<a href="{% url 'candidate_portal_dashboard' %}" class="btn btn-main-action w-100">
{% trans "Go to Dashboard" %}
</a>
{% endif %}
</div>
</div>
</div>
{% if application.resume %}
<div class="col-md-3 mb-3">
<div class="kaauh-card h-100">
<div class="card-body text-center">
<i class="fas fa-download fa-2x text-primary-theme mb-3"></i>
<h6>{% trans "Download Resume" %}</h6>
<p class="text-muted small">{% trans "Get your submitted resume" %}</p>
<a href="{{ application.resume.url }}"
target="_blank"
class="btn btn-main-action w-100">
<i class="fas fa-download me-2"></i>
{% trans "Download" %}
</a>
</div>
</div>
</div>
{% endif %}
</div>
<!-- Next Steps Section -->
<div class="row">