chart fix
This commit is contained in:
parent
f4bddfc391
commit
dace6bc0c3
4
.gitignore
vendored
4
.gitignore
vendored
@ -27,7 +27,7 @@ var/
|
||||
*.log
|
||||
*.pot
|
||||
*.sqlite3
|
||||
local_settings.py
|
||||
settings.py
|
||||
db.sqlite3
|
||||
|
||||
# Virtual environment
|
||||
@ -95,7 +95,7 @@ coverage.xml
|
||||
# Django stuff:
|
||||
|
||||
# Local settings
|
||||
local_settings.py
|
||||
settings.py
|
||||
|
||||
# Database sqlite files:
|
||||
# The base directory for relative paths in .gitignore
|
||||
|
||||
Binary file not shown.
@ -135,9 +135,9 @@ WSGI_APPLICATION = 'NorahUniversity.wsgi.application'
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'norahuniversity',
|
||||
'USER': 'norahuniversity',
|
||||
'PASSWORD': 'norahuniversity',
|
||||
'NAME': 'haikal_db',
|
||||
'USER': 'faheed',
|
||||
'PASSWORD': 'Faheed@215',
|
||||
'HOST': '127.0.0.1',
|
||||
'PORT': '5432',
|
||||
}
|
||||
@ -185,26 +185,14 @@ ACCOUNT_SIGNUP_FIELDS = ['email*', 'password1*', 'password2*']
|
||||
ACCOUNT_UNIQUE_EMAIL = True
|
||||
ACCOUNT_EMAIL_VERIFICATION = 'none'
|
||||
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
|
||||
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
|
||||
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
|
||||
ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True
|
||||
|
||||
|
||||
ACCOUNT_FORMS = {'signup': 'recruitment.forms.StaffSignupForm'}
|
||||
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_HOST = '10.10.1.110' #'smtp.gmail.com'
|
||||
EMAIL_PORT = 2225 #587
|
||||
EMAIL_USE_TLS = False
|
||||
EMAIL_USE_SSL = False
|
||||
EMAIL_TIMEOUT = 10
|
||||
|
||||
DEFAULT_FROM_EMAIL = 'norahuniversity@example.com'
|
||||
|
||||
# Gmail SMTP credentials
|
||||
# Remove the comment below if you want to use Gmail SMTP server
|
||||
# EMAIL_HOST_USER = 'your_email@gmail.com'
|
||||
# EMAIL_HOST_PASSWORD = 'your_password'
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
|
||||
# Crispy Forms Configuration
|
||||
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -30,54 +30,113 @@
|
||||
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
/* Card Header and Icon Styling */
|
||||
/* ------------------------------------------------------------- */
|
||||
/* CONSOLIDATED CARD HEADER STYLES (for both main and stat cards)*/
|
||||
/* ------------------------------------------------------------- */
|
||||
.card-header {
|
||||
font-weight: 600;
|
||||
padding: 1.25rem;
|
||||
/* Consistent, reduced padding for compact look */
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-bottom: 1px solid var(--kaauh-border);
|
||||
background-color: #f8f9fa;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.card-header h3, .card-header h2 {
|
||||
/* Target h2 (for main headers) and h3 (for stat card headers) */
|
||||
.card-header h1, .card-header h2, .card-header h3, .card-header h6 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--kaauh-primary-text);
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
|
||||
/* Font size for MAIN card titles (e.g., "Data Scope: All Jobs") */
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Override for H3 inside stat cards to make them very small */
|
||||
.stats .card-header h3 {
|
||||
font-size: 0.85rem; /* Smallest size for the 9-card layout */
|
||||
font-weight: 600;
|
||||
white-space: nowrap; /* Prevent title from wrapping */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
color: var(--kaauh-teal);
|
||||
font-size: 1.75rem;
|
||||
margin-right: 0.75rem;
|
||||
font-size: 0.8rem; /* Small icon size */
|
||||
margin-right: 0.25rem;
|
||||
/* Note: For 9-card density, you might still want to hide this on mobile */
|
||||
}
|
||||
|
||||
/* Stats Grid Layout */
|
||||
/* ------------------------------------------------------------- */
|
||||
/* STATS GRID LAYOUT (9 Columns) */
|
||||
/* ------------------------------------------------------------- */
|
||||
.stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 3rem;
|
||||
/* Force 9 columns */
|
||||
grid-template-columns: repeat(9, 1fr);
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
/* Stat Card Specific Styling */
|
||||
.stat-value {
|
||||
font-size: 2.8rem;
|
||||
/* This is the most important number */
|
||||
font-size: 1.5rem; /* Increased slightly for focus, was 1rem/1.25rem */
|
||||
text-align: center;
|
||||
color: var(--kaauh-teal-dark);
|
||||
font-weight: 700;
|
||||
padding: 1rem 1rem 0.5rem;
|
||||
font-weight: 700;
|
||||
padding: 0.5rem 0.25rem 0.1rem; /* Very little bottom padding */
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.stat-caption {
|
||||
font-size: 0.9rem;
|
||||
/* Smallest text for the label below the value */
|
||||
font-size: 0.7rem; /* Minimized size */
|
||||
text-align: center;
|
||||
color: #6c757d;
|
||||
padding-bottom: 1rem;
|
||||
padding: 0 0.25rem 0.5rem;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* RESPONSIVE DESIGN */
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
/* On tablets and smaller laptops (1200px and down) */
|
||||
@media (max-width: 1200px) {
|
||||
.stats {
|
||||
/* Switch to 4 columns on medium screens */
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1rem;
|
||||
}
|
||||
.stat-value {
|
||||
font-size: 1.75rem; /* Increase value size slightly when more space is available */
|
||||
}
|
||||
.stat-caption {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* On phones (576px and down) */
|
||||
@media (max-width: 576px) {
|
||||
.stats {
|
||||
/* Stack to 2 columns on mobile for readability */
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.75rem;
|
||||
}
|
||||
.stat-value {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
.stat-caption {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dropdown/Filter Styling */
|
||||
@ -130,7 +189,7 @@
|
||||
<h2>
|
||||
<i class="fas fa-search stat-icon"></i>
|
||||
{% if current_job %}
|
||||
{% trans "Data Scope: " %} **{{ current_job.title }}**
|
||||
{% trans "Data Scope: " %}{{ current_job.title }}
|
||||
{% else %}
|
||||
{% trans "Data Scope: All Jobs" %}
|
||||
{% endif %}
|
||||
@ -153,9 +212,7 @@
|
||||
{# STATS CARDS SECTION (12 KPIs) #}
|
||||
{# -------------------------------------------------------------------------- #}
|
||||
{% include 'recruitment/partials/stats_cards.html' %}
|
||||
|
||||
|
||||
|
||||
{# Note: The content of 'recruitment/partials/stats_cards.html' uses h3 which is styled correctly here #}
|
||||
|
||||
{# -------------------------------------------------------------------------- #}
|
||||
{# CHARTS SECTION #}
|
||||
@ -197,7 +254,7 @@
|
||||
<h2>
|
||||
<i class="fas fa-funnel-dollar stat-icon"></i>
|
||||
{% if current_job %}
|
||||
{% trans "Pipeline Funnel: " %} **{{ current_job.title }}**
|
||||
{% trans "Pipeline Funnel: " %}{{ current_job.title }}
|
||||
{% else %}
|
||||
{% trans "Total Pipeline Funnel (All Jobs)" %}
|
||||
{% endif %}
|
||||
@ -223,28 +280,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card shadow-sm no-hover mb-4">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="fas fa-chart-pie me-2 text-primary"></i>
|
||||
{% trans "Candidates From Each Sources" %}
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
<div style="height: 300px;">
|
||||
<canvas id="candidatesourceschart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/luxon@3.4.4"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.3.1"></script>
|
||||
|
||||
|
||||
<script>
|
||||
// Pass context data safely to JavaScript
|
||||
const totalCandidatesScoped = parseInt('{{ total_candidates|default:0 }}');
|
||||
@ -462,80 +504,7 @@
|
||||
|
||||
|
||||
|
||||
// Chart for Candidate Categories and Match Scores
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const ctx = document.getElementById('candidatesourceschart');
|
||||
if (!ctx) {
|
||||
console.warn('Candidates sources chart element not found.');
|
||||
return;
|
||||
}
|
||||
const chartCtx = ctx.getContext('2d');
|
||||
|
||||
// Safely get job_category_data from Django context
|
||||
// Using window.jobChartData to avoid template parsing issues
|
||||
|
||||
|
||||
if (categories.length > 0) { // Only render if there's data
|
||||
const chart = new Chart(chartCtx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: categories,
|
||||
datasets: [
|
||||
{
|
||||
label: 'Number of Candidates',
|
||||
data: candidates_count_in_each_source,
|
||||
backgroundColor: [
|
||||
'rgba(0, 99, 110, 0.7)', // --kaauh-teal
|
||||
'rgba(23, 162, 184, 0.7)', // Teal shade
|
||||
'rgba(0, 150, 136, 0.7)', // Teal green
|
||||
'rgba(0, 188, 212, 0.7)', // Cyan
|
||||
'rgba(38, 166, 154, 0.7)', // Turquoise
|
||||
'rgba(77, 182, 172, 0.7)', // Medium teal
|
||||
// Add more colors if you expect more categories
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(0, 99, 110, 1)',
|
||||
'rgba(23, 162, 184, 1)',
|
||||
'rgba(0, 150, 136, 1)',
|
||||
'rgba(0, 188, 212, 1)',
|
||||
'rgba(38, 166, 154, 1)',
|
||||
'rgba(77, 182, 172, 1)',
|
||||
// Add more colors if you expect more categories
|
||||
],
|
||||
borderWidth: 1,
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false, // Important for fixed height container
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'right', // Position legend for doughnut chart
|
||||
},
|
||||
title: {
|
||||
display: false, // Chart title is handled by the card header
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
let label = context.label || '';
|
||||
if (label) {
|
||||
label += ': ';
|
||||
}
|
||||
label += context.parsed + ' candidate(s)';
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Display a message if no data is available
|
||||
chartCtx.canvas.parentNode.innerHTML = '<p class="text-center text-muted mt-4">No candidate category data available for this job.</p>';
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
@ -10,7 +10,7 @@
|
||||
<h3><i class="fas fa-list stat-icon"></i> {% trans "Total Jobs" %}</h3>
|
||||
</div>
|
||||
<div class="stat-value">{{ total_jobs_global }}</div>
|
||||
<div class="stat-caption">{% trans "All Active & Drafted Positions (Global)" %}</div>
|
||||
<div class="stat-caption">{% trans "All Active & Drafted Positions" %}</div>
|
||||
</div>
|
||||
|
||||
{# SCOPED - 2. Total Active Jobs #}
|
||||
@ -19,7 +19,7 @@
|
||||
<h3><i class="fas fa-briefcase stat-icon"></i> {% trans "Active Jobs" %}</h3>
|
||||
</div>
|
||||
<div class="stat-value">{{ total_active_jobs }}</div>
|
||||
<div class="stat-caption">{% trans "Currently Open Requisitions (Scoped)" %}</div>
|
||||
<div class="stat-caption">{% trans "Currently Open Requisitions" %}</div>
|
||||
</div>
|
||||
|
||||
{# SCOPED - 3. Total Candidates #}
|
||||
@ -28,7 +28,7 @@
|
||||
<h3><i class="fas fa-users stat-icon"></i> {% trans "Total Candidates" %}</h3>
|
||||
</div>
|
||||
<div class="stat-value">{{ total_candidates }}</div>
|
||||
<div class="stat-caption">{% trans "Total Profiles in Current Scope" %}</div>
|
||||
<div class="stat-caption">{% trans "Total applications" %}</div>
|
||||
</div>
|
||||
|
||||
{# SCOPED - 4. Open Positions #}
|
||||
@ -37,7 +37,7 @@
|
||||
<h3><i class="fas fa-th-list stat-icon"></i> {% trans "Open Positions" %}</h3>
|
||||
</div>
|
||||
<div class="stat-value">{{ total_open_positions }}</div>
|
||||
<div class="stat-caption">{% trans "Total Slots to be Filled (Scoped)" %}</div>
|
||||
<div class="stat-caption">{% trans "Total Slots to be Filled " %}</div>
|
||||
</div>
|
||||
|
||||
{# GLOBAL - 5. Total Participants #}
|
||||
@ -46,11 +46,11 @@
|
||||
<h3><i class="fas fa-address-book stat-icon"></i> {% trans "Total Participants" %}</h3>
|
||||
</div>
|
||||
<div class="stat-value">{{ total_participants }}</div>
|
||||
<div class="stat-caption">{% trans "Total Recruiters/Interviewers (Global)" %}</div>
|
||||
<div class="stat-caption">{% trans "Total Recruiters/Interviewers" %}</div>
|
||||
</div>
|
||||
|
||||
{# GLOBAL - 6. Total LinkedIn Posts #}
|
||||
<div class="card">
|
||||
{% comment %} <div class="card">
|
||||
<div class="card-header">
|
||||
<h3><i class="fab fa-linkedin stat-icon"></i> {% trans "LinkedIn Posts" %}</h3>
|
||||
</div>
|
||||
@ -65,13 +65,13 @@
|
||||
<div class="stat-value">{{ new_candidates_7days }}</div>
|
||||
<div class="stat-caption">{% trans "Incoming applications last week" %}</div>
|
||||
</div>
|
||||
|
||||
{% endcomment %}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3><i class="fas fa-cogs stat-icon"></i> {% trans "Avg. Apps per Job" %}</h3>
|
||||
</div>
|
||||
<div class="stat-value">{{ average_applications|floatformat:1 }}</div>
|
||||
<div class="stat-caption">{% trans "Average Applications per Job (Scoped)" %}</div>
|
||||
<div class="stat-caption">{% trans "Average Applications per Job" %}</div>
|
||||
</div>
|
||||
|
||||
{# --- Efficiency & Quality Metrics --- #}
|
||||
@ -81,7 +81,7 @@
|
||||
<h3><i class="fas fa-clock stat-icon"></i> {% trans "Time-to-Hire" %}</h3>
|
||||
</div>
|
||||
<div class="stat-value">{{ avg_time_to_hire_days }}</div>
|
||||
<div class="stat-caption">{% trans "Avg. Days (Application to Hired)" %}</div>
|
||||
<div class="stat-caption">{% trans "Average Days" %}</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
@ -89,7 +89,7 @@
|
||||
<h3><i class="fas fa-star stat-icon"></i> {% trans "Avg. Match Score" %}</h3>
|
||||
</div>
|
||||
<div class="stat-value">{{ avg_match_score|floatformat:1 }}</div>
|
||||
<div class="stat-caption">{% trans "Average AI Score (Current Scope)" %}</div>
|
||||
<div class="stat-caption">{% trans "Average AI Score " %}</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
@ -100,13 +100,13 @@
|
||||
<div class="stat-caption">{% trans "Score ≥ 75% Profiles" %} ({{ high_potential_ratio|floatformat:1 }}%)</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
{% comment %} <div class="card">
|
||||
<div class="card-header">
|
||||
<h3><i class="fas fa-calendar-alt stat-icon"></i> {% trans "Meetings This Week" %}</h3>
|
||||
</div>
|
||||
<div class="stat-value">{{ meetings_scheduled_this_week }}</div>
|
||||
<div class="stat-caption">{% trans "Scheduled Interviews (Current Week)" %}</div>
|
||||
</div>
|
||||
</div> {% endcomment %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user