HH/templates/organizations/staff_list.html
2026-01-12 12:19:19 +03:00

381 lines
17 KiB
HTML

{% extends "layouts/base.html" %}
{% load i18n %}
{% block title %}{% trans "Staff Management" %} - PX360{% endblock %}
{% block content %}
<div class="page-header">
<div class="d-flex justify-content-between align-items-center">
<div>
<h1 class="page-title">{% trans "Staff Management" %}</h1>
<p class="text-muted">{% trans "Manage hospital staff and their user accounts" %}</p>
</div>
{% if user.is_px_admin or user.is_hospital_admin %}
<a href="{% url 'organizations:staff_create' %}" class="btn btn-primary">
<i class="fas fa-plus"></i> {% trans "Add New Staff" %}
</a>
{% endif %}
</div>
</div>
<!-- Filters -->
<div class="card mb-4">
<div class="card-body">
<form method="get" class="row g-3">
<div class="col-md-3">
<label class="form-label">{% trans "Hospital" %}</label>
<select name="hospital" class="form-select">
<option value="">{% trans "All Hospitals" %}</option>
{% for hospital in hospitals %}
<option value="{{ hospital.id }}" {% if request.GET.hospital == hospital.id|stringformat:"s" %}selected{% endif %}>
{{ hospital.name }}
</option>
{% endfor %}
</select>
</div>
<div class="col-md-2">
<label class="form-label">{% trans "Status" %}</label>
<select name="status" class="form-select">
<option value="">{% trans "All Status" %}</option>
<option value="active" {% if request.GET.status == 'active' %}selected{% endif %}>{% trans "Active" %}</option>
<option value="inactive" {% if request.GET.status == 'inactive' %}selected{% endif %}>{% trans "Inactive" %}</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label">{% trans "Staff Type" %}</label>
<select name="staff_type" class="form-select">
<option value="">{% trans "All Types" %}</option>
<option value="physician" {% if request.GET.staff_type == 'physician' %}selected{% endif %}>{% trans "Physician" %}</option>
<option value="nurse" {% if request.GET.staff_type == 'nurse' %}selected{% endif %}>{% trans "Nurse" %}</option>
<option value="admin" {% if request.GET.staff_type == 'admin' %}selected{% endif %}>{% trans "Administrative" %}</option>
<option value="other" {% if request.GET.staff_type == 'other' %}selected{% endif %}>{% trans "Other" %}</option>
</select>
</div>
<div class="col-md-3">
<label class="form-label">{% trans "Search" %}</label>
<input type="text" name="search" class="form-control" placeholder="{% trans 'Name, ID, or License...' %}" value="{{ request.GET.search|default:'' }}">
</div>
<div class="col-md-2 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-search"></i> {% trans "Search" %}
</button>
</div>
</form>
</div>
</div>
<!-- Staff List -->
<div class="card">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>{% trans "Name" %}</th>
<th>{% trans "Type" %}</th>
<th>{% trans "Job Title" %}</th>
<th>{% trans "Employee ID" %}</th>
<th>{% trans "Hospital" %}</th>
<th>{% trans "Department" %}</th>
<th>{% trans "User Account" %}</th>
<th>{% trans "Status" %}</th>
<th>{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for staff_member in staff %}
<tr>
<td>
<strong>{{ staff_member.get_full_name }}</strong>
{% if staff_member.license_number %}
<br><small class="text-muted">{{ staff_member.license_number }}</small>
{% endif %}
</td>
<td>
<span class="badge bg-info">{{ staff_member.get_staff_type_display }}</span>
</td>
<td>{{ staff_member.job_title }}</td>
<td>{{ staff_member.employee_id }}</td>
<td>{{ staff_member.hospital.name }}</td>
<td>{{ staff_member.department.name|default:"-" }}</td>
<td>
{% if staff_member.user %}
<span class="badge bg-success">
<i class="fas fa-check"></i> {% trans "Yes" %}
</span>
<br><small class="text-muted">{{ staff_member.user.username }}</small>
{% else %}
<span class="badge bg-danger">
<i class="fas fa-times"></i> {% trans "No" %}
</span>
{% endif %}
</td>
<td>
{% if staff_member.status == 'active' %}
<span class="badge bg-success">{% trans "Active" %}</span>
{% else %}
<span class="badge bg-secondary">{% trans "Inactive" %}</span>
{% endif %}
</td>
<td>
<div class="btn-group">
<a href="{% url 'organizations:staff_detail' staff_member.id %}" class="btn btn-sm btn-outline-primary" title="{% trans 'View Details' %}">
<i class="fas fa-eye"></i>
</a>
{% if user.is_px_admin or user.is_hospital_admin %}
{% if not staff_member.user and staff_member.email %}
<button type="button" class="btn btn-sm btn-outline-success" onclick="createUserAccount('{{ staff_member.id }}', '{{ staff_member.get_full_name }}')" title="{% trans 'Create User Account' %}">
<i class="fas fa-user-plus"></i>
</button>
{% endif %}
{% if staff_member.user %}
<button type="button" class="btn btn-sm btn-outline-warning" onclick="sendInvitation('{{ staff_member.id }}', '{{ staff_member.get_full_name }}')" title="{% trans 'Send Invitation Email' %}">
<i class="fas fa-envelope"></i>
</button>
<button type="button" class="btn btn-sm btn-outline-danger" onclick="unlinkUserAccount('{{ staff_member.id }}', '{{ staff_member.get_full_name }}')" title="{% trans 'Unlink User Account' %}">
<i class="fas fa-user-minus"></i>
</button>
{% endif %}
{% endif %}
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="9" class="text-center py-5">
<i class="fas fa-users fa-3x text-muted mb-3"></i>
<p class="text-muted">{% trans "No staff members found" %}</p>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Pagination -->
{% if page_obj.has_other_pages %}
<nav aria-label="Page navigation" class="mt-4">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1{% for key, value in filters.items %}{% if value %}&{{ key }}={{ value }}{% endif %}{% endfor %}">
<i class="fas fa-angle-double-left"></i>
</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% for key, value in filters.items %}{% if value %}&{{ key }}={{ value }}{% endif %}{% endfor %}">
<i class="fas fa-angle-left"></i>
</a>
</li>
{% endif %}
<li class="page-item active">
<span class="page-link">{{ page_obj.number }}</span>
</li>
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% for key, value in filters.items %}{% if value %}&{{ key }}={{ value }}{% endif %}{% endfor %}">
<i class="fas fa-angle-right"></i>
</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% for key, value in filters.items %}{% if value %}&{{ key }}={{ value }}{% endif %}{% endfor %}">
<i class="fas fa-angle-double-right"></i>
</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
<!-- Create User Modal -->
<div class="modal" id="createUserModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{% trans "Create User Account" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>{% trans "Are you sure you want to create a user account for" %} <strong id="createUserName"></strong>?</p>
<p class="text-muted small">{% trans "A username will be generated automatically and credentials will be emailed to" %} <span id="createUserEmail"></span>.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
<button type="button" class="btn btn-primary" onclick="confirmCreateUser()">{% trans "Create Account" %}</button>
</div>
</div>
</div>
</div>
<!-- Send Invitation Modal -->
<div class="modal" id="sendInvitationModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{% trans "Send Invitation Email" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>{% trans "Are you sure you want to send a new invitation email to" %} <strong id="sendInvitationName"></strong>?</p>
<p class="text-muted small">{% trans "A new password will be generated and sent to" %} <span id="sendInvitationEmail"></span>.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
<button type="button" class="btn btn-primary" onclick="confirmSendInvitation()">{% trans "Send Email" %}</button>
</div>
</div>
</div>
</div>
<!-- Unlink User Modal -->
<div class="modal" id="unlinkUserModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{% trans "Unlink User Account" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>{% trans "Are you sure you want to unlink the user account from" %} <strong id="unlinkUserName"></strong>?</p>
<p class="text-warning small">{% trans "This will remove the login access for this staff member. The user account will still exist but will no longer be linked to this staff profile." %}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
<button type="button" class="btn btn-danger" onclick="confirmUnlinkUser()">{% trans "Unlink Account" %}</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
let currentStaffId = null;
let currentStaffName = null;
let currentStaffEmail = null;
function createUserAccount(staffId, staffName) {
currentStaffId = staffId;
currentStaffName = staffName;
// Get email from table
const row = event.target.closest('tr');
const emailSpan = row.querySelector('td:nth-child(7) small');
currentStaffEmail = emailSpan ? emailSpan.textContent : '';
document.getElementById('createUserName').textContent = staffName;
document.getElementById('createUserEmail').textContent = currentStaffEmail;
new bootstrap.Modal(document.getElementById('createUserModal')).show();
}
function confirmCreateUser() {
const btn = event.target;
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Creating...';
fetch(`/api/organizations/staff/${currentStaffId}/create_user_account/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify({})
})
.then(response => response.json())
.then(data => {
bootstrap.Modal.getInstance(document.getElementById('createUserModal')).hide();
if (data.message) {
alert(data.message);
}
location.reload();
})
.catch(error => {
alert('Error: ' + error.message);
btn.disabled = false;
btn.innerHTML = 'Create Account';
});
}
function sendInvitation(staffId, staffName) {
currentStaffId = staffId;
currentStaffName = staffName;
document.getElementById('sendInvitationName').textContent = staffName;
new bootstrap.Modal(document.getElementById('sendInvitationModal')).show();
}
function confirmSendInvitation() {
const btn = event.target;
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sending...';
fetch(`/api/organizations/staff/${currentStaffId}/send_invitation/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify({})
})
.then(response => response.json())
.then(data => {
bootstrap.Modal.getInstance(document.getElementById('sendInvitationModal')).hide();
if (data.message) {
alert(data.message);
}
location.reload();
})
.catch(error => {
alert('Error: ' + error.message);
btn.disabled = false;
btn.innerHTML = 'Send Email';
});
}
function unlinkUserAccount(staffId, staffName) {
currentStaffId = staffId;
currentStaffName = staffName;
document.getElementById('unlinkUserName').textContent = staffName;
new bootstrap.Modal(document.getElementById('unlinkUserModal')).show();
}
function confirmUnlinkUser() {
const btn = event.target;
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Unlinking...';
fetch(`/api/organizations/staff/${currentStaffId}/unlink_user/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify({})
})
.then(response => response.json())
.then(data => {
bootstrap.Modal.getInstance(document.getElementById('unlinkUserModal')).hide();
if (data.message) {
alert(data.message);
}
location.reload();
})
.catch(error => {
alert('Error: ' + error.message);
btn.disabled = false;
btn.innerHTML = 'Unlink Account';
});
}
</script>
{% endblock %}