38960-vm/includes/pages/queue_management.php
2026-03-22 15:27:17 +00:00

261 lines
11 KiB
PHP

<?php
// includes/pages/queue_management.php
// Fetch Departments
$departments = $db->query("SELECT * FROM departments")->fetchAll(PDO::FETCH_ASSOC);
// Fetch Doctors
$doctors = $db->query("
SELECT e.*
FROM employees e
JOIN positions p ON e.position_id = p.id
WHERE UPPER(p.name_en) = 'DOCTOR'
")->fetchAll(PDO::FETCH_ASSOC);
// Fetch Patients (Limit 50 for initial load, preferably use AJAX for real search)
$patients = $db->query("SELECT * FROM patients ORDER BY id DESC LIMIT 50")->fetchAll(PDO::FETCH_ASSOC);
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h3 class="fw-bold text-secondary"><?php echo __('queue_management'); ?></h3>
<div class="d-flex gap-2">
<a href="queue_display.php" target="_blank" class="btn btn-outline-primary">
<i class="bi bi-tv"></i> Open_tv_display
</a>
<button class="btn btn-success shadow-sm text-white" data-bs-toggle="modal" data-bs-target="#addTokenModal">
<i class="bi bi-plus-lg me-1"></i> <?php echo __('issue_token'); ?>
</button>
</div>
</div>
<!-- Filters -->
<div class="card shadow-sm border-0 mb-4">
<div class="card-body">
<form id="queueFilterForm" class="row g-3">
<div class="col-md-4">
<select id="filterDepartment" class="form-select">
<option value=""><?php echo __('all_departments'); ?></option>
<?php foreach ($departments as $dept): ?>
<option value="<?php echo $dept['id']; ?>"><?php echo $dept['name_' . $lang]; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-4">
<select id="filterStatus" class="form-select">
<option value=""><?php echo __('all_statuses'); ?></option>
<option value="waiting"><?php echo __('waiting'); ?></option>
<option value="serving"><?php echo __('serving'); ?></option>
<option value="completed"><?php echo __('completed'); ?></option>
<option value="cancelled"><?php echo __('cancelled'); ?></option>
</select>
</div>
<div class="col-md-4">
<button type="button" class="btn btn-secondary w-100" onclick="fetchQueue()"><?php echo __('refresh'); ?></button>
</div>
</form>
</div>
</div>
<!-- Queue List -->
<div class="row" id="queueContainer">
<!-- Queue cards/table will be injected here -->
</div>
<!-- Add Token Modal -->
<div class="modal fade" id="addTokenModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?php echo __('issue_new_token'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="addTokenForm">
<div class="mb-3">
<label for="tokenPatient" class="form-label"><?php echo __('patient'); ?></label>
<select class="form-select" id="tokenPatient" required>
<option value=""><?php echo __('select_patient'); ?></option>
<?php foreach ($patients as $p): ?>
<option value="<?php echo $p['id']; ?>"><?php echo $p['name']; ?> (<?php echo $p['phone']; ?>)</option>
<?php endforeach; ?>
</select>
<div class="form-text text-muted"><?php echo __('showing_last_50_patients'); ?></div>
</div>
<div class="mb-3">
<label for="tokenDepartment" class="form-label"><?php echo __('department'); ?></label>
<select class="form-select" id="tokenDepartment" required>
<option value=""><?php echo __('select_department'); ?></option>
<?php foreach ($departments as $dept): ?>
<option value="<?php echo $dept['id']; ?>"><?php echo $dept['name_' . $lang]; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label for="tokenDoctor" class="form-label"><?php echo __('doctor_optional'); ?></label>
<select class="form-select" id="tokenDoctor">
<option value=""><?php echo __('any_doctor'); ?></option>
<?php foreach ($doctors as $doc): ?>
<option value="<?php echo $doc['id']; ?>" data-dept="<?php echo $doc['department_id']; ?>"><?php echo $doc['name_' . $lang]; ?></option>
<?php endforeach; ?>
</select>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
<button type="button" class="btn btn-primary" onclick="issueToken()"><?php echo __('issue_token'); ?></button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
fetchQueue();
// Doctor filter logic based on department
document.getElementById('tokenDepartment').addEventListener('change', function() {
const deptId = this.value;
const doctorSelect = document.getElementById('tokenDoctor');
const options = doctorSelect.querySelectorAll('option');
options.forEach(opt => {
if (!opt.value) return; // Skip default
if (deptId && opt.getAttribute('data-dept') !== deptId) {
opt.style.display = 'none';
} else {
opt.style.display = 'block';
}
});
doctorSelect.value = '';
});
// Auto refresh every 30 seconds
setInterval(fetchQueue, 30000);
});
function fetchQueue() {
const deptId = document.getElementById('filterDepartment').value;
const status = document.getElementById('filterStatus').value;
let url = 'api/queue.php?action=list&lang=<?php echo $lang; ?>';
if (deptId) url += '&department_id=' + deptId;
if (status) url += '&status=' + status;
fetch(url)
.then(response => response.json())
.then(data => {
if (data.success) {
renderQueue(data.data);
}
});
}
function renderQueue(queue) {
const container = document.getElementById('queueContainer');
if (!queue.length) {
container.innerHTML = '<div class="col-12 text-center text-muted py-5"><?php echo __('no_tokens_found'); ?></div>';
return;
}
let html = '<div class="col-12"><div class="table-responsive"><table class="table table-hover align-middle">';
html += '<thead class="table-light"><tr><th><?php echo __('token'); ?></th><th><?php echo __('patient'); ?></th><th><?php echo __('department'); ?></th><th><?php echo __('doctor'); ?></th><th><?php echo __('status'); ?></th><th><?php echo __('wait_time'); ?></th><th class="text-end"><?php echo __('actions'); ?></th></tr></thead><tbody>';
queue.forEach(q => {
let statusBadge = '';
switch(q.status) {
case 'waiting': statusBadge = '<span class="badge bg-warning text-dark"><?php echo __('waiting'); ?></span>'; break;
case 'serving': statusBadge = '<span class="badge bg-success"><?php echo __('serving'); ?></span>'; break;
case 'completed': statusBadge = '<span class="badge bg-secondary"><?php echo __('completed'); ?></span>'; break;
case 'cancelled': statusBadge = '<span class="badge bg-danger"><?php echo __('cancelled'); ?></span>'; break;
}
// Calculate wait time
const created = new Date(q.created_at);
const now = new Date();
const diffMs = now - created;
const diffMins = Math.floor(diffMs / 60000);
const waitTime = diffMins + ' min';
html += `<tr>
<td class="fw-bold fs-5">#${q.token_number}</td>
<td>${q.patient_name}</td>
<td>${q.department_name}</td>
<td>${q.doctor_name || '-'}</td>
<td>${statusBadge}</td>
<td><small class="text-muted">${waitTime}</small></td>
<td class="text-end">
${getActionButtons(q)}
</td>
</tr>`;
});
html += '</tbody></table></div></div>';
container.innerHTML = html;
}
function getActionButtons(q) {
let btns = '';
if (q.status === 'waiting') {
btns += `<button class="btn btn-sm btn-success me-1" onclick="updateStatus(${q.id}, 'serving')"><i class="bi bi-megaphone"></i> <?php echo __('call'); ?></button>`;
btns += `<button class="btn btn-sm btn-danger" onclick="updateStatus(${q.id}, 'cancelled')"><i class="bi bi-x-circle"></i></button>`;
} else if (q.status === 'serving') {
btns += `<button class="btn btn-sm btn-primary me-1" onclick="updateStatus(${q.id}, 'completed')"><i class="bi bi-check-circle"></i> <?php echo __('finish'); ?></button>`;
}
return btns;
}
function updateStatus(id, status) {
const formData = new FormData();
formData.append('queue_id', id);
formData.append('status', status);
// Pass current doctor ID if logged in (assuming stored in session/global JS var, but for now we won't strictly enforce it on frontend, API handles logic)
// Ideally we should pass 'doctor_id' if the user is a doctor claiming the token.
fetch('api/queue.php?action=update_status', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(data => {
if (data.success) {
fetchQueue();
} else {
alert('Error: ' + data.error);
}
});
}
function issueToken() {
const patientId = document.getElementById('tokenPatient').value;
const deptId = document.getElementById('tokenDepartment').value;
const docId = document.getElementById('tokenDoctor').value;
if (!patientId || !deptId) {
alert('Please select patient and department');
return;
}
const formData = new FormData();
formData.append('patient_id', patientId);
formData.append('department_id', deptId);
if (docId) formData.append('doctor_id', docId);
fetch('api/queue.php?action=add', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(data => {
if (data.success) {
const modal = bootstrap.Modal.getInstance(document.getElementById('addTokenModal'));
modal.hide();
fetchQueue();
// Show print dialog or small notification
alert('Token Generated: #' + data.token_number);
} else {
alert('Error: ' + data.error);
}
});
}
</script>