hospital-management/templates/hr/training_management.html
2025-08-12 13:33:25 +03:00

1204 lines
61 KiB
HTML

{% extends 'base.html' %}
{% load static %}
{% block title %}Training Management{% endblock %}
{% block content %}
<div id="content" class="app-content">
<div class="container">
<ul class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item"><a href="{% url 'hr:dashboard' %}">HR</a></li>
<li class="breadcrumb-item active">Training Management</li>
</ul>
<div class="row align-items-center mb-3">
<div class="col">
<h1 class="page-header">Training Management</h1>
<p class="text-muted">Employee training programs and certification tracking</p>
</div>
<div class="col-auto">
<div class="btn-group">
<button class="btn btn-primary" onclick="createTraining()">
<i class="fa fa-plus me-2"></i>New Training
</button>
<button class="btn btn-outline-secondary" onclick="createProgram()">
<i class="fa fa-graduation-cap me-2"></i>New Program
</button>
<button class="btn btn-outline-info" onclick="viewCalendar()">
<i class="fa fa-calendar me-2"></i>Calendar
</button>
<button class="btn btn-outline-success" onclick="generateReport()">
<i class="fa fa-chart-bar me-2"></i>Reports
</button>
</div>
</div>
</div>
<!-- Training Overview -->
<div class="row mb-4">
<div class="col-md-3">
<div class="card bg-primary text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h4 class="mb-0">{{ total_programs }}</h4>
<p class="mb-0">Training Programs</p>
</div>
<div class="ms-3">
<i class="fa fa-graduation-cap fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-success text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h4 class="mb-0">{{ completed_trainings }}</h4>
<p class="mb-0">Completed</p>
</div>
<div class="ms-3">
<i class="fa fa-check-circle fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-warning text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h4 class="mb-0">{{ pending_trainings }}</h4>
<p class="mb-0">In Progress</p>
</div>
<div class="ms-3">
<i class="fa fa-clock fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-danger text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h4 class="mb-0">{{ overdue_trainings }}</h4>
<p class="mb-0">Overdue</p>
</div>
<div class="ms-3">
<i class="fa fa-exclamation-triangle fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Training Tabs -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs" id="trainingTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="programs-tab" data-bs-toggle="tab" data-bs-target="#programs" type="button" role="tab">
<i class="fa fa-graduation-cap me-2"></i>Training Programs
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="sessions-tab" data-bs-toggle="tab" data-bs-target="#sessions" type="button" role="tab">
<i class="fa fa-calendar-alt me-2"></i>Training Sessions
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="certifications-tab" data-bs-toggle="tab" data-bs-target="#certifications" type="button" role="tab">
<i class="fa fa-certificate me-2"></i>Certifications
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="compliance-tab" data-bs-toggle="tab" data-bs-target="#compliance" type="button" role="tab">
<i class="fa fa-shield-alt me-2"></i>Compliance
</button>
</li>
</ul>
</div>
<div class="card-body">
<div class="tab-content" id="trainingTabContent">
<!-- Training Programs Tab -->
<div class="tab-pane fade show active" id="programs" role="tabpanel">
<div class="row mb-3">
<div class="col-md-6">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search programs..." id="programSearch">
<button class="btn btn-outline-secondary" type="button">
<i class="fa fa-search"></i>
</button>
</div>
</div>
<div class="col-md-3">
<select class="form-select" id="programCategory">
<option value="">All Categories</option>
<option value="mandatory">Mandatory</option>
<option value="clinical">Clinical</option>
<option value="safety">Safety</option>
<option value="compliance">Compliance</option>
<option value="professional">Professional Development</option>
</select>
</div>
<div class="col-md-3">
<select class="form-select" id="programStatus">
<option value="">All Status</option>
<option value="active">Active</option>
<option value="draft">Draft</option>
<option value="archived">Archived</option>
</select>
</div>
</div>
<div class="row">
{% for program in training_programs %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="card h-100 training-program-card">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="card-title mb-0">{{ program.title }}</h6>
<span class="badge bg-{{ program.status_color }}">{{ program.get_status_display }}</span>
</div>
<div class="card-body">
<p class="card-text text-muted">{{ program.description|truncatewords:20 }}</p>
<div class="mb-2">
<small class="text-muted">
<i class="fa fa-tag me-1"></i>{{ program.get_category_display }}
</small>
</div>
<div class="mb-2">
<small class="text-muted">
<i class="fa fa-clock me-1"></i>{{ program.duration_hours }}h duration
</small>
</div>
<div class="mb-2">
<small class="text-muted">
<i class="fa fa-users me-1"></i>{{ program.enrolled_count }} enrolled
</small>
</div>
{% if program.is_mandatory %}
<div class="mb-2">
<span class="badge bg-danger">Mandatory</span>
</div>
{% endif %}
<div class="progress mb-2" style="height: 6px;">
<div class="progress-bar bg-success"
role="progressbar"
style="width: {{ program.completion_rate }}%"
title="{{ program.completion_rate }}% completion rate">
</div>
</div>
<small class="text-muted">{{ program.completion_rate }}% completion rate</small>
</div>
<div class="card-footer">
<div class="btn-group w-100">
<button class="btn btn-outline-primary btn-sm" onclick="viewProgram('{{ program.id }}')">
<i class="fa fa-eye"></i> View
</button>
<button class="btn btn-outline-secondary btn-sm" onclick="editProgram('{{ program.id }}')">
<i class="fa fa-edit"></i> Edit
</button>
<button class="btn btn-outline-success btn-sm" onclick="scheduleSession('{{ program.id }}')">
<i class="fa fa-calendar-plus"></i> Schedule
</button>
</div>
</div>
</div>
</div>
{% empty %}
<div class="col-12">
<div class="text-center py-4">
<i class="fa fa-graduation-cap fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No training programs found</h5>
<p class="text-muted">Create your first training program to get started.</p>
<button class="btn btn-primary" onclick="createProgram()">
<i class="fa fa-plus me-2"></i>Create Program
</button>
</div>
</div>
{% endfor %}
</div>
</div>
<!-- Training Sessions Tab -->
<div class="tab-pane fade" id="sessions" role="tabpanel">
<div class="row mb-3">
<div class="col-md-4">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search sessions..." id="sessionSearch">
<button class="btn btn-outline-secondary" type="button">
<i class="fa fa-search"></i>
</button>
</div>
</div>
<div class="col-md-2">
<select class="form-select" id="sessionStatus">
<option value="">All Status</option>
<option value="scheduled">Scheduled</option>
<option value="in_progress">In Progress</option>
<option value="completed">Completed</option>
<option value="cancelled">Cancelled</option>
</select>
</div>
<div class="col-md-2">
<input type="date" class="form-control" id="sessionDate" placeholder="Date">
</div>
<div class="col-md-2">
<select class="form-select" id="sessionInstructor">
<option value="">All Instructors</option>
{% for instructor in instructors %}
<option value="{{ instructor.id }}">{{ instructor.get_full_name }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-2">
<button class="btn btn-primary w-100" onclick="scheduleNewSession()">
<i class="fa fa-plus me-1"></i>Schedule
</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Session</th>
<th>Program</th>
<th>Date & Time</th>
<th>Instructor</th>
<th>Attendees</th>
<th>Location</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for session in training_sessions %}
<tr>
<td>
<div>
<h6 class="mb-0">{{ session.title }}</h6>
<small class="text-muted">{{ session.session_code }}</small>
</div>
</td>
<td>
<span class="badge bg-secondary">{{ session.program.title }}</span>
</td>
<td>
<div>
<strong>{{ session.start_datetime|date:"M d, Y" }}</strong>
<br><small class="text-muted">{{ session.start_datetime|time:"H:i" }} - {{ session.end_datetime|time:"H:i" }}</small>
</div>
</td>
<td>
{% if session.instructor %}
<div class="d-flex align-items-center">
<div class="avatar avatar-sm me-2">
<div class="avatar-initial rounded-circle bg-primary">
{{ session.instructor.first_name|first }}{{ session.instructor.last_name|first }}
</div>
</div>
<div>
<small>{{ session.instructor.get_full_name }}</small>
</div>
</div>
{% else %}
<span class="text-muted">Not assigned</span>
{% endif %}
</td>
<td>
<div class="d-flex align-items-center">
<span class="me-2">{{ session.attendee_count }}/{{ session.max_attendees }}</span>
<div class="progress flex-grow-1" style="height: 6px;">
<div class="progress-bar bg-info"
role="progressbar"
style="width: {{ session.attendance_percentage }}%">
</div>
</div>
</div>
</td>
<td>
<small>{{ session.location|default:"TBD" }}</small>
</td>
<td>
<span class="badge bg-{{ session.status_color }}">
{{ session.get_status_display }}
</span>
</td>
<td>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-primary" onclick="viewSession('{{ session.id }}')" title="View Details">
<i class="fa fa-eye"></i>
</button>
<button class="btn btn-outline-secondary" onclick="editSession('{{ session.id }}')" title="Edit">
<i class="fa fa-edit"></i>
</button>
<button class="btn btn-outline-info" onclick="manageAttendees('{{ session.id }}')" title="Manage Attendees">
<i class="fa fa-users"></i>
</button>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-success dropdown-toggle" data-bs-toggle="dropdown" title="More Actions">
<i class="fa fa-ellipsis-v"></i>
</button>
<ul class="dropdown-menu">
{% if session.status == 'scheduled' %}
<li><a class="dropdown-item" href="#" onclick="startSession('{{ session.id }}')">
<i class="fa fa-play me-2"></i>Start Session
</a></li>
{% elif session.status == 'in_progress' %}
<li><a class="dropdown-item" href="#" onclick="completeSession('{{ session.id }}')">
<i class="fa fa-check me-2"></i>Complete Session
</a></li>
{% endif %}
<li><a class="dropdown-item" href="#" onclick="duplicateSession('{{ session.id }}')">
<i class="fa fa-copy me-2"></i>Duplicate
</a></li>
<li><a class="dropdown-item" href="#" onclick="sendReminders('{{ session.id }}')">
<i class="fa fa-bell me-2"></i>Send Reminders
</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item text-danger" href="#" onclick="cancelSession('{{ session.id }}')">
<i class="fa fa-times me-2"></i>Cancel Session
</a></li>
</ul>
</div>
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="8" class="text-center py-4">
<i class="fa fa-calendar-alt fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No training sessions scheduled</h5>
<p class="text-muted">Schedule your first training session.</p>
<button class="btn btn-primary" onclick="scheduleNewSession()">
<i class="fa fa-plus me-2"></i>Schedule Session
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Certifications Tab -->
<div class="tab-pane fade" id="certifications" role="tabpanel">
<div class="row mb-3">
<div class="col-md-4">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search certifications..." id="certSearch">
<button class="btn btn-outline-secondary" type="button">
<i class="fa fa-search"></i>
</button>
</div>
</div>
<div class="col-md-2">
<select class="form-select" id="certStatus">
<option value="">All Status</option>
<option value="active">Active</option>
<option value="expired">Expired</option>
<option value="expiring_soon">Expiring Soon</option>
</select>
</div>
<div class="col-md-2">
<select class="form-select" id="certType">
<option value="">All Types</option>
<option value="clinical">Clinical</option>
<option value="safety">Safety</option>
<option value="compliance">Compliance</option>
<option value="professional">Professional</option>
</select>
</div>
<div class="col-md-2">
<select class="form-select" id="certDepartment">
<option value="">All Departments</option>
{% for dept in departments %}
<option value="{{ dept.id }}">{{ dept.name }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-2">
<button class="btn btn-primary w-100" onclick="addCertification()">
<i class="fa fa-plus me-1"></i>Add Cert
</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Employee</th>
<th>Certification</th>
<th>Type</th>
<th>Issued Date</th>
<th>Expiry Date</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for cert in certifications %}
<tr>
<td>
<div class="d-flex align-items-center">
<div class="avatar avatar-sm me-2">
{% if cert.employee.photo %}
<img src="{{ cert.employee.photo.url }}" alt="{{ cert.employee.get_full_name }}" class="rounded-circle">
{% else %}
<div class="avatar-initial rounded-circle bg-primary">
{{ cert.employee.first_name|first }}{{ cert.employee.last_name|first }}
</div>
{% endif %}
</div>
<div>
<h6 class="mb-0">{{ cert.employee.get_full_name }}</h6>
<small class="text-muted">{{ cert.employee.job_title }}</small>
</div>
</div>
</td>
<td>
<div>
<strong>{{ cert.certification_name }}</strong>
<br><small class="text-muted">{{ cert.issuing_organization }}</small>
</div>
</td>
<td>
<span class="badge bg-secondary">{{ cert.get_certification_type_display }}</span>
</td>
<td>{{ cert.issue_date|date:"M d, Y" }}</td>
<td>
{% if cert.expiry_date %}
<span class="{% if cert.is_expired %}text-danger{% elif cert.is_expiring_soon %}text-warning{% endif %}">
{{ cert.expiry_date|date:"M d, Y" }}
</span>
{% else %}
<span class="text-muted">No expiry</span>
{% endif %}
</td>
<td>
<span class="badge bg-{{ cert.status_color }}">
{{ cert.get_status_display }}
</span>
</td>
<td>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-primary" onclick="viewCertification('{{ cert.id }}')" title="View Details">
<i class="fa fa-eye"></i>
</button>
<button class="btn btn-outline-secondary" onclick="editCertification('{{ cert.id }}')" title="Edit">
<i class="fa fa-edit"></i>
</button>
{% if cert.is_expiring_soon %}
<button class="btn btn-outline-warning" onclick="renewCertification('{{ cert.id }}')" title="Renew">
<i class="fa fa-refresh"></i>
</button>
{% endif %}
<button class="btn btn-outline-info" onclick="downloadCertificate('{{ cert.id }}')" title="Download">
<i class="fa fa-download"></i>
</button>
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="7" class="text-center py-4">
<i class="fa fa-certificate fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No certifications found</h5>
<p class="text-muted">Add employee certifications to track compliance.</p>
<button class="btn btn-primary" onclick="addCertification()">
<i class="fa fa-plus me-2"></i>Add Certification
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Compliance Tab -->
<div class="tab-pane fade" id="compliance" role="tabpanel">
<div class="row mb-4">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">Compliance Overview</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-6">
<div class="text-center">
<div class="h2 text-success">{{ compliance_rate }}%</div>
<div class="text-muted">Overall Compliance</div>
</div>
</div>
<div class="col-6">
<div class="text-center">
<div class="h2 text-warning">{{ expiring_soon_count }}</div>
<div class="text-muted">Expiring Soon</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">Department Compliance</h5>
</div>
<div class="card-body">
{% for dept in department_compliance %}
<div class="d-flex justify-content-between align-items-center mb-2">
<span>{{ dept.name }}</span>
<div class="d-flex align-items-center">
<div class="progress me-2" style="width: 100px; height: 8px;">
<div class="progress-bar bg-{{ dept.compliance_color }}"
role="progressbar"
style="width: {{ dept.compliance_rate }}%">
</div>
</div>
<span class="text-muted">{{ dept.compliance_rate }}%</span>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">Compliance Alerts</h5>
</div>
<div class="card-body">
{% if compliance_alerts %}
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th>Employee</th>
<th>Requirement</th>
<th>Due Date</th>
<th>Priority</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for alert in compliance_alerts %}
<tr>
<td>{{ alert.employee.get_full_name }}</td>
<td>{{ alert.requirement }}</td>
<td>
<span class="text-{{ alert.urgency_color }}">
{{ alert.due_date|date:"M d, Y" }}
</span>
</td>
<td>
<span class="badge bg-{{ alert.priority_color }}">
{{ alert.get_priority_display }}
</span>
</td>
<td>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-primary" onclick="resolveAlert('{{ alert.id }}')">
<i class="fa fa-check"></i> Resolve
</button>
<button class="btn btn-outline-warning" onclick="snoozeAlert('{{ alert.id }}')">
<i class="fa fa-clock"></i> Snooze
</button>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-4">
<i class="fa fa-shield-alt fa-3x text-success mb-3"></i>
<h5 class="text-success">All Clear!</h5>
<p class="text-muted">No compliance alerts at this time.</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Training Program Modal -->
<div class="modal fade" id="programModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="programModalTitle">Create Training Program</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form id="programForm">
{% csrf_token %}
<input type="hidden" name="program_id" id="programId">
<div class="modal-body">
<div class="row">
<div class="col-md-8">
<div class="mb-3">
<label class="form-label">Program Title <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="title" id="programTitle" required>
</div>
</div>
<div class="col-md-4">
<div class="mb-3">
<label class="form-label">Category <span class="text-danger">*</span></label>
<select class="form-select" name="category" id="programCategorySelect" required>
<option value="">Select category...</option>
<option value="mandatory">Mandatory</option>
<option value="clinical">Clinical</option>
<option value="safety">Safety</option>
<option value="compliance">Compliance</option>
<option value="professional">Professional Development</option>
</select>
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label">Description</label>
<textarea class="form-control" name="description" id="programDescription" rows="3"></textarea>
</div>
<div class="row">
<div class="col-md-4">
<div class="mb-3">
<label class="form-label">Duration (hours)</label>
<input type="number" class="form-control" name="duration_hours" id="programDuration" min="0.5" step="0.5">
</div>
</div>
<div class="col-md-4">
<div class="mb-3">
<label class="form-label">Max Attendees</label>
<input type="number" class="form-control" name="max_attendees" id="programMaxAttendees" min="1">
</div>
</div>
<div class="col-md-4">
<div class="mb-3">
<label class="form-label">Validity Period (months)</label>
<input type="number" class="form-control" name="validity_months" id="programValidity" min="1">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="is_mandatory" id="programMandatory">
<label class="form-check-label" for="programMandatory">
Mandatory training
</label>
</div>
</div>
<div class="col-md-6">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="requires_certification" id="programCertification">
<label class="form-check-label" for="programCertification">
Requires certification
</label>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">
<i class="fa fa-save me-2"></i>Save Program
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script>
$(document).ready(function() {
setupEventHandlers();
setupFilters();
});
function setupEventHandlers() {
// Program form
$('#programForm').on('submit', function(e) {
e.preventDefault();
saveProgram();
});
// Search and filter handlers
$('#programSearch, #sessionSearch, #certSearch').on('input', function() {
filterResults();
});
$('#programCategory, #programStatus, #sessionStatus, #certStatus, #certType').on('change', function() {
filterResults();
});
}
function setupFilters() {
// Initialize filter functionality
$('.training-program-card').each(function() {
$(this).data('original-display', $(this).css('display'));
});
}
function createTraining() {
// Determine which tab is active and create appropriate item
var activeTab = $('.nav-tabs .nav-link.active').attr('id');
switch(activeTab) {
case 'programs-tab':
createProgram();
break;
case 'sessions-tab':
scheduleNewSession();
break;
case 'certifications-tab':
addCertification();
break;
default:
createProgram();
}
}
function createProgram() {
$('#programModalTitle').text('Create Training Program');
$('#programId').val('');
$('#programForm')[0].reset();
$('#programModal').modal('show');
}
function editProgram(programId) {
$('#programModalTitle').text('Edit Training Program');
$('#programId').val(programId);
// Load program data
$.get('{% url "hr:get_program_details" %}', {program_id: programId}, function(data) {
if (data.success) {
populateProgramForm(data.program);
$('#programModal').modal('show');
} else {
toastr.error('Failed to load program details');
}
});
}
function populateProgramForm(program) {
$('#programTitle').val(program.title);
$('#programCategorySelect').val(program.category);
$('#programDescription').val(program.description);
$('#programDuration').val(program.duration_hours);
$('#programMaxAttendees').val(program.max_attendees);
$('#programValidity').val(program.validity_months);
$('#programMandatory').prop('checked', program.is_mandatory);
$('#programCertification').prop('checked', program.requires_certification);
}
function saveProgram() {
var formData = $('#programForm').serialize();
var url = $('#programId').val() ? '{% url "hr:update_program" %}' : '{% url "hr:create_program" %}';
$.post(url, formData, function(data) {
if (data.success) {
toastr.success('Training program saved successfully');
$('#programModal').modal('hide');
location.reload();
} else {
toastr.error('Failed to save program: ' + data.error);
}
});
}
function viewProgram(programId) {
window.location.href = '{% url "hr:program_detail" 0 %}'.replace('0', programId);
}
function scheduleSession(programId) {
window.location.href = '{% url "hr:schedule_session" 0 %}'.replace('0', programId);
}
function scheduleNewSession() {
window.location.href = '{% url "hr:schedule_session" %}';
}
function viewSession(sessionId) {
window.location.href = '{% url "hr:session_detail" 0 %}'.replace('0', sessionId);
}
function editSession(sessionId) {
window.location.href = '{% url "hr:session_edit" 0 %}'.replace('0', sessionId);
}
function manageAttendees(sessionId) {
window.location.href = '{% url "hr:session_attendees" 0 %}'.replace('0', sessionId);
}
function startSession(sessionId) {
$.post('{% url "hr:start_session" %}', {
session_id: sessionId,
csrfmiddlewaretoken: '{{ csrf_token }}'
}, function(data) {
if (data.success) {
toastr.success('Session started');
location.reload();
} else {
toastr.error('Failed to start session: ' + data.error);
}
});
}
function completeSession(sessionId) {
$.post('{% url "hr:complete_session" %}', {
session_id: sessionId,
csrfmiddlewaretoken: '{{ csrf_token }}'
}, function(data) {
if (data.success) {
toastr.success('Session completed');
location.reload();
} else {
toastr.error('Failed to complete session: ' + data.error);
}
});
}
function duplicateSession(sessionId) {
$.post('{% url "hr:duplicate_session" %}', {
session_id: sessionId,
csrfmiddlewaretoken: '{{ csrf_token }}'
}, function(data) {
if (data.success) {
toastr.success('Session duplicated');
location.reload();
} else {
toastr.error('Failed to duplicate session: ' + data.error);
}
});
}
function sendReminders(sessionId) {
$.post('{% url "hr:send_session_reminders" %}', {
session_id: sessionId,
csrfmiddlewaretoken: '{{ csrf_token }}'
}, function(data) {
if (data.success) {
toastr.success('Reminders sent');
} else {
toastr.error('Failed to send reminders: ' + data.error);
}
});
}
function cancelSession(sessionId) {
if (confirm('Are you sure you want to cancel this session?')) {
$.post('{% url "hr:cancel_session" %}', {
session_id: sessionId,
csrfmiddlewaretoken: '{{ csrf_token }}'
}, function(data) {
if (data.success) {
toastr.success('Session cancelled');
location.reload();
} else {
toastr.error('Failed to cancel session: ' + data.error);
}
});
}
}
function addCertification() {
window.location.href = '{% url "hr:add_certification" %}';
}
function viewCertification(certId) {
window.location.href = '{% url "hr:certification_detail" 0 %}'.replace('0', certId);
}
function editCertification(certId) {
window.location.href = '{% url "hr:certification_edit" 0 %}'.replace('0', certId);
}
function renewCertification(certId) {
$.post('{% url "hr:renew_certification" %}', {
certification_id: certId,
csrfmiddlewaretoken: '{{ csrf_token }}'
}, function(data) {
if (data.success) {
toastr.success('Certification renewal initiated');
location.reload();
} else {
toastr.error('Failed to renew certification: ' + data.error);
}
});
}
function downloadCertificate(certId) {
window.open('{% url "hr:download_certificate" 0 %}'.replace('0', certId), '_blank');
}
function resolveAlert(alertId) {
$.post('{% url "hr:resolve_compliance_alert" %}', {
alert_id: alertId,
csrfmiddlewaretoken: '{{ csrf_token }}'
}, function(data) {
if (data.success) {
toastr.success('Alert resolved');
location.reload();
} else {
toastr.error('Failed to resolve alert: ' + data.error);
}
});
}
function snoozeAlert(alertId) {
var days = prompt('Snooze for how many days?', '7');
if (days && !isNaN(days)) {
$.post('{% url "hr:snooze_compliance_alert" %}', {
alert_id: alertId,
days: days,
csrfmiddlewaretoken: '{{ csrf_token }}'
}, function(data) {
if (data.success) {
toastr.success('Alert snoozed for ' + days + ' days');
location.reload();
} else {
toastr.error('Failed to snooze alert: ' + data.error);
}
});
}
}
function filterResults() {
var activeTab = $('.nav-tabs .nav-link.active').attr('id');
switch(activeTab) {
case 'programs-tab':
filterPrograms();
break;
case 'sessions-tab':
filterSessions();
break;
case 'certifications-tab':
filterCertifications();
break;
}
}
function filterPrograms() {
var searchTerm = $('#programSearch').val().toLowerCase();
var category = $('#programCategory').val();
var status = $('#programStatus').val();
$('.training-program-card').each(function() {
var card = $(this);
var title = card.find('.card-title').text().toLowerCase();
var description = card.find('.card-text').text().toLowerCase();
var cardCategory = card.data('category');
var cardStatus = card.data('status');
var matchesSearch = !searchTerm || title.includes(searchTerm) || description.includes(searchTerm);
var matchesCategory = !category || cardCategory === category;
var matchesStatus = !status || cardStatus === status;
if (matchesSearch && matchesCategory && matchesStatus) {
card.show();
} else {
card.hide();
}
});
}
function filterSessions() {
// Implement session filtering
var searchTerm = $('#sessionSearch').val().toLowerCase();
var status = $('#sessionStatus').val();
var date = $('#sessionDate').val();
var instructor = $('#sessionInstructor').val();
// Filter table rows based on criteria
$('tbody tr').each(function() {
var row = $(this);
var text = row.text().toLowerCase();
var rowStatus = row.find('.badge').text().toLowerCase();
var matchesSearch = !searchTerm || text.includes(searchTerm);
var matchesStatus = !status || rowStatus.includes(status.toLowerCase());
if (matchesSearch && matchesStatus) {
row.show();
} else {
row.hide();
}
});
}
function filterCertifications() {
// Implement certification filtering
var searchTerm = $('#certSearch').val().toLowerCase();
var status = $('#certStatus').val();
var type = $('#certType').val();
var department = $('#certDepartment').val();
// Filter table rows based on criteria
$('tbody tr').each(function() {
var row = $(this);
var text = row.text().toLowerCase();
var matchesSearch = !searchTerm || text.includes(searchTerm);
if (matchesSearch) {
row.show();
} else {
row.hide();
}
});
}
function viewCalendar() {
window.location.href = '{% url "hr:training_calendar" %}';
}
function generateReport() {
window.location.href = '{% url "hr:training_reports" %}';
}
</script>
<style>
.training-program-card {
transition: transform 0.2s, box-shadow 0.2s;
}
.training-program-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.avatar {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
}
.avatar-sm {
width: 24px;
height: 24px;
font-size: 0.75rem;
}
.avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.avatar-initial {
background-color: #6c757d;
color: white;
font-weight: 600;
font-size: 0.875rem;
}
.progress {
background-color: #e9ecef;
}
.progress-bar {
transition: width 0.3s ease;
}
.nav-tabs .nav-link {
border: none;
color: #6c757d;
}
.nav-tabs .nav-link.active {
background-color: transparent;
border-bottom: 2px solid #0d6efd;
color: #0d6efd;
}
.badge {
font-size: 0.75em;
font-weight: 500;
}
.table th {
border-top: none;
font-weight: 600;
color: #495057;
background-color: #f8f9fa;
}
.table-hover tbody tr:hover {
background-color: rgba(0, 0, 0, 0.025);
}
.btn-group-sm .btn {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
}
.dropdown-menu {
border: 1px solid #dee2e6;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
}
.dropdown-item:hover {
background-color: #f8f9fa;
}
.card-header-tabs {
margin-bottom: -1px;
}
.card-header-tabs .nav-link {
border: none;
border-bottom: 2px solid transparent;
}
.card-header-tabs .nav-link.active {
border-bottom-color: #0d6efd;
background-color: transparent;
}
@media (max-width: 768px) {
.btn-group {
flex-direction: column;
}
.btn-group .btn {
margin-bottom: 0.25rem;
}
.table-responsive {
font-size: 0.875rem;
}
.training-program-card {
margin-bottom: 1rem;
}
}
</style>
{% endblock %}